Skip to content

Commit eee39dd

Browse files
committed
Initial work on iconview (#51)
1 parent decee2a commit eee39dd

File tree

4 files changed

+270
-2
lines changed

4 files changed

+270
-2
lines changed

index.scss

+1
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@
3434
@import "./src/styles/notifications";
3535
@import "./src/styles/login";
3636
@import "./src/styles/search";
37+
@import "./src/styles/iconview";

src/adapters/ui/iconview.js

+173
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
/*
2+
* OS.js - JavaScript Cloud/Web Desktop Platform
3+
*
4+
* Copyright (c) 2011-2019, Anders Evenrud <[email protected]>
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this
11+
* list of conditions and the following disclaimer
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*
27+
* @author Anders Evenrud <[email protected]>
28+
* @licence Simplified BSD License
29+
*/
30+
import {EventEmitter} from '@osjs/event-emitter';
31+
import {h, app} from 'hyperapp';
32+
33+
const view = (fileIcon, themeIcon, droppable) => (state, actions) =>
34+
h('div', {
35+
class: 'osjs-desktop-iconview__wrapper',
36+
oncontextmenu: ev => actions.openContextMenu({ev}),
37+
oncreate: el => {
38+
droppable(el, {
39+
ondrop: (ev, data, files) => {
40+
if (data && data.path) {
41+
actions.addEntry(data);
42+
} else if (files.length > 0) {
43+
actions.uploadEntries(files);
44+
}
45+
}
46+
});
47+
}
48+
}, state.entries.map(entry => {
49+
return h('div', {
50+
class: 'osjs-desktop-iconview__entry',
51+
oncontextmenu: ev => actions.openContextMenu({ev, entry}),
52+
ondblclick: ev => actions.openEntry({ev, entry})
53+
}, [
54+
h('img', {
55+
src: themeIcon(fileIcon(entry).name)
56+
}),
57+
h('span', {
58+
}, entry.filename)
59+
]);
60+
}));
61+
62+
/**
63+
* Desktop Icon View
64+
*/
65+
export class DesktopIconView extends EventEmitter {
66+
67+
/**
68+
* @param {Core} core Core reference
69+
*/
70+
constructor(core) {
71+
super('DesktopIconView');
72+
73+
this.core = core;
74+
this.$root = null;
75+
this.iconview = null;
76+
}
77+
78+
destroy() {
79+
if (this.$root && this.$root.parentNode) {
80+
this.$root.parentNode.removeChild(this.$root);
81+
}
82+
83+
this.iconview = null;
84+
this.$root = null;
85+
86+
this.emit('destroy');
87+
}
88+
89+
/**
90+
* @param {object} rect Rectangle from desktop
91+
*/
92+
resize(rect) {
93+
this.$root.style.top = `${rect.top}px`;
94+
this.$root.style.left = `${rect.left}px`;
95+
this.$root.style.bottom = `${rect.bottom}px`;
96+
this.$root.style.right = `${rect.right}px`;
97+
}
98+
99+
render() {
100+
if (this.$root) {
101+
return;
102+
}
103+
104+
this.$root = document.createElement('div');
105+
this.$root.className = 'osjs-desktop-iconview';
106+
this.core.$root.appendChild(this.$root);
107+
108+
const root = 'home:/.desktop'; // FIXME
109+
const {droppable} = this.core.make('osjs/dnd');
110+
const {icon: fileIcon} = this.core.make('osjs/fs');
111+
const {icon: themeIcon} = this.core.make('osjs/theme');
112+
const {copy, readdir, unlink} = this.core.make('osjs/vfs');
113+
const error = err => console.error(err);
114+
const reload = () => readdir(root)
115+
.then(entries => entries.filter(e => e.filename !== '..'))
116+
.then(entries => this.iconview.setEntries(entries));
117+
118+
this.iconview = app({
119+
entries: []
120+
}, {
121+
setEntries: entries => ({entries}),
122+
123+
openContextMenu: ({ev, entry}) => {
124+
if (entry) {
125+
this.createFileContextMenu(ev, entry);
126+
}
127+
},
128+
129+
openEntry: ({entry}) => {
130+
if (entry.isDirectory) {
131+
this.core.run('FileManager', {
132+
path: entry
133+
});
134+
} else {
135+
this.core.open(entry);
136+
}
137+
},
138+
139+
uploadEntries: files => {
140+
// TODO
141+
},
142+
143+
addEntry: entry => {
144+
const dest = `${root}/${entry.filename}`;
145+
146+
copy(entry, dest)
147+
.then(reload)
148+
.catch(error);
149+
},
150+
151+
removeEntry: entry => {
152+
unlink(entry)
153+
.then(reload)
154+
.catch(error);
155+
}
156+
}, view(fileIcon, themeIcon, droppable), this.$root);
157+
158+
reload();
159+
}
160+
161+
createFileContextMenu(ev, entry) {
162+
this.core.make('osjs/contextmenu', {
163+
position: ev,
164+
menu: [{
165+
label: 'Open',
166+
onclick: () => this.iconview.openEntry(({entry}))
167+
}, {
168+
label: 'Remove',
169+
onclick: () => this.iconview.removeEntry(entry)
170+
}]
171+
});
172+
}
173+
}

src/desktop.js

+37-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {EventEmitter} from '@osjs/event-emitter';
3232
import Application from './application';
3333
import {handleTabOnTextarea} from './utils/dom';
3434
import {matchKeyCombo} from './utils/input';
35+
import {DesktopIconView} from './adapters/ui/iconview';
3536
import Window from './window';
3637
import Search from './search';
3738
import merge from 'deepmerge';
@@ -120,14 +121,16 @@ export default class Desktop extends EventEmitter {
120121

121122
this.core = core;
122123
this.options = Object.assign({
123-
contextmenu: []
124+
contextmenu: [],
124125
}, options);
125126
this.$theme = [];
126127
this.$icons = [];
127128
this.$styles = document.createElement('style');
128129
this.$styles.setAttribute('type', 'text/css');
129130
this.contextmenuEntries = [];
130131
this.search = core.config('search.enabled') ? new Search(core) : null;
132+
this.iconview = new DesktopIconView(this.core);
133+
131134
this.subtract = {
132135
left: 0,
133136
top: 0,
@@ -144,9 +147,14 @@ export default class Desktop extends EventEmitter {
144147
this.search = this.search.destroy();
145148
}
146149

150+
if (this.iconview) {
151+
this.iconview.destroy();
152+
}
153+
147154
if (this.$styles && this.$styles.parentNode) {
148155
this.$styles.remove();
149156
}
157+
150158
this.$styles = null;
151159

152160
this._removeIcons();
@@ -211,6 +219,7 @@ export default class Desktop extends EventEmitter {
211219
try {
212220
this._updateCSS();
213221
Window.getWindows().forEach(w => w.clampToViewport());
222+
this._updateIconview();
214223
} catch (e) {
215224
console.warn('Panel event error', e);
216225
}
@@ -393,7 +402,6 @@ export default class Desktop extends EventEmitter {
393402
this.core.on('osjs/settings:load', checkRTL);
394403
this.core.on('osjs/settings:save', checkRTL);
395404
this.core.on('osjs/core:started', checkRTL);
396-
397405
}
398406

399407
start() {
@@ -402,6 +410,13 @@ export default class Desktop extends EventEmitter {
402410
}
403411

404412
this._updateCSS();
413+
this._updateIconview();
414+
}
415+
416+
_updateIconview() {
417+
if (this.iconview) {
418+
this.iconview.resize(this.getRect());
419+
}
405420
}
406421

407422
/**
@@ -465,6 +480,10 @@ export default class Desktop extends EventEmitter {
465480
this.applyTheme(newSettings.theme);
466481
this.applyIcons(newSettings.icons);
467482

483+
// TODO
484+
//this.applyIconView(newSettings.iconview.enabled);
485+
this.applyIconView(true);
486+
468487
this.core.emit('osjs/desktop:applySettings');
469488

470489
return Object.assign({}, newSettings);
@@ -505,6 +524,22 @@ export default class Desktop extends EventEmitter {
505524
this.$icons = [];
506525
}
507526

527+
/**
528+
* Adds or removes the icon view
529+
*/
530+
applyIconView(enable) {
531+
if (!this.iconview) {
532+
return;
533+
}
534+
535+
if (enable) {
536+
this.iconview.render();
537+
this.iconview.resize(this.getRect());
538+
} else {
539+
this.iconview.destroy();
540+
}
541+
}
542+
508543
/**
509544
* Sets the current icon theme from settings
510545
*/

src/styles/_iconview.scss

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* OS.js - JavaScript Cloud/Web Desktop Platform
3+
*
4+
* Copyright (c) 2011-2019, Anders Evenrud <[email protected]>
5+
* All rights reserved.
6+
*
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice, this
11+
* list of conditions and the following disclaimer
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17+
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18+
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
20+
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21+
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22+
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24+
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25+
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*
27+
* @author Anders Evenrud <[email protected]>
28+
* @licence Simplified BSD License
29+
*/
30+
31+
.osjs-desktop-iconview {
32+
position: absolute;
33+
top: 0;
34+
right: 0;
35+
width: 100%;
36+
height: 100%;
37+
38+
&__wrapper {
39+
position: absolute;
40+
top: 0;
41+
right: 0;
42+
width: 100%;
43+
height: 100%;
44+
}
45+
46+
&__entry {
47+
width: 3em;
48+
height: 3em;
49+
display: inline-block;
50+
margin: 1em;
51+
52+
& > span {
53+
display: block;
54+
overflow: hidden;
55+
height: 1em;
56+
text-align: center;
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)