mirror of
				https://github.com/mickael-kerjean/filestash.git
				synced 2025-10-31 18:16:00 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			180 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			180 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| import React from 'react';
 | |
| import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
 | |
| 
 | |
| import { NgIf, Icon } from './';
 | |
| import { notify } from '../helpers/';
 | |
| import './notification.scss';
 | |
| 
 | |
| export class Notification extends React.Component {
 | |
|     constructor(props){
 | |
|         super(props);
 | |
|         this.state = {
 | |
|             appear: false,
 | |
|             message_text: null,
 | |
|             message_type: null
 | |
|         };
 | |
|         this.runner = new TaskManager();
 | |
|         this.notification_current = null;
 | |
|         this.notification_is_first = null;
 | |
|         this.notification_is_last = null;
 | |
|     }
 | |
| 
 | |
|     componentDidMount(){
 | |
|         this.runner.before_run((task, isFirst, isLast) => {
 | |
|             this.notification_current = task;
 | |
|         });
 | |
| 
 | |
|         notify.subscribe((message, type) => {
 | |
|             this.runner.addTask(Task(
 | |
|                 this.openNotification.bind(this, {text: stringify(message), type: type}),
 | |
|                 this.closeNotification.bind(this),
 | |
|                 8000,
 | |
|                 500
 | |
|             ));
 | |
|         });
 | |
| 
 | |
|         function stringify(data){
 | |
|             if(typeof data === 'object' && data.message){
 | |
|                 return data.message;
 | |
|             }else if(typeof data === 'string'){
 | |
|                 return data;
 | |
|             }
 | |
|             return JSON.stringify(data);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     closeNotification(){
 | |
|         return new Promise((done ,err) => {
 | |
|             this.setState({
 | |
|                 appear: false
 | |
|             }, done);
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     openNotification(message){
 | |
|         return new Promise((done ,err) => {
 | |
|             this.setState({
 | |
|                 appear: true,
 | |
|                 message_text: message.text,
 | |
|                 message_type: message.type
 | |
|             }, done);
 | |
|         });
 | |
|     }
 | |
| 
 | |
|     cancelAnimation(){
 | |
|         return this.notification_current.cancel();
 | |
|     }
 | |
| 
 | |
|     render(){
 | |
|         return (
 | |
|             <ReactCSSTransitionGroup transitionName="notification" transitionLeave={true} transitionLeaveTimeout={200} transitionEnter={true} transitionEnterTimeout={100} transitionAppear={false} className="component_notification">
 | |
|               <NgIf key={this.state.message_text+this.state.message_type+this.state.appear} cond={this.state.appear === true} className="no-select">
 | |
|                 <div className={"component_notification--container "+(this.state.message_type || 'info')}>
 | |
|                   <div className="message">
 | |
|                     { this.state.message_text }
 | |
|                   </div>
 | |
|                   <div className="close" onClick={this.cancelAnimation.bind(this)}>
 | |
|                     <Icon name="close" />
 | |
|                   </div>
 | |
|                 </div>
 | |
|               </NgIf>
 | |
|             </ReactCSSTransitionGroup>
 | |
|         );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| function TaskManager(){
 | |
|     let tasks = [];
 | |
|     let is_running = false;
 | |
|     let subscriber = null;
 | |
|     let current_task = null;
 | |
|     let is_first = null;
 | |
|     let is_last = null;
 | |
| 
 | |
|     const ret ={
 | |
|         addTask: function(task){
 | |
|             current_task && current_task.cancel();
 | |
|             tasks.push(task);
 | |
|             if(tasks.length > 20){
 | |
|                 tasks.splice(0, tasks.length - 10);
 | |
|             }
 | |
|             if(is_running === false){
 | |
|                 is_running = true;
 | |
|                 ret._run();
 | |
|             }
 | |
|         },
 | |
|         before_run: function(fn){
 | |
|             subscriber = fn;
 | |
|         },
 | |
|         _run: function(){
 | |
|             current_task = tasks.shift();
 | |
|             is_last = tasks.length === 0;
 | |
|             if(!current_task){
 | |
|                 is_running = false;
 | |
|                 return Promise.resolve();
 | |
|             }else{
 | |
|                 const mode = tasks.length > 0 ? 'minimal' : 'normal';
 | |
|                 subscriber(current_task, mode);
 | |
|                 return current_task.run(mode).then(ret._run);
 | |
|             }
 | |
|         }
 | |
|     };
 | |
|     return ret;
 | |
| }
 | |
| 
 | |
| function Task(_runCallback, _finishCallback, wait_time_before_finish, minimum_running_time){
 | |
|     let start_date = null;
 | |
|     let done = null;
 | |
|     let promise = new Promise((_done) => { done = _done; });
 | |
|     let timeout = null;
 | |
| 
 | |
|     const ret = {
 | |
|         run: function(mode = 'normal'){
 | |
|             const wait = mode === 'minimal' ? minimum_running_time : wait_time_before_finish;
 | |
|             start_date = new Date();
 | |
| 
 | |
|             new Promise((_done, err) => {
 | |
|                 timeout = window.setTimeout(() => {
 | |
|                     _done();
 | |
|                 }, 200);
 | |
|             })
 | |
|                 .then(_runCallback)
 | |
|                 .then(() => new Promise((_done, err) => {
 | |
|                     timeout = window.setTimeout(() => {
 | |
|                         _done();
 | |
|                     }, wait);
 | |
|                 }))
 | |
|                 .then(() => {
 | |
|                     ret._complete();
 | |
|                 });
 | |
|             return promise;
 | |
|         },
 | |
|         cancel: function(){
 | |
|             window.clearTimeout(timeout);
 | |
|             timeout = null;
 | |
|             let elapsed_time = new Date() - start_date;
 | |
| 
 | |
|             if(elapsed_time < minimum_running_time){
 | |
|                 window.setTimeout(() => {
 | |
|                     ret._complete();
 | |
|                 }, minimum_running_time - elapsed_time);
 | |
|             }else{
 | |
|                 ret._complete();
 | |
|             }
 | |
|             return promise;
 | |
|         },
 | |
|         _complete: function(){
 | |
|             if(done){
 | |
|                 _finishCallback();
 | |
|                 done();
 | |
|             }
 | |
|             done = null;
 | |
|             return Promise.resolve();
 | |
|         }
 | |
|     };
 | |
|     return ret;
 | |
| }
 | 
