Edition via drag & drop des items

This commit is contained in:
2015-09-11 16:25:45 +02:00
parent 06c809a114
commit 1136b693fd
26 changed files with 665 additions and 67 deletions

View File

@ -11,7 +11,7 @@ module.exports = React.createClass({
mixins: [LazyLoad],
getInitialState: function() {
return { icon: DEFAULT_ICON, currentTheme: undefined };
return { icon: DEFAULT_ICON, currentTheme: '' };
},
onInViewport: function() {
@ -23,7 +23,7 @@ module.exports = React.createClass({
var currentTheme = this.state.currentTheme;
var newTheme = this.props.theme;
if( !this.isInViewport() || newTheme === currentTheme ) return;
if( !this.isInViewport() || newTheme === currentTheme ) return;
this.setState({ icon: LOADING_ICON, currentTheme: newTheme });

View File

@ -1,8 +1,9 @@
var React = require('react');
var Util = require('../../util');
var AppIcon = require('../common/app-icon.jsx');
var DragSource = require('react-dnd').DragSource;
module.exports = React.createClass({
var DesktopAppItem = React.createClass({
render: function() {
@ -11,8 +12,10 @@ module.exports = React.createClass({
var category = desktopEntry.Categories;
var icon = desktopEntry.Icon;
return (
<li className="desktop-app">
var connectDragSource = this.props.connectDragSource;
return connectDragSource(
<li className="desktop-app list-group-item">
<AppIcon className="desktop-app-icon" icon={icon} theme={this.props.theme} />
<span className="desktop-app-label">{label}</span>
</li>
@ -21,3 +24,32 @@ module.exports = React.createClass({
}
});
var dragSourceSpec = {
beginDrag: function(props) {
return props;
},
endDrag: function(props, monitor) {
if (!monitor.didDrop()) {
return;
}
var dropResult = monitor.getDropResult();
return props.onItemDropped(props.desktopEntry, dropResult);
}
};
function dragSourceCollect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
}
module.exports = DragSource('NEW_ITEM', dragSourceSpec, dragSourceCollect)(DesktopAppItem);

View File

@ -1,39 +1,33 @@
var React = require('react');
var Util = require('../../util');
var DesktopAppItem = require('./desktop-app-item.jsx');
var IconThemeSelector = require('./icon-theme-selector.jsx');
var path = require('path');
var debug = require('debug')('pitaya:desktop-app-list');
var debug = require('../../util/debug')('pitaya:desktop-app-list');
module.exports = React.createClass({
getInitialState: function() {
return {
selectedTheme: null
};
},
var DesktopAppList = React.createClass({
render: function() {
var items = this.props.desktopApps.map(function(desktopApp, i) {
var desktopEntry = desktopApp.content['Desktop Entry'];
return <DesktopAppItem theme={this.state.selectedTheme} key={desktopApp.path} desktopEntry={desktopEntry} />;
return (
<DesktopAppItem theme={this.props.selectedTheme}
key={desktopApp.path}
desktopEntry={desktopEntry}
onItemDropped={this.props.onItemDropped} />
);
}.bind(this));
return (
<div>
<IconThemeSelector onThemeSelected={this.onThemeSelected} />
<ul className="desktop-apps">
<div className="apps-list">
<ul className="desktop-apps list-group">
{items}
</ul>
</div>
);
},
onThemeSelected: function(theme) {
console.log('Selected theme %s', theme);
this.setState({ selectedTheme: theme });
}
});
module.exports = DesktopAppList;

View File

@ -1,7 +1,13 @@
var React = require('react');
var connect = require('react-redux').connect;
var ProfileTree = require('./profile-tree.jsx');
var DesktopAppList = require('./desktop-app-list.jsx');
var actions = require('../../actions');
var ItemForm = require('./item-form.jsx');
var IconThemeSelector = require('./icon-theme-selector.jsx');
var actions = require('../../store/actions');
var DragDropContext = require('react-dnd').DragDropContext;
var HTML5Backend = require('react-dnd/modules/backends/HTML5');
var EditView = React.createClass({
@ -13,18 +19,49 @@ var EditView = React.createClass({
return (
<div className="edit">
<DesktopAppList desktopApps={this.props.desktopApps} />
<div className="menu-bar">
</div>
<div className="workspace">
<div className="left-menu">
<IconThemeSelector onThemeSelected={this.onThemeSelected} />
<DesktopAppList
theme={this.props.theme}
desktopApps={this.props.desktopApps}
onItemDropped={this.onItemDropped} />
</div>
<ProfileTree />
<ItemForm />
</div>
</div>
);
},
onItemDropped: function(desktopEntry, targetItem) {
var newProfileItem = {
label: desktopEntry.Name,
icon: desktopEntry.Icon,
exec: desktopEntry.Exec
};
this.props.dispatch(actions.edit.addProfileItem(newProfileItem, targetItem));
},
onThemeSelected: function(theme) {
this.props.dispatch(actions.edit.selectTheme(theme));
}
});
function select(state) {
return {
desktopApps: state.desktopApps
desktopApps: state.desktopApps,
profile: state.profile,
theme: state.theme
};
}
module.exports = connect(select)(EditView);
module.exports = DragDropContext(HTML5Backend)(connect(select)(EditView));

View File

@ -39,9 +39,11 @@ module.exports = React.createClass({
);
return (
<select value={selectedTheme} onChange={this.onChange}>
{options}
</select>
<div className="icon-theme-selector">
<select className="form-control" value={selectedTheme} onChange={this.onChange}>
{options}
</select>
</div>
);
}

View File

@ -0,0 +1,16 @@
var React = require('react');
var ItemForm = React.createClass({
render: function() {
return (
<div className="item-form">
</div>
);
}
});
module.exports = ItemForm;

View File

@ -0,0 +1,67 @@
var React = require('react');
var connect = require('react-redux').connect;
var actions = require('../../store/actions');
var TreeItem = require('./tree-item.jsx');
var TreeNode = React.createClass({
render: function() {
var data = this.props.data || {};
var subItems = data.items || [];
var listElements = subItems.map(function(subItem, i) {
return (
<li key={i} >
<TreeNode data={subItem} onItemMoved={this.props.onItemMoved} />
</li>
);
}.bind(this));
var appEntry = data.icon || data.label ?
<TreeItem data={data} onItemMoved={this.props.onItemMoved} /> :
null
;
return (
<div className="tree-item">
{appEntry}
<ul>
{listElements}
</ul>
</div>
);
}
});
var ProfileTree = React.createClass({
componentDidMount: function() {
this.props.dispatch(actions.launcher.loadProfile('./default-profile.json'));
},
render: function() {
return (
<div className="profile-tree">
<TreeNode data={this.props.profile} onItemMoved={this.onItemMoved} />
</div>
);
},
onItemMoved: function(movedItem, targetItem) {
this.props.dispatch(actions.edit.moveProfileItem(movedItem, targetItem));
}
});
function select(state) {
return {
profile: state.profile
};
}
module.exports = connect(select)(ProfileTree);

View File

@ -0,0 +1,86 @@
var React = require('react/addons');
var classNames = require('classnames');
var AppIcon = require('../common/app-icon.jsx');
var DragSource = require('react-dnd').DragSource;
var DropTarget = require('react-dnd').DropTarget;
var _ = require('lodash');
var TreeItem = React.createClass({
render: function() {
var data = this.props.data;
var appIcon = data.icon ? <AppIcon icon={data.icon} /> : null;
var connectDragSource = this.props.connectDragSource;
var connectDropTarget = this.props.connectDropTarget;
var classes = classNames({
'alert': true,
'alert-default': !this.props.isDragging && !this.props.isOver,
'alert-info': this.props.isDragging,
'alert-success': this.props.isOver
});
return connectDropTarget(connectDragSource(
<div className={classes}>
{appIcon}
<span className="app-label">{data.label}</span>
</div>
));
},
});
var dragSourceSpec = {
beginDrag: function(props) {
return props.data;
},
endDrag: function(props, monitor) {
if (!monitor.didDrop()) {
return;
}
var dropResult = monitor.getDropResult();
return props.onItemMoved(props.data, dropResult);
}
};
var dropTargetSpec = {
drop: function(props, monitor, component) {
return props.data;
},
canDrop: function(props, monitor) {
var draggedItem = monitor.getItem();
return !_.isEqual(draggedItem, props.data);
}
};
function dragSourceCollect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
};
}
function dropTargetCollect(connect, monitor) {
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver()
};
}
module.exports = DropTarget(['ITEM', 'NEW_ITEM'], dropTargetSpec, dropTargetCollect)(
DragSource('ITEM', dragSourceSpec, dragSourceCollect)(TreeItem)
);

View File

@ -2,7 +2,7 @@ var React = require('react');
var CategoryHeader = require('./category-header.jsx');
var AppList = require('./app-list.jsx');
var AnimateMixin = require('../mixins/animate');
var actions = require('../../actions');
var actions = require('../../store/actions');
var connect = require('react-redux').connect;
var debug = require('../../util/debug')('launcher-view');

View File

@ -46,7 +46,7 @@ module.exports = {
};
var computeComponentsVisibilityDebounced = debounce(computeComponentsVisibility, 250);
var computeComponentsVisibilityDebounced = debounce(computeComponentsVisibility, 100);
// Start listening for changes
window.document.addEventListener('scroll', computeComponentsVisibilityDebounced, true);