Merge pull request #7 from asaadmahmoodspin/mm-316

MM-316
Этот коммит содержится в:
Reed Garmsen
2015-08-13 12:03:45 -07:00
родитель 6d9e715e26 6ca6072f47
Коммит afe028ae3a
14 изменённых файлов: 327 добавлений и 36 удалений

Просмотреть файл

@@ -222,7 +222,9 @@ module.exports = React.createClass({
getFileCount={this.getFileCount}
onUploadStart={this.handleUploadStart}
onFileUpload={this.handleFileUploadComplete}
onUploadError={this.handleUploadError} />
onUploadError={this.handleUploadError}
postType='comment'
channelId={this.props.channelId} />
</div>
<MsgTyping channelId={this.props.channelId} parentId={this.props.rootId} />
<div className={postFooterClassName}>

Просмотреть файл

@@ -262,7 +262,9 @@ module.exports = React.createClass({
getFileCount={this.getFileCount}
onUploadStart={this.handleUploadStart}
onFileUpload={this.handleFileUploadComplete}
onUploadError={this.handleUploadError} />
onUploadError={this.handleUploadError}
postType='post'
channelId='' />
</div>
<div className={postFooterClassName}>
{postError}

Просмотреть файл

@@ -21,7 +21,7 @@ module.exports = React.createClass({
var element = $(this.refs.fileInput.getDOMNode());
var files = element.prop('files');
var channelId = ChannelStore.getCurrentId();
var channelId = this.props.channelId || ChannelStore.getCurrentId();
this.props.onUploadError(null);
@@ -87,10 +87,101 @@ module.exports = React.createClass({
}
} catch(e) {}
},
handleDrop: function(e) {
this.props.onUploadError(null);
var files = e.originalEvent.dataTransfer.files;
if (!files.length) {
files = e.originalEvent.dataTransfer.getData('URL');
}
var channelId = this.props.channelId || ChannelStore.getCurrentId();
if (typeof files !== 'string' && files.length) {
var numFiles = files.length;
var numToUpload = Math.min(Constants.MAX_UPLOAD_FILES - this.props.getFileCount(channelId), numFiles);
if (numFiles > numToUpload) {
this.props.onUploadError('Uploads limited to ' + Constants.MAX_UPLOAD_FILES + ' files maximum. Please use additional posts for more files.');
}
for (var i = 0; i < files.length && i < numToUpload; i++) {
if (files[i].size > Constants.MAX_FILE_SIZE) {
this.props.onUploadError('Files must be no more than ' + Constants.MAX_FILE_SIZE / 1000000 + ' MB');
continue;
}
// generate a unique id that can be used by other components to refer back to this file upload
var clientId = utils.generateId();
// Prepare data to be uploaded.
var formData = new FormData();
formData.append('channel_id', channelId);
formData.append('files', files[i], files[i].name);
formData.append('client_ids', clientId);
var request = client.uploadFile(formData,
function(data) {
var parsedData = $.parseJSON(data);
this.props.onFileUpload(parsedData['filenames'], parsedData['client_ids'], channelId);
var requests = this.state.requests;
for (var i = 0; i < parsedData['client_ids'].length; i++) {
delete requests[parsedData['client_ids'][i]];
}
this.setState({requests: requests});
}.bind(this),
function(err) {
this.props.onUploadError(err, clientId);
}.bind(this)
);
var requests = this.state.requests;
requests[clientId] = request;
this.setState({requests: requests});
this.props.onUploadStart([clientId], channelId);
}
}
},
componentDidMount: function() {
var inputDiv = this.refs.input.getDOMNode();
var self = this;
if (this.props.postType === 'post') {
$('.app__content').dragster({
enter: function(dragsterEvent, e) {
$('.center-file-overlay').removeClass('invisible');
$('.center-file-overlay').addClass('visible');
},
leave: function(dragsterEvent, e) {
$('.center-file-overlay').removeClass('visible');
$('.center-file-overlay').addClass('invisible');
},
drop: function(dragsterEvent, e) {
$('.center-file-overlay').removeClass('visible');
$('.center-file-overlay').addClass('invisible');
self.handleDrop(e);
}
});
} else if (this.props.postType === 'comment') {
$('.post-right__container').dragster({
enter: function(dragsterEvent, e) {
$('.right-file-overlay').removeClass('invisible');
$('.right-file-overlay').addClass('visible');
},
leave: function(dragsterEvent, e) {
$('.right-file-overlay').removeClass('visible');
$('.right-file-overlay').addClass('invisible');
},
drop: function(dragsterEvent, e) {
$('.right-file-overlay').removeClass('visible');
$('.right-file-overlay').addClass('invisible');
self.handleDrop(e);
}
});
}
document.addEventListener('paste', function(e) {
var textarea = $(inputDiv.parentNode.parentNode).find('.custom-textarea')[0];
@@ -133,14 +224,13 @@ module.exports = React.createClass({
continue;
}
var channelId = ChannelStore.getCurrentId();
var channelId = this.props.channelId || ChannelStore.getCurrentId();
// generate a unique id that can be used by other components to refer back to this file upload
var clientId = utils.generateId();
var formData = new FormData();
formData.append('channel_id', channelId);
var d = new Date();
var hour;
if (d.getHours() < 10) {

Просмотреть файл

@@ -463,11 +463,19 @@ module.exports = React.createClass({
}
return (
<div ref="postlist" className="post-list-holder-by-time">
<div className="post-list__table">
<div className="post-list__content">
{ more_messages }
{ postCtls }
<div>
<div className='file-overlay center-file-overlay invisible'>
<div>
<i className="fa fa-upload"></i>
<span>Drop a file to upload it.</span>
</div>
</div>
<div ref="postlist" className="post-list-holder-by-time">
<div className="post-list__table">
<div className="post-list__content">
{ more_messages }
{ postCtls }
</div>
</div>
</div>
</div>

Просмотреть файл

@@ -296,6 +296,12 @@ module.exports = React.createClass({
return (
<div className="post-right__container">
<div className='file-overlay right-file-overlay invisible'>
<div>
<i className="fa fa-upload"></i>
<span>Drop a file to upload it.</span>
</div>
</div>
<div className="search-bar__container sidebar--right__search-header">{searchForm}</div>
<div className="sidebar-right__body">
<RhsHeaderPost fromSearch={this.props.fromSearch} isMentionSearch={this.props.isMentionSearch} />

Просмотреть файл

@@ -6,6 +6,13 @@ var utils = require('../utils/utils.jsx');
module.exports = React.createClass({
displayName: 'ViewImageModal',
propTypes: {
filenames: React.PropTypes.array,
modalId: React.PropTypes.string,
channelId: React.PropTypes.string,
userId: React.PropTypes.string,
startId: React.PropTypes.number
},
canSetState: false,
handleNext: function() {
var id = this.state.imgId + 1;
@@ -56,8 +63,8 @@ module.exports = React.createClass({
progress[id] = img.completedPercentage;
self.setState({progress: progress});
});
img.onload = function(imgid) {
return function() {
img.onload = function onload(imgid) {
return function onloadReturn() {
var loaded = self.state.loaded;
loaded[imgid] = true;
self.setState({loaded: loaded});
@@ -83,21 +90,21 @@ module.exports = React.createClass({
},
componentDidMount: function() {
var self = this;
$('#' + this.props.modalId).on('shown.bs.modal', function() {
$('#' + this.props.modalId).on('shown.bs.modal', function onModalShow() {
self.setState({viewed: true});
self.loadImage(self.state.imgId);
});
$(this.refs.modal.getDOMNode()).click(function(e) {
$(this.refs.modal.getDOMNode()).click(function onModalClick(e) {
if (e.target === this || e.target === self.refs.imageBody.getDOMNode()) {
$('.image_modal').modal('hide');
}
});
$(this.refs.imageWrap.getDOMNode()).hover(
function() {
function onModalHover() {
$(self.refs.imageFooter.getDOMNode()).addClass('footer--show');
}, function() {
}, function offModalHover() {
$(self.refs.imageFooter.getDOMNode()).removeClass('footer--show');
}
);
@@ -117,10 +124,14 @@ module.exports = React.createClass({
data.user_id = this.props.userId;
data.filename = this.props.filenames[this.state.imgId];
Client.getPublicLink(data,
function(serverData) {
window.open(serverData.public_link);
function sucess(serverData) {
if (utils.isMobile()) {
window.location.href = serverData.public_link;
} else {
window.open(serverData.public_link);
}
},
function() {
function error() {
}
);
},
@@ -145,7 +156,7 @@ module.exports = React.createClass({
getInitialState: function() {
var loaded = [];
var progress = [];
for (var i = 0; i < this.props.filenames.length; i ++) {
for (var i = 0; i < this.props.filenames.length; i++) {
loaded.push(false);
progress.push(0);
}
@@ -198,7 +209,7 @@ module.exports = React.createClass({
if (!(filename in this.state.fileSizes)) {
var self = this;
utils.getFileSize(utils.getFileUrl(filename), function(fileSize) {
utils.getFileSize(utils.getFileUrl(filename), function fileSizeOp(fileSize) {
if (self.canSetState) {
var fileSizes = self.state.fileSizes;
fileSizes[filename] = fileSize;
@@ -210,14 +221,20 @@ module.exports = React.createClass({
} else {
// display a progress indicator when the preview for an image is still loading
var percentage = Math.floor(this.state.progress[this.state.imgId]);
content = (
<div>
<img className='loader-image' src='/static/images/load.gif' />
{ percentage > 0 ?
<span className='loader-percent' >{'Previewing ' + percentage + '%'}</span>
: ''}
</div>
);
if (percentage) {
content = (
<div>
<img className='loader-image' src='/static/images/load.gif' />
<span className='loader-percent' >{'Previewing ' + percentage + '%'}</span>
</div>
);
} else {
content = (
<div>
<img className='loader-image' src='/static/images/load.gif' />
</div>
);
}
bgClass = 'black-bg';
}

Просмотреть файл

@@ -24,6 +24,7 @@ body {
height: 100%;
> .row.main {
height: 100%;
position: relative;
}
}
> .container-fluid {

Просмотреть файл

@@ -194,11 +194,12 @@
border-right: 1px solid #ddd;
vertical-align: center;
// helper to center the image icon in the preview window
.file-details__preview-helper {
height: 100%;
display: inline-block;
vertical-align: middle;
}
}
// helper to center the image icon in the preview window
.file-details__preview-helper {
height: 100%;
display: inline-block;
vertical-align: middle;
}
}
}

Просмотреть файл

@@ -106,6 +106,39 @@ body.ios {
}
}
.file-overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.6);
text-align: center;
color: #FFF;
display: table;
font-size: 1.7em;
font-weight: 600;
z-index: 6;
> div {
display: table-cell;
vertical-align: middle;
}
.fa {
display: block;
font-size: 2em;
margin: 0 0 0.3em;
}
.invisible {
visibility: hidden;
}
.visible {
visibility: visible;
}
}
#post-list {
.post-list-holder-by-time {
background: #fff;

Просмотреть файл

@@ -189,6 +189,9 @@
}
@media screen and (max-width: 960px) {
.center-file-overlay {
font-size: 1.5em;
}
.post {
.post-header .post-header-col.post-header__reply {
.comment-icon__container__hide {
@@ -240,6 +243,9 @@
}
}
@media screen and (max-width: 768px) {
.center-file-overlay {
font-size: 1.3em;
}
.date-separator, .new-separator {
&.hovered--after {
&:before {

21
web/static/js/jquery-dragster/LICENSE Обычный файл
Просмотреть файл

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Jan Martin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

17
web/static/js/jquery-dragster/README.md Обычный файл
Просмотреть файл

@@ -0,0 +1,17 @@
Include [jquery.dragster.js](https://rawgithub.com/catmanjan/jquery-dragster/master/jquery.dragster.js) in page.
Works in IE.
```javascript
$('.element').dragster({
enter: function (dragsterEvent, event) {
$(this).addClass('hover');
},
leave: function (dragsterEvent, event) {
$(this).removeClass('hover');
},
drop: function (dragsterEvent, event) {
$(this).removeClass('hover');
}
});
```

Просмотреть файл

@@ -0,0 +1,85 @@
// 1.0.3
/*
The MIT License (MIT)
Copyright (c) 2015 Jan Martin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
(function ($) {
$.fn.dragster = function (options) {
var settings = $.extend({
enter: $.noop,
leave: $.noop,
over: $.noop,
drop: $.noop
}, options);
return this.each(function () {
var first = false,
second = false,
$this = $(this);
$this.on({
dragenter: function (event) {
if (first) {
second = true;
return;
} else {
first = true;
$this.trigger('dragster:enter', event);
}
event.preventDefault();
},
dragleave: function (event) {
if (second) {
second = false;
} else if (first) {
first = false;
}
if (!first && !second) {
$this.trigger('dragster:leave', event);
}
event.preventDefault();
},
dragover: function (event) {
$this.trigger('dragster:over', event);
event.preventDefault();
},
drop: function (event) {
if (second) {
second = false;
} else if (first) {
first = false;
}
if (!first && !second) {
$this.trigger('dragster:drop', event);
}
event.preventDefault();
},
'dragster:enter': settings.enter,
'dragster:leave': settings.leave,
'dragster:over': settings.over,
'dragster:drop': settings.drop
});
});
};
}(jQuery));

Просмотреть файл

@@ -32,6 +32,8 @@
<script src="/static/js/perfect-scrollbar-0.6.3.jquery.js"></script>
<script src="/static/js/jquery-dragster/jquery.dragster.js"></script>
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1','packages':['annotationchart']}]}"></script>
<script type="text/javascript" src="https://cloudfront.loggly.com/js/loggly.tracker.js" async></script>