Skip to content

Commit

Permalink
Initial work on iconview (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
andersevenrud committed May 2, 2019
1 parent 94926bd commit b64e7fa
Show file tree
Hide file tree
Showing 4 changed files with 270 additions and 2 deletions.
1 change: 1 addition & 0 deletions index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@
@import "./src/styles/notifications";
@import "./src/styles/login";
@import "./src/styles/search";
@import "./src/styles/iconview";
173 changes: 173 additions & 0 deletions src/adapters/ui/iconview.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/*
* OS.js - JavaScript Cloud/Web Desktop Platform
*
* Copyright (c) 2011-2019, Anders Evenrud <andersevenrud@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Anders Evenrud <andersevenrud@gmail.com>
* @licence Simplified BSD License
*/
import {EventEmitter} from '@osjs/event-emitter';
import {h, app} from 'hyperapp';

const view = (fileIcon, themeIcon, droppable) => (state, actions) =>
h('div', {
class: 'osjs-desktop-iconview__wrapper',
oncontextmenu: ev => actions.openContextMenu({ev}),
oncreate: el => {
droppable(el, {
ondrop: (ev, data, files) => {
if (data && data.path) {
actions.addEntry(data);
} else if (files.length > 0) {
actions.uploadEntries(files);
}
}
});
}
}, state.entries.map(entry => {
return h('div', {
class: 'osjs-desktop-iconview__entry',
oncontextmenu: ev => actions.openContextMenu({ev, entry}),
ondblclick: ev => actions.openEntry({ev, entry})
}, [
h('img', {
src: themeIcon(fileIcon(entry).name)
}),
h('span', {
}, entry.filename)
]);
}));

/**
* Desktop Icon View
*/
export class DesktopIconView extends EventEmitter {

/**
* @param {Core} core Core reference
*/
constructor(core) {
super('DesktopIconView');

this.core = core;
this.$root = null;
this.iconview = null;
}

destroy() {
if (this.$root && this.$root.parentNode) {
this.$root.parentNode.removeChild(this.$root);
}

this.iconview = null;
this.$root = null;

this.emit('destroy');
}

/**
* @param {object} rect Rectangle from desktop
*/
resize(rect) {
this.$root.style.top = `${rect.top}px`;
this.$root.style.left = `${rect.left}px`;
this.$root.style.bottom = `${rect.bottom}px`;
this.$root.style.right = `${rect.right}px`;
}

render() {
if (this.$root) {
return;
}

this.$root = document.createElement('div');
this.$root.className = 'osjs-desktop-iconview';
this.core.$root.appendChild(this.$root);

const root = 'home:/.desktop'; // FIXME
const {droppable} = this.core.make('osjs/dnd');
const {icon: fileIcon} = this.core.make('osjs/fs');
const {icon: themeIcon} = this.core.make('osjs/theme');
const {copy, readdir, unlink} = this.core.make('osjs/vfs');
const error = err => console.error(err);
const reload = () => readdir(root)
.then(entries => entries.filter(e => e.filename !== '..'))
.then(entries => this.iconview.setEntries(entries));

this.iconview = app({
entries: []
}, {
setEntries: entries => ({entries}),

openContextMenu: ({ev, entry}) => {
if (entry) {
this.createFileContextMenu(ev, entry);
}
},

openEntry: ({entry}) => {
if (entry.isDirectory) {
this.core.run('FileManager', {
path: entry
});
} else {
this.core.open(entry);
}
},

uploadEntries: files => {
// TODO
},

addEntry: entry => {
const dest = `${root}/${entry.filename}`;

copy(entry, dest)
.then(reload)
.catch(error);
},

removeEntry: entry => {
unlink(entry)
.then(reload)
.catch(error);
}
}, view(fileIcon, themeIcon, droppable), this.$root);

reload();
}

createFileContextMenu(ev, entry) {
this.core.make('osjs/contextmenu', {
position: ev,
menu: [{
label: 'Open',
onclick: () => this.iconview.openEntry(({entry}))
}, {
label: 'Remove',
onclick: () => this.iconview.removeEntry(entry)
}]
});
}
}
39 changes: 37 additions & 2 deletions src/desktop.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {EventEmitter} from '@osjs/event-emitter';
import Application from './application';
import {handleTabOnTextarea} from './utils/dom';
import {matchKeyCombo} from './utils/input';
import {DesktopIconView} from './adapters/ui/iconview';
import Window from './window';
import Search from './search';
import merge from 'deepmerge';
Expand Down Expand Up @@ -120,14 +121,16 @@ export default class Desktop extends EventEmitter {

this.core = core;
this.options = Object.assign({
contextmenu: []
contextmenu: [],
}, options);
this.$theme = [];
this.$icons = [];
this.$styles = document.createElement('style');
this.$styles.setAttribute('type', 'text/css');
this.contextmenuEntries = [];
this.search = core.config('search.enabled') ? new Search(core) : null;
this.iconview = new DesktopIconView(this.core);

this.subtract = {
left: 0,
top: 0,
Expand All @@ -144,9 +147,14 @@ export default class Desktop extends EventEmitter {
this.search = this.search.destroy();
}

if (this.iconview) {
this.iconview.destroy();
}

if (this.$styles && this.$styles.parentNode) {
this.$styles.remove();
}

this.$styles = null;

this._removeIcons();
Expand Down Expand Up @@ -211,6 +219,7 @@ export default class Desktop extends EventEmitter {
try {
this._updateCSS();
Window.getWindows().forEach(w => w.clampToViewport());
this._updateIconview();
} catch (e) {
console.warn('Panel event error', e);
}
Expand Down Expand Up @@ -393,7 +402,6 @@ export default class Desktop extends EventEmitter {
this.core.on('osjs/settings:load', checkRTL);
this.core.on('osjs/settings:save', checkRTL);
this.core.on('osjs/core:started', checkRTL);

}

start() {
Expand All @@ -402,6 +410,13 @@ export default class Desktop extends EventEmitter {
}

this._updateCSS();
this._updateIconview();
}

_updateIconview() {
if (this.iconview) {
this.iconview.resize(this.getRect());
}
}

/**
Expand Down Expand Up @@ -465,6 +480,10 @@ export default class Desktop extends EventEmitter {
this.applyTheme(newSettings.theme);
this.applyIcons(newSettings.icons);

// TODO
//this.applyIconView(newSettings.iconview.enabled);
this.applyIconView(true);

this.core.emit('osjs/desktop:applySettings');

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

/**
* Adds or removes the icon view
*/
applyIconView(enable) {
if (!this.iconview) {
return;
}

if (enable) {
this.iconview.render();
this.iconview.resize(this.getRect());
} else {
this.iconview.destroy();
}
}

/**
* Sets the current icon theme from settings
*/
Expand Down
59 changes: 59 additions & 0 deletions src/styles/_iconview.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* OS.js - JavaScript Cloud/Web Desktop Platform
*
* Copyright (c) 2011-2019, Anders Evenrud <andersevenrud@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Anders Evenrud <andersevenrud@gmail.com>
* @licence Simplified BSD License
*/

.osjs-desktop-iconview {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;

&__wrapper {
position: absolute;
top: 0;
right: 0;
width: 100%;
height: 100%;
}

&__entry {
width: 3em;
height: 3em;
display: inline-block;
margin: 1em;

& > span {
display: block;
overflow: hidden;
height: 1em;
text-align: center;
}
}
}

0 comments on commit b64e7fa

Please sign in to comment.