summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
Diffstat (limited to 'web')
-rw-r--r--web/react/components/confirm_modal.jsx31
-rw-r--r--web/react/components/create_comment.jsx2
-rw-r--r--web/react/components/create_post.jsx6
-rw-r--r--web/react/components/invite_member_modal.jsx120
-rw-r--r--web/react/components/login.jsx6
-rw-r--r--web/react/components/post_body.jsx16
-rw-r--r--web/react/components/textbox.jsx2
-rw-r--r--web/react/components/user_settings.jsx9
-rw-r--r--web/react/components/view_image.jsx2
-rw-r--r--web/react/utils/async_client.jsx2
-rw-r--r--web/react/utils/constants.jsx1
-rw-r--r--web/react/utils/utils.jsx22
-rw-r--r--web/sass-files/sass/partials/_signup.scss6
-rw-r--r--web/static/config/config.js2
-rw-r--r--web/static/help/configure_links.html22
-rw-r--r--web/static/images/ding.mp3bin25004 -> 34734 bytes
-rw-r--r--web/static/images/salamander.jpgbin17687 -> 0 bytes
-rw-r--r--web/static/images/test.pngbin1549 -> 279591 bytes
-rwxr-xr-xweb/static/images/testgif.gifbin0 -> 38689 bytes
-rwxr-xr-xweb/static/images/testjpg.jpgbin0 -> 70920 bytes
-rw-r--r--web/static/images/toothless.gifbin163454 -> 0 bytes
-rw-r--r--web/templates/signup_team.html3
22 files changed, 180 insertions, 72 deletions
diff --git a/web/react/components/confirm_modal.jsx b/web/react/components/confirm_modal.jsx
new file mode 100644
index 000000000..3be13cf9b
--- /dev/null
+++ b/web/react/components/confirm_modal.jsx
@@ -0,0 +1,31 @@
+// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+module.exports = React.createClass({
+ handleConfirm: function() {
+ $('#'+this.props.parent_id).attr('data-confirm', 'true');
+ $('#'+this.props.parent_id).modal('hide');
+ $('#'+this.props.id).modal('hide');
+ },
+ render: function() {
+ return (
+ <div className="modal fade" id={this.props.id} tabIndex="-1" role="dialog" aria-hidden="true">
+ <div className="modal-dialog">
+ <div className="modal-content">
+ <div className="modal-header">
+ <h4 className="modal-title">{this.props.title}</h4>
+ </div>
+ <div className="modal-body">
+ {this.props.message}
+ </div>
+ <div className="modal-footer">
+ <button type="button" className="btn btn-default" data-dismiss="modal">Cancel</button>
+ <button onClick={this.handleConfirm} type="button" className="btn btn-primary">{this.props.confirm_button}</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ );
+ }
+});
+
diff --git a/web/react/components/create_comment.jsx b/web/react/components/create_comment.jsx
index 9bcbad079..cb7aa371c 100644
--- a/web/react/components/create_comment.jsx
+++ b/web/react/components/create_comment.jsx
@@ -145,7 +145,7 @@ module.exports = React.createClass({
onUserInput={this.handleUserInput}
onKeyPress={this.commentMsgKeyPress}
messageText={this.state.messageText}
- createMessage="Create a comment..."
+ createMessage="Add a comment..."
initialText=""
id="reply_textbox"
ref="textbox" />
diff --git a/web/react/components/create_post.jsx b/web/react/components/create_post.jsx
index 191be9bf8..5a0b6f85f 100644
--- a/web/react/components/create_post.jsx
+++ b/web/react/components/create_post.jsx
@@ -31,9 +31,7 @@ module.exports = React.createClass({
post.message = this.state.messageText;
- var repRegex = new RegExp("<br>", "g");
- if (post.message.replace(repRegex, " ").trim().length === 0
- && this.state.previews.length === 0) {
+ if (post.message.trim().length === 0 && this.state.previews.length === 0) {
return;
}
@@ -250,7 +248,7 @@ module.exports = React.createClass({
onUserInput={this.handleUserInput}
onKeyPress={this.postMsgKeyPress}
messageText={this.state.messageText}
- createMessage="Create a post..."
+ createMessage="Write a message..."
channelId={this.state.channel_id}
id="post_textbox"
ref="textbox" />
diff --git a/web/react/components/invite_member_modal.jsx b/web/react/components/invite_member_modal.jsx
index 1d2bbed84..5980664de 100644
--- a/web/react/components/invite_member_modal.jsx
+++ b/web/react/components/invite_member_modal.jsx
@@ -4,8 +4,37 @@
var utils = require('../utils/utils.jsx');
var Client =require('../utils/client.jsx');
var UserStore = require('../stores/user_store.jsx');
+var ConfirmModal = require('./confirm_modal.jsx');
module.exports = React.createClass({
+ componentDidMount: function() {
+ var self = this;
+ $('#invite_member').on('hide.bs.modal', function(e) {
+ if ($('#invite_member').attr('data-confirm') === 'true') {
+ $('#invite_member').attr('data-confirm', 'false');
+ return;
+ }
+
+ var not_empty = false;
+ for (var i = 0; i < self.state.invite_ids.length; i++) {
+ var index = self.state.invite_ids[i];
+ if (self.refs["email"+index].getDOMNode().value.trim() !== '') {
+ not_empty = true;
+ break;
+ }
+ }
+
+ if (not_empty) {
+ $('#confirm_invite_modal').modal('show');
+ e.preventDefault();
+ }
+
+ });
+
+ $('#invite_member').on('hidden.bs.modal', function() {
+ self.clearFields();
+ });
+ },
handleSubmit: function(e) {
var invite_ids = this.state.invite_ids;
var count = invite_ids.length;
@@ -56,22 +85,8 @@ module.exports = React.createClass({
Client.inviteMembers(data,
function() {
+ $(this.refs.modal.getDOMNode()).attr('data-confirm', 'true');
$(this.refs.modal.getDOMNode()).modal('hide');
- for (var i = 0; i < invite_ids.length; i++) {
- var index = invite_ids[i];
- this.refs["email"+index].getDOMNode().value = "";
- if (config.AllowInviteNames) {
- this.refs["first_name"+index].getDOMNode().value = "";
- this.refs["last_name"+index].getDOMNode().value = "";
- }
- }
- this.setState({
- invite_ids: [0],
- id_count: 0,
- email_errors: {},
- first_name_errors: {},
- last_name_errors: {}
- });
}.bind(this),
function(err) {
this.setState({ server_error: err });
@@ -89,6 +104,26 @@ module.exports = React.createClass({
invite_ids.push(count);
this.setState({ invite_ids: invite_ids, id_count: count });
},
+ clearFields: function() {
+ var invite_ids = this.state.invite_ids;
+
+ for (var i = 0; i < invite_ids.length; i++) {
+ var index = invite_ids[i];
+ this.refs["email"+index].getDOMNode().value = "";
+ if (config.AllowInviteNames) {
+ this.refs["first_name"+index].getDOMNode().value = "";
+ this.refs["last_name"+index].getDOMNode().value = "";
+ }
+ }
+
+ this.setState({
+ invite_ids: [0],
+ id_count: 0,
+ email_errors: {},
+ first_name_errors: {},
+ last_name_errors: {}
+ });
+ },
removeInviteFields: function(index) {
var invite_ids = this.state.invite_ids;
var i = invite_ids.indexOf(index);
@@ -147,29 +182,38 @@ module.exports = React.createClass({
var server_error = this.state.server_error ? <div className='form-group has-error'><label className='control-label'>{ this.state.server_error }</label></div> : null;
return (
- <div className="modal fade" ref="modal" id="invite_member" tabIndex="-1" role="dialog" aria-hidden="true">
- <div className="modal-dialog">
- <div className="modal-content">
- <div className="modal-header">
- <button type="button" className="close" data-dismiss="modal" aria-label="Close" data-reactid=".5.0.0.0.0"><span aria-hidden="true" data-reactid=".5.0.0.0.0.0">×</span></button>
- <h4 className="modal-title" id="myModalLabel">Invite New Member</h4>
- </div>
- <div ref="modalBody" className="modal-body">
- <form role="form">
- { invite_sections }
- </form>
- { server_error }
- <button type="button" className="btn btn-default" onClick={this.addInviteFields}>Add another</button>
- <br/>
- <br/>
- <label className='control-label'>People invited automatically join Town Square channel.</label>
- </div>
- <div className="modal-footer">
- <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
- <button onClick={this.handleSubmit} type="button" className="btn btn-primary">Send Invitations</button>
- </div>
- </div>
- </div>
+ <div>
+ <div className="modal fade" ref="modal" id="invite_member" tabIndex="-1" role="dialog" aria-hidden="true">
+ <div className="modal-dialog">
+ <div className="modal-content">
+ <div className="modal-header">
+ <button type="button" className="close" data-dismiss="modal" aria-label="Close" data-reactid=".5.0.0.0.0"><span aria-hidden="true" data-reactid=".5.0.0.0.0.0">×</span></button>
+ <h4 className="modal-title" id="myModalLabel">Invite New Member</h4>
+ </div>
+ <div ref="modalBody" className="modal-body">
+ <form role="form">
+ { invite_sections }
+ </form>
+ { server_error }
+ <button type="button" className="btn btn-default" onClick={this.addInviteFields}>Add another</button>
+ <br/>
+ <br/>
+ <label className='control-label'>People invited automatically join Town Square channel.</label>
+ </div>
+ <div className="modal-footer">
+ <button type="button" className="btn btn-default" data-dismiss="modal">Close</button>
+ <button onClick={this.handleSubmit} type="button" className="btn btn-primary">Send Invitations</button>
+ </div>
+ </div>
+ </div>
+ </div>
+ <ConfirmModal
+ id="confirm_invite_modal"
+ parent_id="invite_member"
+ title="Discard Invitations?"
+ message="You have unsent invitations, are you sure you want to discard them?"
+ confirm_button="Yes, Discard"
+ />
</div>
);
} else {
diff --git a/web/react/components/login.jsx b/web/react/components/login.jsx
index 103a93bc6..65f1da1f8 100644
--- a/web/react/components/login.jsx
+++ b/web/react/components/login.jsx
@@ -52,20 +52,20 @@ var FindTeamDomain = React.createClass({
<div>
<span className="signup-team__name">{ config.SiteName }</span>
<br/>
- <span className="signup-team__subdomain">Enter your {strings.TeamPlural} domain.</span>
+ <span className="signup-team__subdomain">Enter your {strings.Team}'s domain.</span>
<br/>
<br/>
</div>
<form onSubmit={this.handleSubmit}>
<div className={server_error ? 'form-group has-error' : 'form-group'}>
{ server_error }
- <input type="text" className="form-control" name="domain" ref="domain" placeholder="teamdomain" />
+ <input type="text" className="form-control" name="domain" ref="domain" placeholder="team domain" />
</div>
<div className="form-group">
<button type="submit" className="btn btn-primary">Continue</button>
</div>
<div>
- <span>Don't remember your {strings.TeamPlural} domain? <a href="/find_team">Find it here</a></span>
+ <span>Don't remember your {strings.Team}'s domain? <a href="/find_team">Find it here</a></span>
</div>
<br/>
<br/>
diff --git a/web/react/components/post_body.jsx b/web/react/components/post_body.jsx
index 55fc32c33..3079917ec 100644
--- a/web/react/components/post_body.jsx
+++ b/web/react/components/post_body.jsx
@@ -85,20 +85,22 @@ module.exports = React.createClass({
var postFiles = [];
var images = [];
if (filenames) {
- for (var i = 0; i < filenames.length && i < Constants.MAX_DISPLAY_FILES; i++) {
+ for (var i = 0; i < filenames.length; i++) {
var fileInfo = utils.splitFileLocation(filenames[i]);
if (Object.keys(fileInfo).length === 0) continue;
var type = utils.getFileType(fileInfo.ext);
if (type === "image") {
- postFiles.push(
- <div className="post-image__column" key={filenames[i]}>
- <a href="#" onClick={this.handleImageClick} data-img-id={images.length.toString()} data-toggle="modal" data-target={"#" + postImageModalId }><div ref={filenames[i]} className="post__load" style={{backgroundImage: 'url(/static/images/load.gif)'}}></div></a>
- </div>
- );
+ if (i < Constants.MAX_DISPLAY_FILES) {
+ postFiles.push(
+ <div className="post-image__column" key={filenames[i]}>
+ <a href="#" onClick={this.handleImageClick} data-img-id={images.length.toString()} data-toggle="modal" data-target={"#" + postImageModalId }><div ref={filenames[i]} className="post__load" style={{backgroundImage: 'url(/static/images/load.gif)'}}></div></a>
+ </div>
+ );
+ }
images.push(filenames[i]);
- } else {
+ } else if (i < Constants.MAX_DISPLAY_FILES) {
postFiles.push(
<div className="post-image__column custom-file" key={fileInfo.name}>
<a href={fileInfo.path+"."+fileInfo.ext} download={fileInfo.name+"."+fileInfo.ext}>
diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx
index 45798809f..7a4762e07 100644
--- a/web/react/components/textbox.jsx
+++ b/web/react/components/textbox.jsx
@@ -204,7 +204,7 @@ module.exports = React.createClass({
// If there is a space after the last @, nothing to do.
if (lastSpace > atIndex || lastCharSpace > atIndex) {
- this.setState({ mentionText: '-1' });
+ this.updateMentionTab('-1', null);
return;
}
diff --git a/web/react/components/user_settings.jsx b/web/react/components/user_settings.jsx
index a9c2433f2..7d542a8b7 100644
--- a/web/react/components/user_settings.jsx
+++ b/web/react/components/user_settings.jsx
@@ -658,9 +658,10 @@ var SecurityTab = React.createClass({
);
} else {
var d = new Date(this.props.user.last_password_update);
- var hour = d.getHours() < 10 ? "0" + d.getHours() : String(d.getHours());
+ var hour = d.getHours() % 12 ? String(d.getHours() % 12) : "12";
var min = d.getMinutes() < 10 ? "0" + d.getMinutes() : String(d.getMinutes());
- var dateStr = "Last updated " + Constants.MONTHS[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + " at " + hour + ":" + min;
+ var timeOfDay = d.getHours() >= 12 ? " pm" : " am";
+ var dateStr = "Last updated " + Constants.MONTHS[d.getMonth()] + " " + d.getDate() + ", " + d.getFullYear() + " at " + hour + ":" + min + timeOfDay;
passwordSection = (
<SettingItemMin
@@ -1056,7 +1057,7 @@ var AppearanceTab = React.createClass({
themeSection = (
<SettingItemMax
- title="Theme"
+ title="Theme Color"
inputs={inputs}
submit={this.submitTheme}
server_error={server_error}
@@ -1066,7 +1067,7 @@ var AppearanceTab = React.createClass({
} else {
themeSection = (
<SettingItemMin
- title="Theme"
+ title="Theme Color"
describe={this.state.theme}
updateSection={function(){self.props.updateSection("theme");}}
/>
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index 4cb30e1d3..c573e9dbb 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -124,7 +124,7 @@ module.exports = React.createClass({
<div key={name+"_loading"}>
<img ref="placeholder" className="loader-image" src="/static/images/load.gif" />
{ percentage > 0 ?
- <span className="loader-percent" >{"Downloading " + percentage + "%"}</span>
+ <span className="loader-percent" >{"Previewing " + percentage + "%"}</span>
: ""}
</div>
);
diff --git a/web/react/utils/async_client.jsx b/web/react/utils/async_client.jsx
index bb7ca458f..fc8c23fd5 100644
--- a/web/react/utils/async_client.jsx
+++ b/web/react/utils/async_client.jsx
@@ -15,6 +15,8 @@ var ActionTypes = Constants.ActionTypes;
var callTracker = {};
var dispatchError = function(err, method) {
+ if (err.message === "There appears to be a problem with your internet connection") return;
+
AppDispatcher.handleServerAction({
type: ActionTypes.RECIEVED_ERROR,
err: err,
diff --git a/web/react/utils/constants.jsx b/web/react/utils/constants.jsx
index 0a3b1db3d..deb07409b 100644
--- a/web/react/utils/constants.jsx
+++ b/web/react/utils/constants.jsx
@@ -61,6 +61,7 @@ module.exports = {
"channel",
"internal",
"localhost",
+ "dockerhost",
"stag",
"post",
"cluster",
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index 244c1eab0..a5d1e8895 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -28,6 +28,9 @@ module.exports.isTestDomain = function() {
if ((/^localhost/).test(window.location.hostname))
return true;
+ if ((/^dockerhost/).test(window.location.hostname))
+ return true;
+
if ((/^test/).test(window.location.hostname))
return true;
@@ -75,8 +78,14 @@ module.exports.getDomainWithOutSub = function() {
var parts = window.location.host.split(".");
- if (parts.length == 1)
- return "localhost:8065";
+ if (parts.length == 1) {
+ if (parts[0].indexOf("dockerhost") > -1) {
+ return "dockerhost:8065";
+ }
+ else {
+ return "localhost:8065";
+ }
+ }
return parts[1] + "." + parts[2];
}
@@ -357,9 +366,6 @@ module.exports.textToJsx = function(text, options) {
if (options && options['singleline']) {
var repRegex = new RegExp("\n", "g");
text = text.replace(repRegex, " ");
- } else {
- var repRegex = new RegExp("\n", "g");
- text = text.replace(repRegex, "<br>");
}
var searchTerm = ""
@@ -383,7 +389,7 @@ module.exports.textToJsx = function(text, options) {
implicitKeywords[keywordArray[i]] = true;
}
- var lines = text.split("<br>");
+ var lines = text.split("\n");
var urlMatcher = new LinkifyIt();
for (var i = 0; i < lines.length; i++) {
var line = lines[i];
@@ -425,7 +431,7 @@ module.exports.textToJsx = function(text, options) {
} else if (trimWord.match(hashRegex)) {
var suffix = word.match(puncEndRegex);
var prefix = word.match(puncStartRegex);
- var mClass = trimWord in implicitKeywords ? mentionClass : "";
+ var mClass = trimWord in implicitKeywords || trimWord.toLowerCase() in implicitKeywords ? mentionClass : "";
if (searchTerm === trimWord.substring(1).toLowerCase() || searchTerm === trimWord.toLowerCase()) {
highlightSearchClass = " search-highlight";
@@ -433,7 +439,7 @@ module.exports.textToJsx = function(text, options) {
inner.push(<span key={word+i+z+"_span"}>{prefix}<a key={word+i+z+"_hash"} className={"theme " + mClass + highlightSearchClass} href="#" onClick={function(value) { return function() { module.exports.searchForTerm(value); } }(trimWord)}>{trimWord}</a>{suffix} </span>);
- } else if (trimWord in implicitKeywords) {
+ } else if (trimWord in implicitKeywords || trimWord.toLowerCase() in implicitKeywords) {
var suffix = word.match(puncEndRegex);
var prefix = word.match(puncStartRegex);
diff --git a/web/sass-files/sass/partials/_signup.scss b/web/sass-files/sass/partials/_signup.scss
index 11ccc0fc9..8917ebb9f 100644
--- a/web/sass-files/sass/partials/_signup.scss
+++ b/web/sass-files/sass/partials/_signup.scss
@@ -17,7 +17,7 @@
font-weight: 600;
margin-bottom: 0.5em;
letter-spacing: -0.5px;
- font-size: em(30px);
+ font-size: em(28px);
}
h3 {
font-weight: 600;
@@ -28,6 +28,10 @@
font-size: em(18px);
font-weight: 600;
margin-bottom: 1em;
+ &.text--light {
+ font-weight: 300;
+ color: #999;
+ }
}
p {
color: #555;
diff --git a/web/static/config/config.js b/web/static/config/config.js
index 5a12942c8..82d4bbf70 100644
--- a/web/static/config/config.js
+++ b/web/static/config/config.js
@@ -35,4 +35,4 @@ var strings = {
TeamPlural: "teams",
Company: "company",
CompanyPlural: "companies"
-}
+};
diff --git a/web/static/help/configure_links.html b/web/static/help/configure_links.html
index 61e64a3b9..be6490192 100644
--- a/web/static/help/configure_links.html
+++ b/web/static/help/configure_links.html
@@ -1,5 +1,23 @@
<htmL>
<body>
-<p>update these to your own</p>
+<h1>About Mattermost</h1>
+<p>Mattermost is a team communication service. It brings team real-time messaging and file sharing into one place, with easy archiving and search, accessible across PCs and phones.
+</p>
+<p>We built Mattermost to help teams focus on what matters most to them. It works for us, we hope it works for you too.
+
+Learn more, or download the source code from <a href=http://mattermost.com>http://mattermost.com</a>.</p>
+
+<h1>How to update this link</h1>
+<p>In the source code, search for "config.js" and update the links pointing to this page to whatever policies and product description you prefer.
+</p>
+
+<h1>Join the community</h1>
+<p>To take part in the community building Mattermost, please consider sharing comments, feature requests, votes, and contributions. If you like the project, please Tweet about us at <a href=https://twitter.com/mattermosthq>@mattermosthq</a>.</p>
+
+<p>Here's some links to get started:<br>
+<li><a href=http://bit.ly/1dHmQqX>Mattermost source code and install instructions</a></li>
+<li><a href=http://bit.ly/1JUDoZ3>Mattermost Feature Request and Voting Site</a> </li>
+<li><a href=http://bit.ly/1MH9HKa>Mattermost Issue Tracker for reporting bugs</a></li>
+</p>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/web/static/images/ding.mp3 b/web/static/images/ding.mp3
index b08407e03..bfbd9bb82 100644
--- a/web/static/images/ding.mp3
+++ b/web/static/images/ding.mp3
Binary files differ
diff --git a/web/static/images/salamander.jpg b/web/static/images/salamander.jpg
deleted file mode 100644
index e841b12d5..000000000
--- a/web/static/images/salamander.jpg
+++ /dev/null
Binary files differ
diff --git a/web/static/images/test.png b/web/static/images/test.png
index 7d95d80e5..d8a9513d8 100644
--- a/web/static/images/test.png
+++ b/web/static/images/test.png
Binary files differ
diff --git a/web/static/images/testgif.gif b/web/static/images/testgif.gif
new file mode 100755
index 000000000..83d5eed72
--- /dev/null
+++ b/web/static/images/testgif.gif
Binary files differ
diff --git a/web/static/images/testjpg.jpg b/web/static/images/testjpg.jpg
new file mode 100755
index 000000000..025c8c581
--- /dev/null
+++ b/web/static/images/testjpg.jpg
Binary files differ
diff --git a/web/static/images/toothless.gif b/web/static/images/toothless.gif
deleted file mode 100644
index 8c269c131..000000000
--- a/web/static/images/toothless.gif
+++ /dev/null
Binary files differ
diff --git a/web/templates/signup_team.html b/web/templates/signup_team.html
index e2b9bc1ad..f7e277340 100644
--- a/web/templates/signup_team.html
+++ b/web/templates/signup_team.html
@@ -8,7 +8,8 @@
<div class="col-sm-12">
<div class="signup-team__container">
<img class="signup-team-logo" src="/static/images/logo.png" />
- <h4>{{ .SiteName }} is free for an unlimited time, for unlimited users. </h4>
+ <h2>All team communication in one place, searchable and accessible anywhere</h2>
+ <h4 class="text--light">{{ .SiteName }} is free for an unlimited time, for unlimited users </h4 class="text--light">
<div id="signup-team"></div>
<a class="signup-team-login" href="/login">or Sign In</a>
</div>