mirror of
https://github.com/lxsang/ant-http
synced 2024-11-08 13:18:22 +01:00
16527 lines
514 KiB
JavaScript
16527 lines
514 KiB
JavaScript
window.OSjs = window.OSjs || {};
|
|
/**
|
|
* @preserve OS.js - JavaScript Cloud/Web Desktop Platform
|
|
*
|
|
* Copyright (c) 2011-2016, 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
|
|
*/
|
|
|
|
(function() {
|
|
'use strict';
|
|
(function() {
|
|
window.console = window.console || {};
|
|
console.log = console.log || function() {};
|
|
console.debug = console.debug || console.log;
|
|
console.error = console.error || console.log;
|
|
console.warn = console.warn || console.log;
|
|
console.group = console.group || console.log;
|
|
console.groupEnd = console.groupEnd || console.log;
|
|
})();
|
|
(['forEach', 'every', 'map']).forEach(function(n) {
|
|
(['HTMLCollection', 'NodeList', 'FileList']).forEach(function(p) {
|
|
if ( window[p] ) {
|
|
window[p].prototype[n] = Array.prototype[n];
|
|
}
|
|
});
|
|
});
|
|
(function() {
|
|
function CustomEvent(event, params) {
|
|
params = params || { bubbles: false, cancelable: false, detail: undefined };
|
|
var evt = document.createEvent( 'CustomEvent' );
|
|
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail );
|
|
return evt;
|
|
}
|
|
if ( window.navigator.userAgent.match(/MSIE|Edge|Trident/) ) {
|
|
CustomEvent.prototype = window.Event.prototype;
|
|
window.CustomEvent = CustomEvent;
|
|
}
|
|
})();
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
var handler = null;
|
|
var loaded = false;
|
|
var inited = false;
|
|
var signingOut = false;
|
|
(['Utils', 'API', 'GUI', 'Core', 'Dialogs', 'Helpers', 'Applications', 'Locales', 'VFS', 'Extensions']).forEach(function(ns) {
|
|
OSjs[ns] = OSjs[ns] || {};
|
|
});
|
|
(['Elements', 'Helpers']).forEach(function(ns) {
|
|
OSjs.GUI[ns] = OSjs.GUI[ns] || {};
|
|
});
|
|
(['Helpers', 'Transports']).forEach(function(ns) {
|
|
OSjs.VFS[ns] = OSjs.VFS[ns] || {};
|
|
});
|
|
function checkForbiddenKeyCombo(ev) {
|
|
return false;
|
|
}
|
|
var events = {
|
|
body_contextmenu: function(ev) {
|
|
ev.stopPropagation();
|
|
if ( !OSjs.Utils.$isFormElement(ev) ) {
|
|
ev.preventDefault();
|
|
return false;
|
|
}
|
|
return true;
|
|
},
|
|
body_click: function(ev) {
|
|
OSjs.API.blurMenu();
|
|
if ( ev.target === document.body ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var win = wm ? wm.getCurrentWindow() : null;
|
|
if ( win ) {
|
|
win._blur();
|
|
}
|
|
}
|
|
},
|
|
body_touchstart: function(ev) {
|
|
if ( ev.target.localName !== 'select' ) {
|
|
ev.preventDefault();
|
|
}
|
|
},
|
|
message: function(ev) {
|
|
if ( ev && ev.data && typeof ev.data.message !== 'undefined' && typeof ev.data.pid === 'number' ) {
|
|
var proc = OSjs.API.getProcess(ev.data.pid);
|
|
if ( proc ) {
|
|
if ( typeof proc.onPostMessage === 'function' ) {
|
|
proc.onPostMessage(ev.data.message, ev);
|
|
}
|
|
if ( typeof proc._getWindow === 'function' ) {
|
|
var win = proc._getWindow(ev.data.wid, 'wid');
|
|
if ( win ) {
|
|
win.onPostMessage(ev.data.message, ev);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
fullscreen: function(ev) {
|
|
var notif = OSjs.Core.getWindowManager().getNotificationIcon('_FullscreenNotification');
|
|
if ( notif ) {
|
|
if ( !document.fullScreen && !document.mozFullScreen && !document.webkitIsFullScreen && !document.msFullscreenElement ) {
|
|
notif.opts._isFullscreen = false;
|
|
notif.setImage(OSjs.API.getIcon('actions/gtk-fullscreen.png', '16x16'));
|
|
} else {
|
|
notif.opts._isFullscreen = true;
|
|
notif.setImage(OSjs.API.getIcon('actions/gtk-leave-fullscreen.png', '16x16'));
|
|
}
|
|
}
|
|
},
|
|
keydown: function(ev) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var win = wm ? wm.getCurrentWindow() : null;
|
|
var accept = [122, 123];
|
|
function checkPrevent() {
|
|
var d = ev.srcElement || ev.target;
|
|
var doPrevent = d.tagName === 'BODY' ? true : false;
|
|
if ( (ev.keyCode === OSjs.Utils.Keys.BACKSPACE) && !OSjs.Utils.$isFormElement(ev) ) { // Backspace
|
|
doPrevent = true;
|
|
} else if ( (ev.keyCode === OSjs.Utils.Keys.TAB) && OSjs.Utils.$isFormElement(ev) ) { // Tab
|
|
doPrevent = true;
|
|
} else {
|
|
if ( accept.indexOf(ev.keyCode) !== -1 ) {
|
|
doPrevent = false;
|
|
} else if ( checkForbiddenKeyCombo(ev) ) {
|
|
doPrevent = true;
|
|
}
|
|
}
|
|
if ( doPrevent && (!win || !win._properties.key_capture) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
var reacted = (function() {
|
|
var combination = null;
|
|
if ( wm ) {
|
|
combination = wm.onKeyDown(ev, win);
|
|
if ( win && !combination ) {
|
|
win._onKeyEvent(ev, 'keydown');
|
|
}
|
|
}
|
|
return combination;
|
|
})();
|
|
if ( checkPrevent() || reacted ) {
|
|
ev.preventDefault();
|
|
}
|
|
return true;
|
|
},
|
|
keypress: function(ev) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( checkForbiddenKeyCombo(ev) ) {
|
|
ev.preventDefault();
|
|
}
|
|
if ( wm ) {
|
|
var win = wm.getCurrentWindow();
|
|
if ( win ) {
|
|
return win._onKeyEvent(ev, 'keypress');
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
keyup: function(ev) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.onKeyUp(ev, wm.getCurrentWindow());
|
|
var win = wm.getCurrentWindow();
|
|
if ( win ) {
|
|
return win._onKeyEvent(ev, 'keyup');
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
beforeunload: function(ev) {
|
|
if ( signingOut ) {
|
|
return;
|
|
}
|
|
try {
|
|
if ( OSjs.API.getConfig('ShowQuitWarning') ) {
|
|
return OSjs.API._('MSG_SESSION_WARNING');
|
|
}
|
|
} catch ( e ) {}
|
|
},
|
|
resize: (function() {
|
|
var _timeout;
|
|
function _resize(ev, wasInited) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( !wm ) {
|
|
return;
|
|
}
|
|
wm.resize(ev, wm.getWindowSpace(), wasInited);
|
|
}
|
|
return function(ev, wasInited) {
|
|
if ( _timeout ) {
|
|
clearTimeout(_timeout);
|
|
_timeout = null;
|
|
}
|
|
var self = this;
|
|
_timeout = setTimeout(function() {
|
|
_resize.call(self, ev, wasInited);
|
|
}, 100);
|
|
};
|
|
})(),
|
|
scroll: function(ev) {
|
|
if ( ev.target === document || ev.target === document.body ) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
return false;
|
|
}
|
|
document.body.scrollTop = 0;
|
|
document.body.scrollLeft = 0;
|
|
return true;
|
|
},
|
|
hashchange: function(ev) {
|
|
var hash = window.location.hash.substr(1);
|
|
var spl = hash.split(/^([\w\.\-_]+)\:(.*)/);
|
|
function getArgs(q) {
|
|
var args = {};
|
|
q.split('&').forEach(function(a) {
|
|
var b = a.split('=');
|
|
var k = decodeURIComponent(b[0]);
|
|
args[k] = decodeURIComponent(b[1] || '');
|
|
});
|
|
return args;
|
|
}
|
|
if ( spl.length === 4 ) {
|
|
var root = spl[1];
|
|
var args = getArgs(spl[2]);
|
|
if ( root ) {
|
|
OSjs.API.getProcess(root).forEach(function(p) {
|
|
p._onMessage('hashchange', {
|
|
hash: hash,
|
|
args: args
|
|
}, {source: null});
|
|
});
|
|
}
|
|
}
|
|
},
|
|
orientationchange: function(ev) {
|
|
var orientation = 'landscape';
|
|
if ( window.screen && window.screen.orientation ) {
|
|
if ( window.screen.orientation.type.indexOf('portrait') !== -1 ) {
|
|
orientation = 'portrait';
|
|
}
|
|
}
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.onOrientationChange(ev, orientation);
|
|
}
|
|
document.body.setAttribute('data-orientation', orientation);
|
|
}
|
|
};
|
|
function onError(msg) {
|
|
OSjs.API.error(OSjs.API._('ERR_CORE_INIT_FAILED'), OSjs.API._('ERR_CORE_INIT_FAILED_DESC'), msg, null, true);
|
|
}
|
|
function initLayout() {
|
|
if ( OSjs.API.getConfig('Watermark.enabled') ) {
|
|
var ver = OSjs.API.getConfig('Version', 'unknown version');
|
|
var html = OSjs.API.getConfig('Watermark.lines') || [];
|
|
var el = document.createElement('div');
|
|
el.id = 'DebugNotice';
|
|
el.setAttribute('aria-hidden', 'true');
|
|
el.innerHTML = html.join('<br />').replace(/%VERSION%/, ver);
|
|
document.body.appendChild(el);
|
|
}
|
|
document.getElementById('LoadingScreen').style.display = 'none';
|
|
}
|
|
function initHandler(config, callback) {
|
|
handler = new OSjs.Core.Handler();
|
|
function _done(error) {
|
|
if ( error ) {
|
|
onError(error);
|
|
return;
|
|
}
|
|
if ( !inited ) {
|
|
if ( !handler.loggedIn ) {
|
|
if ( confirm(OSjs.API._('ERR_NO_SESSION')) ) {
|
|
handler.init(_done);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
inited = true;
|
|
callback();
|
|
}
|
|
handler.init(_done);
|
|
}
|
|
function initEvents() {
|
|
document.body.addEventListener('touchstart', events.body_touchstart);
|
|
document.body.addEventListener('contextmenu', events.body_contextmenu, false);
|
|
document.body.addEventListener('click', events.body_click, false);
|
|
document.addEventListener('keydown', events.keydown, true);
|
|
document.addEventListener('keypress', events.keypress, true);
|
|
document.addEventListener('keyup', events.keyup, true);
|
|
window.addEventListener('orientationchange', events.orientationchange, false);
|
|
window.addEventListener('hashchange', events.hashchange, false);
|
|
window.addEventListener('resize', events.resize, false);
|
|
window.addEventListener('scroll', events.scroll, false);
|
|
window.addEventListener('fullscreenchange', events.fullscreen, false);
|
|
window.addEventListener('mozfullscreenchange', events.fullscreen, false);
|
|
window.addEventListener('webkitfullscreenchange', events.fullscreen, false);
|
|
window.addEventListener('msfullscreenchange', events.fullscreen, false);
|
|
window.addEventListener('message', events.message, false);
|
|
window.onbeforeunload = events.beforeunload;
|
|
events.orientationchange();
|
|
window.onerror = function(message, url, linenumber, column, exception) {
|
|
if ( typeof exception === 'string' ) {
|
|
exception = null;
|
|
}
|
|
console.warn('window::onerror()', arguments);
|
|
OSjs.API.error(OSjs.API._('ERR_JAVASCRIPT_EXCEPTION'),
|
|
OSjs.API._('ERR_JAVACSRIPT_EXCEPTION_DESC'),
|
|
OSjs.API._('BUGREPORT_MSG'),
|
|
exception || {name: 'window::onerror()', fileName: url, lineNumber: linenumber + ':' + column, message: message},
|
|
true );
|
|
return false;
|
|
};
|
|
}
|
|
function initPreload(config, callback) {
|
|
var list = [];
|
|
function flatten(a) {
|
|
a.forEach(function(i) {
|
|
if ( i instanceof Array ) {
|
|
flatten(i);
|
|
} else {
|
|
if ( typeof i === 'string' ) {
|
|
i = OSjs.Utils.checkdir(i);
|
|
} else {
|
|
i.src = OSjs.Utils.checkdir(i.src);
|
|
}
|
|
list.push(i);
|
|
}
|
|
});
|
|
}
|
|
flatten(config.Preloads);
|
|
OSjs.Utils.preload(list, function(total, failed) {
|
|
if ( failed.length ) {
|
|
console.warn('doInitialize()', 'some preloads failed to load:', failed);
|
|
}
|
|
setTimeout(function() {
|
|
callback();
|
|
}, 0);
|
|
});
|
|
}
|
|
function initExtensions(config, callback) {
|
|
var exts = Object.keys(OSjs.Extensions);
|
|
var manifest = OSjs.Core.getMetadata();
|
|
OSjs.Utils.asyncs(exts, function(entry, idx, next) {
|
|
try {
|
|
var m = manifest[entry];
|
|
OSjs.Extensions[entry].init(m, function() {
|
|
next();
|
|
});
|
|
} catch ( e ) {
|
|
console.warn('Extension init failed', e.stack, e);
|
|
next();
|
|
}
|
|
}, function() {
|
|
callback();
|
|
});
|
|
}
|
|
function initSettingsManager(cfg, callback) {
|
|
var pools = cfg.SettingsManager || {};
|
|
var manager = OSjs.Core.getSettingsManager();
|
|
Object.keys(pools).forEach(function(poolName) {
|
|
manager.instance(poolName, pools[poolName] || {});
|
|
});
|
|
callback();
|
|
}
|
|
function initPackageManager(cfg, callback) {
|
|
OSjs.Core.getPackageManager().load(function(result, error, pm) {
|
|
if ( error ) {
|
|
callback(error, result);
|
|
return;
|
|
}
|
|
var list = OSjs.API.getConfig('PreloadOnBoot', []);
|
|
OSjs.Utils.asyncs(list, function(iter, index, next) {
|
|
var pkg = pm.getPackage(iter);
|
|
if ( pkg && pkg.preload ) {
|
|
OSjs.Utils.preload(pkg.preload, next);
|
|
} else {
|
|
next();
|
|
}
|
|
}, function() {
|
|
setTimeout(function() {
|
|
callback(false, true);
|
|
}, 0);
|
|
});
|
|
});
|
|
}
|
|
function initVFS(config, callback) {
|
|
OSjs.Core.getMountManager().init(callback);
|
|
}
|
|
function initSearch(config, callback) {
|
|
OSjs.Core.getSearchEngine().init(callback);
|
|
}
|
|
function initWindowManager(config, callback) {
|
|
if ( !config.WM || !config.WM.exec ) {
|
|
onError(OSjs.API._('ERR_CORE_INIT_NO_WM'));
|
|
return;
|
|
}
|
|
OSjs.API.launch(config.WM.exec, (config.WM.args || {}), function(app) {
|
|
app.setup(callback);
|
|
}, function(error, name, args, exception) {
|
|
onError(OSjs.API._('ERR_CORE_INIT_WM_FAILED_FMT', error), exception);
|
|
});
|
|
}
|
|
function initSession(config, callback) {
|
|
OSjs.API.playSound('LOGIN');
|
|
var list = [];
|
|
try {
|
|
list = config.AutoStart;
|
|
} catch ( e ) {
|
|
console.warn('initSession()->autostart()', 'exception', e, e.stack);
|
|
}
|
|
var checkMap = {};
|
|
var skipMap = [];
|
|
list.forEach(function(iter, idx) {
|
|
if ( typeof iter === 'string' ) {
|
|
iter = list[idx] = {name: iter};
|
|
}
|
|
if ( skipMap.indexOf(iter.name) === -1 ) {
|
|
if ( !checkMap[iter.name] ) {
|
|
checkMap[iter.name] = idx;
|
|
skipMap.push(iter.name);
|
|
}
|
|
}
|
|
});
|
|
handler.getLastSession(function(err, adds) {
|
|
if ( !err ) {
|
|
adds.forEach(function(iter) {
|
|
if ( typeof checkMap[iter.name] === 'undefined' ) {
|
|
list.push(iter);
|
|
} else {
|
|
if ( iter.args ) {
|
|
var refid = checkMap[iter.name];
|
|
var ref = list[refid];
|
|
if ( !ref.args ) {
|
|
ref.args = {};
|
|
}
|
|
ref.args = OSjs.Utils.mergeObject(ref.args, iter.args);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
OSjs.API.launchList(list, null, null, callback);
|
|
});
|
|
}
|
|
function initTestEnvironment(config, callback) {
|
|
OSjs.Utils.preload([
|
|
'/vendor/mocha/mocha.js',
|
|
'/vendor/mocha/mocha.css',
|
|
'/vendor/chai/chai.js'
|
|
], function() {
|
|
var h1 = document.createElement('h1');
|
|
h1.style.margin = '20px';
|
|
h1.appendChild(document.createTextNode('OS.js Mocha Client Test Suite'));
|
|
document.body.appendChild(h1);
|
|
var el = document.createElement('div');
|
|
el.id = 'mocha';
|
|
document.body.appendChild(el);
|
|
document.body.style.background = '#fff';
|
|
document.body.style.overflow = 'auto';
|
|
window.mocha.ui('bdd');
|
|
window.mocha.reporter('html');
|
|
(new OSjs.Core.WindowManager('MochaWM', null, {}, {}, {})).init();
|
|
OSjs.Utils.$createCSS(OSjs.API.getThemeCSS('default'));
|
|
OSjs.Utils.preload(['/client/test/test.js'], callback);
|
|
});
|
|
return true;
|
|
}
|
|
function init() {
|
|
var config = OSjs.Core.getConfig();
|
|
var splash = document.getElementById('LoadingScreen');
|
|
var loading = OSjs.API.createSplash('OS.js', null, null, splash);
|
|
var freeze = ['API', 'Core', 'Dialogs', 'Extensions', 'GUI', 'Helpers', 'Locales', 'Utils', 'VFS'];
|
|
var queue = [
|
|
initPreload,
|
|
initHandler,
|
|
initVFS,
|
|
initPackageManager,
|
|
initExtensions,
|
|
initSettingsManager,
|
|
initSearch,
|
|
function(cfg, cb) {
|
|
OSjs.Core.getMountManager().restore(cb);
|
|
},
|
|
function(cfg, cb) {
|
|
return OSjs.GUI.DialogScheme.init(cb);
|
|
}
|
|
];
|
|
function _inited() {
|
|
loading = loading.destroy();
|
|
splash = OSjs.Utils.$remove(splash);
|
|
var wm = OSjs.Core.getWindowManager();
|
|
wm._fullyLoaded = true;
|
|
OSjs.API.triggerHook('onWMInited');
|
|
}
|
|
function _done() {
|
|
OSjs.API.triggerHook('onInited');
|
|
loading.update(queue.length - 1, queue.length + 1);
|
|
freeze.forEach(function(f) {
|
|
if ( typeof OSjs[f] === 'object' ) {
|
|
Object.freeze(OSjs[f]);
|
|
}
|
|
});
|
|
if ( config.DEVMODE || config.MOCHAMODE ) {
|
|
_inited();
|
|
}
|
|
if ( config.MOCHAMODE ) {
|
|
window.mocha.run();
|
|
} else {
|
|
initWindowManager(config, function() {
|
|
initEvents();
|
|
_inited();
|
|
initSession(config, function() {
|
|
OSjs.API.triggerHook('onSessionLoaded');
|
|
});
|
|
});
|
|
}
|
|
}
|
|
initLayout();
|
|
if ( config.MOCHAMODE ) {
|
|
queue.push(initTestEnvironment);
|
|
}
|
|
OSjs.Utils.asyncs(queue, function(entry, index, next) {
|
|
if ( index < 1 ) {
|
|
OSjs.API.triggerHook('onInitialize');
|
|
}
|
|
loading.update(index + 1, queue.length + 1);
|
|
entry(config, next);
|
|
}, _done);
|
|
}
|
|
OSjs.API.shutdown = function() {
|
|
if ( !inited || !loaded ) {
|
|
return;
|
|
}
|
|
signingOut = true;
|
|
document.body.removeEventListener('touchstart', events.body_touchstart);
|
|
document.body.removeEventListener('contextmenu', events.body_contextmenu, false);
|
|
document.body.removeEventListener('click', events.body_click, false);
|
|
document.removeEventListener('keydown', events.keydown, true);
|
|
document.removeEventListener('keypress', events.keypress, true);
|
|
document.removeEventListener('keyup', events.keyup, true);
|
|
window.removeEventListener('orientationchange', events.orientationchange, false);
|
|
window.removeEventListener('hashchange', events.hashchange, false);
|
|
window.removeEventListener('resize', events.resize, false);
|
|
window.removeEventListener('scroll', events.scroll, false);
|
|
window.removeEventListener('message', events.message, false);
|
|
window.onerror = null;
|
|
window.onbeforeunload = null;
|
|
OSjs.API.toggleFullscreen();
|
|
OSjs.API.blurMenu();
|
|
OSjs.API.killAll();
|
|
OSjs.GUI.DialogScheme.destroy();
|
|
var ring = OSjs.API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.destroy();
|
|
}
|
|
var handler = OSjs.Core.getHandler();
|
|
if ( handler ) {
|
|
handler.destroy();
|
|
handler = null;
|
|
}
|
|
OSjs.API.triggerHook('onShutdown');
|
|
console.warn('OS.js was shut down!');
|
|
if ( OSjs.API.getConfig('Connection.Type') === 'nw' ) {
|
|
try {
|
|
var gui = require('nw.gui');
|
|
var win = gui.Window.get();
|
|
setTimeout(function() {
|
|
win.close();
|
|
}, 500);
|
|
} catch ( e ) {
|
|
}
|
|
} else {
|
|
if ( OSjs.API.getConfig('ReloadOnShutdown') === true ) {
|
|
window.location.reload();
|
|
}
|
|
}
|
|
Object.keys(OSjs).forEach(function(k) {
|
|
try {
|
|
delete OSjs[k];
|
|
} catch ( e ) {}
|
|
});
|
|
};
|
|
OSjs.Core.getConfig = OSjs.Core.getConfig || function() {
|
|
return {};
|
|
};
|
|
OSjs.Core.getMetadata = OSjs.Core.getMetadata || function() {
|
|
return {};
|
|
};
|
|
OSjs.API.isShuttingDown = OSjs.API.isShuttingDown || function() {
|
|
return signingOut;
|
|
};
|
|
(function() {
|
|
function onLoad() {
|
|
if ( loaded ) {
|
|
return;
|
|
}
|
|
loaded = true;
|
|
init();
|
|
}
|
|
function onUnload() {
|
|
OSjs.API.shutdown();
|
|
}
|
|
document.addEventListener('DOMContentLoaded', onLoad);
|
|
document.addEventListener('load', onLoad);
|
|
document.addEventListener('unload', onUnload);
|
|
})();
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.getCompability = (function() {
|
|
function _checkSupport(enabled, check, isSupported) {
|
|
var supported = {};
|
|
Object.keys(check).forEach(function(key) {
|
|
var chk = check[key];
|
|
var value = false;
|
|
if ( chk instanceof Array ) {
|
|
chk.forEach(function(c) {
|
|
value = isSupported(c);
|
|
return !value;
|
|
});
|
|
} else {
|
|
value = isSupported(chk);
|
|
}
|
|
supported[key] = value;
|
|
});
|
|
return supported;
|
|
}
|
|
function getUpload() {
|
|
try {
|
|
var xhr = new XMLHttpRequest();
|
|
return (!!(xhr && ('upload' in xhr) && ('onprogress' in xhr.upload)));
|
|
} catch ( e ) {}
|
|
return false;
|
|
}
|
|
function getCanvasSupported() {
|
|
return document.createElement('canvas').getContext ? document.createElement('canvas') : null;
|
|
}
|
|
function getVideoSupported() {
|
|
return document.createElement('video').canPlayType ? document.createElement('video') : null;
|
|
}
|
|
function canPlayCodec(support, check) {
|
|
return _checkSupport(support, check, function(codec) {
|
|
try {
|
|
return !!support.canPlayType(codec);
|
|
} catch ( e ) {
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
function getVideoTypesSupported() {
|
|
return canPlayCodec(getVideoSupported(), {
|
|
webm : 'video/webm; codecs="vp8.0, vorbis"',
|
|
ogg : 'video/ogg; codecs="theora"',
|
|
h264 : [
|
|
'video/mp4; codecs="avc1.42E01E"',
|
|
'video/mp4; codecs="avc1.42E01E, mp4a.40.2"'
|
|
],
|
|
mpeg : 'video/mp4; codecs="mp4v.20.8"',
|
|
mkv : 'video/x-matroska; codecs="theora, vorbis"'
|
|
});
|
|
}
|
|
function getAudioSupported() {
|
|
return document.createElement('audio').canPlayType ? document.createElement('audio') : null;
|
|
}
|
|
function getAudioTypesSupported() {
|
|
return canPlayCodec(getAudioSupported(), {
|
|
ogg : 'audio/ogg; codecs="vorbis',
|
|
mp3 : 'audio/mpeg',
|
|
wav : 'audio/wav; codecs="1"'
|
|
});
|
|
}
|
|
function getAudioContext() {
|
|
if ( window.hasOwnProperty('AudioContext') || window.hasOwnProperty('webkitAudioContext') ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
var getCanvasContexts = (function() {
|
|
var cache = [];
|
|
return function() {
|
|
if ( !cache.length ) {
|
|
var canvas = getCanvasSupported();
|
|
if ( canvas ) {
|
|
var test = ['2d', 'webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl'];
|
|
test.forEach(function(tst, i) {
|
|
try {
|
|
if ( !!canvas.getContext(tst) ) {
|
|
cache.push(tst);
|
|
}
|
|
} catch ( eee ) {}
|
|
});
|
|
}
|
|
}
|
|
return cache;
|
|
};
|
|
})();
|
|
function getWebGL() {
|
|
var result = false;
|
|
var contexts = getCanvasContexts();
|
|
try {
|
|
result = (contexts.length > 1);
|
|
if ( !result ) {
|
|
if ( 'WebGLRenderingContext' in window ) {
|
|
result = true;
|
|
}
|
|
}
|
|
} catch ( e ) {}
|
|
return result;
|
|
}
|
|
function detectCSSFeature(featurename) {
|
|
var feature = false;
|
|
var domPrefixes = 'Webkit Moz ms O'.split(' ');
|
|
var elm = document.createElement('div');
|
|
var featurenameCapital = null;
|
|
featurename = featurename.toLowerCase();
|
|
if ( elm.style[featurename] ) {
|
|
feature = true;
|
|
}
|
|
if ( feature === false ) {
|
|
featurenameCapital = featurename.charAt(0).toUpperCase() + featurename.substr(1);
|
|
for ( var i = 0; i < domPrefixes.length; i++ ) {
|
|
if ( elm.style[domPrefixes[i] + featurenameCapital ] !== undefined ) {
|
|
feature = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return feature;
|
|
}
|
|
function getUserMedia() {
|
|
var getMedia = false;
|
|
if ( window.navigator ) {
|
|
getMedia = ( navigator.getUserMedia ||
|
|
navigator.webkitGetUserMedia ||
|
|
navigator.mozGetUserMedia ||
|
|
navigator.msGetUserMedia);
|
|
}
|
|
return !!getMedia;
|
|
}
|
|
function getRichText() {
|
|
try {
|
|
return !!document.createElement('textarea').contentEditable;
|
|
} catch ( e ) {}
|
|
return false;
|
|
}
|
|
function getTouch() {
|
|
try {
|
|
if ( navigator.userAgent.match(/Windows NT 6\.(2|3)/) ) {
|
|
return false;
|
|
}
|
|
} catch ( e ) {}
|
|
try {
|
|
if ( navigator.userAgent.match(/iOS|Android|BlackBerry|IEMobile|iPad|iPhone|iPad/i) ) {
|
|
return true;
|
|
}
|
|
} catch ( e ) {}
|
|
return false;
|
|
}
|
|
function getDnD() {
|
|
return !!('draggable' in document.createElement('span'));
|
|
}
|
|
function getSVG() {
|
|
return (!!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
|
|
}
|
|
function getFileSystem() {
|
|
return (('requestFileSystem' in window) || ('webkitRequestFileSystem' in window));
|
|
}
|
|
var checkWindow = {
|
|
indexedDB : 'indexedDB',
|
|
localStorage : 'localStorage',
|
|
sessionStorage : 'sessionStorage',
|
|
globalStorage : 'globalStorage',
|
|
openDatabase : 'openDatabase',
|
|
socket : 'WebSocket',
|
|
worker : 'Worker',
|
|
file : 'File',
|
|
blob : 'Blob',
|
|
orientation : 'onorientationchange'
|
|
};
|
|
var compability = {
|
|
touch : getTouch(),
|
|
upload : getUpload(),
|
|
getUserMedia : getUserMedia(),
|
|
fileSystem : getFileSystem(),
|
|
localStorage : false,
|
|
sessionStorage : false,
|
|
globalStorage : false,
|
|
openDatabase : false,
|
|
socket : false,
|
|
worker : false,
|
|
file : false,
|
|
blob : false,
|
|
orientation : false,
|
|
dnd : getDnD(),
|
|
css : {
|
|
transition : detectCSSFeature('transition'),
|
|
animation : detectCSSFeature('animation')
|
|
},
|
|
canvas : !!getCanvasSupported(),
|
|
canvasContext : getCanvasContexts(),
|
|
webgl : getWebGL(),
|
|
audioContext : getAudioContext(),
|
|
svg : getSVG(),
|
|
video : !!getVideoSupported(),
|
|
videoTypes : getVideoTypesSupported(),
|
|
audio : !!getAudioSupported(),
|
|
audioTypes : getAudioTypesSupported(),
|
|
richtext : getRichText()
|
|
};
|
|
Object.keys(checkWindow).forEach(function(key) {
|
|
compability[key] = (checkWindow[key] in window) && window[checkWindow[key]] !== null;
|
|
});
|
|
return function() {
|
|
return compability;
|
|
};
|
|
})();
|
|
OSjs.Utils.isIE = function() {
|
|
var dm = parseInt(document.documentMode, 10);
|
|
return dm <= 11 || !!navigator.userAgent.match(/(MSIE|Edge)/);
|
|
};
|
|
OSjs.Utils.getUserLocale = function() {
|
|
var loc = ((window.navigator.userLanguage || window.navigator.language) || 'en-EN').replace('-', '_');
|
|
var map = {
|
|
'nb' : 'no_NO',
|
|
'es' : 'es_ES',
|
|
'ru' : 'ru_RU',
|
|
'en' : 'en_EN'
|
|
};
|
|
var major = loc.split('_')[0] || 'en';
|
|
var minor = loc.split('_')[1] || major.toUpperCase();
|
|
if ( map[major] ) {
|
|
return map[major];
|
|
}
|
|
return major + '_' + minor;
|
|
};
|
|
OSjs.Utils.getRect = function() {
|
|
return {
|
|
top : 0,
|
|
left : 0,
|
|
width : document.body.offsetWidth,
|
|
height : document.body.offsetHeight
|
|
};
|
|
};
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.Keys = (function() {
|
|
var list = {
|
|
F1: 112,
|
|
F2: 113,
|
|
F3: 114,
|
|
F4: 115,
|
|
F6: 118,
|
|
F7: 119,
|
|
F8: 120,
|
|
F9: 121,
|
|
F10: 122,
|
|
F11: 123,
|
|
F12: 124,
|
|
TILDE: 220,
|
|
GRAVE: 192,
|
|
CMD: 17,
|
|
LSUPER: 91,
|
|
RSUPER: 92,
|
|
DELETE: 46,
|
|
INSERT: 45,
|
|
HOME: 36,
|
|
END: 35,
|
|
PGDOWN: 34,
|
|
PGUP: 33,
|
|
PAUSE: 19,
|
|
BREAK: 19,
|
|
CAPS_LOCK: 20,
|
|
SCROLL_LOCK:186,
|
|
BACKSPACE: 8,
|
|
SPACE: 32,
|
|
TAB: 9,
|
|
ENTER: 13,
|
|
ESC: 27,
|
|
LEFT: 37,
|
|
RIGHT: 39,
|
|
UP: 38,
|
|
DOWN: 40
|
|
};
|
|
for ( var n = 33; n <= 126; n++ ) {
|
|
list[String.fromCharCode(n).toUpperCase()] = n;
|
|
}
|
|
return Object.freeze(list);
|
|
})();
|
|
OSjs.Utils.mousePosition = function(ev) {
|
|
if ( ev.detail && typeof ev.detail.x !== 'undefined' && typeof ev.detail.y !== 'undefined' ) {
|
|
return {x: ev.detail.x, y: ev.detail.y};
|
|
}
|
|
var touch = ev.touches || ev.changedTouches;
|
|
if ( touch && touch[0] ) {
|
|
return {x: touch[0].clientX, y: touch[0].clientY};
|
|
}
|
|
return {x: ev.clientX, y: ev.clientY};
|
|
};
|
|
OSjs.Utils.mouseButton = function(ev) {
|
|
if ( typeof ev.button !== 'undefined' ) {
|
|
if ( ev.button === 0 ) {
|
|
return 'left';
|
|
} else if ( ev.button === 1 ) {
|
|
return 'middle';
|
|
}
|
|
return 'right';
|
|
}
|
|
if ( ev.which === 2 || ev.which === 4 ) {
|
|
return 'middle';
|
|
} else if ( ev.which === 1 ) {
|
|
return 'left';
|
|
}
|
|
return 'right';
|
|
};
|
|
OSjs.Utils.keyCombination = (function() {
|
|
var modifiers = {
|
|
CTRL: function(ev) {
|
|
return ev.ctrlKey;
|
|
},
|
|
SHIFT: function(ev) {
|
|
return ev.shiftKey;
|
|
},
|
|
ALT: function(ev) {
|
|
return ev.altKey;
|
|
},
|
|
META: function(ev) {
|
|
return ev.metaKey;
|
|
}
|
|
};
|
|
function getKeyName(keyCode) {
|
|
var result = false;
|
|
Object.keys(OSjs.Utils.Keys).forEach(function(k) {
|
|
if ( !result && (keyCode === OSjs.Utils.Keys[k]) ) {
|
|
result = k;
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
return function(ev, checkFor) {
|
|
var checks = checkFor.toUpperCase().split('+');
|
|
var checkMods = {CTRL: false, SHIFT: false, ALT: false};
|
|
var checkKeys = [];
|
|
checks.forEach(function(f) {
|
|
if ( modifiers[f] ) {
|
|
checkMods[f] = true;
|
|
} else {
|
|
checkKeys.push(f);
|
|
}
|
|
});
|
|
return Object.keys(checkMods).every(function(f) {
|
|
var fk = !!modifiers[f](ev);
|
|
return checkMods[f] === fk;
|
|
}) && checkKeys.every(function(f) {
|
|
return getKeyName(ev.keyCode) === f;
|
|
});
|
|
};
|
|
})();
|
|
OSjs.Utils.$bind = (function() {
|
|
var TOUCH_CONTEXTMENU = 1000;
|
|
var TOUCH_CLICK_MIN = 30;
|
|
var TOUCH_CLICK_MAX = 1000;
|
|
var TOUCH_DBLCLICK = 400;
|
|
function addEventHandler(el, n, t, callback, handler, useCapture, realType) {
|
|
var args = [t, handler, useCapture];
|
|
el.addEventListener.apply(el, args);
|
|
el._boundEvents[n].push({
|
|
realType: realType,
|
|
args: args,
|
|
callback: callback
|
|
});
|
|
}
|
|
function createWheelHandler(el, n, t, callback, useCapture) {
|
|
function _wheel(ev) {
|
|
var pos = OSjs.Utils.mousePosition(ev);
|
|
var direction = (ev.detail < 0 || ev.wheelDelta > 0) ? 1 : -1;
|
|
pos.z = direction;
|
|
return callback(ev, pos);
|
|
}
|
|
addEventHandler(el, n, 'mousewheel', callback, _wheel, useCapture, 'mousewheel');
|
|
addEventHandler(el, n, 'DOMMouseScroll', callback, _wheel, useCapture, 'DOMMouseScroll');
|
|
}
|
|
function createGestureHandler(el, n, t, callback, useCapture) {
|
|
var started;
|
|
var contextTimeout;
|
|
var dblTimeout;
|
|
var moved = false;
|
|
var clicks = 0;
|
|
function _done() {
|
|
contextTimeout = clearTimeout(contextTimeout);
|
|
started = null;
|
|
moved = false;
|
|
el.removeEventListener('touchend', _touchend, false);
|
|
el.removeEventListener('touchmove', _touchmove, false);
|
|
el.removeEventListener('touchcancel', _touchcancel, false);
|
|
}
|
|
function _touchstart(ev) {
|
|
if ( ev.target === document.body ) {
|
|
ev.preventDefault();
|
|
}
|
|
contextTimeout = clearTimeout(contextTimeout);
|
|
started = new Date();
|
|
moved = false;
|
|
if ( t === 'contextmenu' ) {
|
|
contextTimeout = setTimeout(function() {
|
|
emitTouchEvent(ev, t, {button: 2, which: 3, buttons: 2});
|
|
_done();
|
|
}, TOUCH_CONTEXTMENU);
|
|
} else if ( t === 'dblclick' ) {
|
|
if ( clicks === 0 ) {
|
|
dblTimeout = clearTimeout(dblTimeout);
|
|
dblTimeout = setTimeout(function() {
|
|
clicks = 0;
|
|
}, TOUCH_DBLCLICK);
|
|
clicks++;
|
|
} else {
|
|
if ( !moved ) {
|
|
emitTouchEvent(ev, t);
|
|
}
|
|
clicks = 0;
|
|
}
|
|
}
|
|
el.addEventListener('touchend', _touchend, false);
|
|
el.addEventListener('touchmove', _touchmove, false);
|
|
el.addEventListener('touchcancel', _touchcancel, false);
|
|
}
|
|
function _touchend(ev) {
|
|
contextTimeout = clearTimeout(contextTimeout);
|
|
if ( !started ) {
|
|
return _done();
|
|
}
|
|
if ( !OSjs.Utils.$isFormElement(ev) ) {
|
|
ev.preventDefault();
|
|
}
|
|
var now = new Date();
|
|
var diff = now - started;
|
|
if ( !moved && t === 'click' ) {
|
|
if ( (diff > TOUCH_CLICK_MIN) && (diff < TOUCH_CLICK_MAX) ) {
|
|
ev.stopPropagation();
|
|
emitTouchEvent(ev, t);
|
|
}
|
|
}
|
|
return _done();
|
|
}
|
|
function _touchmove(ev) {
|
|
if ( ev.target === document.body || !moved ) {
|
|
ev.preventDefault();
|
|
}
|
|
if ( !started ) {
|
|
return;
|
|
}
|
|
contextTimeout = clearTimeout(contextTimeout);
|
|
dblTimeout = clearTimeout(dblTimeout);
|
|
clicks = 0;
|
|
moved = true;
|
|
}
|
|
function _touchcancel(ev) {
|
|
dblTimeout = clearTimeout(dblTimeout);
|
|
clicks = 0;
|
|
_done();
|
|
}
|
|
addEventHandler(el, n, 'touchstart', callback, _touchstart, false, 'touchstart');
|
|
}
|
|
function emitTouchEvent(ev, type, combineWith) {
|
|
if ( ev.target === document.body ) {
|
|
ev.preventDefault();
|
|
}
|
|
if ( !ev.currentTarget || ev.changedTouches.length > 1 || (ev.type === 'touchend' && ev.changedTouches > 0) ) {
|
|
return;
|
|
}
|
|
var copy = ['ctrlKey', 'altKey', 'shiftKey', 'metaKey', 'screenX', 'screenY'];
|
|
var touch = ev.changedTouches[0];
|
|
var evtArgs = {
|
|
clientX: touch.clientX,
|
|
clientY: touch.clientY,
|
|
relatedTarget: ev.target
|
|
};
|
|
copy.forEach(function(k) {
|
|
evtArgs[k] = ev[k];
|
|
});
|
|
if ( combineWith ) {
|
|
Object.keys(combineWith).forEach(function(k) {
|
|
evtArgs[k] = combineWith[k];
|
|
});
|
|
}
|
|
ev.currentTarget.dispatchEvent(new MouseEvent(type, evtArgs));
|
|
}
|
|
var customEvents = {
|
|
mousedown: 'touchstart',
|
|
mouseup: 'touchend',
|
|
mousemove: 'touchmove',
|
|
mousewheel: createWheelHandler,
|
|
contextmenu: createGestureHandler,
|
|
click: createGestureHandler,
|
|
dblclick: createGestureHandler
|
|
};
|
|
return function(el, evName, callback, useCapture, noBind) {
|
|
useCapture = (useCapture === true);
|
|
if ( arguments.length < 3 ) {
|
|
throw new Error('$bind expects 3 or more arguments');
|
|
}
|
|
if ( typeof evName !== 'string' ) {
|
|
throw new Error('Given event type was not a string');
|
|
}
|
|
if ( typeof callback !== 'function' ) {
|
|
throw new Error('Given callback was not a function');
|
|
}
|
|
function addEvent(nsType, type) {
|
|
addEventHandler(el, nsType, type, callback, function mouseEventHandler(ev) {
|
|
if ( noBind ) {
|
|
return callback(ev, OSjs.Utils.mousePosition(ev));
|
|
}
|
|
return callback.call(el, ev, OSjs.Utils.mousePosition(ev));
|
|
}, useCapture);
|
|
if ( customEvents[type] ) {
|
|
if ( typeof customEvents[type] === 'function' ) {
|
|
customEvents[type](el, nsType, type, callback, useCapture);
|
|
} else {
|
|
addEventHandler(el, nsType, customEvents[type], callback, function touchEventHandler(ev) {
|
|
emitTouchEvent(ev, type);
|
|
}, useCapture, customEvents[type]);
|
|
}
|
|
}
|
|
}
|
|
function initNamespace(ns) {
|
|
if ( !el._boundEvents ) {
|
|
el._boundEvents = {};
|
|
}
|
|
if ( !el._boundEvents[ns] ) {
|
|
el._boundEvents[ns] = [];
|
|
}
|
|
var found = el._boundEvents[ns].filter(function(iter) {
|
|
return iter.callback === callback;
|
|
});
|
|
return found.length === 0;
|
|
}
|
|
evName.replace(/\s/g, '').split(',').forEach(function(ns) {
|
|
var type = ns.split(':')[0];
|
|
if ( !initNamespace(ns) ) {
|
|
console.warn('Utils::$bind()', 'This event was already bound, skipping');
|
|
return;
|
|
}
|
|
addEvent(ns, type);
|
|
});
|
|
};
|
|
})();
|
|
OSjs.Utils.$unbind = function(el, evName, callback, param) {
|
|
function unbindAll() {
|
|
if ( el._boundEvents ) {
|
|
Object.keys(el._boundEvents).forEach(function(type) {
|
|
unbindNamed(type);
|
|
});
|
|
delete el._boundEvents;
|
|
}
|
|
}
|
|
function unbindNamed(type) {
|
|
if ( el._boundEvents ) {
|
|
var list = el._boundEvents || {};
|
|
if ( list[type] ) {
|
|
for ( var i = 0; i < list[type].length; i++ ) {
|
|
var iter = list[type][i];
|
|
if ( callback && iter.callback !== callback ) {
|
|
continue;
|
|
}
|
|
el.removeEventListener.apply(el, iter.args);
|
|
list[type].splice(i, 1);
|
|
i--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( el ) {
|
|
if ( evName ) {
|
|
evName.replace(/\s/g, '').split(',').forEach(function(type) {
|
|
unbindNamed(type);
|
|
});
|
|
} else {
|
|
unbindAll();
|
|
}
|
|
}
|
|
};
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.getCookie = function(k) {
|
|
var map = {};
|
|
document.cookie.split(/;\s+?/g).forEach(function(i) {
|
|
var idx = i.indexOf('=');
|
|
map[i.substr(i, idx)] = i.substr(idx + 1);
|
|
});
|
|
return k ? map[k] : map;
|
|
};
|
|
OSjs.Utils.format = function(format) {
|
|
var args = Array.prototype.slice.call(arguments, 1);
|
|
var sprintfRegex = /\{(\d+)\}/g;
|
|
function sprintf(match, number) {
|
|
return number in args ? args[number] : match;
|
|
}
|
|
return format.replace(sprintfRegex, sprintf);
|
|
};
|
|
OSjs.Utils.cleanHTML = function(html) {
|
|
return html.replace(/\n/g, '')
|
|
.replace(/[\t ]+</g, '<')
|
|
.replace(/\>[\t ]+</g, '><')
|
|
.replace(/\>[\t ]+$/g, '>');
|
|
};
|
|
OSjs.Utils.parseurl = function(url, modify) {
|
|
modify = modify || {};
|
|
if ( !url.match(/^(\w+\:)\/\//) ) {
|
|
url = '//' + url;
|
|
}
|
|
var protocol = url.split(/^(\w+\:)?\/\//);
|
|
var splitted = (function() {
|
|
var tmp = protocol[2].replace(/^\/\//, '').split('/');
|
|
return {
|
|
proto: (modify.protocol || protocol[1] || window.location.protocol || '').replace(/\:$/, ''),
|
|
host: modify.host || tmp.shift(),
|
|
path: modify.path || '/' + tmp.join('/')
|
|
};
|
|
})();
|
|
function _parts() {
|
|
var parts = [splitted.proto, '://'];
|
|
if ( modify.username ) {
|
|
var authstr = String(modify.username) + ':' + String(modify.password);
|
|
parts.push(authstr);
|
|
parts.push('@');
|
|
}
|
|
parts.push(splitted.host);
|
|
parts.push(splitted.path);
|
|
return parts.join('');
|
|
}
|
|
return {
|
|
protocol: splitted.proto,
|
|
host: splitted.host,
|
|
path: splitted.path,
|
|
url: _parts()
|
|
};
|
|
};
|
|
OSjs.Utils.argumentDefaults = function(args, defaults, undef) {
|
|
args = args || {};
|
|
Object.keys(defaults).forEach(function(key) {
|
|
if ( typeof defaults[key] === 'boolean' || typeof defaults[key] === 'number' ) {
|
|
if ( typeof args[key] === 'undefined' || args[key] === null ) {
|
|
args[key] = defaults[key];
|
|
}
|
|
} else {
|
|
args[key] = args[key] || defaults[key];
|
|
}
|
|
});
|
|
return args;
|
|
};
|
|
OSjs.Utils.mergeObject = function(obj1, obj2, opts) {
|
|
opts = opts || {};
|
|
for ( var p in obj2 ) {
|
|
if ( obj2.hasOwnProperty(p) ) {
|
|
try {
|
|
if (opts.overwrite === false && obj1.hasOwnProperty(p)) {
|
|
continue;
|
|
}
|
|
if ( obj2[p].constructor === Object ) {
|
|
obj1[p] = OSjs.Utils.mergeObject(obj1[p], obj2[p]);
|
|
} else {
|
|
obj1[p] = obj2[p];
|
|
}
|
|
} catch (e) {
|
|
obj1[p] = obj2[p];
|
|
}
|
|
}
|
|
}
|
|
return obj1;
|
|
};
|
|
OSjs.Utils.cloneObject = function(o) {
|
|
return JSON.parse(JSON.stringify(o, function(key, value) {
|
|
if ( value && typeof value === 'object' && value.tagName ) {
|
|
return undefined;
|
|
}
|
|
return value;
|
|
}));
|
|
};
|
|
OSjs.Utils.extend = function(obj, methods) {
|
|
if ( obj && methods ) {
|
|
Object.keys(methods).forEach(function(k) {
|
|
obj[k] = methods[k];
|
|
});
|
|
}
|
|
};
|
|
OSjs.Utils.inherit = function(to, from, extend) {
|
|
from.prototype = Object.create(to.prototype);
|
|
from.constructor = to;
|
|
if ( extend ) {
|
|
OSjs.Utils.extend(from.prototype, extend);
|
|
}
|
|
return from;
|
|
};
|
|
OSjs.Utils.convertToRGB = function(hex) {
|
|
var rgb = parseInt(hex.replace('#', ''), 16);
|
|
var val = {};
|
|
val.r = (rgb & (255 << 16)) >> 16;
|
|
val.g = (rgb & (255 << 8)) >> 8;
|
|
val.b = (rgb & 255);
|
|
return val;
|
|
};
|
|
OSjs.Utils.convertToHEX = function(r, g, b) {
|
|
if ( typeof r === 'object' ) {
|
|
g = r.g;
|
|
b = r.b;
|
|
r = r.r;
|
|
}
|
|
if ( typeof r === 'undefined' || typeof g === 'undefined' || typeof b === 'undefined' ) {
|
|
throw new Error('Invalid RGB supplied to convertToHEX()');
|
|
}
|
|
var hex = [
|
|
parseInt(r, 10).toString( 16 ),
|
|
parseInt(g, 10).toString( 16 ),
|
|
parseInt(b, 10).toString( 16 )
|
|
];
|
|
Object.keys(hex).forEach(function(i) {
|
|
if ( hex[i].length === 1 ) {
|
|
hex[i] = '0' + hex[i];
|
|
}
|
|
});
|
|
return '#' + hex.join('').toUpperCase();
|
|
};
|
|
OSjs.Utils.invertHEX = function(hex) {
|
|
var color = parseInt(hex.replace('#', ''), 16);
|
|
color = 0xFFFFFF ^ color;
|
|
color = color.toString(16);
|
|
color = ('000000' + color).slice(-6);
|
|
return '#' + color;
|
|
};
|
|
OSjs.Utils.asyncs = function(queue, onentry, ondone) {
|
|
onentry = onentry || function(e, i, n) {
|
|
return n();
|
|
};
|
|
ondone = ondone || function() {};
|
|
var finished = [];
|
|
var isdone = false;
|
|
(function next(i) {
|
|
if ( isdone || finished.indexOf(i) !== -1 ) {
|
|
return;
|
|
}
|
|
finished.push(i);
|
|
if ( i >= queue.length ) {
|
|
isdone = true;
|
|
return ondone();
|
|
}
|
|
try {
|
|
onentry(queue[i], i, function() {
|
|
next(i + 1);
|
|
});
|
|
} catch ( e ) {
|
|
console.warn('Utils::asyncs()', 'Exception while stepping', e.stack, e);
|
|
next(i + 1);
|
|
}
|
|
})(0);
|
|
};
|
|
OSjs.Utils.asyncp = function(queue, opts, onentry, ondone) {
|
|
opts = opts || {};
|
|
var running = 0;
|
|
var max = opts.max || 3;
|
|
var qleft = Object.keys(queue);
|
|
var finished = [];
|
|
var isdone = false;
|
|
function spawn(i, cb) {
|
|
function _done() {
|
|
running--;
|
|
cb();
|
|
}
|
|
if ( finished.indexOf(i) !== -1 ) {
|
|
return;
|
|
}
|
|
finished.push(i);
|
|
running++;
|
|
try {
|
|
onentry(queue[i], i, _done);
|
|
} catch ( e ) {
|
|
console.warn('Utils::asyncp()', 'Exception while stepping', e.stack, e);
|
|
_done();
|
|
}
|
|
}
|
|
(function check() {
|
|
if ( !qleft.length ) {
|
|
if ( running || isdone ) {
|
|
return;
|
|
}
|
|
isdone = true;
|
|
return ondone();
|
|
}
|
|
var d = Math.min(qleft.length, max - running);
|
|
for ( var i = 0; i < d; i++ ) {
|
|
spawn(qleft.shift(), check);
|
|
}
|
|
})();
|
|
};
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.$ = function(id) {
|
|
return document.getElementById(id);
|
|
};
|
|
OSjs.Utils.$safeName = function(str) {
|
|
return (str || '').replace(/[^a-zA-Z0-9]/g, '_');
|
|
};
|
|
OSjs.Utils.$remove = function(node) {
|
|
if ( node && node.parentNode ) {
|
|
node.parentNode.removeChild(node);
|
|
}
|
|
return null;
|
|
};
|
|
OSjs.Utils.$empty = function(myNode) {
|
|
if ( myNode ) {
|
|
while (myNode.firstChild) {
|
|
myNode.removeChild(myNode.firstChild);
|
|
}
|
|
}
|
|
};
|
|
OSjs.Utils.$getStyle = function(oElm, strCssRule) {
|
|
var strValue = '';
|
|
if ( document.defaultView && document.defaultView.getComputedStyle ) {
|
|
strValue = document.defaultView.getComputedStyle(oElm, '').getPropertyValue(strCssRule);
|
|
} else if ( oElm.currentStyle ) {
|
|
strCssRule = strCssRule.replace(/\-(\w)/g, function(strMatch, p1) {
|
|
return p1.toUpperCase();
|
|
});
|
|
strValue = oElm.currentStyle[strCssRule];
|
|
}
|
|
return strValue;
|
|
};
|
|
OSjs.Utils.$position = function(el, parentEl) {
|
|
if ( el ) {
|
|
if ( parentEl ) {
|
|
var result = {left:0, top:0, width: el.offsetWidth, height: el.offsetHeight};
|
|
while ( true ) {
|
|
result.left += el.offsetLeft;
|
|
result.top += el.offsetTop;
|
|
if ( el.offsetParent === parentEl || el.offsetParent === null ) {
|
|
break;
|
|
}
|
|
el = el.offsetParent;
|
|
}
|
|
return result;
|
|
}
|
|
return el.getBoundingClientRect();
|
|
}
|
|
return null;
|
|
};
|
|
OSjs.Utils.$parent = function(el, cb) {
|
|
var result = null;
|
|
if ( el && cb ) {
|
|
var current = el;
|
|
while ( current.parentNode ) {
|
|
if ( cb(current) ) {
|
|
result = current;
|
|
break;
|
|
}
|
|
current = current.parentNode;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
OSjs.Utils.$index = function(el, parentEl) {
|
|
if ( el ) {
|
|
parentEl = parentEl || el.parentNode;
|
|
if ( parentEl ) {
|
|
var nodeList = Array.prototype.slice.call(parentEl.children);
|
|
var nodeIndex = nodeList.indexOf(el, parentEl);
|
|
return nodeIndex;
|
|
}
|
|
}
|
|
return -1;
|
|
};
|
|
OSjs.Utils.$selectRange = function(field, start, end) {
|
|
if ( !field ) {
|
|
throw new Error('Cannot select range: missing element');
|
|
}
|
|
if ( typeof start === 'undefined' || typeof end === 'undefined' ) {
|
|
throw new Error('Cannot select range: mising start/end');
|
|
}
|
|
if ( field.createTextRange ) {
|
|
var selRange = field.createTextRange();
|
|
selRange.collapse(true);
|
|
selRange.moveStart('character', start);
|
|
selRange.moveEnd('character', end);
|
|
selRange.select();
|
|
field.focus();
|
|
} else if ( field.setSelectionRange ) {
|
|
field.focus();
|
|
field.setSelectionRange(start, end);
|
|
} else if ( typeof field.selectionStart !== 'undefined' ) {
|
|
field.selectionStart = start;
|
|
field.selectionEnd = end;
|
|
field.focus();
|
|
}
|
|
};
|
|
OSjs.Utils.$addClass = function(el, name) {
|
|
if ( el ) {
|
|
name.split(' ').forEach(function(n) {
|
|
el.classList.add(n);
|
|
});
|
|
}
|
|
};
|
|
OSjs.Utils.$removeClass = function(el, name) {
|
|
if ( el ) {
|
|
name.split(' ').forEach(function(n) {
|
|
el.classList.remove(n);
|
|
});
|
|
}
|
|
};
|
|
OSjs.Utils.$hasClass = function(el, name) {
|
|
if ( el && name ) {
|
|
return name.split(' ').every(function(n) {
|
|
return el.classList.contains(n);
|
|
});
|
|
}
|
|
return false;
|
|
};
|
|
OSjs.Utils.$escape = function(str) {
|
|
var div = document.createElement('div');
|
|
div.appendChild(document.createTextNode(str));
|
|
return div.innerHTML;
|
|
};
|
|
OSjs.Utils.$create = function(tagName, properties) {
|
|
var element = document.createElement(tagName);
|
|
function _foreach(dict, l) {
|
|
dict = dict || {};
|
|
Object.keys(dict).forEach(function(name) {
|
|
l(name.replace(/_/g, '-'), String(dict[name]));
|
|
});
|
|
}
|
|
_foreach(properties.style, function(key, val) {
|
|
element.style[key] = val;
|
|
});
|
|
_foreach(properties.aria, function(key, val) {
|
|
if ( (['role']).indexOf(key) !== -1 ) {
|
|
key = 'aria-' + key;
|
|
}
|
|
element.setAttribute(key, val);
|
|
});
|
|
_foreach(properties.data, function(key, val) {
|
|
element.setAttribute('data-' + key, val);
|
|
});
|
|
_foreach(properties, function(key, val) {
|
|
if ( (['style', 'aria', 'data']).indexOf(key) === -1 ) {
|
|
element[key] = val;
|
|
}
|
|
});
|
|
return element;
|
|
};
|
|
OSjs.Utils.$createCSS = function(src, onload, onerror) {
|
|
var link = document.createElement('link');
|
|
link.setAttribute('rel', 'stylesheet');
|
|
link.setAttribute('type', 'text/css');
|
|
link.onload = onload || function() {};
|
|
link.onerror = onerror || function() {};
|
|
link.setAttribute('href', src);
|
|
document.getElementsByTagName('head')[0].appendChild(link);
|
|
return link;
|
|
};
|
|
OSjs.Utils.$createJS = function(src, onreadystatechange, onload, onerror, attrs) {
|
|
var res = document.createElement('script');
|
|
res.onreadystatechange = onreadystatechange || function() {};
|
|
res.onerror = onerror || function() {};
|
|
res.onload = onload || function() {};
|
|
attrs = OSjs.Utils.mergeObject({
|
|
type: 'text/javascript',
|
|
charset: 'utf-8',
|
|
src: src
|
|
}, attrs || {});
|
|
Object.keys(attrs).forEach(function(k) {
|
|
res[k] = String(attrs[k]);
|
|
});
|
|
document.getElementsByTagName('head')[0].appendChild(res);
|
|
return res;
|
|
};
|
|
OSjs.Utils.$isFormElement = function(input, types) {
|
|
types = types || ['TEXTAREA', 'INPUT', 'SELECT'];
|
|
if ( input instanceof window.Event ) {
|
|
input = input.srcElement || input.target;
|
|
}
|
|
if ( input instanceof window.Element ) {
|
|
if ( types.indexOf(input.tagName.toUpperCase()) >= 0 ) {
|
|
if ( !(input.readOnly || input.disabled) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
OSjs.Utils.$css = function(el, ink, inv) {
|
|
function rep(k) {
|
|
return k.replace(/\-(\w)/g, function(strMatch, p1) {
|
|
return p1.toUpperCase();
|
|
});
|
|
}
|
|
var obj = {};
|
|
if ( arguments.length === 2 ) {
|
|
if ( typeof ink === 'string' ) {
|
|
return el.parentNode ? OSjs.Utils.$getStyle(el, ink) : el.style[rep(ink)];
|
|
}
|
|
obj = ink;
|
|
} else if ( arguments.length === 3 ) {
|
|
obj[ink] = inv;
|
|
}
|
|
Object.keys(obj).forEach(function(k) {
|
|
el.style[rep(k)] = String(obj[k]);
|
|
});
|
|
};
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.ajax = function(args) {
|
|
var request;
|
|
args = OSjs.Utils.argumentDefaults(args, {
|
|
onerror : function() {},
|
|
onsuccess : function() {},
|
|
onprogress : function() {},
|
|
oncreated : function() {},
|
|
onfailed : function() {},
|
|
oncanceled : function() {},
|
|
ontimeout : function() {},
|
|
acceptcodes : [200, 201, 304],
|
|
method : 'GET',
|
|
responseType : null,
|
|
requestHeaders : {},
|
|
body : null,
|
|
timeout : 0,
|
|
json : false,
|
|
url : '',
|
|
jsonp : false
|
|
});
|
|
function onReadyStateChange() {
|
|
var result;
|
|
function _onError(error) {
|
|
error = OSjs.API._('ERR_UTILS_XHR_FMT', error);
|
|
console.warn('Utils::ajax()', 'onReadyStateChange()', error);
|
|
args.onerror(error, result, this, args.url);
|
|
}
|
|
if ( this.readyState === 4 ) {
|
|
result = this.responseText;
|
|
try {
|
|
var ctype = this.getResponseHeader('content-type') || '';
|
|
if ( args.json && ctype.match(/^application\/json/) ) {
|
|
result = JSON.parse(this.responseText);
|
|
}
|
|
} catch (ex) {
|
|
_onError.call(this, ex.toString());
|
|
return;
|
|
}
|
|
if ( this.status === 200 || this.status === 201 ) {
|
|
args.onsuccess(result, this, args.url);
|
|
} else {
|
|
_onError.call(this, String(this.status));
|
|
}
|
|
}
|
|
}
|
|
function requestJSONP() {
|
|
var loaded = false;
|
|
OSjs.Utils.$createJS(args.url, function() {
|
|
if ( (this.readyState === 'complete' || this.readyState === 'loaded') && !loaded) {
|
|
loaded = true;
|
|
args.onsuccess();
|
|
}
|
|
}, function() {
|
|
if ( loaded ) {
|
|
return;
|
|
}
|
|
loaded = true;
|
|
args.onsuccess();
|
|
}, function() {
|
|
if ( loaded ) {
|
|
return;
|
|
}
|
|
loaded = true;
|
|
args.onerror();
|
|
});
|
|
}
|
|
function cleanup() {
|
|
if ( request.upload ) {
|
|
request.upload.removeEventListener('progress', args.onprogress, false);
|
|
} else {
|
|
request.removeEventListener('progress', args.onprogress, false);
|
|
}
|
|
request.removeEventListener('error', args.onfailed, false);
|
|
request.removeEventListener('abort', args.oncanceled, false);
|
|
request.onerror = null;
|
|
request.onload = null;
|
|
request.onreadystatechange = null;
|
|
request.ontimeut = null;
|
|
request = null;
|
|
args = null;
|
|
}
|
|
function requestJSON() {
|
|
request = new XMLHttpRequest();
|
|
try {
|
|
request.timeout = args.timeout;
|
|
} catch ( e ) {}
|
|
if ( request.upload ) {
|
|
request.upload.addEventListener('progress', args.onprogress, false);
|
|
} else {
|
|
request.addEventListener('progress', args.onprogress, false);
|
|
}
|
|
request.ontimeout = function(evt) {
|
|
args.ontimeout(evt);
|
|
};
|
|
if ( args.responseType === 'arraybuffer' ) { // Binary
|
|
request.onerror = function(evt) {
|
|
var error = request.response || OSjs.API._('ERR_UTILS_XHR_FATAL');
|
|
args.onerror(error, evt, request, args.url);
|
|
cleanup();
|
|
};
|
|
request.onload = function(evt) {
|
|
if ( args.acceptcodes.indexOf(request.status) >= 0 ) {
|
|
args.onsuccess(request.response, request, args.url);
|
|
} else {
|
|
OSjs.VFS.Helpers.abToText(request.response, 'text/plain', function(err, txt) {
|
|
var error = txt || err || OSjs.API._('ERR_UTILS_XHR_FATAL');
|
|
args.onerror(error, evt, request, args.url);
|
|
});
|
|
}
|
|
cleanup();
|
|
};
|
|
} else {
|
|
request.addEventListener('error', args.onfailed, false);
|
|
request.addEventListener('abort', args.oncanceled, false);
|
|
request.onreadystatechange = onReadyStateChange;
|
|
}
|
|
request.open(args.method, args.url, true);
|
|
Object.keys(args.requestHeaders).forEach(function(h) {
|
|
request.setRequestHeader(h, args.requestHeaders[h]);
|
|
});
|
|
request.responseType = args.responseType || '';
|
|
args.oncreated(request);
|
|
request.send(args.body);
|
|
}
|
|
if ( (OSjs.API.getConfig('Connection.Type') === 'standalone') ) {
|
|
args.onerror('You are currently running locally and cannot perform this operation!', null, request, args.url);
|
|
return;
|
|
}
|
|
if ( args.json && (typeof args.body !== 'string') && !(args.body instanceof FormData) ) {
|
|
args.body = JSON.stringify(args.body);
|
|
if ( typeof args.requestHeaders['Content-Type'] === 'undefined' ) {
|
|
args.requestHeaders['Content-Type'] = 'application/json';
|
|
}
|
|
}
|
|
return args.jsonp ? requestJSONP() : requestJSON();
|
|
};
|
|
OSjs.Utils.preload = (function() {
|
|
var _LOADED = {};
|
|
var _CACHE = {};
|
|
function checkCache(item, args) {
|
|
if ( item && _LOADED[item.src] === true ) {
|
|
if ( item.force !== true && args.force !== true ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
var preloadTypes = {
|
|
stylesheet: function createStylesheet(item, cb) {
|
|
var src = item.src;
|
|
var loaded = false;
|
|
var timeout;
|
|
function _done(res) {
|
|
timeout = clearTimeout(timeout);
|
|
if ( !loaded ) {
|
|
_LOADED[src] = true;
|
|
loaded = true;
|
|
cb(res, src);
|
|
}
|
|
}
|
|
function _check(path) {
|
|
var result = false;
|
|
(document.styleSheet || []).forEach(function(iter, i) {
|
|
if ( iter.href.indexOf(path) !== -1 ) {
|
|
result = true;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
OSjs.Utils.$createCSS(src, function() {
|
|
_done(true);
|
|
}, function() {
|
|
_done(false);
|
|
});
|
|
if ( typeof document.styleSheet === 'undefined' || (!loaded && _check(src)) ) {
|
|
return _done(true);
|
|
}
|
|
timeout = setTimeout(function() {
|
|
_done(false);
|
|
}, 30000);
|
|
},
|
|
javascript: function createScript(item, cb) {
|
|
var src = item.src;
|
|
var loaded = false;
|
|
function _done(res) {
|
|
if ( !loaded ) {
|
|
_LOADED[src] = true;
|
|
loaded = true;
|
|
cb(res, src);
|
|
}
|
|
}
|
|
OSjs.Utils.$createJS(src, function() {
|
|
if ( (this.readyState === 'complete' || this.readyState === 'loaded') ) {
|
|
_done(true);
|
|
}
|
|
}, function() {
|
|
_done(true);
|
|
}, function() {
|
|
_done(false);
|
|
}, {async: false});
|
|
},
|
|
scheme: function createHTML(item, cb, args) {
|
|
var scheme;
|
|
function _cache(err, html) {
|
|
if ( !err && html ) {
|
|
_CACHE[item.src] = html;
|
|
}
|
|
}
|
|
function _cb() {
|
|
scheme = null;
|
|
cb.apply(null, arguments);
|
|
}
|
|
if ( _CACHE[item.src] && item.force !== true && args.force !== true ) {
|
|
scheme = new OSjs.GUI.Scheme();
|
|
scheme.loadString(_CACHE[item.src]);
|
|
_cb(true, item.src, scheme);
|
|
} else {
|
|
if ( OSjs.API.isStandalone() ) {
|
|
scheme = new OSjs.GUI.Scheme();
|
|
preloadTypes.javascript({
|
|
src: OSjs.Utils.pathJoin(OSjs.Utils.dirname(item.src), '_scheme.js'),
|
|
type: 'javascript'
|
|
}, function() {
|
|
var look = item.src.replace(OSjs.API.getBrowserPath(), '/').replace(/^\/?packages/, '');
|
|
var html = OSjs.STANDALONE.SCHEMES[look];
|
|
scheme.loadString(html);
|
|
_cache(false, html);
|
|
_cb(true, item.src, scheme);
|
|
});
|
|
} else {
|
|
scheme = new OSjs.GUI.Scheme(item.src);
|
|
scheme.load(function(err, res) {
|
|
_cb(err ? false : true, item.src, scheme);
|
|
}, function(err, html) {
|
|
_cache(err, html);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
};
|
|
function getType(src) {
|
|
if ( src.match(/\.js$/i) ) {
|
|
return 'javascript';
|
|
} else if ( src.match(/\.css$/i) ) {
|
|
return 'stylesheet';
|
|
}
|
|
return 'unknown';
|
|
}
|
|
function getTypeCorrected(t) {
|
|
var typemap = {
|
|
script: 'javascript',
|
|
js: 'javascript',
|
|
style: 'stylesheet',
|
|
css: 'stylesheet'
|
|
};
|
|
return typemap[t] || t;
|
|
}
|
|
function preloadList(list, ondone, onprogress, args) {
|
|
args = args || {};
|
|
ondone = ondone || function() {};
|
|
onprogress = onprogress || function() {};
|
|
var succeeded = [];
|
|
var failed = [];
|
|
var len = list.length;
|
|
var total = 0;
|
|
list = (list || []).map(function(item) {
|
|
if ( typeof item === 'string' ) {
|
|
item = {src: item};
|
|
}
|
|
item._src = item.src;
|
|
item.type = item.type ? getTypeCorrected(item.type) : getType(item.src);
|
|
return item;
|
|
});
|
|
var data = [];
|
|
OSjs.Utils.asyncp(list, {max: args.max || 1}, function(item, index, next) {
|
|
function _onentryloaded(state, src, setData) {
|
|
total++;
|
|
(state ? succeeded : failed).push(src);
|
|
onprogress(index, len, src, succeeded, failed, total);
|
|
if ( setData ) {
|
|
data.push({
|
|
item: item,
|
|
data: setData
|
|
});
|
|
}
|
|
next();
|
|
}
|
|
if ( item ) {
|
|
if ( checkCache(item, args) ) {
|
|
return _onentryloaded(true, item.src);
|
|
} else {
|
|
if ( preloadTypes[item.type] ) {
|
|
return preloadTypes[item.type](item, _onentryloaded, args);
|
|
}
|
|
}
|
|
failed.push(item.src);
|
|
}
|
|
return next();
|
|
}, function() {
|
|
ondone(len, failed, succeeded, data);
|
|
});
|
|
}
|
|
return preloadList;
|
|
})();
|
|
})();
|
|
|
|
(function() {
|
|
'use strict';
|
|
OSjs.Utils.getPathProtocol = function getPathProtocol(orig) {
|
|
var tmp = document.createElement('a');
|
|
tmp.href = orig;
|
|
return tmp.protocol.replace(/:$/, '');
|
|
};
|
|
OSjs.Utils.checkdir = function(path) {
|
|
if ( path && window.location.href.match(/^file\:\/\//) ) {
|
|
path = path.replace(/^\//, '');
|
|
}
|
|
return path;
|
|
};
|
|
OSjs.Utils.filext = function(d) {
|
|
var ext = OSjs.Utils.filename(d).split('.').pop();
|
|
return ext ? ext.toLowerCase() : null;
|
|
};
|
|
OSjs.Utils.dirname = function(f) {
|
|
function _parentDir(p) {
|
|
var pstr = p.split(/^(.*)\:\/\/(.*)/).filter(function(n) {
|
|
return n !== '';
|
|
});
|
|
var args = pstr.pop();
|
|
var prot = pstr.pop();
|
|
var result = '';
|
|
var tmp = args.split('/').filter(function(n) {
|
|
return n !== '';
|
|
});
|
|
if ( tmp.length ) {
|
|
tmp.pop();
|
|
}
|
|
result = tmp.join('/');
|
|
if ( !result.match(/^\//) ) {
|
|
result = '/' + result;
|
|
}
|
|
if ( prot ) {
|
|
result = prot + '://' + result;
|
|
}
|
|
return result;
|
|
}
|
|
return f.match(/^((.*)\:\/\/)?\/$/) ? f : _parentDir(f.replace(/\/$/, ''));
|
|
};
|
|
OSjs.Utils.filename = function(p) {
|
|
return (p || '').replace(/\/$/, '').split('/').pop();
|
|
};
|
|
OSjs.Utils.humanFileSize = function(bytes, si) {
|
|
var thresh = si ? 1000 : 1024;
|
|
if (bytes < thresh) {
|
|
return bytes + ' B';
|
|
}
|
|
var units = si ? ['kB','MB','GB','TB','PB','EB','ZB','YB'] : ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
|
|
var u = -1;
|
|
do {
|
|
bytes /= thresh;
|
|
++u;
|
|
} while (bytes >= thresh);
|
|
return bytes.toFixed(1) + ' ' + units[u];
|
|
};
|
|
OSjs.Utils.escapeFilename = function(n) {
|
|
return (n || '').replace(/[\|&;\$%@"<>\(\)\+,\*\/]/g, '').trim();
|
|
};
|
|
OSjs.Utils.replaceFileExtension = function(filename, rep) {
|
|
var spl = filename.split('.');
|
|
spl.pop();
|
|
spl.push(rep);
|
|
return spl.join('.');
|
|
};
|
|
OSjs.Utils.replaceFilename = function(orig, newname) {
|
|
var spl = orig.split('/');
|
|
spl.pop();
|
|
spl.push(newname);
|
|
return spl.join('/');
|
|
};
|
|
OSjs.Utils.pathJoin = function() {
|
|
var parts = [];
|
|
var prefix = '';
|
|
var i, s;
|
|
for ( i = 0; i < arguments.length; i++ ) {
|
|
s = String(arguments[i]);
|
|
if ( s.match(/^([A-z0-9\-_]+)\:\//) ) {
|
|
prefix = s.replace(/\/+$/, '//');
|
|
continue;
|
|
}
|
|
s = s.replace(/^\/+/, '').replace(/\/+$/, '');
|
|
parts.push(s);
|
|
}
|
|
return prefix + '/' + parts.join('/');
|
|
};
|
|
OSjs.Utils.getFilenameRange = function(val) {
|
|
val = val || '';
|
|
var range = {min: 0, max: val.length};
|
|
if ( val.match(/^\./) ) {
|
|
if ( val.length >= 2 ) {
|
|
range.min = 1;
|
|
}
|
|
} else {
|
|
if ( val.match(/\.(\w+)$/) ) {
|
|
var m = val.split(/\.(\w+)$/);
|
|
for ( var i = m.length - 1; i >= 0; i-- ) {
|
|
if ( m[i].length ) {
|
|
range.max = val.length - m[i].length - 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return range;
|
|
};
|
|
OSjs.Utils.btoaUrlsafe = function(str) {
|
|
return (!str || !str.length) ? '' : btoa(str)
|
|
.replace(/\+/g, '-')
|
|
.replace(/\//g, '_')
|
|
.replace(/=+$/, '');
|
|
};
|
|
OSjs.Utils.atobUrlsafe = function(str) {
|
|
if ( str && str.length ) {
|
|
str = (str + '===').slice(0, str.length + (str.length % 4));
|
|
return atob(str.replace(/-/g, '+').replace(/_/g, '/'));
|
|
}
|
|
return '';
|
|
};
|
|
OSjs.Utils.btoaUtf = function(str) { // Encode
|
|
var _unescape = window.unescape || function(s) {
|
|
function d(x, n) {
|
|
return String.fromCharCode(parseInt(n, 16));
|
|
}
|
|
return s.replace(/%([0-9A-F]{2})/i, d);
|
|
};
|
|
str = _unescape(encodeURIComponent(str));
|
|
return btoa(str);
|
|
};
|
|
OSjs.Utils.atobUtf = function(str) { // Decode
|
|
var _escape = window.escape || function(s) {
|
|
function q(c) {
|
|
c = c.charCodeAt();
|
|
return '%' + (c < 16 ? '0' : '') + c.toString(16).toUpperCase();
|
|
}
|
|
return s.replace(/[\x00-),:-?[-^`{-\xFF]/g, q);
|
|
};
|
|
var trans = _escape(atob(str));
|
|
return decodeURIComponent(trans);
|
|
};
|
|
OSjs.Utils.checkAcceptMime = function(mime, list) {
|
|
if ( mime && list.length ) {
|
|
var re;
|
|
for ( var i = 0; i < list.length; i++ ) {
|
|
re = new RegExp(list[i]);
|
|
if ( re.test(mime) === true ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
})();
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var DefaultLocale = 'en_EN';
|
|
var CurrentLocale = 'en_EN';
|
|
var _CLIPBOARD; // Current 'clipboard' data
|
|
var _hooks = {
|
|
'onInitialize': [],
|
|
'onInited': [],
|
|
'onWMInited': [],
|
|
'onSessionLoaded': [],
|
|
'onShutdown': [],
|
|
'onApplicationPreload': [],
|
|
'onApplicationLaunch': [],
|
|
'onApplicationLaunched': [],
|
|
'onBlurMenu': []
|
|
};
|
|
function ServiceNotificationIcon() {
|
|
this.entries = {};
|
|
this.size = 0;
|
|
this.notif = null;
|
|
this.init();
|
|
}
|
|
ServiceNotificationIcon.prototype.init = function() {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var self = this;
|
|
function show(ev) {
|
|
self.displayMenu(ev);
|
|
return false;
|
|
}
|
|
if ( wm ) {
|
|
this.notif = wm.createNotificationIcon('ServiceNotificationIcon', {
|
|
image: API.getIcon('status/gtk-dialog-authentication.png'),
|
|
onContextMenu: show,
|
|
onClick: show,
|
|
onInited: function(el, img) {
|
|
self._updateIcon();
|
|
}
|
|
});
|
|
this._updateIcon();
|
|
}
|
|
};
|
|
ServiceNotificationIcon.prototype.destroy = function() {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.removeNotificationIcon('ServiceNotificationIcon');
|
|
}
|
|
this.size = 0;
|
|
this.entries = {};
|
|
this.notif = null;
|
|
};
|
|
ServiceNotificationIcon.prototype._updateIcon = function() {
|
|
if ( this.notif ) {
|
|
if ( this.notif.$container ) {
|
|
this.notif.$container.style.display = this.size ? 'inline-block' : 'none';
|
|
}
|
|
this.notif.setTitle(API._('SERVICENOTIFICATION_TOOLTIP', this.size.toString()));
|
|
}
|
|
};
|
|
ServiceNotificationIcon.prototype.displayMenu = function(ev) {
|
|
var menu = [];
|
|
var entries = this.entries;
|
|
Object.keys(entries).forEach(function(name) {
|
|
menu.push({
|
|
title: name,
|
|
menu: entries[name]
|
|
});
|
|
});
|
|
API.createMenu(menu, ev);
|
|
};
|
|
ServiceNotificationIcon.prototype.add = function(name, menu) {
|
|
if ( !this.entries[name] ) {
|
|
this.entries[name] = menu;
|
|
this.size++;
|
|
this._updateIcon();
|
|
}
|
|
};
|
|
ServiceNotificationIcon.prototype.remove = function(name) {
|
|
if ( this.entries[name] ) {
|
|
delete this.entries[name];
|
|
this.size--;
|
|
this._updateIcon();
|
|
}
|
|
};
|
|
API._ = function _apiTranslate() {
|
|
var s = arguments[0];
|
|
var a = arguments;
|
|
if ( OSjs.Locales[CurrentLocale][s] ) {
|
|
a[0] = OSjs.Locales[CurrentLocale][s];
|
|
} else {
|
|
a[0] = OSjs.Locales[DefaultLocale][s] || s;
|
|
}
|
|
return a.length > 1 ? Utils.format.apply(null, a) : a[0];
|
|
};
|
|
API.__ = function _apiTranslateList() {
|
|
var l = arguments[0];
|
|
var s = arguments[1];
|
|
var a = Array.prototype.slice.call(arguments, 1);
|
|
if ( l[CurrentLocale] && l[CurrentLocale][s] ) {
|
|
a[0] = l[CurrentLocale][s];
|
|
} else {
|
|
a[0] = l[DefaultLocale] ? (l[DefaultLocale][s] || s) : s;
|
|
if ( a[0] && a[0] === s ) {
|
|
a[0] = API._.apply(null, a);
|
|
}
|
|
}
|
|
return a.length > 1 ? Utils.format.apply(null, a) : a[0];
|
|
};
|
|
API.getLocale = function _apiGetLocale() {
|
|
return CurrentLocale;
|
|
};
|
|
API.setLocale = function _apiSetLocale(l) {
|
|
var RTL = API.getConfig('LocaleOptions.RTL', []);
|
|
if ( OSjs.Locales[l] ) {
|
|
CurrentLocale = l;
|
|
} else {
|
|
console.warn('API::setLocale()', 'Invalid locale', l, '(Using default)');
|
|
CurrentLocale = DefaultLocale;
|
|
}
|
|
var major = CurrentLocale.split('_')[0];
|
|
var html = document.querySelector('html');
|
|
if ( html ) {
|
|
html.setAttribute('lang', l);
|
|
html.setAttribute('dir', RTL.indexOf(major) !== -1 ? 'rtl' : 'ltr');
|
|
}
|
|
};
|
|
API.curl = function _apiCurl(args, callback) {
|
|
args = args || {};
|
|
callback = callback || {};
|
|
var opts = args.body;
|
|
if ( typeof opts === 'object' ) {
|
|
console.warn('DEPRECATION WARNING', 'The \'body\' wrapper is no longer needed');
|
|
} else {
|
|
opts = args;
|
|
}
|
|
API.call('curl', opts, callback, args.options);
|
|
};
|
|
var _CALL_INDEX = 1;
|
|
API.call = function _apiCall(m, a, cb, options) {
|
|
a = a || {};
|
|
var lname = 'APICall_' + _CALL_INDEX;
|
|
if ( typeof a.__loading === 'undefined' || a.__loading === true ) {
|
|
API.createLoading(lname, {className: 'BusyNotification', tooltip: 'API Call'});
|
|
}
|
|
if ( typeof cb !== 'function' ) {
|
|
throw new TypeError('call() expects a function as callback');
|
|
}
|
|
if ( options && typeof options !== 'object' ) {
|
|
throw new TypeError('call() expects an object as options');
|
|
}
|
|
_CALL_INDEX++;
|
|
var handler = OSjs.Core.getHandler();
|
|
return handler.callAPI(m, a, function(response) {
|
|
API.destroyLoading(lname);
|
|
response = response || {};
|
|
cb(response.error || false, response.result);
|
|
}, function(err) {
|
|
cb(err);
|
|
}, options);
|
|
};
|
|
API.open = function _apiOpen(file, launchArgs) {
|
|
launchArgs = launchArgs || {};
|
|
if ( !file.path ) {
|
|
throw new Error('Cannot API::open() without a path');
|
|
}
|
|
var settingsManager = OSjs.Core.getSettingsManager();
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var args = {file: file};
|
|
function getApplicationNameByFile(file, forceList, callback) {
|
|
if ( !(file instanceof OSjs.VFS.File) ) {
|
|
throw new Error('This function excepts a OSjs.VFS.File object');
|
|
}
|
|
var pacman = OSjs.Core.getPackageManager();
|
|
var val = settingsManager.get('DefaultApplication', file.mime);
|
|
if ( !forceList && val ) {
|
|
if ( pacman.getPackage(val) ) {
|
|
callback([val]);
|
|
return;
|
|
}
|
|
}
|
|
callback(pacman.getPackagesByMime(file.mime));
|
|
}
|
|
function setDefaultApplication(mime, app, callback) {
|
|
callback = callback || function() {};
|
|
settingsManager.set('DefaultApplication', mime, app);
|
|
settingsManager.save('DefaultApplication', callback);
|
|
}
|
|
function _launch(name) {
|
|
if ( name ) {
|
|
API.launch(name, args, launchArgs.onFinished, launchArgs.onError, launchArgs.onConstructed);
|
|
}
|
|
}
|
|
function _launchApp(name, ar) {
|
|
API.launch(name, ar);
|
|
}
|
|
function _onDone(app) {
|
|
if ( app.length ) {
|
|
if ( app.length === 1 ) {
|
|
_launch(app[0]);
|
|
} else {
|
|
if ( wm ) {
|
|
API.createDialog('ApplicationChooser', {
|
|
file: file,
|
|
list: app
|
|
}, function(ev, btn, result) {
|
|
if ( btn !== 'ok' ) {
|
|
return;
|
|
}
|
|
_launch(result.name);
|
|
setDefaultApplication(file.mime, result.useDefault ? result.name : null);
|
|
});
|
|
} else {
|
|
API.error(API._('ERR_FILE_OPEN'),
|
|
API._('ERR_FILE_OPEN_FMT', file.path),
|
|
API._('ERR_NO_WM_RUNNING') );
|
|
}
|
|
}
|
|
} else {
|
|
API.error(API._('ERR_FILE_OPEN'),
|
|
API._('ERR_FILE_OPEN_FMT', file.path),
|
|
API._('ERR_APP_MIME_NOT_FOUND_FMT', file.mime) );
|
|
}
|
|
}
|
|
if ( file.mime === 'osjs/application' ) {
|
|
_launchApp(Utils.filename(file.path), launchArgs);
|
|
} else if ( file.type === 'dir' ) {
|
|
var fm = settingsManager.instance('DefaultApplication').get('dir', 'ApplicationFileManager');
|
|
_launchApp(fm, {path: file.path});
|
|
} else {
|
|
if ( launchArgs.args ) {
|
|
Object.keys(launchArgs.args).forEach(function(i) {
|
|
args[i] = launchArgs.args[i];
|
|
});
|
|
}
|
|
getApplicationNameByFile(file, launchArgs.forceList, _onDone);
|
|
}
|
|
};
|
|
API.relaunch = function _apiRelaunch(n) {
|
|
function relaunch(p) {
|
|
var data = null;
|
|
var args = {};
|
|
if ( p instanceof OSjs.Core.Application ) {
|
|
data = p._getSessionData();
|
|
}
|
|
try {
|
|
p.destroy(); // kill
|
|
} catch ( e ) {
|
|
console.warn('OSjs.API.relaunch()', e.stack, e);
|
|
}
|
|
if ( data !== null ) {
|
|
args = data.args;
|
|
args.__resume__ = true;
|
|
args.__windows__ = data.windows || [];
|
|
}
|
|
args.__preload__ = {force: true};
|
|
setTimeout(function() {
|
|
API.launch(n, args);
|
|
}, 500);
|
|
}
|
|
API.getProcess(n).forEach(relaunch);
|
|
};
|
|
API.launch = function _apiLaunch(name, args, ondone, onerror, onconstruct) {
|
|
args = args || {};
|
|
var err;
|
|
var splash = null;
|
|
var instance = null;
|
|
var pargs = {};
|
|
var packman = OSjs.Core.getPackageManager();
|
|
var compability = Utils.getCompability();
|
|
var metadata = packman.getPackage(name);
|
|
var running = API.getProcess(name, true);
|
|
var preloads = (function() {
|
|
var list = (metadata.preload || []).slice(0);
|
|
var additions = [];
|
|
function _add(chk) {
|
|
if ( chk && chk.preload ) {
|
|
chk.preload.forEach(function(p) {
|
|
additions.push(p);
|
|
});
|
|
}
|
|
}
|
|
if ( metadata.depends instanceof Array ) {
|
|
metadata.depends.forEach(function(k) {
|
|
if ( !OSjs.Applications[k] ) {
|
|
_add(packman.getPackage(k));
|
|
}
|
|
});
|
|
}
|
|
var pkgs = packman.getPackages(false);
|
|
Object.keys(pkgs).forEach(function(pn) {
|
|
var p = pkgs[pn];
|
|
if ( p.type === 'extension' && p.uses === name ) {
|
|
_add(p);
|
|
}
|
|
});
|
|
list = additions.concat(list);
|
|
additions = [];
|
|
if ( metadata.scope === 'user' ) {
|
|
list = list.map(function(p) {
|
|
if ( p.src.substr(0, 1) !== '/' && !p.src.match(/^(https?|ftp)/) ) {
|
|
OSjs.VFS.url(p.src, function(error, url) {
|
|
if ( !error ) {
|
|
p.src = url;
|
|
}
|
|
});
|
|
}
|
|
return p;
|
|
});
|
|
}
|
|
return list;
|
|
})();
|
|
function _createSplash() {
|
|
API.createLoading(name, {className: 'StartupNotification', tooltip: API._('LBL_STARTING') + ' ' + name});
|
|
if ( !OSjs.Applications[name] ) {
|
|
if ( metadata.splash !== false ) {
|
|
splash = API.createSplash(metadata.name, metadata.icon);
|
|
}
|
|
}
|
|
}
|
|
function _destroySplash() {
|
|
API.destroyLoading(name);
|
|
if ( splash ) {
|
|
splash.destroy();
|
|
splash = null;
|
|
}
|
|
}
|
|
function _onError(err, exception) {
|
|
_destroySplash();
|
|
API.error(API._('ERR_APP_LAUNCH_FAILED'),
|
|
API._('ERR_APP_LAUNCH_FAILED_FMT', name),
|
|
err, exception, true);
|
|
(onerror || function() {})(err, name, args, exception);
|
|
}
|
|
function _onFinished(skip) {
|
|
_destroySplash();
|
|
(ondone || function() {})(instance, metadata);
|
|
}
|
|
function _preLaunch(cb) {
|
|
var isCompatible = (function() {
|
|
var list = (metadata.compability || []).filter(function(c) {
|
|
if ( typeof compability[c] !== 'undefined' ) {
|
|
return !compability[c];
|
|
}
|
|
return false;
|
|
});
|
|
if ( list.length ) {
|
|
return API._('ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT', name, list.join(', '));
|
|
}
|
|
return true;
|
|
})();
|
|
if ( isCompatible !== true ) {
|
|
throw new Error(isCompatible);
|
|
}
|
|
if ( metadata.singular === true && running ) {
|
|
if ( running instanceof OSjs.Core.Application ) {
|
|
console.warn('API::launch()', 'detected that this application is a singular and already running...');
|
|
running._onMessage('attention', args);
|
|
_onFinished(true);
|
|
return; // muy importante!
|
|
} else {
|
|
throw new Error(API._('ERR_APP_LAUNCH_ALREADY_RUNNING_FMT', name));
|
|
}
|
|
}
|
|
Utils.asyncs(_hooks.onApplicationPreload, function(qi, i, n) {
|
|
qi(name, args, preloads, function(p) {
|
|
if ( p && (p instanceof Array) ) {
|
|
preloads = p;
|
|
}
|
|
n();
|
|
});
|
|
}, function() {
|
|
_createSplash();
|
|
cb();
|
|
});
|
|
API.triggerHook('onApplicationLaunch', [name, args]);
|
|
}
|
|
function _preload(cb) {
|
|
Utils.preload(preloads, function(total, failed, succeeded, data) {
|
|
if ( failed.length ) {
|
|
cb(API._('ERR_APP_PRELOAD_FAILED_FMT', name, failed.join(',')));
|
|
} else {
|
|
setTimeout(function() {
|
|
cb(false, data);
|
|
}, 0);
|
|
}
|
|
}, function(index, count, src, succeeded, failed, progress) {
|
|
if ( splash ) {
|
|
splash.update(progress, count);
|
|
}
|
|
}, pargs);
|
|
}
|
|
function _createProcess(preloadData, cb) {
|
|
function __onprocessinitfailed() {
|
|
if ( instance ) {
|
|
try {
|
|
instance.destroy();
|
|
instance = null;
|
|
} catch ( ee ) {
|
|
console.warn('Something awful happened when trying to clean up failed launch Oo', ee);
|
|
console.warn(ee.stack);
|
|
}
|
|
}
|
|
}
|
|
if ( typeof OSjs.Applications[name] === 'undefined' ) {
|
|
throw new Error(API._('ERR_APP_RESOURCES_MISSING_FMT', name));
|
|
}
|
|
if ( typeof OSjs.Applications[name] === 'function' ) {
|
|
OSjs.Applications[name]();
|
|
cb(false, true);
|
|
return;
|
|
}
|
|
function __onschemesloaded(scheme) {
|
|
try {
|
|
if ( metadata.classType === 'simple' ) {
|
|
instance = new OSjs.Core.Application(name, args, metadata);
|
|
OSjs.Applications[name].run(instance);
|
|
} else {
|
|
instance = new OSjs.Applications[name].Class(args, metadata);
|
|
}
|
|
(onconstruct || function() {})(instance, metadata);
|
|
} catch ( e ) {
|
|
console.warn('Error on constructing application', e, e.stack);
|
|
__onprocessinitfailed();
|
|
cb(API._('ERR_APP_CONSTRUCT_FAILED_FMT', name, e), e);
|
|
return false;
|
|
}
|
|
try {
|
|
var settings = OSjs.Core.getSettingsManager().get(instance.__pname) || {};
|
|
instance.init(settings, metadata, scheme);
|
|
API.triggerHook('onApplicationLaunched', [{
|
|
application: instance,
|
|
name: name,
|
|
args: args,
|
|
settings: settings,
|
|
metadata: metadata
|
|
}]);
|
|
} catch ( ex ) {
|
|
console.warn('Error on init() application', ex, ex.stack);
|
|
__onprocessinitfailed();
|
|
cb(API._('ERR_APP_INIT_FAILED_FMT', name, ex.toString()), ex);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
var scheme = null;
|
|
if ( preloadData ) {
|
|
preloadData.forEach(function(f) {
|
|
if ( !scheme && f.item.type === 'scheme' ) {
|
|
scheme = f.data;
|
|
}
|
|
});
|
|
}
|
|
if ( __onschemesloaded(scheme) ) {
|
|
cb(false, true);
|
|
}
|
|
}
|
|
if ( !name ) {
|
|
err = 'Cannot API::launch() witout a application name';
|
|
_onError(err);
|
|
throw new Error(err);
|
|
}
|
|
if ( !metadata ) {
|
|
err = API._('ERR_APP_LAUNCH_MANIFEST_FAILED_FMT', name);
|
|
_onError(err);
|
|
throw new Error(err);
|
|
}
|
|
console.group('API::launch()', {
|
|
name: name,
|
|
args: args,
|
|
metadata: metadata,
|
|
preloads: preloads
|
|
});
|
|
if ( args.__preload__ ) { // This is for relaunch()
|
|
pargs = args.__preload__;
|
|
delete args.__preload__;
|
|
}
|
|
pargs.max = (function(p) {
|
|
if ( p === true ) {
|
|
p = API.getConfig('Connection.PreloadParallel');
|
|
}
|
|
return p;
|
|
})(metadata.preloadParallel);
|
|
try {
|
|
_preLaunch(function() {
|
|
_preload(function(err, res) {
|
|
if ( err ) {
|
|
_onError(err, res);
|
|
} else {
|
|
try {
|
|
_createProcess(res, function(err, res) {
|
|
if ( err ) {
|
|
_onError(err, res);
|
|
} else {
|
|
try {
|
|
_onFinished(res);
|
|
} catch ( e ) {
|
|
_onError(e.toString(), e);
|
|
}
|
|
}
|
|
});
|
|
} catch ( e ) {
|
|
_onError(e.toString(), e);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
} catch ( e ) {
|
|
_onError(e.toString());
|
|
}
|
|
};
|
|
API.launchList = function _apiLaunchList(list, onSuccess, onError, onFinished) {
|
|
list = list || [];
|
|
onSuccess = onSuccess || function() {};
|
|
onError = onError || function() {};
|
|
onFinished = onFinished || function() {};
|
|
Utils.asyncs(list, function(s, current, next) {
|
|
if ( typeof s === 'string' ) {
|
|
var args = {};
|
|
var spl = s.split('@');
|
|
var name = spl[0];
|
|
if ( typeof spl[1] !== 'undefined' ) {
|
|
try {
|
|
args = JSON.parse(spl[1]);
|
|
} catch ( e ) {}
|
|
}
|
|
s = {
|
|
name: name,
|
|
args: args
|
|
};
|
|
}
|
|
var aname = s.name;
|
|
var aargs = (typeof s.args === 'undefined') ? {} : (s.args || {});
|
|
if ( !aname ) {
|
|
console.warn('API::launchList() next()', 'No application name defined');
|
|
next();
|
|
return;
|
|
}
|
|
API.launch(aname, aargs, function(app, metadata) {
|
|
onSuccess(app, metadata, aname, aargs);
|
|
next();
|
|
}, function(err, name, args) {
|
|
console.warn('API::launchList() _onError()', err);
|
|
onError(err, name, args);
|
|
next();
|
|
});
|
|
}, onFinished);
|
|
};
|
|
API.getApplicationResource = function _apiGetAppResource(app, name, vfspath) {
|
|
if ( name.match(/^\//) ) {
|
|
return name;
|
|
}
|
|
name = name.replace(/^\.\//, '');
|
|
function getName() {
|
|
var appname = null;
|
|
if ( app instanceof OSjs.Core.Process ) {
|
|
appname = app.__pname;
|
|
} else if ( typeof app === 'string' ) {
|
|
appname = app;
|
|
}
|
|
return appname;
|
|
}
|
|
function getResultPath(path, userpkg) {
|
|
path = Utils.checkdir(path);
|
|
if ( vfspath ) {
|
|
if ( userpkg ) {
|
|
path = path.substr(API.getConfig('Connection.FSURI').length);
|
|
} else {
|
|
path = 'osjs:///' + path;
|
|
}
|
|
}
|
|
return path;
|
|
}
|
|
return (function() {
|
|
var pacman = OSjs.Core.getPackageManager();
|
|
var appname = getName();
|
|
var pkg = pacman.getPackage(appname);
|
|
var path = '';
|
|
if ( pkg ) {
|
|
if ( pkg.scope === 'user' ) {
|
|
path = API.getConfig('Connection.FSURI') + '/get/' + Utils.pathJoin(pkg.path, name);
|
|
} else {
|
|
path = API.getConfig('Connection.PackageURI') + '/' + pkg.path + '/' + name;
|
|
}
|
|
}
|
|
return getResultPath(path, pkg.scope === 'user');
|
|
})();
|
|
};
|
|
API.getThemeCSS = function _apiGetThemeCSS(name) {
|
|
var root = API.getConfig('Connection.RootURI', '/');
|
|
if ( name === null ) {
|
|
return root + 'blank.css';
|
|
}
|
|
root = API.getConfig('Connection.ThemeURI');
|
|
return Utils.checkdir(root + '/' + name + '.css');
|
|
};
|
|
API.getFileIcon = function _apiGetFileIcon(file, size, icon) {
|
|
icon = icon || 'mimetypes/gnome-fs-regular.png';
|
|
if ( typeof file === 'object' && !(file instanceof OSjs.VFS.File) ) {
|
|
file = new OSjs.VFS.File(file);
|
|
}
|
|
if ( !file.filename ) {
|
|
throw new Error('Filename is required for getFileIcon()');
|
|
}
|
|
var map = [
|
|
{match: 'application/pdf', icon: 'mimetypes/gnome-mime-application-pdf.png'},
|
|
{match: 'application/zip', icon: 'mimetypes/folder_tar.png'},
|
|
{match: 'application/x-python', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'application/x-lua', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'application/javascript', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'text/html', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'text/xml', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'text/css', icon: 'mimetypes/stock_script.png'},
|
|
{match: 'osjs/document', icon: 'mimetypes/gnome-mime-application-msword.png'},
|
|
{match: 'osjs/draw', icon: 'mimetypes/image.png'},
|
|
{match: /^text\//, icon: 'mimetypes/txt.png'},
|
|
{match: /^audio\//, icon: 'mimetypes/sound.png'},
|
|
{match: /^video\//, icon: 'mimetypes/video.png'},
|
|
{match: /^image\//, icon: 'mimetypes/image.png'},
|
|
{match: /^application\//, icon: 'mimetypes/binary.png'}
|
|
];
|
|
if ( file.type === 'dir' ) {
|
|
icon = 'places/folder.png';
|
|
} else if ( file.type === 'trash' ) {
|
|
icon = 'places/user-trash.png';
|
|
} else {
|
|
var mime = file.mime || 'application/octet-stream';
|
|
map.every(function(iter) {
|
|
var match = false;
|
|
if ( typeof iter.match === 'string' ) {
|
|
match = (mime === iter.match);
|
|
} else {
|
|
match = mime.match(iter.match);
|
|
}
|
|
if ( match ) {
|
|
icon = iter.icon;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return API.getIcon(icon, size);
|
|
};
|
|
API.getThemeResource = function _apiGetThemeResource(name, type) {
|
|
name = name || null;
|
|
type = type || null;
|
|
var root = API.getConfig('Connection.ThemeURI');
|
|
if ( !root.match(/^\//) ) {
|
|
root = API.getBrowserPath() + root;
|
|
}
|
|
function getName(str, theme) {
|
|
if ( !str.match(/^\//) ) {
|
|
if ( type === 'base' || type === null ) {
|
|
str = root + '/' + theme + '/' + str;
|
|
} else {
|
|
str = root + '/' + theme + '/' + type + '/' + str;
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
if ( name ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var theme = (wm ? wm.getSetting('theme') : 'default') || 'default';
|
|
name = getName(name, theme);
|
|
}
|
|
return Utils.checkdir(name);
|
|
};
|
|
API.getSound = function _apiGetSound(name) {
|
|
name = name || null;
|
|
if ( name ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var theme = wm ? wm.getSoundTheme() : 'default';
|
|
var root = API.getConfig('Connection.SoundURI');
|
|
var compability = Utils.getCompability();
|
|
if ( !name.match(/^\//) ) {
|
|
var ext = 'oga';
|
|
if ( !compability.audioTypes.ogg ) {
|
|
ext = 'mp3';
|
|
}
|
|
name = root + '/' + theme + '/' + name + '.' + ext;
|
|
}
|
|
}
|
|
return Utils.checkdir(name);
|
|
};
|
|
API.getIcon = function _apiGetIcon(name, size, app) {
|
|
name = name || null;
|
|
size = size || '16x16';
|
|
app = app || null;
|
|
var root = API.getConfig('Connection.IconURI');
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var theme = wm ? wm.getIconTheme() : 'default';
|
|
function checkIcon() {
|
|
if ( name.match(/^\.\//) ) {
|
|
name = name.replace(/^\.\//, '');
|
|
if ( (app instanceof OSjs.Core.Application) || (typeof app === 'string') ) {
|
|
return API.getApplicationResource(app, name);
|
|
} else {
|
|
if ( app !== null && typeof app === 'object' ) {
|
|
return API.getApplicationResource(app.className, name);
|
|
} else if ( typeof app === 'string' ) {
|
|
return API.getApplicationResource(app, name);
|
|
}
|
|
}
|
|
} else {
|
|
if ( !name.match(/^\//) ) {
|
|
name = root + '/' + theme + '/' + size + '/' + name;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
if ( name && !name.match(/^(http|\/\/)/) ) {
|
|
var chk = checkIcon();
|
|
if ( chk !== null ) {
|
|
return chk;
|
|
}
|
|
}
|
|
return Utils.checkdir(name);
|
|
};
|
|
API.getConfig = function _apiGetConfig(path, defaultValue) {
|
|
var config = OSjs.Core.getConfig();
|
|
if ( typeof path === 'string' ) {
|
|
var result = config[path];
|
|
if ( path.indexOf('.') !== -1 ) {
|
|
var queue = path.split(/\./);
|
|
var ns = config;
|
|
queue.forEach(function(k, i) {
|
|
if ( i >= queue.length - 1 ) {
|
|
if ( ns ) {
|
|
result = ns[k];
|
|
}
|
|
} else {
|
|
ns = ns[k];
|
|
}
|
|
});
|
|
}
|
|
if ( typeof result === 'undefined' && typeof defaultValue !== 'undefined' ) {
|
|
return defaultValue;
|
|
}
|
|
return typeof result === 'object' ? Utils.cloneObject(result) : result;
|
|
}
|
|
return config;
|
|
};
|
|
API.getDefaultPath = function _apiGetDefaultPath(fallback) {
|
|
if ( fallback && fallback.match(/^\//) ) {
|
|
fallback = null;
|
|
}
|
|
return API.getConfig('VFS.Home') || fallback || 'osjs:///';
|
|
};
|
|
API.createNotification = function _apiCreateNotification(opts) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
return wm.notification(opts);
|
|
};
|
|
API.createDialog = function _apiCreateDialog(className, args, callback, parentObj) {
|
|
callback = callback || function() {};
|
|
function cb() {
|
|
if ( parentObj ) {
|
|
if ( (parentObj instanceof OSjs.Core.Window) && parentObj._destroyed ) {
|
|
console.warn('API::createDialog()', 'INGORED EVENT: Window was destroyed');
|
|
return;
|
|
}
|
|
if ( (parentObj instanceof OSjs.Core.Process) && parentObj.__destroyed ) {
|
|
console.warn('API::createDialog()', 'INGORED EVENT: Process was destroyed');
|
|
return;
|
|
}
|
|
}
|
|
callback.apply(null, arguments);
|
|
}
|
|
var win = typeof className === 'string' ? new OSjs.Dialogs[className](args, cb) : className(args, cb);
|
|
if ( !parentObj ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
wm.addWindow(win, true);
|
|
} else if ( parentObj instanceof OSjs.Core.Window ) {
|
|
win._on('destroy', function() {
|
|
if ( parentObj ) {
|
|
parentObj._focus();
|
|
}
|
|
});
|
|
parentObj._addChild(win, true);
|
|
} else if ( parentObj instanceof OSjs.Core.Application ) {
|
|
parentObj._addWindow(win);
|
|
}
|
|
setTimeout(function() {
|
|
win._focus();
|
|
}, 10);
|
|
return win;
|
|
};
|
|
API.createLoading = function _apiCreateLoading(name, opts, panelId) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
if ( wm.createNotificationIcon(name, opts, panelId) ) {
|
|
return name;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
API.destroyLoading = function _apiDestroyLoading(name, panelId) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( name ) {
|
|
if ( wm ) {
|
|
if ( wm.removeNotificationIcon(name, panelId) ) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
API.checkPermission = function _apiCheckPermission(group) {
|
|
var user = OSjs.Core.getHandler().getUserData();
|
|
var userGroups = user.groups || [];
|
|
if ( !(group instanceof Array) ) {
|
|
group = [group];
|
|
}
|
|
var result = true;
|
|
if ( userGroups.indexOf('admin') < 0 ) {
|
|
group.every(function(g) {
|
|
if ( userGroups.indexOf(g) < 0 ) {
|
|
result = false;
|
|
}
|
|
return result;
|
|
});
|
|
}
|
|
return result;
|
|
};
|
|
API.createSplash = function _apiCreateSplash(name, icon, label, parentEl) {
|
|
label = label || API._('LBL_STARTING');
|
|
parentEl = parentEl || document.body;
|
|
var splash = document.createElement('application-splash');
|
|
splash.setAttribute('role', 'dialog');
|
|
var img;
|
|
if ( icon ) {
|
|
img = document.createElement('img');
|
|
img.alt = name;
|
|
img.src = API.getIcon(icon);
|
|
}
|
|
var titleText = document.createElement('b');
|
|
titleText.appendChild(document.createTextNode(name));
|
|
var title = document.createElement('span');
|
|
title.appendChild(document.createTextNode(label + ' '));
|
|
title.appendChild(titleText);
|
|
title.appendChild(document.createTextNode('...'));
|
|
var splashBar = document.createElement('gui-progress-bar');
|
|
OSjs.GUI.Elements['gui-progress-bar'].build(splashBar);
|
|
if ( img ) {
|
|
splash.appendChild(img);
|
|
}
|
|
splash.appendChild(title);
|
|
splash.appendChild(splashBar);
|
|
parentEl.appendChild(splash);
|
|
return {
|
|
destroy: function() {
|
|
splash = Utils.$remove(splash);
|
|
img = null;
|
|
title = null;
|
|
titleText = null;
|
|
splashBar = null;
|
|
},
|
|
update: function(p, c) {
|
|
if ( !splash || !splashBar ) {
|
|
return;
|
|
}
|
|
var per = c ? 0 : 100;
|
|
if ( c ) {
|
|
per = (p / c) * 100;
|
|
}
|
|
(new OSjs.GUI.Element(splashBar)).set('value', per);
|
|
}
|
|
};
|
|
};
|
|
API.error = function _apiError(title, message, error, exception, bugreport) {
|
|
bugreport = (function() {
|
|
if ( API.getConfig('BugReporting.enabled') ) {
|
|
return typeof bugreport === 'undefined' ? false : (bugreport ? true : false);
|
|
}
|
|
return false;
|
|
})();
|
|
function _dialog() {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm && wm._fullyLoaded ) {
|
|
try {
|
|
API.createDialog('Error', {
|
|
title: title,
|
|
message: message,
|
|
error: error,
|
|
exception: exception,
|
|
bugreport: bugreport
|
|
});
|
|
return true;
|
|
} catch ( e ) {
|
|
console.warn('An error occured while creating Dialogs.Error', e);
|
|
console.warn('stack', e.stack);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
API.blurMenu();
|
|
if ( exception && (exception.message.match(/^Script Error/i) && String(exception.lineNumber).match(/^0/)) ) {
|
|
console.error('VENDOR ERROR', {
|
|
title: title,
|
|
message: message,
|
|
error: error,
|
|
exception: exception
|
|
});
|
|
return;
|
|
}
|
|
if ( API.getConfig('MOCHAMODE') ) {
|
|
console.error(title, message, error, exception);
|
|
} else {
|
|
if ( _dialog() ) {
|
|
return;
|
|
}
|
|
window.alert(title + '\n\n' + message + '\n\n' + error);
|
|
}
|
|
};
|
|
API.playSound = function _apiPlaySound(name, volume) {
|
|
var compability = Utils.getCompability();
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var filename = wm ? wm.getSoundFilename(name) : null;
|
|
if ( !wm || !compability.audio || !wm.getSetting('enableSounds') || !filename ) {
|
|
return false;
|
|
}
|
|
if ( typeof volume === 'undefined' ) {
|
|
volume = 1.0;
|
|
}
|
|
var f = API.getSound(filename);
|
|
var a = new Audio(f);
|
|
a.volume = volume;
|
|
a.play();
|
|
return a;
|
|
};
|
|
API.setClipboard = function _apiSetClipboard(data) {
|
|
_CLIPBOARD = data;
|
|
};
|
|
API.getClipboard = function _apiGetClipboard() {
|
|
return _CLIPBOARD;
|
|
};
|
|
API.getServiceNotificationIcon = (function() {
|
|
var _instance;
|
|
return function _apiGetServiceNotificationIcon() {
|
|
if ( !_instance ) {
|
|
_instance = new ServiceNotificationIcon();
|
|
}
|
|
return _instance;
|
|
};
|
|
})();
|
|
API.toggleFullscreen = (function() {
|
|
var _prev;
|
|
function trigger(el, state) {
|
|
function _request() {
|
|
if ( el.requestFullscreen ) {
|
|
el.requestFullscreen();
|
|
} else if ( el.mozRequestFullScreen ) {
|
|
el.mozRequestFullScreen();
|
|
} else if ( el.webkitRequestFullScreen ) {
|
|
el.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
|
}
|
|
}
|
|
function _restore() {
|
|
if ( el.webkitCancelFullScreen ) {
|
|
el.webkitCancelFullScreen();
|
|
} else if ( el.mozCancelFullScreen ) {
|
|
el.mozCancelFullScreen();
|
|
} else if ( el.exitFullscreen ) {
|
|
el.exitFullscreen();
|
|
}
|
|
}
|
|
if ( el ) {
|
|
if ( state ) {
|
|
_request();
|
|
} else {
|
|
_restore();
|
|
}
|
|
}
|
|
}
|
|
return function _apiToggleFullscreen(el, t) {
|
|
if ( typeof t === 'boolean' ) {
|
|
trigger(el, t);
|
|
} else {
|
|
if ( _prev && _prev !== el ) {
|
|
trigger(_prev, false);
|
|
}
|
|
trigger(el, _prev !== el);
|
|
}
|
|
_prev = el;
|
|
};
|
|
})();
|
|
API.isStandalone = function _apiIsStandlone() {
|
|
return API.getConfig('Connection.Type') === 'standalone' && window.location.protocol === 'file:';
|
|
};
|
|
API.getBrowserPath = function _apiGetBrowserPath() {
|
|
return (window.location.pathname || '/').replace(/index\.(.*)$/, '');
|
|
}
|
|
API.signOut = function _apiSignOut() {
|
|
var handler = OSjs.Core.getHandler();
|
|
var wm = OSjs.Core.getWindowManager();
|
|
function signOut(save) {
|
|
API.playSound('LOGOUT');
|
|
handler.logout(save, function() {
|
|
API.shutdown();
|
|
});
|
|
}
|
|
if ( wm ) {
|
|
var user = handler.getUserData() || {name: API._('LBL_UNKNOWN')};
|
|
API.createDialog('Confirm', {
|
|
title: API._('DIALOG_LOGOUT_TITLE'),
|
|
message: API._('DIALOG_LOGOUT_MSG_FMT', user.name)
|
|
}, function(ev, btn) {
|
|
if ( btn === 'yes' ) {
|
|
signOut(true);
|
|
} else if ( btn === 'no' ) {
|
|
signOut(false);
|
|
}
|
|
});
|
|
} else {
|
|
signOut(true);
|
|
}
|
|
};
|
|
API.triggerHook = function _apiTriggerHook(name, args, thisarg) {
|
|
thisarg = thisarg || OSjs;
|
|
args = args || [];
|
|
if ( _hooks[name] ) {
|
|
_hooks[name].forEach(function(hook) {
|
|
if ( typeof hook === 'function' ) {
|
|
try {
|
|
hook.apply(thisarg, args);
|
|
} catch ( e ) {
|
|
console.warn('Error on Hook', e, e.stack);
|
|
}
|
|
} else {
|
|
console.warn('No such Hook', name);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
API.addHook = function _apiAddHook(name, fn) {
|
|
if ( typeof _hooks[name] !== 'undefined' ) {
|
|
return _hooks[name].push(fn) - 1;
|
|
}
|
|
return -1;
|
|
};
|
|
API.removeHook = function _apiRemoveHook(name, index) {
|
|
if ( typeof _hooks[name] !== 'undefined' ) {
|
|
if ( _hooks[name][index] ) {
|
|
_hooks[name][index] = null;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
API.shutdown = API.shutdown || function() {}; // init.js
|
|
API.isShuttingDown = API.isShuttingDown || function() {}; // init.js
|
|
API.createMenu = function() {
|
|
return OSjs.GUI.Helpers.createMenu.apply(null, arguments);
|
|
};
|
|
API.blurMenu = function() {
|
|
return OSjs.GUI.Helpers.blurMenu.apply(null, arguments);
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var _PROCS = []; // Running processes
|
|
function _kill(pid) {
|
|
if ( pid >= 0 && _PROCS[pid] ) {
|
|
var res = _PROCS[pid].destroy();
|
|
console.warn('Killing application', pid, res);
|
|
if ( res !== false ) {
|
|
_PROCS[pid] = null;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
function doKillAllProcesses(match) {
|
|
if ( match ) {
|
|
var isMatching;
|
|
if ( match instanceof RegExp && _PROCS ) {
|
|
isMatching = function(p) {
|
|
return p.__pname && p.__pname.match(match);
|
|
};
|
|
} else if ( typeof match === 'string' ) {
|
|
isMatching = function(p) {
|
|
return p.__pname === match;
|
|
};
|
|
}
|
|
if ( isMatching ) {
|
|
_PROCS.forEach(function(p) {
|
|
if ( p && isMatching(p) ) {
|
|
_kill(p.__pid);
|
|
}
|
|
});
|
|
}
|
|
return;
|
|
}
|
|
_PROCS.forEach(function(proc, i) {
|
|
if ( proc ) {
|
|
proc.destroy(true);
|
|
}
|
|
_PROCS[i] = null;
|
|
});
|
|
_PROCS = [];
|
|
}
|
|
function doKillProcess(pid) {
|
|
return _kill(pid);
|
|
}
|
|
function doProcessMessage(msg, obj, opts) {
|
|
opts = opts || {};
|
|
var filter = opts.filter || function() {
|
|
return true;
|
|
};
|
|
if ( typeof filter === 'string' ) {
|
|
var s = filter;
|
|
filter = function(p) {
|
|
return p.__pname === s;
|
|
};
|
|
}
|
|
_PROCS.forEach(function(p, i) {
|
|
if ( p && (p instanceof OSjs.Core.Application || p instanceof OSjs.Core.Process) ) {
|
|
if ( filter(p) ) {
|
|
p._onMessage(msg, obj, opts);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function doGetProcess(name, first) {
|
|
var result = first ? null : [];
|
|
if ( typeof name === 'number' ) {
|
|
return _PROCS[name];
|
|
}
|
|
_PROCS.every(function(p, i) {
|
|
if ( p ) {
|
|
if ( p.__pname === name ) {
|
|
if ( first ) {
|
|
result = p;
|
|
return false;
|
|
}
|
|
result.push(p);
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
}
|
|
function doGetProcesses() {
|
|
return _PROCS;
|
|
}
|
|
function Process(name, args, metadata) {
|
|
this.__pid = _PROCS.push(this) - 1;
|
|
this.__pname = name;
|
|
this.__args = args || {};
|
|
this.__metadata = metadata || {};
|
|
this.__started = new Date();
|
|
this.__destroyed = false;
|
|
this.__evHandler = new OSjs.Helpers.EventHandler(name, [
|
|
'message', 'attention', 'hashchange', 'api', 'destroy', 'destroyWindow', 'vfs',
|
|
'vfs:mount', 'vfs:unmount', 'vfs:mkdir', 'vfs:write', 'vfs:move',
|
|
'vfs:copy', 'vfs:delete', 'vfs:upload', 'vfs:update'
|
|
]);
|
|
this.__label = this.__metadata.name;
|
|
this.__path = this.__metadata.path;
|
|
this.__scope = this.__metadata.scope || 'system';
|
|
this.__iter = this.__metadata.className;
|
|
}
|
|
Process.prototype.destroy = function() {
|
|
if ( !this.__destroyed ) {
|
|
this.__destroyed = true;
|
|
this._emit('destroy', []);
|
|
if ( this.__evHandler ) {
|
|
this.__evHandler = this.__evHandler.destroy();
|
|
}
|
|
if ( this.__pid >= 0 ) {
|
|
_PROCS[this.__pid] = null;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
Process.prototype._onMessage = function(msg, obj, opts) {
|
|
opts = opts || {};
|
|
var sourceId = opts.source;
|
|
if ( sourceId instanceof Process ) {
|
|
sourceId = sourceId.__pid;
|
|
} else if ( sourceId instanceof OSjs.Core.Window ) {
|
|
sourceId = sourceId._app ? sourceId._app.__pid : -1;
|
|
}
|
|
if ( this.__evHandler && sourceId !== this.__pid ) {
|
|
this.__evHandler.emit('message', [msg, obj, opts]);
|
|
if ( msg.substr(0, 3) === 'vfs' ) {
|
|
this.__evHandler.emit('vfs', [msg, obj, opts]);
|
|
}
|
|
this.__evHandler.emit(msg, [obj, opts, msg]);
|
|
}
|
|
};
|
|
Process.prototype._emit = function(k, args) {
|
|
return this.__evHandler.emit(k, args);
|
|
};
|
|
Process.prototype._on = function(k, func) {
|
|
return this.__evHandler.on(k, func, this);
|
|
};
|
|
Process.prototype._off = function(k, idx) {
|
|
return this.__evHandler.off(k, idx);
|
|
};
|
|
Process.prototype._api = function(method, args, callback, showLoading) {
|
|
var self = this;
|
|
function cb(err, res) {
|
|
if ( self.__destroyed ) {
|
|
console.warn('Process::_api()', 'INGORED RESPONSE: Process was closed');
|
|
return;
|
|
}
|
|
callback(err, res);
|
|
}
|
|
this._emit('api', [method]);
|
|
return OSjs.API.call('application', {
|
|
application: this.__iter,
|
|
path: this.__path,
|
|
method: method,
|
|
'arguments': args, __loading: showLoading
|
|
}, cb);
|
|
};
|
|
Process.prototype._getArgument = function(k) {
|
|
return typeof this.__args[k] === 'undefined' ? null : this.__args[k];
|
|
};
|
|
Process.prototype._getArguments = function() {
|
|
return this.__args;
|
|
};
|
|
Process.prototype._getResource = function(src) {
|
|
return API.getApplicationResource(this, src);
|
|
};
|
|
Process.prototype._setArgument = function(k, v) {
|
|
this.__args[k] = v;
|
|
};
|
|
OSjs.Core.Process = Object.seal(Process);
|
|
OSjs.API.killAll = doKillAllProcesses;
|
|
OSjs.API.kill = doKillProcess;
|
|
OSjs.API.message = doProcessMessage;
|
|
OSjs.API.getProcess = doGetProcess;
|
|
OSjs.API.getProcesses = doGetProcesses;
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API, Process) {
|
|
'use strict';
|
|
function Application(name, args, metadata, settings) {
|
|
this.__inited = false;
|
|
this.__mainwindow = null;
|
|
this.__scheme = null;
|
|
this.__windows = [];
|
|
this.__settings = {};
|
|
this.__destroying = false;
|
|
try {
|
|
this.__settings = OSjs.Core.getSettingsManager().instance(name, settings || {});
|
|
} catch ( e ) {
|
|
console.warn('Application::construct()', 'An error occured while loading application settings', e);
|
|
console.warn(e.stack);
|
|
this.__settings = OSjs.Core.getSettingsManager().instance(name, {});
|
|
}
|
|
Process.apply(this, arguments);
|
|
}
|
|
Application.prototype = Object.create(Process.prototype);
|
|
Application.constructor = Process;
|
|
Application.prototype.init = function(settings, metadata, scheme) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var self = this;
|
|
function focusLastWindow() {
|
|
var last;
|
|
if ( wm ) {
|
|
self.__windows.forEach(function(win, i) {
|
|
if ( win ) {
|
|
wm.addWindow(win);
|
|
last = win;
|
|
}
|
|
});
|
|
}
|
|
if ( last ) {
|
|
last._focus();
|
|
}
|
|
}
|
|
if ( !this.__inited ) {
|
|
if ( scheme ) {
|
|
this._setScheme(scheme);
|
|
}
|
|
this.__settings.set(null, settings);
|
|
this.__inited = true;
|
|
this.__evHandler.emit('init', [settings, metadata, scheme]);
|
|
focusLastWindow();
|
|
}
|
|
};
|
|
Application.prototype.destroy = function(sourceWid) {
|
|
if ( this.__destroying || this.__destroyed ) { // From 'process.js'
|
|
return true;
|
|
}
|
|
this.__destroying = true;
|
|
this.__windows.forEach(function(w) {
|
|
try {
|
|
if ( w && w._wid !== sourceWid ) {
|
|
w.destroy();
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('Application::destroy()', e, e.stack);
|
|
}
|
|
});
|
|
this.__mainwindow = null;
|
|
this.__settings = {};
|
|
this.__windows = [];
|
|
if ( this.__scheme ) {
|
|
this.__scheme.destroy();
|
|
}
|
|
this.__scheme = null;
|
|
var result = Process.prototype.destroy.apply(this, arguments);
|
|
return result;
|
|
};
|
|
Application.prototype._onMessage = function(msg, obj, args) {
|
|
if ( this.__destroying || this.__destroyed ) {
|
|
return false;
|
|
}
|
|
if ( msg === 'destroyWindow' ) {
|
|
if ( obj._name === this.__mainwindow ) {
|
|
this.destroy(obj._wid);
|
|
} else {
|
|
this._removeWindow(obj);
|
|
}
|
|
} else if ( msg === 'attention' ) {
|
|
if ( this.__windows.length && this.__windows[0] ) {
|
|
this.__windows[0]._focus();
|
|
}
|
|
}
|
|
return Process.prototype._onMessage.apply(this, arguments);
|
|
};
|
|
Application.prototype._loadScheme = function(s, cb) {
|
|
var scheme = OSjs.GUI.createScheme(this._getResource(s));
|
|
scheme.load(function __onApplicationLoadScheme(error, result) {
|
|
if ( error ) {
|
|
console.error('Application::_loadScheme()', error);
|
|
}
|
|
cb(scheme);
|
|
});
|
|
this._setScheme(scheme);
|
|
};
|
|
Application.prototype._addWindow = function(w, cb, setmain) {
|
|
if ( !(w instanceof OSjs.Core.Window) ) {
|
|
throw new TypeError('Application::_addWindow() expects Core.Window');
|
|
}
|
|
this.__windows.push(w);
|
|
if ( setmain || this.__windows.length === 1 ) {
|
|
this.__mainwindow = w._name;
|
|
}
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( this.__inited ) {
|
|
if ( wm ) {
|
|
wm.addWindow(w);
|
|
}
|
|
if ( w._properties.start_focused ) {
|
|
setTimeout(function() {
|
|
w._focus();
|
|
}, 5);
|
|
}
|
|
}
|
|
(cb || function() {})(w, wm);
|
|
return w;
|
|
};
|
|
Application.prototype._removeWindow = function(w) {
|
|
if ( !(w instanceof OSjs.Core.Window) ) {
|
|
throw new TypeError('Application::_removeWindow() expects Core.Window');
|
|
}
|
|
var self = this;
|
|
this.__windows.forEach(function(win, i) {
|
|
if ( win ) {
|
|
if ( win._wid === w._wid ) {
|
|
win.destroy();
|
|
self.__windows.splice(i, 1);
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
};
|
|
Application.prototype._getWindow = function(value, key) {
|
|
key = key || 'name';
|
|
if ( value === null ) {
|
|
value = this.__mainwindow;
|
|
}
|
|
var result = key === 'tag' ? [] : null;
|
|
this.__windows.every(function(win, i) {
|
|
if ( win ) {
|
|
if ( win['_' + key] === value ) {
|
|
if ( key === 'tag' ) {
|
|
result.push(win);
|
|
} else {
|
|
result = win;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
};
|
|
Application.prototype._getWindowByName = function(name) {
|
|
return this._getWindow(name);
|
|
};
|
|
Application.prototype._getWindowsByTag = function(tag) {
|
|
return this._getWindow(tag, 'tag');
|
|
};
|
|
Application.prototype._getWindows = function() {
|
|
return this.__windows;
|
|
};
|
|
Application.prototype._getMainWindow = function() {
|
|
return this._getWindow(this.__mainwindow, 'name');
|
|
};
|
|
Application.prototype._getSetting = function(k) {
|
|
return this.__settings.get(k);
|
|
};
|
|
Application.prototype._getSessionData = function() {
|
|
var args = this.__args;
|
|
var wins = this.__windows;
|
|
var data = {name: this.__pname, args: args, windows: []};
|
|
wins.forEach(function(win, i) {
|
|
if ( win && win._properties.allow_session ) {
|
|
data.windows.push({
|
|
name : win._name,
|
|
dimension : win._dimension,
|
|
position : win._position,
|
|
state : win._state
|
|
});
|
|
}
|
|
});
|
|
return data;
|
|
};
|
|
Application.prototype._getScheme = function() {
|
|
return this.__scheme;
|
|
};
|
|
Application.prototype._setSetting = function(k, v, save, saveCallback) {
|
|
save = (typeof save === 'undefined' || save === true);
|
|
this.__settings.set(k, v, save ? (saveCallback || function() {}) : false);
|
|
};
|
|
Application.prototype._setScheme = function(s) {
|
|
this.__scheme = s;
|
|
};
|
|
OSjs.Core.Application = Object.seal(Application);
|
|
})(OSjs.Utils, OSjs.API, OSjs.Core.Process);
|
|
|
|
(function(Utils, API, Process) {
|
|
'use strict';
|
|
function Service(name, args, metadata) {
|
|
Process.apply(this, arguments);
|
|
}
|
|
Service.prototype = Object.create(Process.prototype);
|
|
Service.constructor = Process;
|
|
Service.prototype.init = function() {
|
|
};
|
|
OSjs.Core.Service = Object.seal(Service);
|
|
})(OSjs.Utils, OSjs.API, OSjs.Core.Process);
|
|
|
|
(function(Utils, API, GUI, Process) {
|
|
'use strict';
|
|
function _noEvent(ev) {
|
|
OSjs.API.blurMenu();
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
return false;
|
|
}
|
|
function camelCased(str) {
|
|
return str.replace(/_([a-z])/g, function(g) {
|
|
return g[1].toUpperCase();
|
|
});
|
|
}
|
|
var getNextZindex = (function() {
|
|
var _lzindex = 1;
|
|
var _ltzindex = 100000;
|
|
return function(ontop) {
|
|
if ( typeof ontop !== 'undefined' && ontop === true ) {
|
|
return (_ltzindex += 2);
|
|
}
|
|
return (_lzindex += 2);
|
|
};
|
|
})();
|
|
function stopPropagation(ev) {
|
|
if ( ev ) {
|
|
ev.stopPropagation();
|
|
}
|
|
return false;
|
|
}
|
|
function getWindowSpace() {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
return wm.getWindowSpace();
|
|
}
|
|
return Utils.getRect();
|
|
}
|
|
function waitForAnimation(win, cb) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var anim = wm ? wm.getSetting('animations') : false;
|
|
if ( anim ) {
|
|
win._animationCallback = cb;
|
|
} else {
|
|
cb();
|
|
}
|
|
}
|
|
var createMediaQueries = (function() {
|
|
var queries;
|
|
function _createQueries() {
|
|
var result = {};
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
var qs = wm._settings.get('mediaQueries') || {};
|
|
Object.keys(qs).forEach(function(k) {
|
|
if ( qs[k] ) {
|
|
result[k] = function(w, h, ref) {
|
|
return w <= qs[k];
|
|
};
|
|
}
|
|
});
|
|
}
|
|
return result;
|
|
}
|
|
return function() {
|
|
if ( !queries ) {
|
|
queries = _createQueries();
|
|
}
|
|
return queries;
|
|
};
|
|
})();
|
|
function checkMediaQueries(win) {
|
|
if ( !win._$element ) {
|
|
return;
|
|
}
|
|
var qs = win._properties.media_queries || {};
|
|
var w = win._dimension.w;
|
|
var h = win._dimension.h;
|
|
var n = '';
|
|
var k;
|
|
for ( k in qs ) {
|
|
if ( qs.hasOwnProperty(k) ) {
|
|
if ( qs[k](w, h, win) ) {
|
|
n = k;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
win._$element.setAttribute('data-media', n);
|
|
}
|
|
var Window = (function() {
|
|
var _WID = 0;
|
|
var _DEFAULT_WIDTH = 200;
|
|
var _DEFAULT_HEIGHT = 200;
|
|
var _DEFAULT_MIN_HEIGHT = 150;
|
|
var _DEFAULT_MIN_WIDTH = 150;
|
|
var _DEFAULT_SND_VOLUME = 1.0;
|
|
var _NAMES = [];
|
|
return function(name, opts, appRef, schemeRef) {
|
|
var self = this;
|
|
if ( _NAMES.indexOf(name) >= 0 ) {
|
|
throw new Error(API._('ERR_WIN_DUPLICATE_FMT', name));
|
|
}
|
|
if ( appRef && !(appRef instanceof OSjs.Core.Application) ) {
|
|
throw new TypeError('appRef given was not instance of Core.Application');
|
|
}
|
|
if ( schemeRef && !(schemeRef instanceof OSjs.GUI.Scheme) ) {
|
|
throw new TypeError('schemeRef given was not instance of GUI.Scheme');
|
|
}
|
|
opts = Utils.argumentDefaults(opts, {
|
|
icon: API.getThemeResource('wm.png', 'wm'),
|
|
width: _DEFAULT_WIDTH,
|
|
height: _DEFAULT_HEIGHT,
|
|
title: name,
|
|
tag: name
|
|
});
|
|
this._$element = null;
|
|
this._$root = null;
|
|
this._$top = null;
|
|
this._$winicon = null;
|
|
this._$loading = null;
|
|
this._$disabled = null;
|
|
this._$resize = null;
|
|
this._$warning = null;
|
|
this._opts = opts;
|
|
this._app = appRef || null;
|
|
this._scheme = schemeRef || null;
|
|
this._destroyed = false;
|
|
this._restored = false;
|
|
this._loaded = false;
|
|
this._initialized = false;
|
|
this._disabled = true;
|
|
this._loading = false;
|
|
this._wid = _WID;
|
|
this._icon = opts.icon;
|
|
this._name = name;
|
|
this._title = opts.title;
|
|
this._tag = opts.tag;
|
|
this._position = {x:opts.x, y:opts.y};
|
|
this._dimension = {w:opts.width, h:opts.height};
|
|
this._children = [];
|
|
this._parent = null;
|
|
this._origtitle = this._title;
|
|
this._lastDimension = this._dimension;
|
|
this._lastPosition = this._position;
|
|
this._sound = null;
|
|
this._soundVolume = _DEFAULT_SND_VOLUME;
|
|
this._properties = {
|
|
gravity : null,
|
|
allow_move : true,
|
|
allow_resize : true,
|
|
allow_minimize : true,
|
|
allow_maximize : true,
|
|
allow_close : true,
|
|
allow_windowlist : true,
|
|
allow_drop : false,
|
|
allow_iconmenu : true,
|
|
allow_ontop : true,
|
|
allow_hotkeys : true,
|
|
allow_session : true,
|
|
key_capture : false,
|
|
start_focused : true,
|
|
min_width : _DEFAULT_MIN_HEIGHT,
|
|
min_height : _DEFAULT_MIN_WIDTH,
|
|
max_width : null,
|
|
max_height : null,
|
|
media_queries : createMediaQueries()
|
|
};
|
|
this._state = {
|
|
focused : false,
|
|
modal : false,
|
|
minimized : false,
|
|
maximized : false,
|
|
ontop : false,
|
|
onbottom : false
|
|
};
|
|
this._animationCallback = null;
|
|
this._queryTimer = null;
|
|
this._evHandler = new OSjs.Helpers.EventHandler(name, [
|
|
'focus', 'blur', 'destroy', 'maximize', 'minimize', 'restore',
|
|
'move', 'moved', 'resize', 'resized',
|
|
'keydown', 'keyup', 'keypress',
|
|
'drop', 'drop:upload', 'drop:file'
|
|
]);
|
|
Object.keys(opts).forEach(function(k) {
|
|
if ( typeof self._properties[k] !== 'undefined' ) {
|
|
self._properties[k] = opts[k];
|
|
} else if ( typeof self._state[k] !== 'undefined' && k !== 'focused' ) {
|
|
self._state[k] = opts[k];
|
|
} else if ( ('sound', 'sound_volume').indexOf(k) !== -1 ) {
|
|
self['_' + camelCased(k)] = opts[k];
|
|
}
|
|
});
|
|
(function _initPosition(properties, position) {
|
|
if ( !properties.gravity && (typeof position.x === 'undefined') || (typeof position.y === 'undefined') ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var np = wm ? wm.getWindowPosition() : {x:0, y:0};
|
|
position.x = np.x;
|
|
position.y = np.y;
|
|
}
|
|
})(this._properties, this._position);
|
|
(function _initDimension(properties, dimension) {
|
|
if ( properties.min_height && (dimension.h < properties.min_height) ) {
|
|
dimension.h = properties.min_height;
|
|
}
|
|
if ( properties.max_width && (dimension.w < properties.max_width) ) {
|
|
dimension.w = properties.max_width;
|
|
}
|
|
if ( properties.max_height && (dimension.h > properties.max_height) ) {
|
|
dimension.h = properties.max_height;
|
|
}
|
|
if ( properties.max_width && (dimension.w > properties.max_width) ) {
|
|
dimension.w = properties.max_width;
|
|
}
|
|
})(this._properties, this._dimension);
|
|
(function _initRestore(position, dimension) {
|
|
if ( appRef && appRef.__args && appRef.__args.__windows__ ) {
|
|
appRef.__args.__windows__.forEach(function(restore) {
|
|
if ( !self._restored && restore.name && restore.name === self._name ) {
|
|
position.x = restore.position.x;
|
|
position.y = restore.position.y;
|
|
if ( self._properties.allow_resize ) {
|
|
dimension.w = restore.dimension.w;
|
|
dimension.h = restore.dimension.h;
|
|
}
|
|
self._restored = true;
|
|
}
|
|
});
|
|
}
|
|
})(this._position, this._dimension);
|
|
(function _initGravity(properties, position, dimension, restored) {
|
|
var grav = properties.gravity;
|
|
if ( grav && !restored ) {
|
|
if ( grav === 'center' ) {
|
|
position.y = (window.innerHeight / 2) - (self._dimension.h / 2);
|
|
position.x = (window.innerWidth / 2) - (self._dimension.w / 2);
|
|
} else {
|
|
var space = getWindowSpace();
|
|
if ( grav.match(/^south/) ) {
|
|
position.y = space.height - dimension.h;
|
|
} else {
|
|
position.y = space.top;
|
|
}
|
|
if ( grav.match(/west$/) ) {
|
|
position.x = space.left;
|
|
} else {
|
|
position.x = space.width - dimension.w;
|
|
}
|
|
}
|
|
}
|
|
})(this._properties, this._position, this._dimension, this._restored);
|
|
_WID++;
|
|
};
|
|
})();
|
|
Window.prototype.init = function(_wm, _app, _scheme) {
|
|
var self = this;
|
|
if ( this._initialized || this._loaded ) {
|
|
return this._$root;
|
|
}
|
|
this._$element = Utils.$create('application-window', {
|
|
className: (function(n, t) {
|
|
var classNames = ['Window', Utils.$safeName(n)];
|
|
if ( t && (n !== t) ) {
|
|
classNames.push(Utils.$safeName(t));
|
|
}
|
|
return classNames;
|
|
})(this._name, this._tag).join(' '),
|
|
style: {
|
|
width: this._dimension.w + 'px',
|
|
height: this._dimension.h + 'px',
|
|
top: this._position.y + 'px',
|
|
left: this._position.x + 'px',
|
|
zIndex: getNextZindex(this._state.ontop)
|
|
},
|
|
data: {
|
|
window_id: this._wid,
|
|
allow_resize: this._properties.allow_resize,
|
|
allow_minimize: this._properties.allow_minimize,
|
|
allow_maximize: this._properties.allow_maximize,
|
|
allow_close: this._properties.allow_close
|
|
},
|
|
aria: {
|
|
role: 'application',
|
|
live: 'polite',
|
|
hidden: 'false'
|
|
}
|
|
});
|
|
this._$root = document.createElement('application-window-content');
|
|
this._$resize = document.createElement('application-window-resize');
|
|
['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'].forEach(function(i) {
|
|
var h = document.createElement('application-window-resize-handle');
|
|
h.setAttribute('data-direction', i);
|
|
self._$resize.appendChild(h);
|
|
h = null;
|
|
});
|
|
this._$loading = document.createElement('application-window-loading');
|
|
this._$disabled = document.createElement('application-window-disabled');
|
|
this._$top = document.createElement('application-window-top');
|
|
this._$winicon = document.createElement('application-window-icon');
|
|
this._$winicon.setAttribute('role', 'button');
|
|
this._$winicon.setAttribute('aria-haspopup', 'true');
|
|
this._$winicon.setAttribute('aria-label', 'Window Menu');
|
|
var windowTitle = document.createElement('application-window-title');
|
|
windowTitle.setAttribute('role', 'heading');
|
|
Utils.$bind(this._$loading, 'mousedown', _noEvent);
|
|
Utils.$bind(this._$disabled, 'mousedown', _noEvent);
|
|
var preventTimeout;
|
|
function _onanimationend(ev) {
|
|
if ( typeof self._animationCallback === 'function') {
|
|
clearTimeout(preventTimeout);
|
|
preventTimeout = setTimeout(function() {
|
|
self._animationCallback(ev);
|
|
self._animationCallback = false;
|
|
preventTimeout = clearTimeout(preventTimeout);
|
|
}, 10);
|
|
}
|
|
}
|
|
Utils.$bind(this._$element, 'transitionend', _onanimationend);
|
|
Utils.$bind(this._$element, 'animationend', _onanimationend);
|
|
Utils.$bind(this._$element, 'mousedown', function(ev) {
|
|
self._focus();
|
|
return stopPropagation(ev);
|
|
});
|
|
Utils.$bind(this._$element, 'contextmenu', function(ev) {
|
|
var r = Utils.$isFormElement(ev);
|
|
if ( !r ) {
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
}
|
|
OSjs.API.blurMenu();
|
|
return !!r;
|
|
});
|
|
Utils.$bind(this._$top, 'click', function(ev) {
|
|
var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target);
|
|
ev.preventDefault();
|
|
if ( t ) {
|
|
if ( t.tagName.match(/^APPLICATION\-WINDOW\-BUTTON/) ) {
|
|
self._onWindowButtonClick(ev, t, t.getAttribute('data-action'));
|
|
} else if ( t.tagName === 'APPLICATION-WINDOW-ICON' ) {
|
|
ev.stopPropagation();
|
|
self._onWindowIconClick(ev, t);
|
|
}
|
|
}
|
|
}, true);
|
|
Utils.$bind(windowTitle, 'mousedown', _noEvent);
|
|
Utils.$bind(windowTitle, 'dblclick', function() {
|
|
self._maximize();
|
|
});
|
|
(function _initDnD(properties, main, compability) {
|
|
if ( properties.allow_drop && compability.dnd ) {
|
|
var border = document.createElement('div');
|
|
border.className = 'WindowDropRect';
|
|
OSjs.GUI.Helpers.createDroppable(main, {
|
|
onOver: function(ev, el, args) {
|
|
main.setAttribute('data-dnd-state', 'true');
|
|
},
|
|
onLeave : function() {
|
|
main.setAttribute('data-dnd-state', 'false');
|
|
},
|
|
onDrop : function() {
|
|
main.setAttribute('data-dnd-state', 'false');
|
|
},
|
|
onItemDropped: function(ev, el, item, args) {
|
|
main.setAttribute('data-dnd-state', 'false');
|
|
return self._onDndEvent(ev, 'itemDrop', item, args, el);
|
|
},
|
|
onFilesDropped: function(ev, el, files, args) {
|
|
main.setAttribute('data-dnd-state', 'false');
|
|
return self._onDndEvent(ev, 'filesDrop', files, args, el);
|
|
}
|
|
});
|
|
}
|
|
})(this._properties, this._$element, Utils.getCompability());
|
|
windowTitle.appendChild(document.createTextNode(this._title));
|
|
this._$top.appendChild(this._$winicon);
|
|
this._$top.appendChild(windowTitle);
|
|
this._$top.appendChild(Utils.$create('application-window-button-minimize', {
|
|
className: 'application-window-button-entry',
|
|
data: {
|
|
action: 'minimize'
|
|
},
|
|
aria: {
|
|
role: 'button',
|
|
label: 'Minimize Window'
|
|
}
|
|
}));
|
|
this._$top.appendChild(Utils.$create('application-window-button-maximize', {
|
|
className: 'application-window-button-entry',
|
|
data: {
|
|
action: 'maximize'
|
|
},
|
|
aria: {
|
|
role: 'button',
|
|
label: 'Maximize Window'
|
|
}
|
|
}));
|
|
this._$top.appendChild(Utils.$create('application-window-button-close', {
|
|
className: 'application-window-button-entry',
|
|
data: {
|
|
action: 'close'
|
|
},
|
|
aria: {
|
|
role: 'button',
|
|
label: 'Close Window'
|
|
}
|
|
}));
|
|
this._$loading.appendChild(document.createElement('application-window-loading-indicator'));
|
|
this._$element.appendChild(this._$top);
|
|
this._$element.appendChild(this._$root);
|
|
this._$element.appendChild(this._$resize);
|
|
this._$element.appendChild(this._$disabled);
|
|
document.body.appendChild(this._$element);
|
|
this._onChange('create');
|
|
this._toggleLoading(false);
|
|
this._toggleDisabled(false);
|
|
this._setIcon(API.getIcon(this._icon, null, this._app));
|
|
this._updateMarkup();
|
|
if ( this._sound ) {
|
|
API.playSound(this._sound, this._soundVolume);
|
|
}
|
|
this._initialized = true;
|
|
this._emit('init', [this._$root, _scheme]);
|
|
return this._$root;
|
|
};
|
|
Window.prototype._inited = function() {
|
|
if ( this._loaded ) {
|
|
return;
|
|
}
|
|
this._loaded = true;
|
|
this._onResize();
|
|
if ( !this._restored ) {
|
|
if ( this._state.maximized ) {
|
|
this._maximize(true);
|
|
} else if ( this._state.minimized ) {
|
|
this._minimize(true);
|
|
}
|
|
}
|
|
var self = this;
|
|
var inittimeout = setTimeout(function() {
|
|
self._emit('inited', [self._scheme]);
|
|
inittimeout = clearTimeout(inittimeout);
|
|
}, 10);
|
|
if ( this._app ) {
|
|
this._app._onMessage('initedWindow', this, {});
|
|
}
|
|
};
|
|
Window.prototype.destroy = function(shutdown) {
|
|
var self = this;
|
|
if ( this._destroyed ) {
|
|
return false;
|
|
}
|
|
this._emit('destroy');
|
|
this._destroyed = true;
|
|
var wm = OSjs.Core.getWindowManager();
|
|
function _removeDOM() {
|
|
self._setWarning(null);
|
|
self._$root = null;
|
|
self._$top = null;
|
|
self._$winicon = null;
|
|
self._$loading = null;
|
|
self._$disabled = null;
|
|
self._$resize = null;
|
|
self._$warning = null;
|
|
self._$element = Utils.$remove(self._$element);
|
|
}
|
|
function _destroyDOM() {
|
|
if ( self._$element ) {
|
|
self._$element.querySelectorAll('*').forEach(function(iter) {
|
|
if ( iter ) {
|
|
Utils.$unbind(iter);
|
|
}
|
|
});
|
|
}
|
|
if ( self._parent ) {
|
|
self._parent._removeChild(self);
|
|
}
|
|
self._parent = null;
|
|
self._removeChildren();
|
|
}
|
|
function _destroyWin() {
|
|
if ( wm ) {
|
|
wm.removeWindow(self);
|
|
}
|
|
var curWin = wm ? wm.getCurrentWindow() : null;
|
|
if ( curWin && curWin._wid === self._wid ) {
|
|
wm.setCurrentWindow(null);
|
|
}
|
|
var lastWin = wm ? wm.getLastWindow() : null;
|
|
if ( lastWin && lastWin._wid === self._wid ) {
|
|
wm.setLastWindow(null);
|
|
}
|
|
}
|
|
function _animateClose(fn) {
|
|
if ( API.isShuttingDown() ) {
|
|
fn();
|
|
} else {
|
|
if ( self._$element ) {
|
|
var anim = wm ? wm.getSetting('animations') : false;
|
|
if ( anim ) {
|
|
self._$element.setAttribute('data-hint', 'closing');
|
|
self._animationCallback = fn;
|
|
var animatetimeout = setTimeout(function() {
|
|
if ( self._animationCallback ) {
|
|
self._animationCallback();
|
|
}
|
|
animatetimeout = clearTimeout(animatetimeout);
|
|
}, 1000);
|
|
} else {
|
|
self._$element.style.display = 'none';
|
|
fn();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this._onChange('close');
|
|
_animateClose(function() {
|
|
_removeDOM();
|
|
});
|
|
_destroyDOM();
|
|
_destroyWin();
|
|
if ( this._app ) {
|
|
this._app._onMessage('destroyWindow', this, {});
|
|
}
|
|
if ( this._evHandler ) {
|
|
this._evHandler.destroy();
|
|
}
|
|
this._scheme = null;
|
|
this._app = null;
|
|
this._evHandler = null;
|
|
this._args = {};
|
|
this._queryTimer = clearTimeout(this._queryTimer);
|
|
return true;
|
|
};
|
|
Window.prototype._find = function(id) {
|
|
return this._scheme ? this._scheme.find(this, id) : null;
|
|
};
|
|
Window.prototype._findByQuery = function(q, root, all) {
|
|
return this._scheme ? this._scheme.findByQuery(this, q, root, all) : null;
|
|
};
|
|
Window.prototype._emit = function(k, args) {
|
|
if ( !this._destroyed ) {
|
|
if ( this._evHandler ) {
|
|
return this._evHandler.emit(k, args);
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
Window.prototype._on = function(k, func) {
|
|
if ( this._evHandler ) {
|
|
return this._evHandler.on(k, func, this);
|
|
}
|
|
return false;
|
|
};
|
|
Window.prototype._off = function(k, idx) {
|
|
if ( this._evHandler ) {
|
|
return this._evHandler.off(k, idx);
|
|
}
|
|
return false;
|
|
};
|
|
Window.prototype._addChild = function(w, wmAdd, wmFocus) {
|
|
w._parent = this;
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wmAdd && wm ) {
|
|
wm.addWindow(w, wmFocus);
|
|
}
|
|
this._children.push(w);
|
|
return w;
|
|
};
|
|
Window.prototype._removeChild = function(w) {
|
|
var self = this;
|
|
this._children.forEach(function(child, i) {
|
|
if ( child && child._wid === w._wid ) {
|
|
child.destroy();
|
|
self._children[i] = null;
|
|
}
|
|
});
|
|
};
|
|
Window.prototype._getChild = function(value, key) {
|
|
key = key || 'wid';
|
|
var result = key === 'tag' ? [] : null;
|
|
this._children.every(function(child, i) {
|
|
if ( child ) {
|
|
if ( key === 'tag' ) {
|
|
result.push(child);
|
|
} else {
|
|
if ( child['_' + key] === value ) {
|
|
result = child;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
return result;
|
|
};
|
|
Window.prototype._getChildById = function(id) {
|
|
return this._getChild(id, 'wid');
|
|
};
|
|
Window.prototype._getChildByName = function(name) {
|
|
return this._getChild(name, 'name');
|
|
};
|
|
Window.prototype._getChildrenByTag = function(tag) {
|
|
return this._getChild(tag, 'tag');
|
|
};
|
|
Window.prototype._getChildren = function() {
|
|
return this._children;
|
|
};
|
|
Window.prototype._removeChildren = function() {
|
|
if ( this._children && this._children.length ) {
|
|
this._children.forEach(function(child, i) {
|
|
if ( child ) {
|
|
child.destroy();
|
|
}
|
|
});
|
|
}
|
|
this._children = [];
|
|
};
|
|
Window.prototype._close = function() {
|
|
if ( this._disabled || this._destroyed ) {
|
|
return false;
|
|
}
|
|
this._blur();
|
|
this.destroy();
|
|
return true;
|
|
};
|
|
Window.prototype._minimize = function(force) {
|
|
var self = this;
|
|
if ( !this._properties.allow_minimize || this._destroyed ) {
|
|
return false;
|
|
}
|
|
if ( !force && this._state.minimized ) {
|
|
this._restore(false, true);
|
|
return true;
|
|
}
|
|
this._blur();
|
|
this._state.minimized = true;
|
|
this._$element.setAttribute('data-minimized', 'true');
|
|
waitForAnimation(this, function() {
|
|
self._$element.style.display = 'none';
|
|
self._emit('minimize');
|
|
});
|
|
this._onChange('minimize');
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var win = wm ? wm.getCurrentWindow() : null;
|
|
if ( win && win._wid === this._wid ) {
|
|
wm.setCurrentWindow(null);
|
|
}
|
|
this._updateMarkup();
|
|
return true;
|
|
};
|
|
Window.prototype._maximize = function(force) {
|
|
var self = this;
|
|
if ( !this._properties.allow_maximize || this._destroyed || !this._$element ) {
|
|
return false;
|
|
}
|
|
if ( !force && this._state.maximized ) {
|
|
this._restore(true, false);
|
|
return true;
|
|
}
|
|
this._lastPosition = {x: this._position.x, y: this._position.y};
|
|
this._lastDimension = {w: this._dimension.w, h: this._dimension.h};
|
|
this._state.maximized = true;
|
|
var s = this._getMaximizedSize();
|
|
this._$element.style.zIndex = getNextZindex(this._state.ontop);
|
|
this._$element.style.top = (s.top) + 'px';
|
|
this._$element.style.left = (s.left) + 'px';
|
|
this._$element.style.width = (s.width) + 'px';
|
|
this._$element.style.height = (s.height) + 'px';
|
|
this._$element.setAttribute('data-maximized', 'true');
|
|
this._dimension.w = s.width;
|
|
this._dimension.h = s.height;
|
|
this._position.x = s.left;
|
|
this._position.y = s.top;
|
|
this._focus();
|
|
waitForAnimation(this, function() {
|
|
self._emit('maximize');
|
|
});
|
|
this._onChange('maximize');
|
|
this._onResize();
|
|
this._updateMarkup();
|
|
return true;
|
|
};
|
|
Window.prototype._restore = function(max, min) {
|
|
var self = this;
|
|
if ( !this._$element || this._destroyed ) {
|
|
return;
|
|
}
|
|
function restoreMaximized() {
|
|
if ( max && self._state.maximized ) {
|
|
self._move(self._lastPosition.x, self._lastPosition.y);
|
|
self._resize(self._lastDimension.w, self._lastDimension.h);
|
|
self._state.maximized = false;
|
|
self._$element.setAttribute('data-maximized', 'false');
|
|
}
|
|
}
|
|
function restoreMinimized() {
|
|
if ( min && self._state.minimized ) {
|
|
self._$element.style.display = 'block';
|
|
self._$element.setAttribute('data-minimized', 'false');
|
|
self._state.minimized = false;
|
|
}
|
|
}
|
|
max = (typeof max === 'undefined') ? true : (max === true);
|
|
min = (typeof min === 'undefined') ? true : (min === true);
|
|
restoreMaximized();
|
|
restoreMinimized();
|
|
waitForAnimation(this, function() {
|
|
self._emit('restore');
|
|
});
|
|
this._onChange('restore');
|
|
this._onResize();
|
|
this._focus();
|
|
this._updateMarkup();
|
|
};
|
|
Window.prototype._focus = function(force) {
|
|
if ( !this._$element || this._destroyed ) {
|
|
return false;
|
|
}
|
|
this._toggleAttentionBlink(false);
|
|
this._$element.style.zIndex = getNextZindex(this._state.ontop);
|
|
this._$element.setAttribute('data-focused', 'true');
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var win = wm ? wm.getCurrentWindow() : null;
|
|
if ( win && win._wid !== this._wid ) {
|
|
win._blur();
|
|
}
|
|
if ( wm ) {
|
|
wm.setCurrentWindow(this);
|
|
wm.setLastWindow(this);
|
|
}
|
|
if ( !this._state.focused || force) {
|
|
this._onChange('focus');
|
|
this._emit('focus');
|
|
}
|
|
this._state.focused = true;
|
|
this._updateMarkup();
|
|
return true;
|
|
};
|
|
Window.prototype._blur = function(force) {
|
|
if ( !this._$element || this._destroyed || (!force && !this._state.focused) ) {
|
|
return false;
|
|
}
|
|
this._$element.setAttribute('data-focused', 'false');
|
|
this._state.focused = false;
|
|
this._onChange('blur');
|
|
this._emit('blur');
|
|
this._blurGUI();
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var win = wm ? wm.getCurrentWindow() : null;
|
|
if ( win && win._wid === this._wid ) {
|
|
wm.setCurrentWindow(null);
|
|
}
|
|
this._updateMarkup();
|
|
return true;
|
|
};
|
|
Window.prototype._blurGUI = function() {
|
|
this._$root.querySelectorAll('input, textarea, select, iframe, button').forEach(function(el) {
|
|
el.blur();
|
|
});
|
|
};
|
|
Window.prototype._resizeTo = function(dw, dh, limit, move, container, force) {
|
|
var self = this;
|
|
if ( !this._$element || (dw <= 0 || dh <= 0) ) {
|
|
return;
|
|
}
|
|
limit = (typeof limit === 'undefined' || limit === true);
|
|
var dx = 0;
|
|
var dy = 0;
|
|
if ( container ) {
|
|
var cpos = Utils.$position(container, this._$root);
|
|
dx = parseInt(cpos.left, 10);
|
|
dy = parseInt(cpos.top, 10);
|
|
}
|
|
var space = this._getMaximizedSize();
|
|
var cx = this._position.x + dx;
|
|
var cy = this._position.y + dy;
|
|
var newW = dw;
|
|
var newH = dh;
|
|
var newX = null;
|
|
var newY = null;
|
|
function _limitTo() {
|
|
if ( (cx + newW) > space.width ) {
|
|
if ( move ) {
|
|
newW = space.width;
|
|
newX = space.left;
|
|
} else {
|
|
newW = (space.width - cx) + dx;
|
|
}
|
|
} else {
|
|
newW += dx;
|
|
}
|
|
if ( (cy + newH) > space.height ) {
|
|
if ( move ) {
|
|
newH = space.height;
|
|
newY = space.top;
|
|
} else {
|
|
newH = (space.height - cy + self._$top.offsetHeight) + dy;
|
|
}
|
|
} else {
|
|
newH += dy;
|
|
}
|
|
}
|
|
function _moveTo() {
|
|
if ( newX !== null ) {
|
|
self._move(newX, self._position.y);
|
|
}
|
|
if ( newY !== null ) {
|
|
self._move(self._position.x, newY);
|
|
}
|
|
}
|
|
function _resizeFinished() {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var anim = wm ? wm.getSetting('animations') : false;
|
|
if ( anim ) {
|
|
self._animationCallback = function() {
|
|
self._emit('resized');
|
|
};
|
|
} else {
|
|
self._emit('resized');
|
|
}
|
|
}
|
|
if ( limit ) {
|
|
_limitTo();
|
|
}
|
|
this._resize(newW, newH, force);
|
|
_moveTo();
|
|
_resizeFinished();
|
|
};
|
|
Window.prototype._resize = function(w, h, force) {
|
|
if ( !this._$element || this._destroyed ) {
|
|
return false;
|
|
}
|
|
var p = this._properties;
|
|
if ( !force ) {
|
|
if ( !p.allow_resize ) {
|
|
return false;
|
|
}
|
|
(function() {
|
|
if ( !isNaN(w) && w ) {
|
|
if ( w < p.min_width ) {
|
|
w = p.min_width;
|
|
}
|
|
if ( p.max_width !== null ) {
|
|
if ( w > p.max_width ) {
|
|
w = p.max_width;
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
(function() {
|
|
if ( !isNaN(h) && h ) {
|
|
if ( h < p.min_height ) {
|
|
h = p.min_height;
|
|
}
|
|
if ( p.max_height !== null ) {
|
|
if ( h > p.max_height ) {
|
|
h = p.max_height;
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
}
|
|
if ( !isNaN(w) && w ) {
|
|
this._$element.style.width = w + 'px';
|
|
this._dimension.w = w;
|
|
}
|
|
if ( !isNaN(h) && h ) {
|
|
this._$element.style.height = h + 'px';
|
|
this._dimension.h = h;
|
|
}
|
|
this._onResize();
|
|
return true;
|
|
};
|
|
Window.prototype._moveTo = function(pos) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( !wm ) {
|
|
return;
|
|
}
|
|
var s = wm.getWindowSpace();
|
|
var cx = this._position.x;
|
|
var cy = this._position.y;
|
|
if ( pos === 'left' ) {
|
|
this._move(s.left, cy);
|
|
} else if ( pos === 'right' ) {
|
|
this._move((s.width - this._dimension.w), cy);
|
|
} else if ( pos === 'top' ) {
|
|
this._move(cx, s.top);
|
|
} else if ( pos === 'bottom' ) {
|
|
this._move(cx, (s.height - this._dimension.h));
|
|
}
|
|
};
|
|
Window.prototype._move = function(x, y) {
|
|
if ( !this._$element || this._destroyed || !this._properties.allow_move ) {
|
|
return false;
|
|
}
|
|
if ( typeof x === 'undefined' || typeof y === 'undefined') {
|
|
return false;
|
|
}
|
|
this._$element.style.top = y + 'px';
|
|
this._$element.style.left = x + 'px';
|
|
this._position.x = x;
|
|
this._position.y = y;
|
|
return true;
|
|
};
|
|
Window.prototype._toggleDisabled = function(t) {
|
|
if ( this._$disabled ) {
|
|
this._$disabled.style.display = t ? 'block' : 'none';
|
|
}
|
|
this._disabled = t ? true : false;
|
|
this._updateMarkup();
|
|
};
|
|
Window.prototype._toggleLoading = function(t) {
|
|
if ( this._$loading ) {
|
|
this._$loading.style.display = t ? 'block' : 'none';
|
|
}
|
|
this._loading = t ? true : false;
|
|
this._updateMarkup();
|
|
};
|
|
Window.prototype._updateMarkup = function(ui) {
|
|
if ( !this._$element ) {
|
|
return;
|
|
}
|
|
var t = this._loading || this._disabled;
|
|
var d = this._disabled;
|
|
var h = this._state.minimized;
|
|
var f = !this._state.focused;
|
|
this._$element.setAttribute('aria-busy', String(t));
|
|
this._$element.setAttribute('aria-hidden', String(h));
|
|
this._$element.setAttribute('aria-disabled', String(d));
|
|
this._$root.setAttribute('aria-hidden', String(f));
|
|
if ( !ui ) {
|
|
return;
|
|
}
|
|
var dmax = this._properties.allow_maximize === true ? 'inline-block' : 'none';
|
|
var dmin = this._properties.allow_minimize === true ? 'inline-block' : 'none';
|
|
var dclose = this._properties.allow_close === true ? 'inline-block' : 'none';
|
|
this._$top.querySelector('application-window-button-maximize').style.display = dmax;
|
|
this._$top.querySelector('application-window-button-minimize').style.display = dmin;
|
|
this._$top.querySelector('application-window-button-close').style.display = dclose;
|
|
var dres = this._properties.allow_resize === true;
|
|
this._$element.setAttribute('data-allow-resize', String(dres));
|
|
};
|
|
Window.prototype._toggleAttentionBlink = function(t) {
|
|
if ( !this._$element || this._destroyed || this._state.focused ) {
|
|
return false;
|
|
}
|
|
var el = this._$element;
|
|
var self = this;
|
|
function _blink(stat) {
|
|
if ( el ) {
|
|
if ( stat ) {
|
|
Utils.$addClass(el, 'WindowAttentionBlink');
|
|
} else {
|
|
Utils.$removeClass(el, 'WindowAttentionBlink');
|
|
}
|
|
}
|
|
self._onChange(stat ? 'attention_on' : 'attention_off');
|
|
}
|
|
_blink(t);
|
|
return true;
|
|
};
|
|
Window.prototype._nextTabIndex = function(ev) {
|
|
var nextElement = OSjs.GUI.Helpers.getNextElement(ev.shiftKey, document.activeElement, this._$root);
|
|
if ( nextElement ) {
|
|
if ( Utils.$hasClass(nextElement, 'gui-data-view') ) {
|
|
new OSjs.GUI.ElementDataView(nextElement)._call('focus');
|
|
} else {
|
|
try {
|
|
nextElement.focus();
|
|
} catch ( e ) {}
|
|
}
|
|
}
|
|
};
|
|
Window.prototype._onDndEvent = function(ev, type, item, args, el) {
|
|
if ( this._disabled || this._destroyed ) {
|
|
return false;
|
|
}
|
|
this._emit('drop', [ev, type, item, args, el]);
|
|
if ( item ) {
|
|
if ( type === 'filesDrop' ) {
|
|
this._emit('drop:upload', [ev, item, args, el]);
|
|
} else if ( type === 'itemDrop' && item.type === 'file' && item.data ) {
|
|
this._emit('drop:file', [ev, new OSjs.VFS.File(item.data || {}), args, el]);
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
Window.prototype._onKeyEvent = function(ev, type) {
|
|
if ( this._destroyed ) {
|
|
return false;
|
|
}
|
|
if ( type === 'keydown' && ev.keyCode === Utils.Keys.TAB ) {
|
|
this._nextTabIndex(ev);
|
|
}
|
|
this._emit(type, [ev, ev.keyCode, ev.shiftKey, ev.ctrlKey, ev.altKey]);
|
|
return true;
|
|
};
|
|
Window.prototype._onResize = function() {
|
|
clearTimeout(this._queryTimer);
|
|
var self = this;
|
|
this._queryTimer = setTimeout(function() {
|
|
checkMediaQueries(self);
|
|
self._queryTimer = clearTimeout(self._queryTimer);
|
|
}, 20);
|
|
};
|
|
Window.prototype._onWindowIconClick = function(ev, el) {
|
|
if ( !this._properties.allow_iconmenu || this._destroyed ) {
|
|
return;
|
|
}
|
|
var self = this;
|
|
var control = [
|
|
[this._properties.allow_minimize, function() {
|
|
return {
|
|
title: API._('WINDOW_MINIMIZE'),
|
|
icon: API.getIcon('actions/stock_up.png'),
|
|
onClick: function(name, iter) {
|
|
self._minimize();
|
|
}
|
|
};
|
|
}],
|
|
[this._properties.allow_maximize, function() {
|
|
return {
|
|
title: API._('WINDOW_MAXIMIZE'),
|
|
icon: API.getIcon('actions/window_fullscreen.png'),
|
|
onClick: function(name, iter) {
|
|
self._maximize();
|
|
self._focus();
|
|
}
|
|
};
|
|
}],
|
|
[this._state.maximized, function() {
|
|
return {
|
|
title: API._('WINDOW_RESTORE'),
|
|
icon: API.getIcon('actions/view-restore.png'),
|
|
onClick: function(name, iter) {
|
|
self._restore();
|
|
self._focus();
|
|
}
|
|
};
|
|
}],
|
|
[this._properties.allow_ontop, function() {
|
|
if ( self._state.ontop ) {
|
|
return {
|
|
title: API._('WINDOW_ONTOP_OFF'),
|
|
icon: API.getIcon('actions/window-new.png'),
|
|
onClick: function(name, iter) {
|
|
self._state.ontop = false;
|
|
if ( self._$element ) {
|
|
self._$element.style.zIndex = getNextZindex(false);
|
|
}
|
|
self._focus();
|
|
}
|
|
};
|
|
}
|
|
return {
|
|
title: API._('WINDOW_ONTOP_ON'),
|
|
icon: API.getIcon('actions/window-new.png'),
|
|
onClick: function(name, iter) {
|
|
self._state.ontop = true;
|
|
if ( self._$element ) {
|
|
self._$element.style.zIndex = getNextZindex(true);
|
|
}
|
|
self._focus();
|
|
}
|
|
};
|
|
}],
|
|
[this._properties.allow_close, function() {
|
|
return {
|
|
title: API._('WINDOW_CLOSE'),
|
|
icon: API.getIcon('actions/window-close.png'),
|
|
onClick: function(name, iter) {
|
|
self._close();
|
|
}
|
|
};
|
|
}]
|
|
];
|
|
var list = [];
|
|
control.forEach(function(iter) {
|
|
if (iter[0] ) {
|
|
list.push(iter[1]());
|
|
}
|
|
});
|
|
OSjs.API.createMenu(list, ev);
|
|
};
|
|
Window.prototype._onWindowButtonClick = function(ev, el, btn) {
|
|
this._blurGUI();
|
|
if ( btn === 'close' ) {
|
|
this._close();
|
|
} else if ( btn === 'minimize' ) {
|
|
this._minimize();
|
|
} else if ( btn === 'maximize' ) {
|
|
this._maximize();
|
|
}
|
|
};
|
|
Window.prototype._onChange = function(ev, byUser) {
|
|
ev = ev || '';
|
|
if ( ev ) {
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.eventWindow(ev, this);
|
|
}
|
|
}
|
|
};
|
|
Window.prototype._getMaximizedSize = function() {
|
|
var s = getWindowSpace();
|
|
if ( !this._$element || this._destroyed ) {
|
|
return s;
|
|
}
|
|
var topMargin = 23;
|
|
var borderSize = 0;
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
var theme = wm.getStyleTheme(true);
|
|
if ( theme && theme.style && theme.style.window ) {
|
|
topMargin = theme.style.window.margin;
|
|
borderSize = theme.style.window.border;
|
|
}
|
|
}
|
|
s.left += borderSize;
|
|
s.top += borderSize;
|
|
s.width -= (borderSize * 2);
|
|
s.height -= topMargin + (borderSize * 2);
|
|
return Object.freeze(s);
|
|
};
|
|
Window.prototype._getViewRect = function() {
|
|
return this._$element ? Object.freeze(Utils.$position(this._$element)) : null;
|
|
};
|
|
Window.prototype._getRoot = function() {
|
|
return this._$root;
|
|
};
|
|
Window.prototype._getZindex = function() {
|
|
if ( this._$element ) {
|
|
return parseInt(this._$element.style.zIndex, 10);
|
|
}
|
|
return -1;
|
|
};
|
|
Window.prototype._setTitle = function(t, append, delimiter) {
|
|
if ( !this._$element || this._destroyed ) {
|
|
return;
|
|
}
|
|
delimiter = delimiter || '-';
|
|
var tel = this._$element.getElementsByTagName('application-window-title')[0];
|
|
var text = [];
|
|
if ( append ) {
|
|
text = [this._origtitle, delimiter, t];
|
|
} else {
|
|
text = [t || this._origtitle];
|
|
}
|
|
this._title = text.join(' ') || this._origtitle;
|
|
if ( tel ) {
|
|
Utils.$empty(tel);
|
|
tel.appendChild(document.createTextNode(this._title));
|
|
}
|
|
this._onChange('title');
|
|
this._updateMarkup();
|
|
};
|
|
Window.prototype._setIcon = function(i) {
|
|
if ( this._$winicon ) {
|
|
this._$winicon.title = this._title;
|
|
this._$winicon.style.backgroundImage = 'url(' + i + ')';
|
|
}
|
|
this._icon = i;
|
|
this._onChange('icon');
|
|
};
|
|
Window.prototype._setWarning = function(message) {
|
|
var self = this;
|
|
this._$warning = Utils.$remove(this._$warning);
|
|
if ( this._destroyed || message === null ) {
|
|
return;
|
|
}
|
|
message = message || '';
|
|
var container = document.createElement('application-window-warning');
|
|
var close = document.createElement('div');
|
|
close.innerHTML = 'X';
|
|
Utils.$bind(close, 'click', function() {
|
|
self._setWarning(null);
|
|
});
|
|
var msg = document.createElement('div');
|
|
msg.appendChild(document.createTextNode(message));
|
|
container.appendChild(close);
|
|
container.appendChild(msg);
|
|
this._$warning = container;
|
|
this._$root.appendChild(this._$warning);
|
|
};
|
|
Window.prototype._setProperty = function(p, v) {
|
|
if ( (v === '' || v === null) || !this._$element || (typeof this._properties[p] === 'undefined') ) {
|
|
return;
|
|
}
|
|
this._properties[p] = String(v) === 'true';
|
|
this._updateMarkup(true);
|
|
};
|
|
OSjs.Core.Window = Object.seal(Window);
|
|
})(OSjs.Utils, OSjs.API, OSjs.GUI, OSjs.Core.Process);
|
|
|
|
(function(Utils, API, Window) {
|
|
'use strict';
|
|
function DialogWindow(className, opts, args, callback) {
|
|
var self = this;
|
|
opts = opts || {};
|
|
args = args || {};
|
|
callback = callback || function() {};
|
|
if ( typeof callback !== 'function' ) {
|
|
throw new TypeError('DialogWindow expects a callback Function, gave: ' + typeof callback);
|
|
}
|
|
Window.apply(this, [className, opts]);
|
|
this._properties.gravity = 'center';
|
|
this._properties.allow_resize = false;
|
|
this._properties.allow_minimize = false;
|
|
this._properties.allow_maximize = false;
|
|
this._properties.allow_windowlist = false;
|
|
this._properties.allow_session = false;
|
|
this._state.ontop = true;
|
|
this._tag = 'DialogWindow';
|
|
if ( args.scheme && args.scheme instanceof OSjs.GUI.Scheme ) {
|
|
this.scheme = args.scheme;
|
|
delete args.scheme;
|
|
} else {
|
|
this.scheme = OSjs.GUI.DialogScheme.get();
|
|
}
|
|
this.args = args;
|
|
this.className = className;
|
|
this.buttonClicked = false;
|
|
this.closeCallback = function(ev, button, result) {
|
|
if ( self._destroyed ) {
|
|
return;
|
|
}
|
|
self.buttonClicked = true;
|
|
callback.apply(self, arguments);
|
|
self._close();
|
|
};
|
|
}
|
|
DialogWindow.prototype = Object.create(Window.prototype);
|
|
DialogWindow.constructor = Window;
|
|
DialogWindow.prototype.init = function() {
|
|
var self = this;
|
|
var root = Window.prototype.init.apply(this, arguments);
|
|
root.setAttribute('role', 'dialog');
|
|
this.scheme.render(this, this.className.replace(/Dialog$/, ''), root, 'application-dialog', function(node) {
|
|
node.querySelectorAll('gui-label').forEach(function(el) {
|
|
if ( el.childNodes.length && el.childNodes[0].nodeType === 3 && el.childNodes[0].nodeValue ) {
|
|
var label = el.childNodes[0].nodeValue;
|
|
Utils.$empty(el);
|
|
el.appendChild(document.createTextNode(API._(label)));
|
|
}
|
|
});
|
|
});
|
|
var buttonMap = {
|
|
ButtonOK: 'ok',
|
|
ButtonCancel: 'cancel',
|
|
ButtonYes: 'yes',
|
|
ButtonNo: 'no'
|
|
};
|
|
var focusButtons = ['ButtonCancel', 'ButtonNo'];
|
|
Object.keys(buttonMap).forEach(function(id) {
|
|
if ( self.scheme.findDOM(self, id) ) {
|
|
var btn = self.scheme.find(self, id);
|
|
btn.on('click', function(ev) {
|
|
self.onClose(ev, buttonMap[id]);
|
|
});
|
|
if ( focusButtons.indexOf(id) >= 0 ) {
|
|
btn.focus();
|
|
}
|
|
}
|
|
});
|
|
Utils.$addClass(root, 'DialogWindow');
|
|
return root;
|
|
};
|
|
DialogWindow.prototype.onClose = function(ev, button) {
|
|
this.closeCallback(ev, button, null);
|
|
};
|
|
DialogWindow.prototype._close = function() {
|
|
if ( !this.buttonClicked ) {
|
|
this.onClose(null, 'cancel', null);
|
|
}
|
|
return Window.prototype._close.apply(this, arguments);
|
|
};
|
|
DialogWindow.prototype._onKeyEvent = function(ev) {
|
|
Window.prototype._onKeyEvent.apply(this, arguments);
|
|
if ( ev.keyCode === Utils.Keys.ESC ) {
|
|
this.onClose(ev, 'cancel');
|
|
}
|
|
};
|
|
DialogWindow.parseMessage = function(msg) {
|
|
msg = Utils.$escape(msg || '').replace(/\*\*(.*)\*\*/g, '<span>$1</span>');
|
|
var tmp = document.createElement('div');
|
|
tmp.innerHTML = msg;
|
|
var frag = document.createDocumentFragment();
|
|
for ( var i = 0; i < tmp.childNodes.length; i++ ) {
|
|
frag.appendChild(tmp.childNodes[i].cloneNode(true));
|
|
}
|
|
tmp = null;
|
|
return frag;
|
|
};
|
|
OSjs.Core.DialogWindow = Object.seal(DialogWindow);
|
|
})(OSjs.Utils, OSjs.API, OSjs.Core.Window);
|
|
|
|
(function(Utils, API, Process, Window) {
|
|
'use strict';
|
|
var _WM; // Running Window Manager process
|
|
function BehaviourState(win, action, mousePosition) {
|
|
var self = this;
|
|
this.win = win;
|
|
this.$element = win._$element;
|
|
this.$top = win._$top;
|
|
this.$handle = win._$resize;
|
|
this.rectWorkspace = _WM.getWindowSpace(true);
|
|
this.rectWindow = {
|
|
x: win._position.x,
|
|
y: win._position.y,
|
|
w: win._dimension.w,
|
|
h: win._dimension.h,
|
|
r: win._dimension.w + win._position.x,
|
|
b: win._dimension.h + win._position.y
|
|
};
|
|
var theme = _WM.getStyleTheme(true);
|
|
if ( !theme.style ) {
|
|
theme.style = {'window': {margin: 0, border: 0}};
|
|
}
|
|
this.theme = {
|
|
topMargin : theme.style.window.margin || 0,
|
|
borderSize: theme.style.window.border || 0
|
|
};
|
|
this.snapping = {
|
|
cornerSize : _WM.getSetting('windowCornerSnap') || 0,
|
|
windowSize : _WM.getSetting('windowSnap') || 0
|
|
};
|
|
this.action = action;
|
|
this.moved = false;
|
|
this.direction = null;
|
|
this.startX = mousePosition.x;
|
|
this.startY = mousePosition.y;
|
|
this.minWidth = win._properties.min_width;
|
|
this.minHeight = win._properties.min_height;
|
|
var windowRects = [];
|
|
_WM.getWindows().forEach(function(w) {
|
|
if ( w && w._wid !== win._wid ) {
|
|
var pos = w._position;
|
|
var dim = w._dimension;
|
|
var rect = {
|
|
left : pos.x - self.theme.borderSize,
|
|
top : pos.y - self.theme.borderSize,
|
|
width: dim.w + (self.theme.borderSize * 2),
|
|
height: dim.h + (self.theme.borderSize * 2) + self.theme.topMargin
|
|
};
|
|
rect.right = rect.left + rect.width;
|
|
rect.bottom = (pos.y + dim.h) + self.theme.topMargin + self.theme.borderSize;//rect.top + rect.height;
|
|
windowRects.push(rect);
|
|
}
|
|
});
|
|
this.snapRects = windowRects;
|
|
}
|
|
BehaviourState.prototype.getRect = function() {
|
|
var win = this.win;
|
|
return {
|
|
left: win._position.x,
|
|
top: win._position.y,
|
|
width: win._dimension.w,
|
|
height: win._dimension.h
|
|
};
|
|
};
|
|
BehaviourState.prototype.calculateDirection = function() {
|
|
var dir = Utils.$position(this.$handle);
|
|
var dirX = this.startX - dir.left;
|
|
var dirY = this.startY - dir.top;
|
|
var dirD = 20;
|
|
var direction = 's';
|
|
var checks = {
|
|
nw: (dirX <= dirD) && (dirY <= dirD),
|
|
n: (dirX > dirD) && (dirY <= dirD),
|
|
w: (dirX <= dirD) && (dirY >= dirD),
|
|
ne: (dirX >= (dir.width - dirD)) && (dirY <= dirD),
|
|
e: (dirX >= (dir.width - dirD)) && (dirY > dirD),
|
|
se: (dirX >= (dir.width - dirD)) && (dirY >= (dir.height - dirD)),
|
|
sw: (dirX <= dirD) && (dirY >= (dir.height - dirD))
|
|
};
|
|
Object.keys(checks).forEach(function(k) {
|
|
if ( checks[k] ) {
|
|
direction = k;
|
|
}
|
|
});
|
|
this.direction = direction;
|
|
};
|
|
function createWindowBehaviour(win, wm) {
|
|
var current = null;
|
|
var newRect = {};
|
|
function onMouseDown(ev, action, win, mousePosition) {
|
|
OSjs.API.blurMenu();
|
|
ev.preventDefault();
|
|
if ( win._state.maximized ) {
|
|
return;
|
|
}
|
|
current = new BehaviourState(win, action, mousePosition);
|
|
newRect = {};
|
|
win._focus();
|
|
if ( action === 'move' ) {
|
|
current.$element.setAttribute('data-hint', 'moving');
|
|
} else {
|
|
current.calculateDirection();
|
|
current.$element.setAttribute('data-hint', 'resizing');
|
|
newRect = current.getRect();
|
|
}
|
|
win._emit('preop');
|
|
Utils.$bind(document, 'mousemove:movewindow', _onMouseMove, false);
|
|
Utils.$bind(document, 'mouseup:movewindowstop', _onMouseUp, false);
|
|
function _onMouseMove(ev, pos) {
|
|
if ( wm._mouselock ) {
|
|
onMouseMove(ev, action, win, pos);
|
|
}
|
|
}
|
|
function _onMouseUp(ev, pos) {
|
|
onMouseUp(ev, action, win, pos);
|
|
Utils.$unbind(document, 'mousemove:movewindow');
|
|
Utils.$unbind(document, 'mouseup:movewindowstop');
|
|
}
|
|
}
|
|
function onMouseUp(ev, action, win, mousePosition) {
|
|
if ( !current ) {
|
|
return;
|
|
}
|
|
if ( current.moved ) {
|
|
if ( action === 'move' ) {
|
|
win._onChange('move', true);
|
|
win._emit('moved', [win._position.x, win._position.y]);
|
|
} else if ( action === 'resize' ) {
|
|
win._onChange('resize', true);
|
|
win._emit('resized', [win._dimension.w, win._dimension.h]);
|
|
}
|
|
}
|
|
current.$element.setAttribute('data-hint', '');
|
|
win._emit('postop');
|
|
current = null;
|
|
}
|
|
function onMouseMove(ev, action, win, mousePosition) {
|
|
if ( !_WM.getMouseLocked() || !action || !current ) {
|
|
return;
|
|
}
|
|
var result;
|
|
var dx = mousePosition.x - current.startX;
|
|
var dy = mousePosition.y - current.startY;
|
|
if ( action === 'move' ) {
|
|
result = onWindowMove(ev, mousePosition, dx, dy);
|
|
} else {
|
|
result = onWindowResize(ev, mousePosition, dx, dy);
|
|
}
|
|
if ( result ) {
|
|
if ( result.left !== null && result.top !== null ) {
|
|
win._move(result.left, result.top);
|
|
win._emit('move', [result.left, result.top]);
|
|
}
|
|
if ( result.width !== null && result.height !== null ) {
|
|
win._resize(result.width, result.height, true);
|
|
win._emit('resize', [result.width, result.height]);
|
|
}
|
|
}
|
|
current.moved = true;
|
|
}
|
|
function onWindowResize(ev, mousePosition, dx, dy) {
|
|
if ( !current || !current.direction ) {
|
|
return false;
|
|
}
|
|
var nw, nh, nl, nt;
|
|
(function() { // North/South
|
|
if ( current.direction.indexOf('s') !== -1 ) {
|
|
nh = current.rectWindow.h + dy;
|
|
newRect.height = Math.max(current.minHeight, nh);
|
|
} else if ( current.direction.indexOf('n') !== -1 ) {
|
|
nh = current.rectWindow.h - dy;
|
|
nt = current.rectWindow.y + dy;
|
|
if ( nt < current.rectWorkspace.top ) {
|
|
nt = current.rectWorkspace.top;
|
|
nh = newRect.height;
|
|
} else {
|
|
if ( nh < current.minHeight ) {
|
|
nt = current.rectWindow.b - current.minHeight;
|
|
}
|
|
}
|
|
newRect.height = Math.max(current.minHeight, nh);
|
|
newRect.top = nt;
|
|
}
|
|
})();
|
|
(function() { // East/West
|
|
if ( current.direction.indexOf('e') !== -1 ) {
|
|
nw = current.rectWindow.w + dx;
|
|
newRect.width = Math.max(current.minWidth, nw);
|
|
} else if ( current.direction.indexOf('w') !== -1 ) {
|
|
nw = current.rectWindow.w - dx;
|
|
nl = current.rectWindow.x + dx;
|
|
if ( nw < current.minWidth ) {
|
|
nl = current.rectWindow.r - current.minWidth;
|
|
}
|
|
newRect.width = Math.max(current.minWidth, nw);
|
|
newRect.left = nl;
|
|
}
|
|
})();
|
|
return newRect;
|
|
}
|
|
function onWindowMove(ev, mousePosition, dx, dy) {
|
|
var newWidth = null;
|
|
var newHeight = null;
|
|
var newLeft = current.rectWindow.x + dx;
|
|
var newTop = current.rectWindow.y + dy;
|
|
var borderSize = current.theme.borderSize;
|
|
var topMargin = current.theme.topMargin;
|
|
var cornerSnapSize = current.snapping.cornerSize;
|
|
var windowSnapSize = current.snapping.windowSize;
|
|
if ( newTop < current.rectWorkspace.top ) {
|
|
newTop = current.rectWorkspace.top;
|
|
}
|
|
var newRight = newLeft + current.rectWindow.w + (borderSize * 2);
|
|
var newBottom = newTop + current.rectWindow.h + topMargin + (borderSize);
|
|
if ( cornerSnapSize > 0 ) {
|
|
if ( ((newLeft - borderSize) <= cornerSnapSize) && ((newLeft - borderSize) >= -cornerSnapSize) ) { // Left
|
|
newLeft = borderSize;
|
|
} else if ( (newRight >= (current.rectWorkspace.width - cornerSnapSize)) && (newRight <= (current.rectWorkspace.width + cornerSnapSize)) ) { // Right
|
|
newLeft = current.rectWorkspace.width - current.rectWindow.w - borderSize;
|
|
}
|
|
if ( (newTop <= (current.rectWorkspace.top + cornerSnapSize)) && (newTop >= (current.rectWorkspace.top - cornerSnapSize)) ) { // Top
|
|
newTop = current.rectWorkspace.top + (borderSize);
|
|
} else if (
|
|
(newBottom >= ((current.rectWorkspace.height + current.rectWorkspace.top) - cornerSnapSize)) &&
|
|
(newBottom <= ((current.rectWorkspace.height + current.rectWorkspace.top) + cornerSnapSize))
|
|
) { // Bottom
|
|
newTop = (current.rectWorkspace.height + current.rectWorkspace.top) - current.rectWindow.h - topMargin - borderSize;
|
|
}
|
|
}
|
|
if ( windowSnapSize > 0 ) {
|
|
current.snapRects.every(function(rect) {
|
|
if ( newRight >= (rect.left - windowSnapSize) && newRight <= (rect.left + windowSnapSize) ) { // Left
|
|
newLeft = rect.left - (current.rectWindow.w + (borderSize * 2));
|
|
return false;
|
|
}
|
|
if ( (newLeft - borderSize) <= (rect.right + windowSnapSize) && (newLeft - borderSize) >= (rect.right - windowSnapSize) ) { // Right
|
|
newLeft = rect.right + (borderSize * 2);
|
|
return false;
|
|
}
|
|
if ( newBottom >= (rect.top - windowSnapSize) && newBottom <= (rect.top + windowSnapSize) ) { // Top
|
|
newTop = rect.top - (current.rectWindow.h + (borderSize * 2) + topMargin);
|
|
return false;
|
|
}
|
|
if ( newTop <= (rect.bottom + windowSnapSize) && newTop >= (rect.bottom - windowSnapSize) ) { // Bottom
|
|
newTop = rect.bottom + borderSize * 2;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
return {left: newLeft, top: newTop, width: newWidth, height: newHeight};
|
|
}
|
|
if ( win._properties.allow_move ) {
|
|
Utils.$bind(win._$top, 'mousedown', function(ev, pos) {
|
|
onMouseDown(ev, 'move', win, pos);
|
|
}, true);
|
|
}
|
|
if ( win._properties.allow_resize ) {
|
|
Utils.$bind(win._$resize, 'mousedown', function(ev, pos) {
|
|
onMouseDown(ev, 'resize', win, pos);
|
|
});
|
|
}
|
|
}
|
|
function WindowManager(name, ref, args, metadata, settings) {
|
|
this._$notifications = null;
|
|
this._windows = [];
|
|
this._settings = OSjs.Core.getSettingsManager().instance(name, settings);
|
|
this._currentWin = null;
|
|
this._lastWin = null;
|
|
this._mouselock = true;
|
|
this._stylesheet = null;
|
|
this._sessionLoaded = false;
|
|
this._fullyLoaded = false;
|
|
this._scheme = null;
|
|
this.__name = (name || 'WindowManager');
|
|
this.__path = metadata.path;
|
|
this.__iter = metadata.iter;
|
|
Process.apply(this, [this.__name, args, metadata]);
|
|
_WM = (ref || this);
|
|
}
|
|
WindowManager.prototype = Object.create(Process.prototype);
|
|
WindowManager.prototype.destroy = function() {
|
|
var self = this;
|
|
this.destroyStylesheet();
|
|
Utils.$unbind(document, 'mouseout:windowmanager');
|
|
Utils.$unbind(document, 'mouseenter:windowmanager');
|
|
this._windows.forEach(function(win, i) {
|
|
if ( win ) {
|
|
win.destroy(true);
|
|
self._windows[i] = null;
|
|
}
|
|
});
|
|
if ( this._scheme ) {
|
|
this._scheme.destroy();
|
|
}
|
|
this._windows = [];
|
|
this._currentWin = null;
|
|
this._lastWin = null;
|
|
this._scheme = null;
|
|
_WM = null;
|
|
return Process.prototype.destroy.apply(this, []);
|
|
};
|
|
WindowManager.prototype.init = function(metadata, settings, scheme) {
|
|
this._scheme = scheme;
|
|
var self = this;
|
|
Utils.$bind(document, 'mouseout:windowmanager', function(ev) {
|
|
self._onMouseLeave(ev);
|
|
});
|
|
Utils.$bind(document, 'mouseenter:windowmanager', function(ev) {
|
|
self._onMouseLeave(ev);
|
|
});
|
|
};
|
|
WindowManager.prototype.setup = function(cb) {
|
|
};
|
|
WindowManager.prototype.getWindow = function(name) {
|
|
var result = null;
|
|
this._windows.every(function(w) {
|
|
if ( w && w._name === name ) {
|
|
result = w;
|
|
}
|
|
return w ? false : true;
|
|
});
|
|
return result;
|
|
};
|
|
WindowManager.prototype.addWindow = function(w, focus) {
|
|
if ( !(w instanceof Window) ) {
|
|
console.warn('WindowManager::addWindow()', 'Got', w);
|
|
throw new TypeError('given argument was not instance of Core.Window');
|
|
}
|
|
try {
|
|
w.init(this, w._app, w._scheme);
|
|
} catch ( e ) {
|
|
console.error('WindowManager::addWindow()', '=>', 'Window::init()', e, e.stack);
|
|
}
|
|
createWindowBehaviour(w, this);
|
|
this._windows.push(w);
|
|
w._inited();
|
|
if ( focus === true || (w instanceof OSjs.Core.DialogWindow) ) {
|
|
setTimeout(function() {
|
|
w._focus();
|
|
}, 10);
|
|
}
|
|
return w;
|
|
};
|
|
WindowManager.prototype.removeWindow = function(w) {
|
|
var self = this;
|
|
if ( !(w instanceof Window) ) {
|
|
console.warn('WindowManager::removeWindow()', 'Got', w);
|
|
throw new TypeError('given argument was not instance of Core.Window');
|
|
}
|
|
var result = false;
|
|
this._windows.every(function(win, i) {
|
|
if ( win && win._wid === w._wid ) {
|
|
self._windows[i] = null;
|
|
result = true;
|
|
}
|
|
return result ? false : true;
|
|
});
|
|
return result;
|
|
};
|
|
WindowManager.prototype.applySettings = function(settings, force, save, triggerWatch) {
|
|
settings = settings || {};
|
|
var result = force ? settings : Utils.mergeObject(this._settings.get(), settings);
|
|
this._settings.set(null, result, save, triggerWatch);
|
|
return true;
|
|
};
|
|
WindowManager.prototype.createStylesheet = function(styles, rawStyles) {
|
|
this.destroyStylesheet();
|
|
var innerHTML = [];
|
|
Object.keys(styles).forEach(function(key) {
|
|
var rules = [];
|
|
Object.keys(styles[key]).forEach(function(r) {
|
|
rules.push(Utils.format(' {0}: {1};', r, styles[key][r]));
|
|
});
|
|
rules = rules.join('\n');
|
|
innerHTML.push(Utils.format('{0} {\n{1}\n}', key, rules));
|
|
});
|
|
innerHTML = innerHTML.join('\n');
|
|
if ( rawStyles ) {
|
|
innerHTML += '\n' + rawStyles;
|
|
}
|
|
var style = document.createElement('style');
|
|
style.type = 'text/css';
|
|
style.id = 'WMGeneratedStyles';
|
|
style.innerHTML = innerHTML;
|
|
document.getElementsByTagName('head')[0].appendChild(style);
|
|
this._stylesheet = style;
|
|
};
|
|
WindowManager.prototype.destroyStylesheet = function() {
|
|
if ( this._stylesheet ) {
|
|
if ( this._stylesheet.parentNode ) {
|
|
this._stylesheet.parentNode.removeChild(this._stylesheet);
|
|
}
|
|
}
|
|
this._stylesheet = null;
|
|
};
|
|
WindowManager.prototype.onKeyDown = function(ev, win) {
|
|
};
|
|
WindowManager.prototype.onOrientationChange = function(ev, orientation) {
|
|
};
|
|
WindowManager.prototype.onSessionLoaded = function() {
|
|
if ( this._sessionLoaded ) {
|
|
return false;
|
|
}
|
|
this._sessionLoaded = true;
|
|
return true;
|
|
};
|
|
WindowManager.prototype.resize = function(ev, rect) {
|
|
};
|
|
WindowManager.prototype.notification = function() {
|
|
};
|
|
WindowManager.prototype.createNotificationIcon = function() {
|
|
};
|
|
WindowManager.prototype.removeNotificationIcon = function() {
|
|
};
|
|
WindowManager.prototype.eventWindow = function(ev, win) {
|
|
};
|
|
WindowManager.prototype.showSettings = function() {
|
|
};
|
|
WindowManager.prototype._onMouseEnter = function(ev) {
|
|
this._mouselock = true;
|
|
};
|
|
WindowManager.prototype._onMouseLeave = function(ev) {
|
|
var from = ev.relatedTarget || ev.toElement;
|
|
if ( !from || from.nodeName === 'HTML' ) {
|
|
this._mouselock = false;
|
|
} else {
|
|
this._mouselock = true;
|
|
}
|
|
};
|
|
WindowManager.prototype.getDefaultSetting = function() {
|
|
return null;
|
|
};
|
|
WindowManager.prototype.getPanel = function() {
|
|
return null;
|
|
};
|
|
WindowManager.prototype.getPanels = function() {
|
|
return [];
|
|
};
|
|
WindowManager.prototype.getStyleTheme = function(returnMetadata) {
|
|
return returnMetadata ? {} : 'default';
|
|
};
|
|
WindowManager.prototype.getSoundTheme = function() {
|
|
return 'default';
|
|
};
|
|
WindowManager.prototype.getSoundFilename = function(k) {
|
|
return null;
|
|
};
|
|
WindowManager.prototype.getIconTheme = function() {
|
|
return 'default';
|
|
};
|
|
WindowManager.prototype.getStyleThemes = function() {
|
|
return API.getConfig('Styles', []);
|
|
};
|
|
WindowManager.prototype.getSoundThemes = function() {
|
|
return API.getConfig('Sounds', []);
|
|
};
|
|
WindowManager.prototype.getIconThemes = function() {
|
|
return API.getConfig('Icons', []);
|
|
};
|
|
WindowManager.prototype.setSetting = function(k, v) {
|
|
return this._settings.set(k, v);
|
|
};
|
|
WindowManager.prototype.getWindowSpace = function() {
|
|
return Utils.getRect();
|
|
};
|
|
WindowManager.prototype.getWindowPosition = (function() {
|
|
var _LNEWX = 0;
|
|
var _LNEWY = 0;
|
|
return function() {
|
|
if ( _LNEWY >= (window.innerHeight - 100) ) {
|
|
_LNEWY = 0;
|
|
}
|
|
if ( _LNEWX >= (window.innerWidth - 100) ) {
|
|
_LNEWX = 0;
|
|
}
|
|
return {x: _LNEWX += 10, y: _LNEWY += 10};
|
|
};
|
|
})();
|
|
WindowManager.prototype.getSetting = function(k) {
|
|
return this._settings.get(k);
|
|
};
|
|
WindowManager.prototype.getSettings = function() {
|
|
return this._settings.get();
|
|
};
|
|
WindowManager.prototype.getWindows = function() {
|
|
return this._windows;
|
|
};
|
|
WindowManager.prototype.getCurrentWindow = function() {
|
|
return this._currentWin;
|
|
};
|
|
WindowManager.prototype.setCurrentWindow = function(w) {
|
|
this._currentWin = w || null;
|
|
};
|
|
WindowManager.prototype.getLastWindow = function() {
|
|
return this._lastWin;
|
|
};
|
|
WindowManager.prototype.setLastWindow = function(w) {
|
|
this._lastWin = w || null;
|
|
};
|
|
WindowManager.prototype.getMouseLocked = function() {
|
|
return this._mouselock;
|
|
};
|
|
OSjs.Core.WindowManager = Object.seal(WindowManager);
|
|
OSjs.Core.getWindowManager = function() {
|
|
return _WM;
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.Core.Process, OSjs.Core.Window);
|
|
|
|
(function(Utils, VFS, API) {
|
|
'use strict';
|
|
var PackageManager = (function() {
|
|
var blacklist = [];
|
|
var packages = {};
|
|
return Object.seal({
|
|
load: function(callback) {
|
|
var self = this;
|
|
callback = callback || {};
|
|
function loadMetadata(cb) {
|
|
self._loadMetadata(function(err) {
|
|
if ( err ) {
|
|
callback(err, false, PackageManager);
|
|
return;
|
|
}
|
|
var len = Object.keys(packages).length;
|
|
if ( len ) {
|
|
cb();
|
|
return;
|
|
}
|
|
callback(false, 'No packages found!', PackageManager);
|
|
});
|
|
}
|
|
loadMetadata(function() {
|
|
self._loadExtensions(function() {
|
|
callback(true, false, PackageManager);
|
|
});
|
|
});
|
|
},
|
|
_loadExtensions: function(callback) {
|
|
var preloads = [];
|
|
Object.keys(packages).forEach(function(k) {
|
|
var iter = packages[k];
|
|
if ( iter.type === 'extension' && iter.sources ) {
|
|
iter.sources.forEach(function(p) {
|
|
preloads.push(p);
|
|
});
|
|
}
|
|
});
|
|
if ( preloads.length ) {
|
|
Utils.preload(preloads, function(total, failed) {
|
|
callback();
|
|
});
|
|
} else {
|
|
callback();
|
|
}
|
|
},
|
|
_loadMetadata: function(callback) {
|
|
var rootURI = API.getBrowserPath().replace(/\/$/, '/packages/'); // FIXME
|
|
function checkEntry(key, iter, scope) {
|
|
iter = Utils.cloneObject(iter);
|
|
iter.type = iter.type || 'application';
|
|
if ( scope ) {
|
|
iter.scope = scope;
|
|
}
|
|
if ( iter.preload ) {
|
|
iter.preload.forEach(function(it) {
|
|
if ( it.src && !it.src.match(/^(\/)|(http)|(ftp)/) ) {
|
|
if ( iter.scope === 'user' ) {
|
|
it.src = Utils.pathJoin(iter.path, it.src);
|
|
} else {
|
|
it.src = Utils.pathJoin(rootURI, key, it.src);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return iter;
|
|
}
|
|
if ( API.isStandalone() || API.getConfig('PackageManager.UseStaticManifest') === true ) {
|
|
var uri = Utils.checkdir(API.getConfig('Connection.MetadataURI'));
|
|
Utils.preload([uri], function(total, failed) {
|
|
if ( failed.length ) {
|
|
callback('Failed to load package manifest', failed);
|
|
return;
|
|
}
|
|
packages = {};
|
|
var list = OSjs.Core.getMetadata();
|
|
Object.keys(list).forEach(function(name) {
|
|
var iter = list[name];
|
|
packages[iter.className] = checkEntry(name, iter);
|
|
});
|
|
callback();
|
|
});
|
|
return;
|
|
}
|
|
var paths = OSjs.Core.getSettingsManager().instance('PackageManager').get('PackagePaths', []);
|
|
API.call('packages', {command: 'list', args: {paths: paths}}, function(err, res) {
|
|
if ( res ) {
|
|
packages = {};
|
|
Object.keys(res).forEach(function(key) {
|
|
var iter = res[key];
|
|
if ( iter && !packages[iter.className] ) {
|
|
packages[iter.className] = checkEntry(key, iter);
|
|
}
|
|
});
|
|
}
|
|
callback();
|
|
});
|
|
},
|
|
generateUserMetadata: function(callback) {
|
|
var self = this;
|
|
var paths = OSjs.Core.getSettingsManager().instance('PackageManager').get('PackagePaths', []);
|
|
API.call('packages', {command: 'cache', args: {action: 'generate', scope: 'user', paths: paths}}, function() {
|
|
self._loadMetadata(callback);
|
|
});
|
|
},
|
|
_addPackages: function(result, scope) {
|
|
var keys = Object.keys(result);
|
|
if ( !keys.length ) {
|
|
return;
|
|
}
|
|
var currLocale = API.getLocale();
|
|
keys.forEach(function(i) {
|
|
var newIter = Utils.cloneObject(result[i]);
|
|
if ( typeof newIter !== 'object' ) {
|
|
return;
|
|
}
|
|
if ( typeof newIter.names !== 'undefined' && newIter.names[currLocale] ) {
|
|
newIter.name = newIter.names[currLocale];
|
|
}
|
|
if ( typeof newIter.descriptions !== 'undefined' && newIter.descriptions[currLocale] ) {
|
|
newIter.description = newIter.descriptions[currLocale];
|
|
}
|
|
if ( !newIter.description ) {
|
|
newIter.description = newIter.name;
|
|
}
|
|
newIter.scope = scope || 'system';
|
|
newIter.type = newIter.type || 'application';
|
|
packages[i] = newIter;
|
|
});
|
|
},
|
|
install: function(file, root, cb) {
|
|
var self = this;
|
|
var paths = OSjs.Core.getSettingsManager().instance('PackageManager').get('PackagePaths', []);
|
|
if ( typeof root !== 'string' ) {
|
|
root = paths[0];
|
|
}
|
|
var dest = Utils.pathJoin(root, file.filename.replace(/\.zip$/i, ''));
|
|
API.call('packages', {command: 'install', args: {zip: file.path, dest: dest, paths: paths}}, function(e, r) {
|
|
if ( e ) {
|
|
cb(e);
|
|
} else {
|
|
self.generateUserMetadata(cb);
|
|
}
|
|
});
|
|
},
|
|
uninstall: function(file, cb) {
|
|
var self = this;
|
|
API.call('packages', {command: 'uninstall', args: {path: file.path}}, function(e, r) {
|
|
if ( e ) {
|
|
cb(e);
|
|
} else {
|
|
self.generateUserMetadata(cb);
|
|
}
|
|
});
|
|
},
|
|
setBlacklist: function(list) {
|
|
blacklist = list || [];
|
|
},
|
|
getStorePackages: function(opts, callback) {
|
|
var sm = OSjs.Core.getSettingsManager();
|
|
var repos = sm.instance('PackageManager').get('Repositories', []);
|
|
var entries = [];
|
|
Utils.asyncs(repos, function(url, idx, next) {
|
|
API.curl({
|
|
url: url,
|
|
method: 'GET'
|
|
}, function(error, result) {
|
|
if ( !error && result.body ) {
|
|
var list = [];
|
|
if ( typeof result.body === 'string' ) {
|
|
try {
|
|
list = JSON.parse(result.body);
|
|
} catch ( e ) {}
|
|
}
|
|
entries = entries.concat(list.map(function(iter) {
|
|
iter._repository = url;
|
|
return iter;
|
|
}));
|
|
}
|
|
next();
|
|
});
|
|
}, function() {
|
|
callback(false, entries);
|
|
});
|
|
},
|
|
getPackage: function(name) {
|
|
if ( typeof packages[name] !== 'undefined' ) {
|
|
return Object.freeze(Utils.cloneObject(packages)[name]);
|
|
}
|
|
return false;
|
|
},
|
|
getPackages: function(filtered) {
|
|
var hidden = OSjs.Core.getSettingsManager().instance('PackageManager').get('Hidden', []);
|
|
var p = Utils.cloneObject(packages);
|
|
function allowed(i, iter) {
|
|
if ( blacklist.indexOf(i) >= 0 ) {
|
|
return false;
|
|
}
|
|
if ( iter && (iter.groups instanceof Array) ) {
|
|
if ( !API.checkPermission(iter.groups) ) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
if ( typeof filtered === 'undefined' || filtered === true ) {
|
|
var result = {};
|
|
Object.keys(p).forEach(function(name) {
|
|
var iter = p[name];
|
|
if ( !allowed(name, iter) ) {
|
|
return;
|
|
}
|
|
if ( iter && hidden.indexOf(name) < 0 ) {
|
|
result[name] = iter;
|
|
}
|
|
});
|
|
return Object.freeze(result);
|
|
}
|
|
return Object.freeze(p);
|
|
},
|
|
getPackagesByMime: function(mime) {
|
|
var list = [];
|
|
var p = Utils.cloneObject(packages);
|
|
Object.keys(p).forEach(function(i) {
|
|
if ( blacklist.indexOf(i) < 0 ) {
|
|
var a = p[i];
|
|
if ( a && a.mime ) {
|
|
if ( Utils.checkAcceptMime(mime, a.mime) ) {
|
|
list.push(i);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return list;
|
|
},
|
|
addDummyPackage: function(n, title, icon, fn) {
|
|
if ( packages[n] || OSjs.Applications[n] ) {
|
|
throw new Error('A package already exists with this name!');
|
|
}
|
|
if ( typeof fn !== 'function' ) {
|
|
throw new TypeError('You need to specify a function/callback!');
|
|
}
|
|
packages[n] = Object.seal({
|
|
type: 'application',
|
|
className: n,
|
|
description: title,
|
|
name: title,
|
|
icon: icon,
|
|
cateogry: 'other',
|
|
scope: 'system'
|
|
});
|
|
OSjs.Applications[n] = fn;
|
|
}
|
|
});
|
|
})();
|
|
OSjs.Core.getPackageManager = function() {
|
|
return PackageManager;
|
|
};
|
|
})(OSjs.Utils, OSjs.VFS, OSjs.API);
|
|
|
|
(function(Utils, VFS, API) {
|
|
'use strict';
|
|
var SettingsManager = {
|
|
storage: {},
|
|
defaults: {},
|
|
watches: []
|
|
};
|
|
SettingsManager.init = function(settings) {
|
|
this.storage = settings || {};
|
|
};
|
|
SettingsManager.get = function(pool, key) {
|
|
try {
|
|
if ( this.storage[pool] && Object.keys(this.storage[pool]).length ) {
|
|
return key ? this.storage[pool][key] : this.storage[pool];
|
|
}
|
|
return key ? this.defaults[pool][key] : this.defaults[pool];
|
|
} catch ( e ) {
|
|
console.warn('SettingsManager::get()', 'exception', e, e.stack);
|
|
}
|
|
return false;
|
|
};
|
|
SettingsManager.set = function(pool, key, value, save, triggerWatch) {
|
|
try {
|
|
if ( key ) {
|
|
if ( typeof this.storage[pool] === 'undefined' ) {
|
|
this.storage[pool] = {};
|
|
}
|
|
if ( (['number', 'string']).indexOf(typeof key) >= 0 ) {
|
|
this.storage[pool][key] = value;
|
|
} else {
|
|
console.warn('SettingsManager::set()', 'expects key to be a valid iter, not', key);
|
|
}
|
|
} else {
|
|
this.storage[pool] = value;
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('SettingsManager::set()', 'exception', e, e.stack);
|
|
}
|
|
if ( save ) {
|
|
this.save(pool, save);
|
|
}
|
|
if ( typeof triggerWatch === 'undefined' || triggerWatch === true ) {
|
|
this.changed(pool);
|
|
}
|
|
return true;
|
|
};
|
|
SettingsManager.save = function(pool, callback) {
|
|
if ( typeof callback !== 'function' ) {
|
|
callback = function() {};
|
|
}
|
|
var handler = OSjs.Core.getHandler();
|
|
handler.saveSettings(pool, this.storage, callback);
|
|
};
|
|
SettingsManager.defaults = function(pool, defaults) {
|
|
this.defaults[pool] = defaults;
|
|
};
|
|
SettingsManager.instance = function(pool, defaults) {
|
|
if ( !this.storage[pool] || (this.storage[pool] instanceof Array) ) {
|
|
this.storage[pool] = {};
|
|
}
|
|
var instance = new OSjs.Helpers.SettingsFragment(this.storage[pool], pool);
|
|
if ( arguments.length > 1 ) {
|
|
SettingsManager.defaults(pool, defaults);
|
|
instance.mergeDefaults(defaults);
|
|
}
|
|
return instance;
|
|
};
|
|
SettingsManager.unwatch = function(index) {
|
|
if ( typeof this.watches[index] !== 'undefined' ) {
|
|
delete this.watches[index];
|
|
}
|
|
};
|
|
SettingsManager.watch = function(pool, callback) {
|
|
if ( !this.storage[pool] ) {
|
|
return false;
|
|
}
|
|
var index = this.watches.push({
|
|
pool: pool,
|
|
callback: callback
|
|
});
|
|
return index - 1;
|
|
};
|
|
SettingsManager.changed = function(pool) {
|
|
var self = this;
|
|
this.watches.forEach(function(watch) {
|
|
if ( watch && watch.pool === pool ) {
|
|
watch.callback(self.storage[pool]);
|
|
}
|
|
});
|
|
return this;
|
|
};
|
|
SettingsManager.clear = function(pool, save) {
|
|
save = (typeof save === 'undefined') || (save === true);
|
|
this.set(pool, null, {}, save);
|
|
};
|
|
Object.seal(SettingsManager);
|
|
OSjs.Core.getSettingsManager = function() {
|
|
return SettingsManager;
|
|
};
|
|
})(OSjs.Utils, OSjs.VFS, OSjs.API);
|
|
|
|
(function(Utils, VFS, API) {
|
|
'use strict';
|
|
var DefaultModule = 'User';
|
|
function createMatch(name) {
|
|
return new RegExp('^' + name.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'));
|
|
}
|
|
var MountManager = (function() {
|
|
var _queue = [];
|
|
var _inited = false;
|
|
var _modules = {};
|
|
return Object.seal({
|
|
_create: function(params) {
|
|
var target = VFS.Transports[params.transport];
|
|
if ( target && typeof target.defaults === 'function' ) {
|
|
target.defaults(params);
|
|
}
|
|
function _checkReadOnly(name, params, args) {
|
|
if ( params.readOnly ) {
|
|
var restricted = ['upload', 'unlink', 'write', 'mkdir', 'move', 'trash', 'untrash', 'emptyTrash'];
|
|
if ( name === 'copy' ) {
|
|
var dest = MountManager.getModuleFromPath(args[1].path, false, true);
|
|
return dest.internal !== params.internal;
|
|
}
|
|
if ( restricted.indexOf(name) !== -1 ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
var mparams = (function() {
|
|
var o = {};
|
|
Object.keys(params).forEach(function(k) {
|
|
if ( typeof params[k] !== 'function' ) {
|
|
o[k] = params[k];
|
|
}
|
|
});
|
|
return Object.freeze(o);
|
|
})();
|
|
var cfg = Utils.argumentDefaults(params, {
|
|
request: function(name, args, callback, options) {
|
|
callback = callback || function() {
|
|
console.warn('NO CALLBACK FUNCTION WAS ASSIGNED IN VFS REQUEST');
|
|
};
|
|
if ( !target ) {
|
|
callback(API._('ERR_VFSMODULE_INVALID_TYPE_FMT', params.transport));
|
|
return;
|
|
}
|
|
if ( _checkReadOnly(name, params, args) ) {
|
|
callback(API._('ERR_VFSMODULE_READONLY'));
|
|
return;
|
|
}
|
|
var module = target.module || {};
|
|
if ( !module[name] ) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
return;
|
|
}
|
|
var fargs = args || [];
|
|
fargs.push(callback);
|
|
fargs.push(options);
|
|
fargs.push(mparams);
|
|
module[name].apply(module, fargs);
|
|
},
|
|
unmount: function(cb) {
|
|
(cb || function() {})(API._('ERR_VFS_UNAVAILABLE'), false);
|
|
},
|
|
mounted: function() {
|
|
return true;
|
|
},
|
|
enabled: function() {
|
|
return true;
|
|
}
|
|
});
|
|
return cfg;
|
|
},
|
|
_add: function(opts, emitEvent) {
|
|
if ( _inited ) {
|
|
_modules[opts.name] = Object.seal(opts);
|
|
if ( emitEvent ) {
|
|
API.message('vfs:mount', opts.name, {source: null});
|
|
}
|
|
} else {
|
|
_queue.push(arguments);
|
|
}
|
|
},
|
|
init: function(callback) {
|
|
if ( _inited ) {
|
|
callback();
|
|
return;
|
|
}
|
|
_inited = true;
|
|
_queue.forEach(function(i) {
|
|
var add = MountManager._create.apply(MountManager, i);
|
|
MountManager._add(add, false);
|
|
});
|
|
var config = API.getConfig('VFS.Mountpoints', {});
|
|
Object.keys(config).forEach(function(key) {
|
|
var iter = config[key];
|
|
if ( iter.enabled !== false ) {
|
|
var mp = MountManager._create({
|
|
readOnly: (typeof iter.readOnly === 'undefined') ? false : (iter.readOnly === true),
|
|
name: key,
|
|
transport: iter.transport || 'Internal',
|
|
description: iter.description || key,
|
|
icon: iter.icon || 'devices/harddrive.png',
|
|
root: key + ':///',
|
|
options: iter.options,
|
|
visible: iter.visible !== false,
|
|
internal: true,
|
|
searchable: true,
|
|
match: createMatch(key + '://')
|
|
});
|
|
MountManager._add(mp, false);
|
|
}
|
|
});
|
|
_queue = [];
|
|
callback();
|
|
},
|
|
restore: function(callback) {
|
|
var sm = OSjs.Core.getSettingsManager();
|
|
Utils.asyncs(sm.instance('VFS').get('mounts', []), function(iter, idx, next) {
|
|
try {
|
|
MountManager.add(iter, next);
|
|
} catch ( e ) {
|
|
console.warn('MountManager::restore()', e, e.stack);
|
|
next();
|
|
}
|
|
}, function() {
|
|
callback();
|
|
});
|
|
},
|
|
add: function(opts, cb) {
|
|
opts = Utils.argumentDefaults(opts, {
|
|
description: 'My VFS Module',
|
|
transport: 'Internal',
|
|
name: 'MyModule',
|
|
icon: 'places/server.png',
|
|
searchable: false,
|
|
visible: true,
|
|
readOnly: false
|
|
});
|
|
if ( _modules[opts.name] ) {
|
|
throw new Error(API._('ERR_VFSMODULE_ALREADY_MOUNTED_FMT', opts.name));
|
|
}
|
|
if ( opts.transport.toLowerCase() === 'owndrive' ) {
|
|
opts.transport = 'WebDAV';
|
|
}
|
|
var modulePath = opts.name.replace(/\s/g, '-').toLowerCase() + '://';
|
|
var moduleRoot = modulePath + '/';
|
|
var moduleMatch = createMatch(modulePath);
|
|
var moduleOptions = opts.options || {};
|
|
var module = (function createMountpointModule() {
|
|
var isMounted = true;
|
|
return MountManager._create({
|
|
readOnly: opts.readOnly,
|
|
transport: opts.transport,
|
|
name: opts.name,
|
|
description: opts.description,
|
|
visible: opts.visible,
|
|
dynamic: true,
|
|
unmount: function(cb) {
|
|
isMounted = false;
|
|
API.message('vfs:unmount', opts.name, {source: null});
|
|
(cb || function() {})(false, true);
|
|
},
|
|
mounted: function() {
|
|
return isMounted;
|
|
},
|
|
root: moduleRoot,
|
|
icon: opts.icon,
|
|
match: moduleMatch,
|
|
options: moduleOptions
|
|
});
|
|
})();
|
|
var validModule = (function() {
|
|
if ( Object.keys(VFS.Transports).indexOf(opts.transport) < 0 ) {
|
|
return 'No such transport \'' + opts.transport + '\'';
|
|
}
|
|
if ( opts.transport === 'WebDAV' && !moduleOptions.username ) {
|
|
return 'Connection requires username (authorization)';
|
|
}
|
|
return true;
|
|
})();
|
|
if ( validModule !== true ) {
|
|
throw new Error(API._('ERR_VFSMODULE_INVALID_CONFIG_FMT', validModule));
|
|
}
|
|
MountManager._add(module, true);
|
|
(cb || function() {})(false, true);
|
|
},
|
|
remove: function(moduleName, cb) {
|
|
if ( !_modules[moduleName] ) {
|
|
throw new Error(API._('ERR_VFSMODULE_NOT_MOUNTED_FMT', moduleName));
|
|
}
|
|
_modules[moduleName].unmount(function() {
|
|
delete _modules[moduleName];
|
|
cb.apply(MountManager, arguments);
|
|
});
|
|
},
|
|
isInternal: function isInternalModule(test) {
|
|
test = test || '';
|
|
var m = _modules;
|
|
var d = null;
|
|
if ( test !== null ) {
|
|
Object.keys(m).forEach(function(name) {
|
|
if ( d !== true ) {
|
|
var i = m[name];
|
|
if ( i.internal === true && i.match && test.match(i.match) ) {
|
|
d = true;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
return d;
|
|
},
|
|
isInternalEnabled: function(module) {
|
|
try {
|
|
if ( API.getConfig('VFS.Internal.' + module + '.enabled') === false ) {
|
|
return false;
|
|
}
|
|
} catch ( e ) {}
|
|
return true;
|
|
},
|
|
getModules: function(opts) {
|
|
opts = Utils.argumentDefaults(opts, {
|
|
visible: true,
|
|
special: false
|
|
});
|
|
var m = _modules;
|
|
var a = [];
|
|
Object.keys(m).forEach(function(name) {
|
|
var iter = m[name];
|
|
if ( !iter.enabled() || (!opts.special && iter.special) ) {
|
|
return;
|
|
}
|
|
if ( opts.visible && iter.visible === opts.visible ) {
|
|
a.push({
|
|
name: name,
|
|
module: iter
|
|
});
|
|
}
|
|
});
|
|
return a;
|
|
},
|
|
getModule: function(name) {
|
|
return _modules[name];
|
|
},
|
|
getModuleFromPath: function getModuleFromPath(test, retdef, retobj) {
|
|
retdef = typeof retdef === 'undefined' ? true : (retdef === true);
|
|
var d = null;
|
|
if ( typeof test === 'string' ) {
|
|
Object.keys(_modules).forEach(function(name) {
|
|
if ( d === null ) {
|
|
var i = _modules[name];
|
|
if ( i.enabled() === true && i.match && test.match(i.match) ) {
|
|
d = name;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
var moduleName = d || (retdef ? DefaultModule : null);
|
|
return retobj ? _modules[moduleName] : moduleName;
|
|
},
|
|
getRootFromPath: function getRootFromPath(path) {
|
|
return MountManager.getModuleFromPath(path, false, true).root;
|
|
},
|
|
getModuleProperty: function(module, property) {
|
|
if ( typeof module === 'string' ) {
|
|
module = _modules[module];
|
|
}
|
|
return module[property];
|
|
}
|
|
});
|
|
})();
|
|
OSjs.Core.getMountManager = function() {
|
|
return MountManager;
|
|
};
|
|
})(OSjs.Utils, OSjs.VFS, OSjs.API);
|
|
|
|
(function(Utils, VFS, API) {
|
|
'use strict';
|
|
function search(list, query) {
|
|
var result = [];
|
|
list.forEach(function(obj) {
|
|
var found = false;
|
|
obj.fields.forEach(function(s) {
|
|
if ( found ) {
|
|
return;
|
|
}
|
|
var qry = String(query).toLowerCase();
|
|
var str = String(s).toLowerCase();
|
|
if ( str.indexOf(qry) !== -1 ) {
|
|
result.push(obj.value);
|
|
found = true;
|
|
}
|
|
});
|
|
});
|
|
return result;
|
|
}
|
|
function SearchObject(obj) {
|
|
var self = this;
|
|
Object.keys(obj).forEach(function(k) {
|
|
self[k] = obj[k];
|
|
});
|
|
}
|
|
var ApplicationModule = (function() {
|
|
function query() {
|
|
var packages = OSjs.Core.getPackageManager().getPackages();
|
|
return Object.keys(packages).map(function(pn) {
|
|
var p = packages[pn];
|
|
return new SearchObject({
|
|
value: {
|
|
title: p.name,
|
|
description: p.description,
|
|
icon: API.getIcon(p.icon, '16x16', p),
|
|
launch: {application: pn, args: {}}
|
|
},
|
|
fields: [
|
|
p.className,
|
|
p.name,
|
|
p.description
|
|
]
|
|
});
|
|
});
|
|
}
|
|
return {
|
|
search: function(q, args, settings, cb) {
|
|
if ( settings.applications ) {
|
|
var results = search(query(), q);
|
|
if ( args.limit && results.length > args.dlimit ) {
|
|
results = results.splice(0, args.dlimit);
|
|
}
|
|
cb(false, results);
|
|
} else {
|
|
cb(false, []);
|
|
}
|
|
},
|
|
reindex: function(args, cb) {
|
|
cb(false, true);
|
|
},
|
|
destroy: function() {
|
|
}
|
|
};
|
|
})();
|
|
var FilesystemModule = {
|
|
search: function(q, args, settings, cb) {
|
|
if ( !settings.files || !settings.paths ) {
|
|
cb(false, []);
|
|
return;
|
|
}
|
|
var found = [];
|
|
Utils.asyncs(settings.paths, function(e, i, n) {
|
|
VFS.find(e, {query: q, limit: (args.limit ? args.dlimit : 0), recursive: args.recursive}, function(error, result) {
|
|
if ( error ) {
|
|
console.warn(error);
|
|
}
|
|
if ( result ) {
|
|
var list = result.map(function(iter) {
|
|
return {
|
|
title: iter.filename,
|
|
description: iter.path,
|
|
icon: API.getFileIcon(new VFS.File(iter)),
|
|
launch: {application: '', args: '', file: iter}
|
|
};
|
|
});
|
|
found = found.concat(list);
|
|
}
|
|
n();
|
|
});
|
|
}, function() {
|
|
cb(false, found);
|
|
});
|
|
},
|
|
reindex: function(args, cb) {
|
|
cb(false, true);
|
|
},
|
|
destroy: function() {
|
|
}
|
|
};
|
|
var SearchEngine = (function() {
|
|
var modules = [
|
|
ApplicationModule,
|
|
FilesystemModule
|
|
];
|
|
var settings = {};
|
|
var inited = false;
|
|
return Object.seal({
|
|
init: function(cb) {
|
|
if ( inited ) {
|
|
return;
|
|
}
|
|
var manager = OSjs.Core.getSettingsManager();
|
|
settings = manager.get('SearchEngine') || {};
|
|
inited = true;
|
|
cb();
|
|
},
|
|
destroy: function() {
|
|
modules.forEach(function(m) {
|
|
m.destroy();
|
|
});
|
|
modules = [];
|
|
settings = {};
|
|
},
|
|
search: function(q, args, cb) {
|
|
var result = [];
|
|
var errors = [];
|
|
args = Utils.argumentDefaults(args, {
|
|
recursive: false,
|
|
limit: 0,
|
|
dlimit: 0
|
|
});
|
|
if ( args.limit ) {
|
|
args.dlimit = args.limit;
|
|
}
|
|
Utils.asyncs(modules, function(module, index, next) {
|
|
if ( !args.limit || args.dlimit > 0 ) {
|
|
module.search(q, args, settings, function(err, res) {
|
|
if ( err ) {
|
|
errors.push(err);
|
|
} else {
|
|
args.dlimit -= res.length;
|
|
result = result.concat(res);
|
|
}
|
|
next();
|
|
});
|
|
} else {
|
|
cb(errors, result);
|
|
}
|
|
}, function() {
|
|
cb(errors, result);
|
|
});
|
|
},
|
|
reindex: function(args, cb) {
|
|
var errors = [];
|
|
Utils.asyncs(modules, function(module, index, next) {
|
|
module.reindex(args, function(err, res) {
|
|
if ( err ) {
|
|
errors.push(err);
|
|
}
|
|
next();
|
|
});
|
|
}, function() {
|
|
cb(errors, true);
|
|
});
|
|
},
|
|
configure: function(opts, save) {
|
|
}
|
|
});
|
|
})();
|
|
OSjs.Core.getSearchEngine = function() {
|
|
return SearchEngine;
|
|
};
|
|
})(OSjs.Utils, OSjs.VFS, OSjs.API);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
GUI.Helpers = GUI.Helpers || {};
|
|
GUI.Helpers.getWindowId = function getWindowId(el) {
|
|
while ( el.parentNode ) {
|
|
var attr = el.getAttribute('data-window-id');
|
|
if ( attr !== null ) {
|
|
return parseInt(attr, 10);
|
|
}
|
|
el = el.parentNode;
|
|
}
|
|
return null;
|
|
};
|
|
GUI.Helpers.getLabel = function getLabel(el) {
|
|
var label = el.getAttribute('data-label');
|
|
return label || '';
|
|
};
|
|
GUI.Helpers.getValueLabel = function getValueLabel(el, attr) {
|
|
var label = attr ? el.getAttribute('data-label') : null;
|
|
if ( el.childNodes.length && el.childNodes[0].nodeType === 3 && el.childNodes[0].nodeValue ) {
|
|
label = el.childNodes[0].nodeValue;
|
|
Utils.$empty(el);
|
|
}
|
|
return label || '';
|
|
};
|
|
GUI.Helpers.getViewNodeValue = function getViewNodeValue(el) {
|
|
var value = el.getAttribute('data-value');
|
|
if ( typeof value === 'string' && value.match(/^\[|\{/) ) {
|
|
try {
|
|
value = JSON.parse(value);
|
|
} catch ( e ) {
|
|
value = null;
|
|
}
|
|
}
|
|
return value;
|
|
};
|
|
GUI.Helpers.getIcon = function getIcon(el, win) {
|
|
var image = el.getAttribute('data-icon');
|
|
if ( image && image !== 'undefined') {
|
|
if ( image.match(/^stock:\/\//) ) {
|
|
image = image.replace('stock://', '');
|
|
var size = '16x16';
|
|
try {
|
|
var spl = image.split('/');
|
|
var tmp = spl.shift();
|
|
var siz = tmp.match(/^\d+x\d+/);
|
|
if ( siz ) {
|
|
size = siz[0];
|
|
image = spl.join('/');
|
|
}
|
|
image = API.getIcon(image, size);
|
|
} catch ( e ) {}
|
|
} else if ( image.match(/^app:\/\//) ) {
|
|
image = API.getApplicationResource(win._app, image.replace('app://', ''));
|
|
}
|
|
return image;
|
|
}
|
|
return null;
|
|
};
|
|
GUI.Helpers.getProperty = function getProperty(el, param, tagName) {
|
|
tagName = tagName || el.tagName.toLowerCase();
|
|
var isDataView = tagName.match(/^gui\-(tree|icon|list|file)\-view$/);
|
|
if ( param === 'value' && !isDataView) {
|
|
if ( (['gui-text', 'gui-password', 'gui-textarea', 'gui-slider', 'gui-select', 'gui-select-list']).indexOf(tagName) >= 0 ) {
|
|
return el.querySelector('input, textarea, select').value;
|
|
}
|
|
if ( (['gui-checkbox', 'gui-radio', 'gui-switch']).indexOf(tagName) >= 0 ) {
|
|
return !!el.querySelector('input').checked;
|
|
}
|
|
return null;
|
|
}
|
|
if ( (param === 'value' || param === 'selected') && isDataView ) {
|
|
return GUI.Elements[tagName].values(el);
|
|
}
|
|
return el.getAttribute('data-' + param);
|
|
};
|
|
GUI.Helpers.setProperty = function setProperty(el, param, value, tagName) {
|
|
tagName = tagName || el.tagName.toLowerCase();
|
|
function _setKnownAttribute(i, k, v, a) {
|
|
if ( v ) {
|
|
i.setAttribute(k, k);
|
|
} else {
|
|
i.removeAttribute(k);
|
|
}
|
|
if ( a ) {
|
|
el.setAttribute('aria-' + k, String(value === true));
|
|
}
|
|
}
|
|
function _setValueAttribute(i, k, v) {
|
|
if ( typeof v === 'object' ) {
|
|
try {
|
|
v = JSON.stringify(value);
|
|
} catch ( e ) {}
|
|
}
|
|
i.setAttribute(k, String(v));
|
|
}
|
|
var inner = el.children[0];
|
|
var accept = ['gui-slider', 'gui-text', 'gui-password', 'gui-textarea', 'gui-checkbox', 'gui-radio', 'gui-select', 'gui-select-list', 'gui-button'];
|
|
(function() {
|
|
var firstChild;
|
|
var params = {
|
|
readonly: function() {
|
|
_setKnownAttribute(firstChild, 'readonly', value, true);
|
|
},
|
|
disabled: function() {
|
|
_setKnownAttribute(firstChild, 'disabled', value, true);
|
|
},
|
|
value: function() {
|
|
if ( tagName === 'gui-radio' || tagName === 'gui-checkbox' ) {
|
|
_setKnownAttribute(firstChild, 'checked', value);
|
|
firstChild.checked = !!value;
|
|
}
|
|
firstChild.value = value;
|
|
},
|
|
label: function() {
|
|
el.appendChild(firstChild);
|
|
Utils.$remove(el.querySelector('label'));
|
|
GUI.Helpers.createInputLabel(el, tagName.replace(/^gui\-/, ''), firstChild, value);
|
|
}
|
|
};
|
|
if ( accept.indexOf(tagName) >= 0 ) {
|
|
firstChild = el.querySelector('textarea, input, select, button');
|
|
if ( firstChild ) {
|
|
if ( params[param] ) {
|
|
params[param]();
|
|
} else {
|
|
_setValueAttribute(firstChild, param, value || '');
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
accept = ['gui-image', 'gui-audio', 'gui-video'];
|
|
if ( (['src', 'controls', 'autoplay', 'alt']).indexOf(param) >= 0 && accept.indexOf(tagName) >= 0 ) {
|
|
inner[param] = value;
|
|
}
|
|
if ( (['_id', '_class', '_style']).indexOf(param) >= 0 ) {
|
|
inner.setAttribute(param.replace(/^_/, ''), value);
|
|
return;
|
|
}
|
|
if ( param !== 'value' ) {
|
|
_setValueAttribute(el, 'data-' + param, value);
|
|
}
|
|
};
|
|
GUI.Helpers.createInputLabel = function createInputLabel(el, type, input, label) {
|
|
label = label || GUI.Helpers.getLabel(el);
|
|
if ( label ) {
|
|
var lbl = document.createElement('label');
|
|
var span = document.createElement('span');
|
|
span.appendChild(document.createTextNode(label));
|
|
if ( type === 'checkbox' || type === 'radio' ) {
|
|
lbl.appendChild(input);
|
|
lbl.appendChild(span);
|
|
} else {
|
|
lbl.appendChild(span);
|
|
lbl.appendChild(input);
|
|
}
|
|
el.appendChild(lbl);
|
|
} else {
|
|
el.appendChild(input);
|
|
}
|
|
};
|
|
GUI.Helpers.createElement = function createElement(tagName, params, ignoreParams) {
|
|
ignoreParams = ignoreParams || [];
|
|
var el = document.createElement(tagName);
|
|
var classMap = {
|
|
textalign: function(v) {
|
|
Utils.$addClass(el, 'gui-align-' + v);
|
|
},
|
|
className: function(v) {
|
|
Utils.$addClass(el, v);
|
|
}
|
|
};
|
|
function getValue(k, value) {
|
|
if ( typeof value === 'boolean' ) {
|
|
value = value ? 'true' : 'false';
|
|
} else if ( typeof value === 'object' ) {
|
|
try {
|
|
value = JSON.stringify(value);
|
|
} catch ( e ) {}
|
|
}
|
|
return value;
|
|
}
|
|
if ( typeof params === 'object' ) {
|
|
Object.keys(params).forEach(function(k) {
|
|
if ( ignoreParams.indexOf(k) >= 0 ) {
|
|
return;
|
|
}
|
|
var value = params[k];
|
|
if ( typeof value !== 'undefined' && typeof value !== 'function' ) {
|
|
if ( classMap[k] ) {
|
|
classMap[k](value);
|
|
return;
|
|
}
|
|
var fvalue = getValue(k, value);
|
|
el.setAttribute('data-' + k, fvalue);
|
|
}
|
|
});
|
|
}
|
|
return el;
|
|
};
|
|
GUI.Helpers.setFlexbox = function setFlexbox(el, grow, shrink, basis, checkel) {
|
|
checkel = checkel || el;
|
|
(function() {
|
|
if ( typeof basis === 'undefined' || basis === null ) {
|
|
basis = checkel.getAttribute('data-basis') || 'auto';
|
|
}
|
|
})();
|
|
(function() {
|
|
if ( typeof grow === 'undefined' || grow === null ) {
|
|
grow = checkel.getAttribute('data-grow') || 0;
|
|
}
|
|
})();
|
|
(function() {
|
|
if ( typeof shrink === 'undefined' || shrink === null ) {
|
|
shrink = checkel.getAttribute('data-shrink') || 0;
|
|
}
|
|
})();
|
|
var flex = [grow, shrink];
|
|
if ( basis.length ) {
|
|
flex.push(basis);
|
|
}
|
|
var style = flex.join(' ');
|
|
el.style.WebkitBoxFlex = style;
|
|
el.style.MozBoxFlex = style;
|
|
el.style.WebkitFlex = style;
|
|
el.style.MozFlex = style;
|
|
el.style.MSFlex = style;
|
|
el.style.OFlex = style;
|
|
el.style.flex = style;
|
|
var align = el.getAttribute('data-align');
|
|
Utils.$removeClass(el, 'gui-flex-align-start');
|
|
Utils.$removeClass(el, 'gui-flex-align-end');
|
|
if ( align ) {
|
|
Utils.$addClass(el, 'gui-flex-align-' + align);
|
|
}
|
|
};
|
|
OSjs.GUI.Helpers.createDrag = function createDrag(el, onDown, onMove, onUp) {
|
|
onDown = onDown || function() {};
|
|
onMove = onMove || function() {};
|
|
onUp = onUp || function() {};
|
|
var startX, startY, currentX, currentY;
|
|
var dragging = false;
|
|
function _onMouseDown(ev, pos, touchDevice) {
|
|
ev.preventDefault();
|
|
startX = pos.x;
|
|
startY = pos.y;
|
|
onDown(ev, {x: startX, y: startY});
|
|
dragging = true;
|
|
Utils.$bind(window, 'mouseup:guidrag', _onMouseUp, false);
|
|
Utils.$bind(window, 'mousemove:guidrag', _onMouseMove, false);
|
|
}
|
|
function _onMouseMove(ev, pos, touchDevice) {
|
|
ev.preventDefault();
|
|
if ( dragging ) {
|
|
currentX = pos.x;
|
|
currentY = pos.y;
|
|
var diffX = currentX - startX;
|
|
var diffY = currentY - startY;
|
|
onMove(ev, {x: diffX, y: diffY}, {x: currentX, y: currentY});
|
|
}
|
|
}
|
|
function _onMouseUp(ev, pos, touchDevice) {
|
|
onUp(ev, {x: currentX, y: currentY});
|
|
dragging = false;
|
|
Utils.$unbind(window, 'mouseup:guidrag');
|
|
Utils.$unbind(window, 'mousemove:guidrag');
|
|
}
|
|
Utils.$bind(el, 'mousedown', _onMouseDown, false);
|
|
};
|
|
GUI.Helpers.getNextElement = function getNextElement(prev, current, root) {
|
|
function getElements() {
|
|
var ignore_roles = ['menu', 'menuitem', 'grid', 'gridcell', 'listitem'];
|
|
var list = [];
|
|
root.querySelectorAll('.gui-element').forEach(function(e) {
|
|
if ( Utils.$hasClass(e, 'gui-focus-element') || ignore_roles.indexOf(e.getAttribute('role')) >= 0 || e.getAttribute('data-disabled') === 'true' ) {
|
|
return;
|
|
}
|
|
if ( e.offsetParent ) {
|
|
list.push(e);
|
|
}
|
|
});
|
|
return list;
|
|
}
|
|
function getCurrentIndex(els, m) {
|
|
var found = -1;
|
|
if ( m ) {
|
|
els.every(function(e, idx) {
|
|
if ( e === m ) {
|
|
found = idx;
|
|
}
|
|
return found === -1;
|
|
});
|
|
}
|
|
return found;
|
|
}
|
|
function getCurrentParent(els, m) {
|
|
if ( m ) {
|
|
var cur = m;
|
|
while ( cur.parentNode ) {
|
|
if ( Utils.$hasClass(cur, 'gui-element') ) {
|
|
return cur;
|
|
}
|
|
cur = cur.parentNode;
|
|
}
|
|
return null;
|
|
}
|
|
return els[0];
|
|
}
|
|
function getNextIndex(els, p, i) {
|
|
if ( prev ) {
|
|
i = (i <= 0) ? (els.length) - 1 : (i - 1);
|
|
} else {
|
|
i = (i >= (els.length - 1)) ? 0 : (i + 1);
|
|
}
|
|
return i;
|
|
}
|
|
function getNext(els, i) {
|
|
var next = els[i];
|
|
if ( next.tagName.match(/^GUI\-(BUTTON|TEXT|PASSWORD|SWITCH|CHECKBOX|RADIO|SELECT)/) ) {
|
|
next = next.querySelectorAll('input, textarea, button, select')[0];
|
|
}
|
|
if ( next.tagName === 'GUI-FILE-VIEW' ) {
|
|
next = next.children[0];
|
|
}
|
|
return next;
|
|
}
|
|
if ( root ) {
|
|
var elements = getElements();
|
|
if ( elements.length ) {
|
|
var currentParent = getCurrentParent(elements, current);
|
|
var currentIndex = getCurrentIndex(elements, currentParent);
|
|
if ( currentIndex >= 0 ) {
|
|
var nextIndex = getNextIndex(elements, currentParent, currentIndex);
|
|
return getNext(elements, nextIndex);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
GUI.Helpers.createDraggable = function createDraggable(el, args) {
|
|
args = OSjs.Utils.argumentDefaults(args, {
|
|
type : null,
|
|
effect : 'move',
|
|
data : null,
|
|
mime : 'application/json',
|
|
dragImage : null,
|
|
onStart : function() {
|
|
return true;
|
|
},
|
|
onEnd : function() {
|
|
return true;
|
|
}
|
|
});
|
|
if ( OSjs.Utils.isIE() ) {
|
|
args.mime = 'text';
|
|
}
|
|
function _toString(mime) {
|
|
return JSON.stringify({
|
|
type: args.type,
|
|
effect: args.effect,
|
|
data: args.data,
|
|
mime: args.mime
|
|
});
|
|
}
|
|
function _dragStart(ev) {
|
|
try {
|
|
ev.dataTransfer.effectAllowed = args.effect;
|
|
if ( args.dragImage && (typeof args.dragImage === 'function') ) {
|
|
if ( ev.dataTransfer.setDragImage ) {
|
|
var dragImage = args.dragImage(ev, el);
|
|
if ( dragImage ) {
|
|
var dragEl = dragImage.element;
|
|
var dragPos = dragImage.offset;
|
|
document.body.appendChild(dragEl);
|
|
ev.dataTransfer.setDragImage(dragEl, dragPos.x, dragPos.y);
|
|
}
|
|
}
|
|
}
|
|
ev.dataTransfer.setData(args.mime, _toString(args.mime));
|
|
} catch ( e ) {
|
|
console.warn('Failed to dragstart: ' + e);
|
|
console.warn(e.stack);
|
|
}
|
|
}
|
|
el.setAttribute('draggable', 'true');
|
|
el.setAttribute('aria-grabbed', 'false');
|
|
Utils.$bind(el, 'dragstart', function(ev) {
|
|
this.setAttribute('aria-grabbed', 'true');
|
|
this.style.opacity = '0.4';
|
|
if ( ev.dataTransfer ) {
|
|
_dragStart(ev);
|
|
}
|
|
return args.onStart(ev, this, args);
|
|
}, false);
|
|
Utils.$bind(el, 'dragend', function(ev) {
|
|
this.setAttribute('aria-grabbed', 'false');
|
|
this.style.opacity = '1.0';
|
|
return args.onEnd(ev, this, args);
|
|
}, false);
|
|
};
|
|
GUI.Helpers.createDroppable = function createDroppable(el, args) {
|
|
args = OSjs.Utils.argumentDefaults(args, {
|
|
accept : null,
|
|
effect : 'move',
|
|
mime : 'application/json',
|
|
files : true,
|
|
onFilesDropped : function() {
|
|
return true;
|
|
},
|
|
onItemDropped : function() {
|
|
return true;
|
|
},
|
|
onEnter : function() {
|
|
return true;
|
|
},
|
|
onOver : function() {
|
|
return true;
|
|
},
|
|
onLeave : function() {
|
|
return true;
|
|
},
|
|
onDrop : function() {
|
|
return true;
|
|
}
|
|
});
|
|
if ( OSjs.Utils.isIE() ) {
|
|
args.mime = 'text';
|
|
}
|
|
function getParent(start, matcher) {
|
|
if ( start === matcher ) {
|
|
return true;
|
|
}
|
|
var i = 10;
|
|
while ( start && i > 0 ) {
|
|
if ( start === matcher ) {
|
|
return true;
|
|
}
|
|
start = start.parentNode;
|
|
i--;
|
|
}
|
|
return false;
|
|
}
|
|
function _onDrop(ev, el) {
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
args.onDrop(ev, el);
|
|
if ( !ev.dataTransfer ) {
|
|
return true;
|
|
}
|
|
if ( args.files ) {
|
|
var files = ev.dataTransfer.files;
|
|
if ( files && files.length ) {
|
|
return args.onFilesDropped(ev, el, files, args);
|
|
}
|
|
}
|
|
var data;
|
|
try {
|
|
data = ev.dataTransfer.getData(args.mime);
|
|
} catch ( e ) {
|
|
console.warn('Failed to drop: ' + e);
|
|
}
|
|
if ( data ) {
|
|
var item = JSON.parse(data);
|
|
if ( args.accept === null || args.accept === item.type ) {
|
|
return args.onItemDropped(ev, el, item, args);
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
el.setAttribute('aria-dropeffect', args.effect);
|
|
Utils.$bind(el, 'drop', function(ev) {
|
|
return _onDrop(ev, this);
|
|
}, false);
|
|
Utils.$bind(el, 'dragenter', function(ev) {
|
|
return args.onEnter.call(this, ev, this, args);
|
|
}, false);
|
|
Utils.$bind(el, 'dragover', function(ev) {
|
|
ev.preventDefault();
|
|
if ( !getParent(ev.target, el) ) {
|
|
return false;
|
|
}
|
|
ev.stopPropagation();
|
|
ev.dataTransfer.dropEffect = args.effect;
|
|
return args.onOver.call(this, ev, this, args);
|
|
}, false);
|
|
Utils.$bind(el, 'dragleave', function(ev) {
|
|
return args.onLeave.call(this, ev, this, args);
|
|
}, false);
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function parseDynamic(scheme, node, win, args) {
|
|
args = args || {};
|
|
var translator = args._ || API._;
|
|
node.querySelectorAll('*[data-label]').forEach(function(el) {
|
|
var label = translator(el.getAttribute('data-label'));
|
|
el.setAttribute('data-label', label);
|
|
});
|
|
node.querySelectorAll('gui-label, gui-button, gui-list-view-column, gui-select-option, gui-select-list-option').forEach(function(el) {
|
|
if ( !el.children.length && !el.getAttribute('data-no-translate') ) {
|
|
var lbl = GUI.Helpers.getValueLabel(el);
|
|
el.appendChild(document.createTextNode(translator(lbl)));
|
|
}
|
|
});
|
|
node.querySelectorAll('gui-button').forEach(function(el) {
|
|
var label = GUI.Helpers.getValueLabel(el);
|
|
if ( label ) {
|
|
el.appendChild(document.createTextNode(API._(label)));
|
|
}
|
|
});
|
|
node.querySelectorAll('*[data-icon]').forEach(function(el) {
|
|
var image = GUI.Helpers.getIcon(el, win);
|
|
el.setAttribute('data-icon', image);
|
|
});
|
|
node.querySelectorAll('*[data-src]').forEach(function(el) {
|
|
var old = el.getAttribute('data-src') || '';
|
|
if ( win._app && old.match(/^app:\/\//) ) {
|
|
var source = API.getApplicationResource(win._app, old.replace('app://', ''));
|
|
el.setAttribute('data-src', source);
|
|
}
|
|
});
|
|
}
|
|
function addChildren(frag, root, before) {
|
|
if ( frag ) {
|
|
var children = frag.children;
|
|
var i = 0;
|
|
while ( children.length && i < 10000 ) {
|
|
if ( before ) {
|
|
root.parentNode.insertBefore(children[0], root);
|
|
} else {
|
|
root.appendChild(children[0]);
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
}
|
|
function resolveFragments(scheme, node) {
|
|
function _resolve() {
|
|
var nodes = node.querySelectorAll('gui-fragment');
|
|
if ( nodes.length ) {
|
|
nodes.forEach(function(el) {
|
|
var id = el.getAttribute('data-fragment-id');
|
|
if ( id ) {
|
|
var frag = scheme.getFragment(id, 'application-fragment');
|
|
if ( frag ) {
|
|
addChildren(frag.cloneNode(true), el.parentNode);
|
|
} else {
|
|
console.warn('Fragment', id, 'not found');
|
|
}
|
|
}
|
|
Utils.$remove(el); // Or else we'll never get out of the loop!
|
|
});
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
if ( scheme ) {
|
|
var resolving = true;
|
|
while ( resolving ) {
|
|
resolving = _resolve();
|
|
}
|
|
}
|
|
}
|
|
function removeSelfClosingTags(str) {
|
|
var split = (str || '').split('/>');
|
|
var newhtml = '';
|
|
for (var i = 0; i < split.length - 1;i++) {
|
|
var edsplit = split[i].split('<');
|
|
newhtml += split[i] + '></' + edsplit[edsplit.length - 1].split(' ')[0] + '>';
|
|
}
|
|
return newhtml + split[split.length - 1];
|
|
}
|
|
function cleanScheme(html) {
|
|
return Utils.cleanHTML(removeSelfClosingTags(html));
|
|
}
|
|
function resolveExternalFragments(root, html, cb) {
|
|
var doc = document.createElement('div');
|
|
doc.innerHTML = html;
|
|
var nodes = doc.querySelectorAll('gui-fragment[data-fragment-external]');
|
|
Utils.asyncs(nodes.map(function(el) {
|
|
return {
|
|
element: el,
|
|
uri: el.getAttribute('data-fragment-external')
|
|
};
|
|
}), function(iter, index, next) {
|
|
var uri = iter.uri.replace(/^\//, '');
|
|
if ( uri.length < 3 ) {
|
|
console.warn('resolveExternalFragments()', 'invalid', iter);
|
|
return next();
|
|
}
|
|
Utils.ajax({
|
|
url: Utils.pathJoin(root, uri),
|
|
onsuccess: function(h) {
|
|
var tmp = document.createElement('div');
|
|
tmp.innerHTML = cleanScheme(h);
|
|
addChildren(tmp, iter.element, iter.element);
|
|
tmp = next();
|
|
},
|
|
onerror: function() {
|
|
next();
|
|
}
|
|
});
|
|
}, function() {
|
|
cb(doc.innerHTML);
|
|
doc = null;
|
|
nodes = null;
|
|
});
|
|
}
|
|
function UIScheme(url) {
|
|
this.url = url;
|
|
this.scheme = null;
|
|
this.triggers = {render: []};
|
|
}
|
|
UIScheme.prototype.destroy = function() {
|
|
Utils.$empty(this.scheme);
|
|
this.scheme = null;
|
|
this.triggers = {};
|
|
};
|
|
UIScheme.prototype.on = function(f, fn) {
|
|
this.triggers[f].push(fn);
|
|
};
|
|
UIScheme.prototype._trigger = function(f, args) {
|
|
args = args || [];
|
|
var self = this;
|
|
if ( this.triggers[f] ) {
|
|
this.triggers[f].forEach(function(fn) {
|
|
fn.apply(self, args);
|
|
});
|
|
}
|
|
};
|
|
UIScheme.prototype._load = function(html) {
|
|
var doc = document.createDocumentFragment();
|
|
var wrapper = document.createElement('div');
|
|
wrapper.innerHTML = html;
|
|
doc.appendChild(wrapper);
|
|
this.scheme = doc.cloneNode(true);
|
|
wrapper = null;
|
|
doc = null;
|
|
};
|
|
UIScheme.prototype.loadString = function(html, cb) {
|
|
this._load(cleanScheme(html));
|
|
if ( cb ) {
|
|
cb(false, this.scheme);
|
|
}
|
|
};
|
|
UIScheme.prototype.load = function(cb, cbxhr) {
|
|
cbxhr = cbxhr || function() {};
|
|
var self = this;
|
|
var src = this.url;
|
|
if ( src.substr(0, 1) !== '/' && !src.match(/^(https?|ftp)/) ) {
|
|
src = window.location.pathname + src;
|
|
}
|
|
var root = Utils.dirname(src);
|
|
Utils.ajax({
|
|
url: src,
|
|
onsuccess: function(html) {
|
|
html = cleanScheme(html);
|
|
resolveExternalFragments(root, html, function(result) {
|
|
cbxhr(false, result);
|
|
self._load(result);
|
|
cb(false, self.scheme);
|
|
});
|
|
},
|
|
onerror: function() {
|
|
cb('Failed to fetch scheme');
|
|
cbxhr(true);
|
|
}
|
|
});
|
|
};
|
|
UIScheme.prototype.getFragment = function(id, type) {
|
|
var content = null;
|
|
if ( id ) {
|
|
if ( type ) {
|
|
content = this.scheme.querySelector(type + '[data-id="' + id + '"]');
|
|
} else {
|
|
content = this.scheme.querySelector('application-window[data-id="' + id + '"]') ||
|
|
this.scheme.querySelector('application-fragment[data-id="' + id + '"]');
|
|
}
|
|
}
|
|
return content;
|
|
};
|
|
UIScheme.prototype.parse = function(id, type, win, onparse, args) {
|
|
var content = this.getFragment(id, type);
|
|
if ( !content ) {
|
|
console.error('UIScheme::parse()', 'No fragment found', id + '@' + type);
|
|
return null;
|
|
}
|
|
type = type || content.tagName.toLowerCase();
|
|
if ( content ) {
|
|
var node = content.cloneNode(true);
|
|
UIScheme.parseNode(this, win, node, type, args, onparse, id);
|
|
return node;
|
|
}
|
|
return null;
|
|
};
|
|
UIScheme.prototype.render = function(win, id, root, type, onparse, args) {
|
|
root = root || win._getRoot();
|
|
if ( root instanceof GUI.Element ) {
|
|
root = root.$element;
|
|
}
|
|
function setWindowProperties(frag) {
|
|
if ( frag ) {
|
|
var width = parseInt(frag.getAttribute('data-width'), 10) || 0;
|
|
var height = parseInt(frag.getAttribute('data-height'), 10) || 0;
|
|
var allow_maximize = frag.getAttribute('data-allow_maximize');
|
|
var allow_minimize = frag.getAttribute('data-allow_minimize');
|
|
var allow_close = frag.getAttribute('data-allow_close');
|
|
var allow_resize = frag.getAttribute('data-allow_resize');
|
|
if ( (!isNaN(width) && width > 0) || (!isNaN(height) && height > 0) ) {
|
|
win._resize(width, height);
|
|
}
|
|
win._setProperty('allow_maximize', allow_maximize);
|
|
win._setProperty('allow_minimize', allow_minimize);
|
|
win._setProperty('allow_close', allow_close);
|
|
win._setProperty('allow_resize', allow_resize);
|
|
}
|
|
}
|
|
var content = this.parse(id, type, win, onparse, args);
|
|
addChildren(content, root);
|
|
root.querySelectorAll('application-fragment').forEach(function(e) {
|
|
Utils.$remove(e);
|
|
});
|
|
if ( !win._restored ) {
|
|
setWindowProperties(this.getFragment(id));
|
|
}
|
|
this._trigger('render', [root]);
|
|
};
|
|
UIScheme.prototype.create = function(win, tagName, params, parentNode, applyArgs) {
|
|
tagName = tagName || '';
|
|
params = params || {};
|
|
parentNode = parentNode || win._getRoot();
|
|
if ( parentNode instanceof GUI.Element ) {
|
|
parentNode = parentNode.$element;
|
|
}
|
|
var el;
|
|
if ( GUI.Elements[tagName] && GUI.Elements[tagName].create ) {
|
|
el = GUI.Elements[tagName].create(params);
|
|
} else {
|
|
el = GUI.Helpers.createElement(tagName, params);
|
|
}
|
|
parentNode.appendChild(el);
|
|
GUI.Elements[tagName].build(el, applyArgs, win);
|
|
return this.get(el);
|
|
};
|
|
UIScheme.prototype.find = function(win, id, root) {
|
|
root = this._findRoot(win, root);
|
|
var res = this._findDOM(win, id, root);
|
|
return this.get(res.el, res.q);
|
|
};
|
|
UIScheme.prototype.findByQuery = function(win, query, root, all) {
|
|
root = this._findRoot(win, root);
|
|
var el;
|
|
var self = this;
|
|
if ( all ) {
|
|
el = root.querySelectorAll(query).map(function(e) {
|
|
return self.get(e, query);
|
|
});
|
|
}
|
|
el = root.querySelector(query);
|
|
return this.get(el, query);
|
|
};
|
|
UIScheme.prototype.findDOM = function(win, id, root) {
|
|
root = this._findRoot(win, root);
|
|
return this._findDOM(win, id, root).el;
|
|
};
|
|
UIScheme.prototype._findRoot = function(win, root) {
|
|
if ( !(win instanceof OSjs.Core.Window) ) {
|
|
throw new Error('UIScheme::_findDOM() expects a instance of Window');
|
|
}
|
|
return root || win._getRoot();
|
|
};
|
|
UIScheme.prototype._findDOM = function(win, id, root) {
|
|
var q = '[data-id="' + id + '"]';
|
|
return {
|
|
q: q,
|
|
el: root.querySelector(q)
|
|
};
|
|
};
|
|
UIScheme.prototype.get = function(el, q) {
|
|
return UIScheme.getElementInstance(el, q);
|
|
};
|
|
UIScheme.prototype.getHTML = function() {
|
|
return this.scheme.firstChild.innerHTML;
|
|
};
|
|
UIScheme.parseNode = function(scheme, win, node, type, args, onparse, id) {
|
|
onparse = onparse || function() {};
|
|
args = args || {};
|
|
type = type || 'snipplet';
|
|
if ( args.resolve !== false ) {
|
|
resolveFragments(scheme, node);
|
|
}
|
|
node.querySelectorAll('*').forEach(function(el) {
|
|
var lcase = el.tagName.toLowerCase();
|
|
if ( lcase.match(/^gui\-/) && !lcase.match(/(\-container|\-(h|v)box|\-columns?|\-rows?|(status|tool)bar|(button|menu)\-bar|bar\-entry)$/) ) {
|
|
Utils.$addClass(el, 'gui-element');
|
|
}
|
|
});
|
|
parseDynamic(scheme, node, win, args);
|
|
onparse(node);
|
|
Object.keys(GUI.Elements).forEach(function(key) {
|
|
node.querySelectorAll(key).forEach(function(pel) {
|
|
if ( pel._wasParsed ) {
|
|
return;
|
|
}
|
|
try {
|
|
GUI.Elements[key].build(pel);
|
|
} catch ( e ) {
|
|
console.warn('parseNode()', id, type, win, 'exception');
|
|
console.warn(e, e.stack);
|
|
}
|
|
pel._wasParsed = true;
|
|
});
|
|
});
|
|
};
|
|
UIScheme.getElementInstance = function(el, q) {
|
|
if ( el ) {
|
|
var tagName = el.tagName.toLowerCase();
|
|
if ( tagName.match(/^gui\-(list|tree|icon|file)\-view$/) || tagName.match(/^gui\-select/) ) {
|
|
return new GUI.ElementDataView(el, q);
|
|
}
|
|
}
|
|
return new GUI.Element(el, q);
|
|
};
|
|
var DialogScheme = (function() {
|
|
var dialogScheme;
|
|
return {
|
|
get: function() {
|
|
return dialogScheme;
|
|
},
|
|
destroy: function() {
|
|
if ( dialogScheme ) {
|
|
dialogScheme.destroy();
|
|
}
|
|
dialogScheme = null;
|
|
},
|
|
init: function(cb) {
|
|
if ( dialogScheme ) {
|
|
cb();
|
|
return;
|
|
}
|
|
if ( OSjs.API.isStandalone() ) {
|
|
var html = OSjs.STANDALONE.SCHEMES['/dialogs.html'];
|
|
dialogScheme = new OSjs.GUI.Scheme();
|
|
dialogScheme.loadString(html);
|
|
cb();
|
|
return;
|
|
}
|
|
var root = API.getConfig('Connection.RootURI');
|
|
var url = root + 'client/dialogs.html';
|
|
if ( API.getConfig('Connection.Dist') === 'dist' ) {
|
|
url = root + 'dialogs.html';
|
|
}
|
|
dialogScheme = GUI.createScheme(url);
|
|
dialogScheme.load(function(error) {
|
|
if ( error ) {
|
|
console.warn('OSjs.GUI.initDialogScheme()', 'error loading dialog schemes', error);
|
|
}
|
|
cb();
|
|
});
|
|
}
|
|
};
|
|
})();
|
|
function createScheme(url) {
|
|
return new UIScheme(url);
|
|
}
|
|
GUI.Scheme = Object.seal(UIScheme);
|
|
GUI.DialogScheme = DialogScheme;
|
|
GUI.createScheme = createScheme;
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function getFocusElement(inst) {
|
|
var tagMap = {
|
|
'gui-switch': 'button',
|
|
'gui-list-view': 'textarea',
|
|
'gui-tree-view': 'textarea',
|
|
'gui-icon-view': 'textarea',
|
|
'gui-input-modal': 'button'
|
|
};
|
|
if ( tagMap[inst.tagName] ) {
|
|
return inst.$element.querySelector(tagMap[inst.tagName]);
|
|
}
|
|
return inst.$element.firstChild || inst.$element;
|
|
}
|
|
function UIElement(el, q) {
|
|
this.$element = el || null;
|
|
this.tagName = el ? el.tagName.toLowerCase() : null;
|
|
this.oldDisplay = null;
|
|
if ( !el ) {
|
|
console.error('UIElement() was constructed without a DOM element', q);
|
|
}
|
|
}
|
|
UIElement.prototype.remove = function() {
|
|
this.$element = Utils.$remove(this.$element);
|
|
};
|
|
UIElement.prototype.empty = function() {
|
|
Utils.$empty(this.$element);
|
|
return this;
|
|
};
|
|
UIElement.prototype.blur = function() {
|
|
if ( this.$element ) {
|
|
var firstChild = getFocusElement(this);
|
|
if ( firstChild ) {
|
|
firstChild.blur();
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.focus = function() {
|
|
if ( this.$element ) {
|
|
var firstChild = getFocusElement(this);
|
|
if ( firstChild ) {
|
|
firstChild.focus();
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.show = function() {
|
|
if ( this.$element && !this.$element.offsetParent ) {
|
|
if ( GUI.Elements[this.tagName] && GUI.Elements[this.tagName].show ) {
|
|
GUI.Elements[this.tagName].show.apply(this, arguments);
|
|
} else {
|
|
if ( this.$element ) {
|
|
this.$element.style.display = this.oldDisplay || '';
|
|
}
|
|
}
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.hide = function() {
|
|
if ( this.$element && this.$element.offsetParent ) {
|
|
if ( !this.oldDisplay ) {
|
|
this.oldDisplay = this.$element.style.display;
|
|
}
|
|
this.$element.style.display = 'none';
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.on = function(evName, callback, args) {
|
|
if ( GUI.Elements[this.tagName] && GUI.Elements[this.tagName].bind ) {
|
|
GUI.Elements[this.tagName].bind(this.$element, evName, callback, args);
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.son = function(evName, thisArg, callback, args) {
|
|
return this.on(evName, function() {
|
|
var args = Array.prototype.slice.call(arguments);
|
|
args.unshift(this);
|
|
callback.apply(thisArg, args);
|
|
}, args);
|
|
};
|
|
UIElement.prototype.set = function(param, value, arg, arg2) {
|
|
if ( this.$element ) {
|
|
if ( GUI.Elements[this.tagName] && GUI.Elements[this.tagName].set ) {
|
|
if ( GUI.Elements[this.tagName].set(this.$element, param, value, arg, arg2) === true ) {
|
|
return this;
|
|
}
|
|
}
|
|
GUI.Helpers.setProperty(this.$element, param, value, arg, arg2);
|
|
}
|
|
return this;
|
|
};
|
|
UIElement.prototype.get = function() {
|
|
if ( this.$element ) {
|
|
if ( GUI.Elements[this.tagName] && GUI.Elements[this.tagName].get ) {
|
|
var args = ([this.$element]).concat(Array.prototype.slice.call(arguments));
|
|
return GUI.Elements[this.tagName].get.apply(this, args);
|
|
} else {
|
|
return GUI.Helpers.getProperty(this.$element, arguments[0]);
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
UIElement.prototype.fn = function(name, args, thisArg) {
|
|
args = args || [];
|
|
thisArg = thisArg || this;
|
|
if ( this.$element ) {
|
|
return GUI.Elements[this.tagName][name].apply(thisArg, args);
|
|
}
|
|
return null;
|
|
};
|
|
UIElement.prototype.append = function(el) {
|
|
if ( el instanceof UIElement ) {
|
|
el = el.$element;
|
|
} else if ( typeof el === 'string' || typeof el === 'number' ) {
|
|
el = document.createTextNode(String(el));
|
|
}
|
|
var outer = document.createElement('div');
|
|
outer.appendChild(el);
|
|
this._append(outer);
|
|
outer = null;
|
|
return this;
|
|
};
|
|
UIElement.prototype.appendHTML = function(html, scheme, win, args) {
|
|
var el = document.createElement('div');
|
|
el.innerHTML = html;
|
|
return this._append(el, scheme, win, args);
|
|
};
|
|
UIElement.prototype._append = function(el, scheme, win, args) {
|
|
if ( el instanceof Element ) {
|
|
GUI.Scheme.parseNode(scheme, win, el, null, args);
|
|
}
|
|
while ( el.childNodes.length ) {
|
|
this.$element.appendChild(el.childNodes[0]);
|
|
}
|
|
el = null;
|
|
return this;
|
|
};
|
|
UIElement.prototype.querySelector = function(q, rui) {
|
|
var el = this.$element.querySelector(q);
|
|
if ( rui ) {
|
|
return GUI.Scheme.getElementInstance(el, q);
|
|
}
|
|
return el;
|
|
};
|
|
UIElement.prototype.querySelectorAll = function(q, rui) {
|
|
var el = this.$element.querySelectorAll(q);
|
|
if ( rui ) {
|
|
el = el.map(function(i) {
|
|
return GUI.Scheme.getElementInstance(i, q);
|
|
});
|
|
}
|
|
return el;
|
|
};
|
|
UIElement.prototype.css = function(k, v) {
|
|
return Utils.$css(this.$element, k, v);
|
|
};
|
|
UIElement.prototype.position = function() {
|
|
return Utils.$position(this.$element);
|
|
};
|
|
UIElement.prototype._call = function(method, args) {
|
|
if ( GUI.Elements[this.tagName] && GUI.Elements[this.tagName].call ) {
|
|
var cargs = ([this.$element, method, args]);//.concat(args);
|
|
return GUI.Elements[this.tagName].call.apply(this, cargs);
|
|
}
|
|
return null;//this;
|
|
};
|
|
function UIElementDataView() {
|
|
UIElement.apply(this, arguments);
|
|
}
|
|
UIElementDataView.prototype = Object.create(UIElement.prototype);
|
|
UIElementDataView.constructor = UIElement;
|
|
UIElementDataView.prototype.clear = function() {
|
|
return this._call('clear', []);
|
|
};
|
|
UIElementDataView.prototype.add = function(props) {
|
|
return this._call('add', [props]);
|
|
};
|
|
UIElementDataView.prototype.patch = function(props) {
|
|
return this._call('patch', [props]);
|
|
};
|
|
UIElementDataView.prototype.remove = function(id, key) {
|
|
return this._call('remove', [id, key]);
|
|
};
|
|
GUI.Element = Object.seal(UIElement);
|
|
GUI.ElementDataView = Object.seal(UIElementDataView);
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
var _classMap = { // Defaults to (foo-bar)-entry
|
|
'gui-list-view': 'gui-list-view-row'
|
|
};
|
|
function getEntryTagName(type) {
|
|
if ( typeof type !== 'string' ) {
|
|
type = type.tagName.toLowerCase();
|
|
}
|
|
var className = _classMap[type];
|
|
if ( !className ) {
|
|
className = type + '-entry';
|
|
}
|
|
return className;
|
|
}
|
|
function getEntryFromEvent(ev) {
|
|
var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target);
|
|
var tn = t.tagName.toLowerCase();
|
|
if ( tn.match(/(view|textarea|body)$/) ) {
|
|
return null;
|
|
} else if ( tn === 'gui-list-view-column' ) {
|
|
return t.parentNode;
|
|
}
|
|
return t;
|
|
}
|
|
function handleItemSelection(ev, item, idx, className, selected, root, multipleSelect) {
|
|
root = root || item.parentNode;
|
|
if ( idx === -1 ) {
|
|
root.querySelectorAll(getEntryTagName(root)).forEach(function(e) {
|
|
Utils.$removeClass(e, 'gui-active');
|
|
});
|
|
selected = [];
|
|
} else {
|
|
if ( !multipleSelect || !ev.shiftKey ) {
|
|
root.querySelectorAll(className).forEach(function(i) {
|
|
Utils.$removeClass(i, 'gui-active');
|
|
});
|
|
selected = [];
|
|
}
|
|
var findex = selected.indexOf(idx);
|
|
if ( findex >= 0 ) {
|
|
selected.splice(findex, 1);
|
|
Utils.$removeClass(item, 'gui-active');
|
|
} else {
|
|
selected.push(idx);
|
|
Utils.$addClass(item, 'gui-active');
|
|
}
|
|
}
|
|
selected.sort(function(a, b) {
|
|
return a - b;
|
|
});
|
|
return selected;
|
|
}
|
|
function getSelected(el) {
|
|
return GUI.Elements[el.tagName.toLowerCase()].values(el);
|
|
}
|
|
function handleKeyPress(el, ev) {
|
|
var map = {};
|
|
var key = ev.keyCode;
|
|
var type = el.tagName.toLowerCase();
|
|
var className = getEntryTagName(type);
|
|
var root = el.querySelector(type + '-body');
|
|
var entries = root.querySelectorAll(className);
|
|
var count = entries.length;
|
|
if ( !count ) {
|
|
return;
|
|
}
|
|
if ( key === Utils.Keys.ENTER ) {
|
|
el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
|
|
return;
|
|
}
|
|
map[Utils.Keys.C] = function(ev) {
|
|
if ( ev.ctrlKey ) {
|
|
var selected = getSelected(el);
|
|
if ( selected && selected.length ) {
|
|
var data = [];
|
|
selected.forEach(function(s) {
|
|
if ( s && s.data ) {
|
|
data.push(new VFS.File(s.data.path, s.data.mime));
|
|
}
|
|
});
|
|
API.setClipboard(data);
|
|
}
|
|
}
|
|
};
|
|
var selected = el._selected.concat() || [];
|
|
var first = selected.length ? selected[0] : 0;
|
|
var last = selected.length > 1 ? selected[selected.length - 1] : first;
|
|
var current = 0;
|
|
function select() {
|
|
var item = entries[current];
|
|
if ( item ) {
|
|
el._selected = handleItemSelection(ev, item, current, className, selected, root, ev.shiftKey);
|
|
GUI.Elements._dataview.scrollIntoView(el, item);
|
|
}
|
|
}
|
|
function getRowSize() {
|
|
var d = 0;
|
|
var lastTop = -1;
|
|
entries.forEach(function(e) {
|
|
if ( lastTop === -1 ) {
|
|
lastTop = e.offsetTop;
|
|
}
|
|
if ( lastTop !== e.offsetTop ) {
|
|
return false;
|
|
}
|
|
lastTop = e.offsetTop;
|
|
d++;
|
|
return true;
|
|
});
|
|
return d;
|
|
}
|
|
function handleKey() {
|
|
function next() {
|
|
current = Math.min(last + 1, count);
|
|
select();
|
|
}
|
|
function prev() {
|
|
current = Math.max(0, first - 1);
|
|
select();
|
|
}
|
|
if ( type === 'gui-tree-view' || type === 'gui-list-view' ) {
|
|
map[Utils.Keys.UP] = prev;
|
|
map[Utils.Keys.DOWN] = next;
|
|
} else {
|
|
map[Utils.Keys.UP] = function() {
|
|
current = Math.max(0, first - getRowSize());
|
|
select();
|
|
};
|
|
map[Utils.Keys.DOWN] = function() {
|
|
current = Math.max(last, last + getRowSize());
|
|
select();
|
|
};
|
|
map[Utils.Keys.LEFT] = prev;
|
|
map[Utils.Keys.RIGHT] = next;
|
|
}
|
|
if ( map[key] ) {
|
|
map[key](ev);
|
|
}
|
|
}
|
|
handleKey();
|
|
}
|
|
function getValueParameter(r) {
|
|
var value = r.getAttribute('data-value');
|
|
try {
|
|
return JSON.parse(value);
|
|
} catch ( e ) {}
|
|
return value;
|
|
}
|
|
function matchValueByKey(r, val, key, idx) {
|
|
var value = r.getAttribute('data-value');
|
|
if ( !key && (val === idx || val === value) ) {
|
|
return r;
|
|
} else {
|
|
try {
|
|
var json = JSON.parse(value);
|
|
if ( typeof json[key] === 'object' ? json[key] === val : String(json[key]) === String(val) ) {
|
|
return r;
|
|
}
|
|
} catch ( e ) {}
|
|
}
|
|
return false;
|
|
}
|
|
GUI.Elements._dataview = {
|
|
clear: function(el, body) {
|
|
body = body || el;
|
|
el.querySelectorAll(getEntryTagName(el)).forEach(function(row) {
|
|
Utils.$unbind(row);
|
|
});
|
|
Utils.$empty(body);
|
|
body.scrollTop = 0;
|
|
el._selected = [];
|
|
},
|
|
add: function(el, args, oncreate) {
|
|
var entries = args[0];
|
|
if ( !(entries instanceof Array) ) {
|
|
entries = [entries];
|
|
}
|
|
entries.forEach(oncreate);
|
|
return this;
|
|
},
|
|
patch: function(el, args, className, body, oncreate, oninit) {
|
|
var self = this;
|
|
var entries = args[0];
|
|
var single = false;
|
|
if ( !(entries instanceof Array) ) {
|
|
entries = [entries];
|
|
single = true;
|
|
}
|
|
var inView = {};
|
|
body.querySelectorAll(className).forEach(function(row) {
|
|
var id = row.getAttribute('data-id');
|
|
if ( id !== null ) {
|
|
inView[id] = row;
|
|
}
|
|
});
|
|
entries.forEach(function(entry) {
|
|
var insertBefore;
|
|
if ( typeof entry.id !== 'undefined' && entry.id !== null ) {
|
|
if ( inView[entry.id] ) {
|
|
insertBefore = inView[entry.id];
|
|
delete inView[entry.id];
|
|
}
|
|
var row = oncreate(entry);
|
|
if ( row ) {
|
|
if ( insertBefore ) {
|
|
if ( Utils.$hasClass(insertBefore, 'gui-active') ) {
|
|
Utils.$addClass(row, 'gui-active');
|
|
}
|
|
body.insertBefore(row, insertBefore);
|
|
self.remove(el, null, className, insertBefore);
|
|
} else {
|
|
body.appendChild(row);
|
|
}
|
|
oninit(el, row);
|
|
}
|
|
}
|
|
});
|
|
if ( !single ) {
|
|
Object.keys(inView).forEach(function(k) {
|
|
self.remove(el, null, className, inView[k]);
|
|
});
|
|
}
|
|
inView = {};
|
|
this.updateActiveSelection(el, className);
|
|
return this;
|
|
},
|
|
remove: function(el, args, className, target, parentEl) {
|
|
function remove(cel) {
|
|
Utils.$remove(cel);
|
|
}
|
|
parentEl = parentEl || el;
|
|
if ( target ) {
|
|
remove(target);
|
|
return;
|
|
}
|
|
if ( typeof args[1] === 'undefined' && typeof args[0] === 'number' ) {
|
|
remove(parentEl.querySelectorAll(className)[args[0]]);
|
|
} else {
|
|
var findId = args[0];
|
|
var findKey = args[1] || 'id';
|
|
var q = 'data-' + findKey + '="' + findId + '"';
|
|
parentEl.querySelectorAll(className + '[' + q + ']').forEach(remove);
|
|
}
|
|
this.updateActiveSelection(el, className);
|
|
return this;
|
|
},
|
|
updateActiveSelection: function(el, className) {
|
|
var active = [];
|
|
el.querySelectorAll(className + '.gui-active').forEach(function(cel) {
|
|
active.push(Utils.$index(cel));
|
|
});
|
|
el._active = active;
|
|
},
|
|
scrollIntoView: function(el, element) {
|
|
var pos = Utils.$position(element, el);
|
|
var marginTop = 0;
|
|
if ( el.tagName.toLowerCase() === 'gui-list-view' ) {
|
|
var header = el.querySelector('gui-list-view-head');
|
|
if ( header ) {
|
|
marginTop = header.offsetHeight;
|
|
}
|
|
}
|
|
var scrollSpace = (el.scrollTop + el.offsetHeight) - marginTop;
|
|
var scrollTop = el.scrollTop + marginTop;
|
|
var elTop = pos.top - marginTop;
|
|
if ( pos !== null && (elTop > scrollSpace || elTop < scrollTop) ) {
|
|
el.scrollTop = elTop;
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
bindEntryEvents: function(el, row, className) {
|
|
function createDraggable() {
|
|
var value = row.getAttribute('data-value');
|
|
if ( value !== null ) {
|
|
try {
|
|
value = JSON.parse(value);
|
|
} catch ( e ) {}
|
|
}
|
|
var source = row.getAttribute('data-draggable-source');
|
|
if ( source === null ) {
|
|
source = GUI.Helpers.getWindowId(el);
|
|
if ( source !== null ) {
|
|
source = {wid: source};
|
|
}
|
|
}
|
|
GUI.Helpers.createDraggable(row, {
|
|
type : el.getAttribute('data-draggable-type') || row.getAttribute('data-draggable-type'),
|
|
source : source,
|
|
data : value
|
|
});
|
|
var tooltip = row.getAttribute('data-tooltip');
|
|
if ( tooltip && !row.getAttribute('title') ) {
|
|
row.setAttribute('title', tooltip);
|
|
}
|
|
}
|
|
el.dispatchEvent(new CustomEvent('_render', {detail: {
|
|
element: row,
|
|
data: GUI.Helpers.getViewNodeValue(row)
|
|
}}));
|
|
if ( el.getAttribute('data-draggable') === 'true' ) {
|
|
createDraggable();
|
|
}
|
|
},
|
|
getSelected: function(el, entries) {
|
|
var selected = [];
|
|
entries.forEach(function(iter, idx) {
|
|
if ( Utils.$hasClass(iter, 'gui-active') ) {
|
|
selected.push({
|
|
index: idx,
|
|
data: GUI.Helpers.getViewNodeValue(iter)
|
|
});
|
|
}
|
|
});
|
|
return selected;
|
|
},
|
|
getEntry: function(el, entries, val, key, asValue) {
|
|
if ( val ) {
|
|
var result = null;
|
|
entries.forEach(function(r, idx) {
|
|
if ( !result && matchValueByKey(r, val, key, idx) ) {
|
|
result = r;
|
|
}
|
|
});
|
|
return (asValue && result) ? getValueParameter(result) : result;
|
|
}
|
|
return !asValue ? entries : (entries || []).map(function(iter) {
|
|
return getValueParameter(iter);
|
|
});
|
|
},
|
|
setSelected: function(el, body, entries, val, key, opts) {
|
|
var self = this;
|
|
var select = [];
|
|
var scrollIntoView = false;
|
|
if ( typeof opts === 'object' ) {
|
|
scrollIntoView = opts.scroll === true;
|
|
}
|
|
function sel(r, idx) {
|
|
select.push(idx);
|
|
Utils.$addClass(r, 'gui-active');
|
|
if ( scrollIntoView ) {
|
|
self.scrollIntoView(el, r);
|
|
}
|
|
}
|
|
entries.forEach(function(r, idx) {
|
|
Utils.$removeClass(r, 'gui-active');
|
|
if ( matchValueByKey(r, val, key, idx) ) {
|
|
sel(r, idx);
|
|
}
|
|
});
|
|
el._selected = select;
|
|
},
|
|
build: function(el, applyArgs) {
|
|
el._selected = [];
|
|
el.scrollTop = 0;
|
|
Utils.$addClass(el, 'gui-data-view');
|
|
var singleClick = el.getAttribute('data-single-click') === 'true';
|
|
var multipleSelect = el.getAttribute('data-multiple');
|
|
multipleSelect = multipleSelect === null || multipleSelect === 'true';
|
|
function select(ev) {
|
|
ev.stopPropagation();
|
|
API.blurMenu();
|
|
var row = getEntryFromEvent(ev);
|
|
var className = row ? row.tagName.toLowerCase() : null;
|
|
if ( className === 'gui-tree-view-expander' ) {
|
|
OSjs.GUI.Elements[el.tagName.toLowerCase()].call(el, 'expand', {ev: ev, entry: row.parentNode});
|
|
return;
|
|
}
|
|
var idx = Utils.$index(row);
|
|
el._selected = handleItemSelection(ev, row, idx, className, el._selected, el, multipleSelect);
|
|
el.dispatchEvent(new CustomEvent('_select', {detail: {entries: getSelected(el)}}));
|
|
}
|
|
function activate(ev) {
|
|
ev.stopPropagation();
|
|
API.blurMenu();
|
|
if ( singleClick ) {
|
|
select(ev);
|
|
}
|
|
el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: getSelected(el)}}));
|
|
}
|
|
function context(ev) {
|
|
select(ev);
|
|
el.dispatchEvent(new CustomEvent('_contextmenu', {detail: {entries: getSelected(el), x: ev.clientX, y: ev.clientY}}));
|
|
}
|
|
if ( !el.querySelector('textarea.gui-focus-element') && !el.getAttribute('no-selection') ) {
|
|
var underlay = document.createElement('textarea');
|
|
underlay.setAttribute('aria-label', '');
|
|
underlay.setAttribute('aria-hidden', 'true');
|
|
underlay.setAttribute('readonly', 'true');
|
|
underlay.className = 'gui-focus-element';
|
|
Utils.$bind(underlay, 'focus', function(ev) {
|
|
ev.preventDefault();
|
|
Utils.$addClass(el, 'gui-element-focused');
|
|
});
|
|
Utils.$bind(underlay, 'blur', function(ev) {
|
|
ev.preventDefault();
|
|
Utils.$removeClass(el, 'gui-element-focused');
|
|
});
|
|
Utils.$bind(underlay, 'keydown', function(ev) {
|
|
ev.preventDefault();
|
|
handleKeyPress(el, ev);
|
|
});
|
|
Utils.$bind(underlay, 'keypress', function(ev) {
|
|
ev.preventDefault();
|
|
});
|
|
if ( singleClick ) {
|
|
Utils.$bind(el, 'click', activate, true);
|
|
} else {
|
|
Utils.$bind(el, 'click', select, true);
|
|
Utils.$bind(el, 'dblclick', activate, true);
|
|
}
|
|
Utils.$bind(el, 'contextmenu', function(ev) {
|
|
ev.preventDefault();
|
|
context(ev);
|
|
return false;
|
|
}, true);
|
|
this.bind(el, 'select', function(ev) {
|
|
if ( Utils.$hasClass(el, 'gui-element-focused') ) {
|
|
return;
|
|
}
|
|
var oldTop = el.scrollTop;
|
|
underlay.focus();
|
|
el.scrollTop = oldTop;
|
|
setTimeout(function() {
|
|
el.scrollTop = oldTop;
|
|
}, 2);
|
|
}, true);
|
|
el.appendChild(underlay);
|
|
}
|
|
},
|
|
focus: function(el) {
|
|
try {
|
|
var underlay = el.querySelector('.gui-focus-element');
|
|
underlay.focus();
|
|
} catch ( e ) {
|
|
console.warn(e, e.stack);
|
|
}
|
|
},
|
|
blur: function(el) {
|
|
try {
|
|
var underlay = el.querySelector('.gui-focus-element');
|
|
underlay.blur();
|
|
} catch ( e ) {
|
|
console.warn(e, e.stack);
|
|
}
|
|
},
|
|
bind: function(el, evName, callback, params) {
|
|
if ( (['activate', 'select', 'expand', 'contextmenu', 'render', 'drop']).indexOf(evName) !== -1 ) {
|
|
evName = '_' + evName;
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
GUI.Elements['gui-color-box'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('div');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
set: function(el, param, value) {
|
|
if ( param === 'value' ) {
|
|
el.firstChild.style.backgroundColor = value;
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var inner = document.createElement('div');
|
|
el.appendChild(inner);
|
|
}
|
|
};
|
|
GUI.Elements['gui-color-swatch'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('canvas');
|
|
if ( evName === 'select' || evName === 'change' ) {
|
|
evName = '_change';
|
|
}
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var cv = document.createElement('canvas');
|
|
cv.width = 100;
|
|
cv.height = 100;
|
|
var ctx = cv.getContext('2d');
|
|
var gradient = ctx.createLinearGradient(0, 0, ctx.canvas.width, 0);
|
|
function getColor(ev) {
|
|
var pos = OSjs.Utils.$position(cv);
|
|
var cx = typeof ev.offsetX === 'undefined' ? (ev.clientX - pos.left) : ev.offsetX;
|
|
var cy = typeof ev.offsetY === 'undefined' ? (ev.clientY - pos.top) : ev.offsetY;
|
|
if ( isNaN(cx) || isNaN(cy) ) {
|
|
return null;
|
|
}
|
|
var data = ctx.getImageData(cx, cy, 1, 1).data;
|
|
return {
|
|
r: data[0],
|
|
g: data[1],
|
|
b: data[2],
|
|
hex: Utils.convertToHEX(data[0], data[1], data[2])
|
|
};
|
|
}
|
|
gradient.addColorStop(0, 'rgb(255, 0, 0)');
|
|
gradient.addColorStop(0.15, 'rgb(255, 0, 255)');
|
|
gradient.addColorStop(0.33, 'rgb(0, 0, 255)');
|
|
gradient.addColorStop(0.49, 'rgb(0, 255, 255)');
|
|
gradient.addColorStop(0.67, 'rgb(0, 255, 0)');
|
|
gradient.addColorStop(0.84, 'rgb(255, 255, 0)');
|
|
gradient.addColorStop(1, 'rgb(255, 0, 0)');
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
gradient = ctx.createLinearGradient(0, 0, 0, ctx.canvas.height);
|
|
gradient.addColorStop(0, 'rgba(255, 255, 255, 1)');
|
|
gradient.addColorStop(0.5, 'rgba(255, 255, 255, 0)');
|
|
gradient.addColorStop(0.5, 'rgba(0, 0, 0, 0)');
|
|
gradient.addColorStop(1, 'rgba(0, 0, 0, 1)');
|
|
ctx.fillStyle = gradient;
|
|
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
|
|
Utils.$bind(cv, 'click', function(ev) {
|
|
var c = getColor(ev);
|
|
if ( c ) {
|
|
cv.dispatchEvent(new CustomEvent('_change', {detail: c}));
|
|
}
|
|
}, false);
|
|
el.appendChild(cv);
|
|
}
|
|
};
|
|
GUI.Elements['gui-iframe'] = (function() {
|
|
var tagName = 'iframe';
|
|
if ( (['nw', 'electron', 'x11']).indexOf(API.getConfig('Connection.Type')) >= 0 ) {
|
|
tagName = 'webview';
|
|
}
|
|
return {
|
|
set: function(el, key, val) {
|
|
if ( key === 'src' ) {
|
|
el.querySelector(tagName).src = val;
|
|
}
|
|
},
|
|
build: function(el) {
|
|
var src = el.getAttribute('data-src') || 'about:blank';
|
|
var iframe = document.createElement(tagName);
|
|
iframe.src = src;
|
|
iframe.setAttribute('border', 0);
|
|
el.appendChild(iframe);
|
|
}
|
|
};
|
|
})();
|
|
GUI.Elements['gui-progress-bar'] = {
|
|
set: function(el, param, value) {
|
|
el.setAttribute('data-' + param, value);
|
|
if ( param === 'progress' || param === 'value' ) {
|
|
value = parseInt(value, 10);
|
|
value = Math.max(0, Math.min(100, value));
|
|
el.setAttribute('aria-label', String(value));
|
|
el.setAttribute('aria-valuenow', String(value));
|
|
el.querySelector('div').style.width = value.toString() + '%';
|
|
el.querySelector('span').innerHTML = value + '%';
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var p = (el.getAttribute('data-progress') || 0);
|
|
p = Math.max(0, Math.min(100, p));
|
|
var percentage = p.toString() + '%';
|
|
var progress = document.createElement('div');
|
|
progress.style.width = percentage;
|
|
var span = document.createElement('span');
|
|
span.appendChild(document.createTextNode(percentage));
|
|
el.setAttribute('role', 'progressbar');
|
|
el.setAttribute('aria-valuemin', 0);
|
|
el.setAttribute('aria-valuemax', 100);
|
|
el.setAttribute('aria-label', 0);
|
|
el.setAttribute('aria-valuenow', 0);
|
|
el.appendChild(progress);
|
|
el.appendChild(span);
|
|
}
|
|
};
|
|
GUI.Elements['gui-statusbar'] = {
|
|
set: function(el, param, value) {
|
|
if ( param === 'label' || param === 'value' ) {
|
|
var span = el.getElementsByTagName('gui-statusbar-label')[0];
|
|
if ( span ) {
|
|
Utils.$empty(span);
|
|
span.innerHTML = value;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var span = document.createElement('gui-statusbar-label');
|
|
var lbl = el.getAttribute('data-label') || el.getAttribute('data-value');
|
|
if ( !lbl ) {
|
|
lbl = (function() {
|
|
var textNodes = [];
|
|
var node, value;
|
|
for ( var i = 0; i < el.childNodes.length; i++ ) {
|
|
node = el.childNodes[i];
|
|
if ( node.nodeType === Node.TEXT_NODE ) {
|
|
value = node.nodeValue.replace(/\s+/g, '').replace(/^\s+/g, '');
|
|
if ( value.length > 0 ) {
|
|
textNodes.push(value);
|
|
}
|
|
el.removeChild(node);
|
|
i++;
|
|
}
|
|
}
|
|
return textNodes.join(' ');
|
|
})();
|
|
}
|
|
span.innerHTML = lbl;
|
|
el.setAttribute('role', 'log');
|
|
el.appendChild(span);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
var lastMenu;
|
|
function blurMenu(ev) {
|
|
if ( lastMenu ) {
|
|
lastMenu(ev);
|
|
}
|
|
lastMenu = null;
|
|
API.triggerHook('onBlurMenu');
|
|
}
|
|
function bindIngores(el) {
|
|
Utils.$bind(el, 'touchstart', function(ev) {
|
|
ev.preventDefault();
|
|
}, true);
|
|
}
|
|
function clickWrapper(ev, pos, onclick, original) {
|
|
var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target);
|
|
ev.preventDefault();
|
|
if ( t && t.tagName === 'GUI-MENU-ENTRY' ) {
|
|
var isExpander = !!t.querySelector('gui-menu');
|
|
var hasInput = t.querySelector('input');
|
|
if ( hasInput || isExpander ) {
|
|
ev.stopPropagation();
|
|
}
|
|
onclick(ev, pos, t, original);
|
|
}
|
|
}
|
|
function onEntryClick(ev, pos, target, original) {
|
|
var isExpander = !!target.querySelector('gui-menu');
|
|
if ( !isExpander ) {
|
|
blurMenu(ev);
|
|
var hasInput = target.querySelector('input');
|
|
if ( hasInput ) {
|
|
if ( !Utils.isIE() && window.MouseEvent ) {
|
|
hasInput.dispatchEvent(new MouseEvent('click', {
|
|
clientX: pos.x,
|
|
clientY: pos.y
|
|
}));
|
|
} else {
|
|
var nev = document.createEvent('MouseEvent');
|
|
nev.initMouseEvent('click', true, true, window, 0, 0, 0, pos.x, pos.y, ev.ctrlKey, ev.altKey, ev.shiftKey, ev.metaKey, ev.button, hasInput);
|
|
}
|
|
}
|
|
var dispatcher = (original || target).querySelector('label');
|
|
dispatcher.dispatchEvent(new CustomEvent('_select', {detail: getSelectionEventAttribs(target, true)}));
|
|
}
|
|
}
|
|
function clampSubmenuPositions(r) {
|
|
function _clamp(rm) {
|
|
rm.querySelectorAll('gui-menu-entry').forEach(function(srm) {
|
|
var sm = srm.querySelector('gui-menu');
|
|
if ( sm ) {
|
|
sm.style.left = String(-parseInt(sm.offsetWidth, 10)) + 'px';
|
|
_clamp(sm);
|
|
}
|
|
});
|
|
}
|
|
var pos = Utils.$position(r);
|
|
if ( pos && (window.innerWidth - pos.right) < r.offsetWidth ) {
|
|
Utils.$addClass(r, 'gui-overflowing');
|
|
_clamp(r);
|
|
}
|
|
Utils.$addClass(r, 'gui-showing');
|
|
}
|
|
function runChildren(pel, level, winRef, cb) {
|
|
level = level || 0;
|
|
cb = cb || function() {};
|
|
(pel.children || []).forEach(function(child, i) {
|
|
if ( child && child.tagName.toLowerCase() === 'gui-menu-entry') {
|
|
GUI.Elements['gui-menu-entry'].build(child, null, winRef);
|
|
cb(child, level);
|
|
}
|
|
});
|
|
}
|
|
function getSelectionEventAttribs(mel, didx) {
|
|
var id = mel.getAttribute('data-id');
|
|
var idx = Utils.$index(mel)
|
|
if ( !didx ) {
|
|
idx = parseInt(mel.getAttribute('data-index'), 10);
|
|
}
|
|
var result = {index: idx, id: id};
|
|
Array.prototype.slice.call(mel.attributes).forEach(function(item) {
|
|
if ( item.name.match(/^data\-/) ) {
|
|
var an = item.name.replace(/^data\-/, '');
|
|
if ( typeof result[an] === 'undefined' ) {
|
|
result[an] = item.value;
|
|
}
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
GUI.Elements['gui-menu-entry'] = (function() {
|
|
function createTyped(child, par) {
|
|
var type = child.getAttribute('data-type');
|
|
var value = child.getAttribute('data-checked') === 'true';
|
|
var input = null;
|
|
if ( type ) {
|
|
var group = child.getAttribute('data-group');
|
|
input = document.createElement('input');
|
|
input.type = type;
|
|
input.name = group ? group + '[]' : '';
|
|
if ( value ) {
|
|
input.setAttribute('checked', 'checked');
|
|
}
|
|
par.setAttribute('role', 'menuitem' + type);
|
|
par.appendChild(input);
|
|
}
|
|
}
|
|
return {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( evName === 'select' ) {
|
|
evName = '_select';
|
|
}
|
|
var target = el.querySelector('gui-menu-entry > label');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(child, arg, winRef) {
|
|
if ( arguments.length < 3 ) {
|
|
return;
|
|
}
|
|
child.setAttribute('role', 'menuitem' + (child.getAttribute('data-type') || ''));
|
|
var label = GUI.Helpers.getLabel(child);
|
|
var icon = GUI.Helpers.getIcon(child, winRef);
|
|
child.setAttribute('aria-label', label);
|
|
var span = document.createElement('label');
|
|
if ( icon ) {
|
|
child.style.backgroundImage = 'url(' + icon + ')';
|
|
Utils.$addClass(span, 'gui-has-image');
|
|
}
|
|
child.appendChild(span);
|
|
createTyped(child, span);
|
|
if ( child.getAttribute('data-labelhtml') === 'true' ) {
|
|
span.innerHTML = label;
|
|
} else {
|
|
span.appendChild(document.createTextNode(label));
|
|
}
|
|
if ( child.querySelector('gui-menu') ) {
|
|
Utils.$addClass(child, 'gui-menu-expand');
|
|
child.setAttribute('aria-haspopup', 'true');
|
|
} else {
|
|
child.setAttribute('aria-haspopup', 'false');
|
|
}
|
|
}
|
|
};
|
|
})();
|
|
GUI.Elements['gui-menu'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( evName === 'select' ) {
|
|
evName = '_select';
|
|
}
|
|
el.querySelectorAll('gui-menu-entry > label').forEach(function(target) {
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
});
|
|
},
|
|
show: function(ev) {
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
var newNode = this.$element.cloneNode(true);
|
|
var el = this.$element;
|
|
OSjs.GUI.Helpers.createMenu(null, ev, newNode);
|
|
Utils.$bind(newNode, 'click', function(ev, pos) {
|
|
clickWrapper(ev, pos, onEntryClick, el);
|
|
}, true);
|
|
},
|
|
set: function(el, param, value, arg) {
|
|
if ( param === 'checked' ) {
|
|
var found = el.querySelector('gui-menu-entry[data-id="' + value + '"]');
|
|
if ( found ) {
|
|
var input = found.querySelector('input');
|
|
if ( input ) {
|
|
if ( arg ) {
|
|
input.setAttribute('checked', 'checked');
|
|
} else {
|
|
input.removeAttribute('checked');
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el, customMenu, winRef) {
|
|
el.setAttribute('role', 'menu');
|
|
runChildren(el, 0, winRef, function(child, level) {
|
|
if ( customMenu ) {
|
|
if ( child ) {
|
|
child.getElementsByTagName('gui-menu').forEach(function(sub) {
|
|
if ( sub ) {
|
|
runChildren(sub, level + 1, winRef);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
});
|
|
if ( !customMenu ) {
|
|
Utils.$bind(el, 'click', function(ev, pos) {
|
|
clickWrapper(ev, pos, onEntryClick);
|
|
}, true);
|
|
}
|
|
}
|
|
};
|
|
GUI.Elements['gui-menu-bar'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( evName === 'select' ) {
|
|
evName = '_select';
|
|
}
|
|
el.querySelectorAll('gui-menu-bar-entry').forEach(function(target) {
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
});
|
|
},
|
|
build: function(el) {
|
|
el.setAttribute('role', 'menubar');
|
|
function updateChildren(sm, level) {
|
|
if ( sm && sm.children ) {
|
|
var children = sm.children;
|
|
var child;
|
|
for ( var i = 0; i < children.length; i++ ) {
|
|
child = children[i];
|
|
if ( child.tagName === 'GUI-MENU-ENTRY' ) {
|
|
child.setAttribute('aria-haspopup', String(!!child.firstChild));
|
|
updateChildren(child.firstChild, level + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function _onClick(ev, mel) {
|
|
blurMenu();
|
|
ev.preventDefault();
|
|
ev.stopPropagation();
|
|
var submenu = mel.querySelector('gui-menu');
|
|
mel.querySelectorAll('gui-menu-entry').forEach(function(c) {
|
|
Utils.$removeClass(c, 'gui-hover');
|
|
});
|
|
if ( submenu ) {
|
|
lastMenu = function(ev) {
|
|
if ( ev ) {
|
|
ev.stopPropagation();
|
|
}
|
|
Utils.$removeClass(mel, 'gui-active');
|
|
};
|
|
}
|
|
if ( Utils.$hasClass(mel, 'gui-active') ) {
|
|
if ( submenu ) {
|
|
Utils.$removeClass(mel, 'gui-active');
|
|
}
|
|
} else {
|
|
if ( submenu ) {
|
|
Utils.$addClass(mel, 'gui-active');
|
|
}
|
|
mel.dispatchEvent(new CustomEvent('_select', {detail: getSelectionEventAttribs(mel)}));
|
|
}
|
|
}
|
|
el.querySelectorAll('gui-menu-bar-entry').forEach(function(mel, idx) {
|
|
var label = GUI.Helpers.getLabel(mel);
|
|
var span = document.createElement('span');
|
|
span.appendChild(document.createTextNode(label));
|
|
mel.setAttribute('role', 'menuitem');
|
|
mel.insertBefore(span, mel.firstChild);
|
|
var submenu = mel.querySelector('gui-menu');
|
|
clampSubmenuPositions(submenu);
|
|
mel.setAttribute('aria-haspopup', String(!!submenu));
|
|
mel.setAttribute('data-index', String(idx));
|
|
updateChildren(submenu, 2);
|
|
});
|
|
Utils.$bind(el, 'click', function(ev) {
|
|
var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target);
|
|
if ( t && t.tagName === 'GUI-MENU-BAR-ENTRY' ) {
|
|
_onClick(ev, t);
|
|
}
|
|
}, true);
|
|
bindIngores(el);
|
|
}
|
|
};
|
|
OSjs.GUI.Helpers.blurMenu = blurMenu;
|
|
OSjs.GUI.Helpers.createMenu = function(items, ev, customInstance) {
|
|
items = items || [];
|
|
blurMenu();
|
|
var root = customInstance;
|
|
var callbackMap = [];
|
|
function resolveItems(arr, par) {
|
|
arr.forEach(function(iter) {
|
|
var props = {label: iter.title, icon: iter.icon, disabled: iter.disabled, labelHTML: iter.titleHTML, type: iter.type, checked: iter.checked};
|
|
var entry = GUI.Helpers.createElement('gui-menu-entry', props);
|
|
if ( iter.menu ) {
|
|
var nroot = GUI.Helpers.createElement('gui-menu', {});
|
|
resolveItems(iter.menu, nroot);
|
|
entry.appendChild(nroot);
|
|
}
|
|
if ( iter.onClick ) {
|
|
var index = callbackMap.push(iter.onClick);
|
|
entry.setAttribute('data-callback-id', String(index - 1));
|
|
}
|
|
par.appendChild(entry);
|
|
});
|
|
}
|
|
if ( !root ) {
|
|
root = GUI.Helpers.createElement('gui-menu', {});
|
|
resolveItems(items || [], root);
|
|
GUI.Elements['gui-menu'].build(root, true);
|
|
Utils.$bind(root, 'click', function(ev, pos) {
|
|
clickWrapper(ev, pos, function(ev, pos, t) {
|
|
var index = parseInt(t.getAttribute('data-callback-id'), 10);
|
|
if ( callbackMap[index] ) {
|
|
callbackMap[index](ev, pos);
|
|
blurMenu(ev); // !last!
|
|
}
|
|
});
|
|
}, true);
|
|
bindIngores(root);
|
|
}
|
|
if ( root.$element ) {
|
|
root = root.$element;
|
|
}
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var space = wm.getWindowSpace(true);
|
|
var pos = Utils.mousePosition(ev);
|
|
Utils.$addClass(root, 'gui-root-menu');
|
|
root.style.left = pos.x + 'px';
|
|
root.style.top = pos.y + 'px';
|
|
document.body.appendChild(root);
|
|
setTimeout(function() {
|
|
var pos = Utils.$position(root);
|
|
if ( pos ) {
|
|
if ( pos.right > space.width ) {
|
|
var newLeft = Math.round(space.width - pos.width);
|
|
root.style.left = Math.max(0, newLeft) + 'px';
|
|
}
|
|
if ( pos.bottom > space.height ) {
|
|
var newTop = Math.round(space.height - pos.height);
|
|
root.style.top = Math.max(0, newTop) + 'px';
|
|
}
|
|
}
|
|
clampSubmenuPositions(root);
|
|
}, 1);
|
|
lastMenu = function() {
|
|
callbackMap = null;
|
|
if ( root ) {
|
|
root.querySelectorAll('gui-menu-entry').forEach(function(el) {
|
|
Utils.$unbind(el);
|
|
});
|
|
Utils.$unbind(root);
|
|
}
|
|
root = Utils.$remove(root);
|
|
};
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function toggleActive(el, eidx, idx) {
|
|
Utils.$removeClass(el, 'gui-active');
|
|
if ( eidx === idx ) {
|
|
Utils.$addClass(el, 'gui-active');
|
|
}
|
|
}
|
|
GUI.Elements['gui-tabs'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( (['select', 'activate']).indexOf(evName) !== -1 ) {
|
|
evName = 'change';
|
|
}
|
|
if ( evName === 'change' ) {
|
|
evName = '_' + evName;
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
get: function(el, param, value) {
|
|
if ( param === 'current' || param === 'selected' ) {
|
|
var cur = el.querySelector('ul > li[class="gui-active"]');
|
|
return Utils.$index(cur);
|
|
}
|
|
return GUI.Helpers.getProperty(el, param);
|
|
},
|
|
build: function(el) {
|
|
var tabs = document.createElement('ul');
|
|
var lastTab;
|
|
function selectTab(ev, idx, tab) {
|
|
if ( lastTab ) {
|
|
Utils.$removeClass(lastTab, 'gui-active');
|
|
}
|
|
tabs.querySelectorAll('li').forEach(function(tel, eidx) {
|
|
toggleActive(tel, eidx, idx);
|
|
});
|
|
el.querySelectorAll('gui-tab-container').forEach(function(tel, eidx) {
|
|
toggleActive(tel, eidx, idx);
|
|
});
|
|
lastTab = tab;
|
|
Utils.$addClass(tab, 'gui-active');
|
|
el.dispatchEvent(new CustomEvent('_change', {detail: {index: idx}}));
|
|
}
|
|
el.querySelectorAll('gui-tab-container').forEach(function(tel, idx) {
|
|
var tab = document.createElement('li');
|
|
var label = GUI.Helpers.getLabel(tel);
|
|
Utils.$bind(tab, 'click', function(ev) {
|
|
selectTab(ev, idx, tab);
|
|
}, false);
|
|
tab.setAttribute('role', 'tab');
|
|
tab.setAttribute('aria-label', label);
|
|
tel.setAttribute('role', 'tabpanel');
|
|
tab.appendChild(document.createTextNode(label));
|
|
tabs.appendChild(tab);
|
|
});
|
|
tabs.setAttribute('role', 'tablist');
|
|
el.setAttribute('role', 'navigation');
|
|
if ( el.children.length ) {
|
|
el.insertBefore(tabs, el.children[0]);
|
|
} else {
|
|
el.appendChild(tabs);
|
|
}
|
|
var currentTab = parseInt(el.getAttribute('data-selected-index'), 10) || 0;
|
|
selectTab(null, currentTab);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
var _buttonCount = 0;
|
|
function createInputOfType(el, type) {
|
|
var group = el.getAttribute('data-group');
|
|
var placeholder = el.getAttribute('data-placeholder');
|
|
var disabled = String(el.getAttribute('data-disabled')) === 'true';
|
|
var value = el.childNodes.length ? el.childNodes[0].nodeValue : null;
|
|
Utils.$empty(el);
|
|
var input = document.createElement(type === 'textarea' ? 'textarea' : 'input');
|
|
var attribs = {
|
|
value: null,
|
|
type: type,
|
|
tabindex: -1,
|
|
placeholder: placeholder,
|
|
disabled: disabled ? 'disabled' : null,
|
|
name: group ? group + '[]' : null
|
|
};
|
|
(['autocomplete', 'autocorrect', 'autocapitalize', 'spellcheck']).forEach(function(a) {
|
|
attribs[a] = el.getAttribute('data-' + a) || 'false';
|
|
});
|
|
function _bindDefaults() {
|
|
if ( ['range', 'slider'].indexOf(type) >= 0 ) {
|
|
attribs.min = el.getAttribute('data-min');
|
|
attribs.max = el.getAttribute('data-max');
|
|
attribs.step = el.getAttribute('data-step');
|
|
} else if ( ['radio', 'checkbox'].indexOf(type) >= 0 ) {
|
|
if ( el.getAttribute('data-value') === 'true' ) {
|
|
attribs.checked = 'checked';
|
|
}
|
|
} else if ( ['text', 'password', 'textarea'].indexOf(type) >= 0 ) {
|
|
attribs.value = value || '';
|
|
}
|
|
Object.keys(attribs).forEach(function(a) {
|
|
if ( attribs[a] !== null ) {
|
|
if ( a === 'value' ) {
|
|
input.value = attribs[a];
|
|
} else {
|
|
input.setAttribute(a, attribs[a]);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function _bindEvents() {
|
|
if ( type === 'text' || type === 'password' || type === 'textarea' ) {
|
|
Utils.$bind(input, 'keydown', function(ev) {
|
|
if ( ev.keyCode === Utils.Keys.ENTER ) {
|
|
input.dispatchEvent(new CustomEvent('_enter', {detail: input.value}));
|
|
} else if ( ev.keyCode === Utils.Keys.C && ev.ctrlKey ) {
|
|
API.setClipboard(input.value);
|
|
}
|
|
if ( type === 'textarea' && ev.keyCode === Utils.Keys.TAB ) {
|
|
ev.preventDefault();
|
|
input.value += '\t';
|
|
}
|
|
}, false);
|
|
}
|
|
}
|
|
function _create() {
|
|
_bindDefaults();
|
|
_bindEvents();
|
|
GUI.Helpers.createInputLabel(el, type, input);
|
|
var rolemap = {
|
|
'TEXTAREA': function() {
|
|
return 'textbox';
|
|
},
|
|
'INPUT': function(i) {
|
|
var typemap = {
|
|
'range': 'slider',
|
|
'text': 'textbox',
|
|
'password': 'textbox'
|
|
};
|
|
return typemap[i.type] || i.type;
|
|
}
|
|
};
|
|
if ( rolemap[el.tagName] ) {
|
|
input.setAttribute('role', rolemap[el.tagName](input));
|
|
}
|
|
input.setAttribute('aria-label', el.getAttribute('title') || '');
|
|
el.setAttribute('role', 'region');
|
|
el.setAttribute('aria-disabled', String(disabled));
|
|
Utils.$bind(input, 'change', function(ev) {
|
|
var value = input.value;
|
|
if ( type === 'radio' || type === 'checkbox' ) {
|
|
value = input.checked; //input.value === 'on';
|
|
}
|
|
input.dispatchEvent(new CustomEvent('_change', {detail: value}));
|
|
}, false);
|
|
}
|
|
_create();
|
|
}
|
|
function bindInputEvents(el, evName, callback, params) {
|
|
if ( evName === 'enter' ) {
|
|
evName = '_enter';
|
|
} else if ( evName === 'change' ) {
|
|
evName = '_change';
|
|
}
|
|
var target = el.querySelector('textarea, input, select');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
}
|
|
function addToSelectBox(el, entries) {
|
|
var target = el.querySelector('select');
|
|
if ( !(entries instanceof Array) ) {
|
|
entries = [entries];
|
|
}
|
|
entries.forEach(function(e) {
|
|
var opt = document.createElement('option');
|
|
opt.setAttribute('role', 'option');
|
|
opt.setAttribute('value', e.value);
|
|
opt.appendChild(document.createTextNode(e.label));
|
|
target.appendChild(opt);
|
|
});
|
|
}
|
|
function removeFromSelectBox(el, what) {
|
|
var target = el.querySelector('select');
|
|
target.querySelectorAll('option').forEach(function(opt) {
|
|
if ( String(opt.value) === String(what) ) {
|
|
Utils.$remove(opt);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
function callSelectBox(el, method, args) {
|
|
if ( method === 'add' ) {
|
|
addToSelectBox(el, args[0]);
|
|
} else if ( method === 'remove' ) {
|
|
removeFromSelectBox(el, args[0]);
|
|
} else if ( method === 'clear' ) {
|
|
var target = el.querySelector('select');
|
|
Utils.$empty(target);
|
|
}
|
|
}
|
|
function createSelectInput(el, multiple) {
|
|
var disabled = el.getAttribute('data-disabled') !== null;
|
|
var selected = el.getAttribute('data-selected');
|
|
var select = document.createElement('select');
|
|
if ( multiple ) {
|
|
select.setAttribute('size', el.getAttribute('data-size') || 2);
|
|
multiple = el.getAttribute('data-multiple') === 'true';
|
|
}
|
|
if ( multiple ) {
|
|
select.setAttribute('multiple', 'multiple');
|
|
}
|
|
if ( disabled ) {
|
|
select.setAttribute('disabled', 'disabled');
|
|
}
|
|
if ( selected !== null ) {
|
|
select.selectedIndex = selected;
|
|
}
|
|
el.querySelectorAll('gui-select-option').forEach(function(sel) {
|
|
var value = sel.getAttribute('data-value') || '';
|
|
var label = sel.childNodes.length ? sel.childNodes[0].nodeValue : '';
|
|
var option = document.createElement('option');
|
|
option.setAttribute('role', 'option');
|
|
option.setAttribute('value', value);
|
|
option.appendChild(document.createTextNode(label));
|
|
if ( sel.getAttribute('selected') ) {
|
|
option.setAttribute('selected', 'selected');
|
|
}
|
|
select.appendChild(option);
|
|
sel.parentNode.removeChild(sel);
|
|
});
|
|
Utils.$bind(select, 'change', function(ev) {
|
|
select.dispatchEvent(new CustomEvent('_change', {detail: select.value}));
|
|
}, false);
|
|
select.setAttribute('role', 'listbox');
|
|
select.setAttribute('aria-label', el.getAttribute('title') || '');
|
|
el.setAttribute('aria-disabled', String(disabled));
|
|
el.setAttribute('role', 'region');
|
|
el.appendChild(select);
|
|
}
|
|
function setSwitchValue(val, input, button) {
|
|
if ( val !== true ) {
|
|
input.removeAttribute('checked');
|
|
Utils.$removeClass(button, 'gui-active');
|
|
button.innerHTML = '0';
|
|
} else {
|
|
input.setAttribute('checked', 'checked');
|
|
Utils.$addClass(button, 'gui-active');
|
|
button.innerHTML = '1';
|
|
}
|
|
}
|
|
var guiSelect = {
|
|
bind: bindInputEvents,
|
|
call: function() {
|
|
callSelectBox.apply(this, arguments);
|
|
return this;
|
|
},
|
|
build: function(el) {
|
|
var multiple = (el.tagName.toLowerCase() === 'gui-select-list');
|
|
createSelectInput(el, multiple);
|
|
}
|
|
};
|
|
GUI.Elements['gui-label'] = {
|
|
set: function(el, param, value, isHTML) {
|
|
if ( param === 'value' || param === 'label' ) {
|
|
el.setAttribute('data-label', String(value));
|
|
var lbl = el.querySelector('label');
|
|
Utils.$empty(lbl);
|
|
if ( isHTML ) {
|
|
lbl.innerHTML = value;
|
|
} else {
|
|
lbl.appendChild(document.createTextNode(value));
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var label = GUI.Helpers.getValueLabel(el, true);
|
|
var lbl = document.createElement('label');
|
|
lbl.appendChild(document.createTextNode(label));
|
|
el.setAttribute('role', 'heading');
|
|
el.setAttribute('data-label', String(label));
|
|
el.appendChild(lbl);
|
|
}
|
|
};
|
|
GUI.Elements['gui-textarea'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
createInputOfType(el, 'textarea');
|
|
},
|
|
set: function(el, param, value) {
|
|
if ( el && param === 'scrollTop' ) {
|
|
if ( typeof value !== 'number' ) {
|
|
value = el.firstChild.scrollHeight;
|
|
}
|
|
el.firstChild.scrollTop = value;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
GUI.Elements['gui-text'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
createInputOfType(el, 'text');
|
|
}
|
|
};
|
|
GUI.Elements['gui-password'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
createInputOfType(el, 'password');
|
|
}
|
|
};
|
|
GUI.Elements['gui-file-upload'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
var input = document.createElement('input');
|
|
input.setAttribute('role', 'button');
|
|
input.setAttribute('type', 'file');
|
|
input.onchange = function(ev) {
|
|
input.dispatchEvent(new CustomEvent('_change', {detail: input.files[0]}));
|
|
};
|
|
el.appendChild(input);
|
|
}
|
|
};
|
|
GUI.Elements['gui-radio'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
createInputOfType(el, 'radio');
|
|
}
|
|
};
|
|
GUI.Elements['gui-checkbox'] = {
|
|
bind: bindInputEvents,
|
|
build: function(el) {
|
|
createInputOfType(el, 'checkbox');
|
|
}
|
|
};
|
|
GUI.Elements['gui-switch'] = {
|
|
bind: bindInputEvents,
|
|
set: function(el, param, value) {
|
|
if ( param === 'value' ) {
|
|
var input = el.querySelector('input');
|
|
var button = el.querySelector('button');
|
|
setSwitchValue(value, input, button);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var input = document.createElement('input');
|
|
input.type = 'checkbox';
|
|
el.appendChild(input);
|
|
var inner = document.createElement('div');
|
|
var button = document.createElement('button');
|
|
inner.appendChild(button);
|
|
GUI.Helpers.createInputLabel(el, 'switch', inner);
|
|
function toggleValue(v) {
|
|
var val = false;
|
|
if ( typeof v === 'undefined' ) {
|
|
val = !!input.checked;
|
|
val = !val;
|
|
} else {
|
|
val = v;
|
|
}
|
|
setSwitchValue(val, input, button);
|
|
}
|
|
Utils.$bind(inner, 'click', function(ev) {
|
|
ev.preventDefault();
|
|
var disabled = el.getAttribute('data-disabled') !== null;
|
|
if ( !disabled ) {
|
|
toggleValue();
|
|
}
|
|
}, false);
|
|
toggleValue(false);
|
|
}
|
|
};
|
|
GUI.Elements['gui-button'] = {
|
|
set: function(el, param, value, isHTML) {
|
|
if ( param === 'value' || param === 'label' ) {
|
|
var lbl = el.querySelector('button');
|
|
Utils.$empty(lbl);
|
|
if ( isHTML ) {
|
|
lbl.innerHTML = value;
|
|
} else {
|
|
lbl.appendChild(document.createTextNode(value));
|
|
}
|
|
lbl.setAttribute('aria-label', value);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
create: function(params) {
|
|
var label = params.label;
|
|
if ( params.label ) {
|
|
delete params.label;
|
|
}
|
|
var el = GUI.Helpers.createElement('gui-button', params);
|
|
if ( label ) {
|
|
el.appendChild(document.createTextNode(label));
|
|
}
|
|
return el;
|
|
},
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('button');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var icon = el.getAttribute('data-icon');
|
|
var disabled = el.getAttribute('data-disabled') !== null;
|
|
var group = el.getAttribute('data-group');
|
|
var label = GUI.Helpers.getValueLabel(el);
|
|
var input = document.createElement('button');
|
|
function setGroup(g) {
|
|
if ( g ) {
|
|
input.setAttribute('name', g + '[' + _buttonCount + ']');
|
|
Utils.$bind(input, 'click', function() {
|
|
var root = el;
|
|
while ( root.parentNode ) {
|
|
if ( root.tagName.toLowerCase() === 'application-window-content' ) {
|
|
break;
|
|
}
|
|
root = root.parentNode;
|
|
}
|
|
Utils.$addClass(input, 'gui-active');
|
|
root.querySelectorAll('gui-button[data-group="' + g + '"] > button').forEach(function(b) {
|
|
if ( b.name === input.name ) {
|
|
return;
|
|
}
|
|
Utils.$removeClass(b, 'gui-active');
|
|
});
|
|
});
|
|
}
|
|
}
|
|
function setImage() {
|
|
if ( icon && icon !== 'null' ) {
|
|
var img = document.createElement('img');
|
|
img.src = icon;
|
|
img.alt = el.getAttribute('data-tooltip') || '';
|
|
img.title = el.getAttribute('data-tooltip') || '';
|
|
if ( input.firstChild ) {
|
|
input.insertBefore(img, input.firstChild);
|
|
} else {
|
|
input.appendChild(img);
|
|
}
|
|
Utils.$addClass(el, 'gui-has-image');
|
|
}
|
|
}
|
|
function setLabel() {
|
|
if ( label ) {
|
|
Utils.$addClass(el, 'gui-has-label');
|
|
}
|
|
input.appendChild(document.createTextNode(label));
|
|
input.setAttribute('aria-label', label);
|
|
}
|
|
if ( disabled ) {
|
|
input.setAttribute('disabled', 'disabled');
|
|
}
|
|
setLabel();
|
|
setImage();
|
|
setGroup(group);
|
|
_buttonCount++;
|
|
el.setAttribute('role', 'navigation');
|
|
el.appendChild(input);
|
|
}
|
|
};
|
|
GUI.Elements['gui-select'] = guiSelect;
|
|
GUI.Elements['gui-select-list'] = guiSelect;
|
|
GUI.Elements['gui-slider'] = {
|
|
bind: bindInputEvents,
|
|
get: function(el, param) {
|
|
var val = GUI.Helpers.getProperty(el, param);
|
|
if ( param === 'value' ) {
|
|
return parseInt(val, 10);
|
|
}
|
|
return val;
|
|
},
|
|
build: function(el) {
|
|
createInputOfType(el, 'range');
|
|
}
|
|
};
|
|
GUI.Elements['gui-input-modal'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( evName === 'open' ) {
|
|
evName = '_open';
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
get: function(el, param) {
|
|
if ( param === 'value' ) {
|
|
var input = el.querySelector('input');
|
|
return input.value;
|
|
}
|
|
return false;
|
|
},
|
|
set: function(el, param, value) {
|
|
if ( param === 'value' ) {
|
|
var input = el.querySelector('input');
|
|
input.removeAttribute('disabled');
|
|
input.value = value;
|
|
input.setAttribute('disabled', 'disabled');
|
|
input.setAttribute('aria-disabled', 'true');
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
var container = document.createElement('div');
|
|
var input = document.createElement('input');
|
|
input.type = 'text';
|
|
input.setAttribute('disabled', 'disabled');
|
|
var button = document.createElement('button');
|
|
button.innerHTML = '...';
|
|
Utils.$bind(button, 'click', function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_open', {detail: input.value}));
|
|
}, false);
|
|
container.appendChild(input);
|
|
container.appendChild(button);
|
|
el.appendChild(container);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function createVisualElement(el, nodeType, applyArgs) {
|
|
applyArgs = applyArgs || {};
|
|
if ( typeof applyArgs !== 'object' ) {
|
|
console.error('Derp', 'applyArgs was not an object ?!');
|
|
applyArgs = {};
|
|
}
|
|
var img = document.createElement(nodeType);
|
|
var src = el.getAttribute('data-src');
|
|
var controls = el.getAttribute('data-controls');
|
|
if ( controls ) {
|
|
img.setAttribute('controls', 'controls');
|
|
}
|
|
var autoplay = el.getAttribute('data-autoplay');
|
|
if ( autoplay ) {
|
|
img.setAttribute('autoplay', 'autoplay');
|
|
}
|
|
Object.keys(applyArgs).forEach(function(k) {
|
|
var val = applyArgs[k];
|
|
if ( typeof val === 'function' ) {
|
|
k = k.replace(/^on/, '');
|
|
if ( (nodeType === 'video' || nodeType === 'audio') && k === 'load' ) {
|
|
k = 'loadedmetadata';
|
|
}
|
|
Utils.$bind(img, k, val.bind(img), false);
|
|
} else {
|
|
if ( typeof applyArgs[k] === 'boolean' ) {
|
|
val = val ? 'true' : 'false';
|
|
}
|
|
img.setAttribute(k, val);
|
|
}
|
|
});
|
|
img.src = src || 'about:blank';
|
|
el.appendChild(img);
|
|
}
|
|
GUI.Elements['gui-audio'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('audio');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el, applyArgs) {
|
|
createVisualElement(el, 'audio', applyArgs);
|
|
}
|
|
};
|
|
GUI.Elements['gui-video'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('video');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el, applyArgs) {
|
|
createVisualElement(el, 'video', applyArgs);
|
|
}
|
|
};
|
|
GUI.Elements['gui-image'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('img');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el, applyArgs) {
|
|
createVisualElement(el, 'img', applyArgs);
|
|
}
|
|
};
|
|
GUI.Elements['gui-canvas'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
var target = el.querySelector('canvas');
|
|
Utils.$bind(target, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var canvas = document.createElement('canvas');
|
|
el.appendChild(canvas);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
var _iconSizes = { // Defaults to 16x16
|
|
'gui-icon-view': '32x32'
|
|
};
|
|
function getChildView(el) {
|
|
return el.children[0];
|
|
}
|
|
function getFileIcon(iter, size) {
|
|
if ( iter.icon && typeof iter.icon === 'object' ) {
|
|
return API.getIcon(iter.icon.filename, size, iter.icon.application);
|
|
}
|
|
var icon = 'status/gtk-dialog-question.png';
|
|
return API.getFileIcon(iter, size, icon);
|
|
}
|
|
function getFileSize(iter) {
|
|
var filesize = '';
|
|
if ( iter.type !== 'dir' && iter.size >= 0 ) {
|
|
filesize = Utils.humanFileSize(iter.size);
|
|
}
|
|
return filesize;
|
|
}
|
|
var removeExtension = (function() {
|
|
var mimeConfig;
|
|
return function(str, opts) {
|
|
if ( !mimeConfig ) {
|
|
mimeConfig = API.getConfig('MIME.mapping');
|
|
}
|
|
if ( opts.extensions === false ) {
|
|
var ext = Utils.filext(str);
|
|
if ( ext ) {
|
|
ext = '.' + ext;
|
|
if ( mimeConfig[ext] ) {
|
|
str = str.substr(0, str.length - ext.length);
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
};
|
|
})();
|
|
function getDateFromStamp(stamp) {
|
|
if ( typeof stamp === 'string' ) {
|
|
var date = null;
|
|
try {
|
|
date = new Date(stamp);
|
|
} catch ( e ) {}
|
|
if ( date ) {
|
|
return OSjs.Helpers.Date.format(date);
|
|
}
|
|
}
|
|
return stamp;
|
|
}
|
|
function getListViewColumns(iter, opts) {
|
|
opts = opts || {};
|
|
var columnMapping = {
|
|
filename: {
|
|
label: 'LBL_FILENAME',
|
|
icon: function() {
|
|
return getFileIcon(iter);
|
|
},
|
|
value: function() {
|
|
return removeExtension(iter.filename, opts);
|
|
}
|
|
},
|
|
mime: {
|
|
label: 'LBL_MIME',
|
|
size: '100px',
|
|
icon: function() {
|
|
return null;
|
|
},
|
|
value: function() {
|
|
return iter.mime;
|
|
}
|
|
},
|
|
mtime: {
|
|
label: 'LBL_MODIFIED',
|
|
size: '160px',
|
|
icon: function() {
|
|
return null;
|
|
},
|
|
value: function() {
|
|
return getDateFromStamp(iter.mtime);
|
|
}
|
|
},
|
|
ctime: {
|
|
label: 'LBL_CREATED',
|
|
size: '160px',
|
|
icon: function() {
|
|
return null;
|
|
},
|
|
value: function() {
|
|
return getDateFromStamp(iter.ctime);
|
|
}
|
|
},
|
|
size: {
|
|
label: 'LBL_SIZE',
|
|
size: '120px',
|
|
icon: function() {
|
|
return null;
|
|
},
|
|
value: function() {
|
|
return getFileSize(iter);
|
|
}
|
|
}
|
|
};
|
|
var defColumns = ['filename', 'mime', 'size'];
|
|
var useColumns = defColumns;
|
|
if ( !opts.defaultcolumns ) {
|
|
var vfsOptions = Utils.cloneObject(OSjs.Core.getSettingsManager().get('VFS') || {});
|
|
var scandirOptions = vfsOptions.scandir || {};
|
|
useColumns = scandirOptions.columns || defColumns;
|
|
}
|
|
var columns = [];
|
|
useColumns.forEach(function(key, idx) {
|
|
var map = columnMapping[key];
|
|
if ( iter ) {
|
|
columns.push({
|
|
label: map.value(),
|
|
icon: map.icon(),
|
|
textalign: idx === 0 ? 'left' : 'right'
|
|
});
|
|
} else {
|
|
columns.push({
|
|
label: API._(map.label),
|
|
size: map.size || '',
|
|
resizable: idx > 0,
|
|
textalign: idx === 0 ? 'left' : 'right'
|
|
});
|
|
}
|
|
});
|
|
return columns;
|
|
}
|
|
function buildChildView(el) {
|
|
var type = el.getAttribute('data-type') || 'list-view';
|
|
if ( !type.match(/^gui\-/) ) {
|
|
type = 'gui-' + type;
|
|
}
|
|
var nel = new GUI.ElementDataView(GUI.Helpers.createElement(type, {'draggable': true, 'draggable-type': 'file'}));
|
|
GUI.Elements[type].build(nel.$element);
|
|
nel.on('select', function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_select', {detail: ev.detail}));
|
|
});
|
|
nel.on('activate', function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_activate', {detail: ev.detail}));
|
|
});
|
|
nel.on('contextmenu', function(ev) {
|
|
if ( !el.hasAttribute('data-has-contextmenu') || el.hasAttribute('data-has-contextmenu') === 'false' ) {
|
|
new GUI.Element(el).fn('contextmenu', [ev]);
|
|
}
|
|
el.dispatchEvent(new CustomEvent('_contextmenu', {detail: ev.detail}));
|
|
});
|
|
if ( type === 'gui-tree-view' ) {
|
|
nel.on('expand', function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_expand', {detail: ev.detail}));
|
|
});
|
|
}
|
|
el.setAttribute('role', 'region');
|
|
el.appendChild(nel.$element);
|
|
}
|
|
function scandir(tagName, dir, opts, cb, oncreate) {
|
|
var file = new VFS.File(dir);
|
|
file.type = 'dir';
|
|
var scanopts = {
|
|
backlink: opts.backlink,
|
|
showDotFiles: opts.dotfiles === true,
|
|
showFileExtensions: opts.extensions === true,
|
|
mimeFilter: opts.filter || [],
|
|
typeFilter: opts.filetype || null
|
|
};
|
|
try {
|
|
VFS.scandir(file, function(error, result) {
|
|
if ( error ) {
|
|
cb(error); return;
|
|
}
|
|
var list = [];
|
|
var summary = {size: 0, directories: 0, files: 0, hidden: 0};
|
|
function isHidden(iter) {
|
|
return (iter.filename || '').substr(0) === '.';
|
|
}
|
|
(result || []).forEach(function(iter) {
|
|
list.push(oncreate(iter));
|
|
summary.size += iter.size || 0;
|
|
summary.directories += iter.type === 'dir' ? 1 : 0;
|
|
summary.files += iter.type !== 'dir' ? 1 : 0;
|
|
summary.hidden += isHidden(iter) ? 1 : 0;
|
|
});
|
|
cb(false, list, summary);
|
|
}, scanopts);
|
|
} catch ( e ) {
|
|
cb(e);
|
|
}
|
|
}
|
|
function readdir(el, dir, done, sopts) {
|
|
sopts = sopts || {};
|
|
var vfsOptions = Utils.cloneObject(OSjs.Core.getSettingsManager().get('VFS') || {});
|
|
var scandirOptions = vfsOptions.scandir || {};
|
|
var target = getChildView(el);
|
|
var tagName = target.tagName.toLowerCase();
|
|
el.setAttribute('data-path', dir);
|
|
var opts = {filter: null, backlink: sopts.backlink};
|
|
function setOption(s, d, c, cc) {
|
|
if ( el.hasAttribute(s) ) {
|
|
opts[d] = c(el.getAttribute(s));
|
|
} else {
|
|
opts[d] = (cc || function() {})();
|
|
}
|
|
}
|
|
setOption('data-dotfiles', 'dotfiles', function(val) {
|
|
return val === 'true';
|
|
}, function() {
|
|
return scandirOptions.showHiddenFiles === true;
|
|
});
|
|
setOption('data-extensions', 'extensions', function(val) {
|
|
return val === 'true';
|
|
}, function() {
|
|
return scandirOptions.showFileExtensions === true;
|
|
});
|
|
setOption('data-filetype', 'filetype', function(val) {
|
|
return val;
|
|
});
|
|
setOption('data-defaultcolumns', 'defaultcolumns', function(val) {
|
|
return val === 'true';
|
|
});
|
|
try {
|
|
opts.filter = JSON.parse(el.getAttribute('data-filter'));
|
|
} catch ( e ) {
|
|
}
|
|
scandir(tagName, dir, opts, function(error, result, summary) {
|
|
if ( tagName === 'gui-list-view' ) {
|
|
GUI.Elements[tagName].set(target, 'zebra', true);
|
|
GUI.Elements[tagName].set(target, 'columns', getListViewColumns(null, opts));
|
|
}
|
|
done(error, result, summary);
|
|
}, function(iter) {
|
|
var tooltip = Utils.format('{0}\n{1}\n{2} {3}', iter.type.toUpperCase(), iter.filename, getFileSize(iter), iter.mime || '');
|
|
function _createEntry() {
|
|
var row = {
|
|
value: iter,
|
|
id: iter.id || removeExtension(iter.filename, opts),
|
|
label: iter.filename,
|
|
tooltip: tooltip,
|
|
icon: getFileIcon(iter, _iconSizes[tagName] || '16x16')
|
|
};
|
|
if ( tagName === 'gui-tree-view' && iter.type === 'dir' ) {
|
|
if ( iter.filename !== '..' ) {
|
|
row.entries = [{
|
|
label: 'Loading...'
|
|
}];
|
|
}
|
|
}
|
|
return row;
|
|
}
|
|
if ( tagName !== 'gui-list-view' ) {
|
|
return _createEntry();
|
|
}
|
|
return {
|
|
value: iter,
|
|
id: iter.id || iter.filename,
|
|
tooltip: tooltip,
|
|
columns: getListViewColumns(iter, opts)
|
|
};
|
|
});
|
|
}
|
|
GUI.Elements['gui-file-view'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( (['activate', 'select', 'contextmenu']).indexOf(evName) !== -1 ) {
|
|
evName = '_' + evName;
|
|
}
|
|
if ( evName === '_contextmenu' ) {
|
|
el.setAttribute('data-has-contextmenu', 'true');
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
set: function(el, param, value, arg, arg2) {
|
|
if ( param === 'type' ) {
|
|
var firstChild = el.children[0];
|
|
if ( firstChild && firstChild.tagName.toLowerCase() === value ) {
|
|
return true;
|
|
}
|
|
Utils.$empty(el);
|
|
el.setAttribute('data-type', value);
|
|
Utils.$bind(el, '_expand', function(ev) {
|
|
var target = ev.detail.element;
|
|
if ( target.getAttribute('data-was-rendered') ) {
|
|
return;
|
|
}
|
|
if ( ev.detail.expanded ) {
|
|
var view = new GUI.ElementDataView(getChildView(el));
|
|
var entry = ev.detail.entries[0].data;
|
|
target.setAttribute('data-was-rendered', String(true));
|
|
readdir(el, entry.path, function(error, result, summary) {
|
|
if ( !error ) {
|
|
target.querySelectorAll('gui-tree-view-entry').forEach(function(e) {
|
|
Utils.$remove(e);
|
|
view.add({
|
|
entries: result,
|
|
parentNode: target
|
|
});
|
|
});
|
|
}
|
|
}, {backlink: false});
|
|
}
|
|
});
|
|
buildChildView(el);
|
|
if ( typeof arg === 'undefined' || arg === true ) {
|
|
GUI.Elements['gui-file-view'].call(el, 'chdir', {
|
|
path: el.getAttribute('data-path')
|
|
});
|
|
}
|
|
return true;
|
|
} else if ( (['filter', 'dotfiles', 'filetype', 'extensions', 'defaultcolumns']).indexOf(param) >= 0 ) {
|
|
GUI.Helpers.setProperty(el, param, value);
|
|
return true;
|
|
}
|
|
var target = getChildView(el);
|
|
if ( target ) {
|
|
var tagName = target.tagName.toLowerCase();
|
|
GUI.Elements[tagName].set(target, param, value, arg, arg2);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
build: function(el) {
|
|
buildChildView(el);
|
|
},
|
|
values: function(el) {
|
|
var target = getChildView(el);
|
|
if ( target ) {
|
|
var tagName = target.tagName.toLowerCase();
|
|
return GUI.Elements[tagName].values(target);
|
|
}
|
|
return null;
|
|
},
|
|
contextmenu: function(ev) {
|
|
var vfsOptions = OSjs.Core.getSettingsManager().instance('VFS');
|
|
var scandirOptions = (vfsOptions.get('scandir') || {});
|
|
function setOption(opt, toggle) {
|
|
var opts = {scandir: {}};
|
|
opts.scandir[opt] = toggle;
|
|
vfsOptions.set(null, opts, true);
|
|
}
|
|
API.createMenu([
|
|
{
|
|
title: API._('LBL_SHOW_HIDDENFILES'),
|
|
type: 'checkbox',
|
|
checked: scandirOptions.showHiddenFiles === true,
|
|
onClick: function() {
|
|
setOption('showHiddenFiles', !scandirOptions.showHiddenFiles);
|
|
}
|
|
},
|
|
{
|
|
title: API._('LBL_SHOW_FILEEXTENSIONS'),
|
|
type: 'checkbox',
|
|
checked: scandirOptions.showFileExtensions === true,
|
|
onClick: function() {
|
|
setOption('showFileExtensions', !scandirOptions.showFileExtensions);
|
|
}
|
|
}
|
|
], ev);
|
|
},
|
|
call: function(el, method, args) {
|
|
args = args || {};
|
|
args.done = args.done || function() {};
|
|
var target = getChildView(el);
|
|
if ( target ) {
|
|
var tagName = target.tagName.toLowerCase();
|
|
if ( method === 'chdir' ) {
|
|
var t = new GUI.ElementDataView(target);
|
|
var dir = args.path || OSjs.API.getDefaultPath();
|
|
clearTimeout(el._readdirTimeout);
|
|
el._readdirTimeout = setTimeout(function() {
|
|
readdir(el, dir, function(error, result, summary) {
|
|
if ( error ) {
|
|
API.error(API._('ERR_VFSMODULE_XHR_ERROR'), API._('ERR_VFSMODULE_SCANDIR_FMT', dir), error);
|
|
} else {
|
|
t.clear();
|
|
t.add(result);
|
|
}
|
|
args.done(error, summary);
|
|
});
|
|
el._readdirTimeout = clearTimeout(el._readdirTimeout);
|
|
}, 50); // Prevent exessive calls
|
|
return;
|
|
}
|
|
GUI.Elements[tagName].call(target, method, args);
|
|
}
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function createEntry(e) {
|
|
var entry = GUI.Helpers.createElement('gui-tree-view-entry', e, ['entries']);
|
|
return entry;
|
|
}
|
|
function handleItemExpand(ev, el, root, expanded) {
|
|
if ( typeof expanded === 'undefined' ) {
|
|
expanded = !Utils.$hasClass(root, 'gui-expanded');
|
|
}
|
|
Utils.$removeClass(root, 'gui-expanded');
|
|
if ( expanded ) {
|
|
Utils.$addClass(root, 'gui-expanded');
|
|
}
|
|
var children = root.children;
|
|
for ( var i = 0; i < children.length; i++ ) {
|
|
if ( children[i].tagName.toLowerCase() === 'gui-tree-view-entry' ) {
|
|
children[i].style.display = expanded ? 'block' : 'none';
|
|
}
|
|
}
|
|
var selected = {
|
|
index: Utils.$index(root),
|
|
data: GUI.Helpers.getViewNodeValue(root)
|
|
};
|
|
root.setAttribute('data-expanded', String(expanded));
|
|
root.setAttribute('aria-expanded', String(expanded));
|
|
el.dispatchEvent(new CustomEvent('_expand', {detail: {entries: [selected], expanded: expanded, element: root}}));
|
|
} // handleItemExpand()
|
|
function initEntry(el, sel) {
|
|
if ( sel._rendered ) {
|
|
return;
|
|
}
|
|
sel._rendered = true;
|
|
var icon = sel.getAttribute('data-icon');
|
|
var label = GUI.Helpers.getLabel(sel);
|
|
var expanded = el.getAttribute('data-expanded') === 'true';
|
|
var next = sel.querySelector('gui-tree-view-entry');
|
|
var container = document.createElement('div');
|
|
var dspan = document.createElement('span');
|
|
function onDndEnter(ev) {
|
|
ev.stopPropagation();
|
|
Utils.$addClass(sel, 'dnd-over');
|
|
}
|
|
function onDndLeave(ev) {
|
|
Utils.$removeClass(sel, 'dnd-over');
|
|
}
|
|
if ( icon ) {
|
|
dspan.style.backgroundImage = 'url(' + icon + ')';
|
|
Utils.$addClass(dspan, 'gui-has-image');
|
|
}
|
|
dspan.appendChild(document.createTextNode(label));
|
|
container.appendChild(dspan);
|
|
if ( next ) {
|
|
Utils.$addClass(sel, 'gui-expandable');
|
|
var expander = document.createElement('gui-tree-view-expander');
|
|
sel.insertBefore(container, next);
|
|
sel.insertBefore(expander, container);
|
|
} else {
|
|
sel.appendChild(container);
|
|
}
|
|
if ( String(sel.getAttribute('data-draggable')) === 'true' ) {
|
|
GUI.Helpers.createDraggable(container, (function() {
|
|
var data = {};
|
|
try {
|
|
data = JSON.parse(sel.getAttribute('data-value'));
|
|
} catch ( e ) {}
|
|
return {data: data};
|
|
})());
|
|
}
|
|
if ( String(sel.getAttribute('data-droppable')) === 'true' ) {
|
|
var timeout;
|
|
GUI.Helpers.createDroppable(container, {
|
|
onEnter: onDndEnter,
|
|
onOver: onDndEnter,
|
|
onLeave: onDndLeave,
|
|
onDrop: onDndLeave,
|
|
onItemDropped: function(ev, eel, item) {
|
|
ev.stopPropagation();
|
|
ev.preventDefault();
|
|
timeout = clearTimeout(timeout);
|
|
timeout = setTimeout(function() {
|
|
Utils.$removeClass(sel, 'dnd-over');
|
|
}, 10);
|
|
var dval = {};
|
|
try {
|
|
dval = JSON.parse(eel.parentNode.getAttribute('data-value'));
|
|
} catch ( e ) {}
|
|
el.dispatchEvent(new CustomEvent('_drop', {detail: {
|
|
src: item.data,
|
|
dest: dval
|
|
}}));
|
|
}
|
|
});
|
|
}
|
|
handleItemExpand(null, el, sel, expanded);
|
|
GUI.Elements._dataview.bindEntryEvents(el, sel, 'gui-tree-view-entry');
|
|
}
|
|
GUI.Elements['gui-tree-view'] = {
|
|
bind: GUI.Elements._dataview.bind,
|
|
values: function(el) {
|
|
return GUI.Elements._dataview.getSelected(el, el.querySelectorAll('gui-tree-view-entry'));
|
|
},
|
|
build: function(el, applyArgs) {
|
|
var body = el.querySelector('gui-tree-view-body');
|
|
var found = !!body;
|
|
if ( !body ) {
|
|
body = document.createElement('gui-tree-view-body');
|
|
el.appendChild(body);
|
|
}
|
|
body.setAttribute('role', 'group');
|
|
el.setAttribute('role', 'tree');
|
|
el.setAttribute('aria-multiselectable', body.getAttribute('data-multiselect') || 'false');
|
|
el.querySelectorAll('gui-tree-view-entry').forEach(function(sel, idx) {
|
|
sel.setAttribute('aria-expanded', 'false');
|
|
if ( !found ) {
|
|
body.appendChild(sel);
|
|
}
|
|
sel.setAttribute('role', 'treeitem');
|
|
initEntry(el, sel);
|
|
});
|
|
GUI.Elements._dataview.build(el, applyArgs);
|
|
},
|
|
get: function(el, param, value, arg) {
|
|
if ( param === 'entry' ) {
|
|
var body = el.querySelector('gui-tree-view-body');
|
|
return GUI.Elements._dataview.getEntry(el, body.querySelectorAll('gui-tree-view-entry'), value, arg);
|
|
}
|
|
return GUI.Helpers.getProperty(el, param);
|
|
},
|
|
set: function(el, param, value, arg, arg2) {
|
|
var body = el.querySelector('gui-tree-view-body');
|
|
if ( param === 'selected' || param === 'value' ) {
|
|
GUI.Elements._dataview.setSelected(el, body, body.querySelectorAll('gui-tree-view-entry'), value, arg, arg2);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
call: function(el, method, args) {
|
|
var body = el.querySelector('gui-tree-view-body');
|
|
function recurse(a, root, level) {
|
|
GUI.Elements._dataview.add(el, a, function(e) {
|
|
if ( e ) {
|
|
if ( e.parentNode ) {
|
|
delete e.parentNode;
|
|
}
|
|
var entry = createEntry(e);
|
|
root.appendChild(entry);
|
|
if ( e.entries ) {
|
|
recurse([e.entries], entry, level + 1);
|
|
}
|
|
initEntry(el, entry);
|
|
}
|
|
});
|
|
}
|
|
function add() {
|
|
var parentNode = body;
|
|
var entries = args;
|
|
if ( typeof args[0] === 'object' && !(args[0] instanceof Array) && Object.keys(args[0]).length ) {
|
|
entries = [args[0].entries || []];
|
|
parentNode = args[0].parentNode || body;
|
|
}
|
|
recurse(entries, parentNode, 0);
|
|
}
|
|
if ( method === 'add' ) {
|
|
add();
|
|
} else if ( method === 'remove' ) {
|
|
GUI.Elements._dataview.remove(el, args, 'gui-tree-view-entry');
|
|
} else if ( method === 'clear' ) {
|
|
GUI.Elements._dataview.clear(el, body);
|
|
} else if ( method === 'patch' ) {
|
|
GUI.Elements._dataview.patch(el, args, 'gui-tree-view-entry', body, createEntry, initEntry);
|
|
} else if ( method === 'focus' ) {
|
|
GUI.Elements._dataview.focus(el);
|
|
} else if ( method === 'expand' ) {
|
|
handleItemExpand(args.ev, el, args.entry);
|
|
}
|
|
return this;
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function createFakeHeader(el) {
|
|
function createResizers() {
|
|
var fhead = el.querySelector('gui-list-view-fake-head');
|
|
var head = el.querySelector('gui-list-view-head');
|
|
var fcols = fhead.querySelectorAll('gui-list-view-column');
|
|
var cols = head.querySelectorAll('gui-list-view-column');
|
|
fhead.querySelectorAll('gui-list-view-column-resizer').forEach(function(rel) {
|
|
Utils.$remove(rel);
|
|
});
|
|
cols.forEach(function(col, idx) {
|
|
var attr = col.getAttribute('data-resizable');
|
|
if ( attr === 'true' ) {
|
|
var fcol = fcols[idx];
|
|
var resizer = document.createElement('gui-list-view-column-resizer');
|
|
fcol.appendChild(resizer);
|
|
var startWidth = 0;
|
|
var maxWidth = 0;
|
|
var widthOffset = 16;
|
|
var minWidth = widthOffset;
|
|
var tmpEl = null;
|
|
GUI.Helpers.createDrag(resizer, function(ev) {
|
|
startWidth = col.offsetWidth;
|
|
minWidth = widthOffset;//calculateWidth();
|
|
maxWidth = el.offsetWidth - (el.children.length * widthOffset);
|
|
}, function(ev, diff) {
|
|
var newWidth = startWidth - diff.x;
|
|
if ( !isNaN(newWidth) && newWidth > minWidth && newWidth < maxWidth ) {
|
|
col.style.width = String(newWidth) + 'px';
|
|
fcol.style.width = String(newWidth) + 'px';
|
|
}
|
|
tmpEl = Utils.$remove(tmpEl);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
var fh = el.querySelector('gui-list-view-fake-head gui-list-view-head');
|
|
Utils.$empty(fh);
|
|
var row = el.querySelector('gui-list-view-head gui-list-view-row');
|
|
if ( row ) {
|
|
fh.appendChild(row.cloneNode(true));
|
|
createResizers();
|
|
}
|
|
}
|
|
function initRow(el, row) {
|
|
row.querySelectorAll('gui-list-view-column').forEach(function(cel, idx) {
|
|
var icon = cel.getAttribute('data-icon');
|
|
if ( icon && icon !== 'null' ) {
|
|
Utils.$addClass(cel, 'gui-has-image');
|
|
cel.style.backgroundImage = 'url(' + icon + ')';
|
|
}
|
|
var text = cel.firstChild;
|
|
if ( text && text.nodeType === 3 ) {
|
|
var span = document.createElement('span');
|
|
span.appendChild(document.createTextNode(text.nodeValue));
|
|
cel.insertBefore(span, text);
|
|
cel.removeChild(text);
|
|
}
|
|
if ( el._columns[idx] && !el._columns[idx].visible ) {
|
|
cel.style.display = 'none';
|
|
}
|
|
cel.setAttribute('role', 'listitem');
|
|
});
|
|
GUI.Elements._dataview.bindEntryEvents(el, row, 'gui-list-view-row');
|
|
}
|
|
function createEntry(v, head) {
|
|
var label = v.label || '';
|
|
if ( v.label ) {
|
|
delete v.label;
|
|
}
|
|
var setSize = null;
|
|
if ( v.size ) {
|
|
setSize = v.size;
|
|
delete v.size;
|
|
}
|
|
var nel = GUI.Helpers.createElement('gui-list-view-column', v);
|
|
if ( setSize ) {
|
|
nel.style.width = setSize;
|
|
}
|
|
if ( typeof label === 'function' ) {
|
|
nel.appendChild(label.call(nel, nel, v));
|
|
} else {
|
|
var span = document.createElement('span');
|
|
span.appendChild(document.createTextNode(label));
|
|
nel.appendChild(span);
|
|
}
|
|
return nel;
|
|
}
|
|
function createRow(e) {
|
|
e = e || {};
|
|
if ( e.columns ) {
|
|
var row = GUI.Helpers.createElement('gui-list-view-row', e, ['columns']);
|
|
e.columns.forEach(function(se) {
|
|
row.appendChild(createEntry(se));
|
|
});
|
|
return row;
|
|
}
|
|
return null;
|
|
}
|
|
GUI.Elements['gui-list-view'] = {
|
|
bind: GUI.Elements._dataview.bind,
|
|
values: function(el) {
|
|
var body = el.querySelector('gui-list-view-body');
|
|
return GUI.Elements._dataview.getSelected(el, body.querySelectorAll('gui-list-view-row'));
|
|
},
|
|
get: function(el, param, value, arg, asValue) {
|
|
if ( param === 'entry' ) {
|
|
var body = el.querySelector('gui-list-view-body');
|
|
var rows = body.querySelectorAll('gui-list-view-row');
|
|
return GUI.Elements._dataview.getEntry(el, rows, value, arg, asValue);
|
|
}
|
|
return GUI.Helpers.getProperty(el, param);
|
|
},
|
|
set: function(el, param, value, arg, arg2) {
|
|
if ( param === 'columns' ) {
|
|
var head = el.querySelector('gui-list-view-head');
|
|
var row = document.createElement('gui-list-view-row');
|
|
Utils.$empty(head);
|
|
el._columns = [];
|
|
value.forEach(function(v) {
|
|
v.visible = (typeof v.visible === 'undefined') || v.visible === true;
|
|
var nel = createEntry(v, true);
|
|
el._columns.push(v);
|
|
if ( !v.visible ) {
|
|
nel.style.display = 'none';
|
|
}
|
|
row.appendChild(nel);
|
|
});
|
|
head.appendChild(row);
|
|
createFakeHeader(el);
|
|
return true;
|
|
} else if ( param === 'selected' || param === 'value' ) {
|
|
var body = el.querySelector('gui-list-view-body');
|
|
GUI.Elements._dataview.setSelected(el, body, body.querySelectorAll('gui-list-view-row'), value, arg, arg2);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
call: function(el, method, args) {
|
|
var body = el.querySelector('gui-list-view-body');
|
|
if ( method === 'add' ) {
|
|
GUI.Elements._dataview.add(el, args, function(e) {
|
|
var cbCreated = e.onCreated || function() {};
|
|
var row = createRow(e);
|
|
if ( row ) {
|
|
body.appendChild(row);
|
|
initRow(el, row);
|
|
}
|
|
cbCreated(row);
|
|
});
|
|
} else if ( method === 'remove' ) {
|
|
GUI.Elements._dataview.remove(el, args, 'gui-list-view-row', null, body);
|
|
} else if ( method === 'clear' ) {
|
|
GUI.Elements._dataview.clear(el, el.querySelector('gui-list-view-body'));
|
|
} else if ( method === 'patch' ) {
|
|
GUI.Elements._dataview.patch(el, args, 'gui-list-view-row', body, createRow, initRow);
|
|
} else if ( method === 'focus' ) {
|
|
GUI.Elements._dataview.focus(el);
|
|
}
|
|
return this;
|
|
},
|
|
build: function(el, applyArgs) {
|
|
el._columns = [];
|
|
var inner = el.querySelector('gui-list-view-inner');
|
|
var head = el.querySelector('gui-list-view-head');
|
|
var body = el.querySelector('gui-list-view-body');
|
|
function moveIntoInner(cel) {
|
|
if ( cel.parentNode.tagName !== 'GUI-LIST-VIEW-INNER' ) {
|
|
inner.appendChild(cel);
|
|
}
|
|
}
|
|
var fakeHead = el.querySelector('gui-list-view-fake-head');
|
|
if ( !fakeHead ) {
|
|
fakeHead = document.createElement('gui-list-view-fake-head');
|
|
var fakeHeadInner = document.createElement('gui-list-view-inner');
|
|
fakeHeadInner.appendChild(document.createElement('gui-list-view-head'));
|
|
fakeHead.appendChild(fakeHeadInner);
|
|
}
|
|
if ( !inner ) {
|
|
inner = document.createElement('gui-list-view-inner');
|
|
el.appendChild(inner);
|
|
}
|
|
(function _createBody() {
|
|
if ( body ) {
|
|
moveIntoInner(body);
|
|
} else {
|
|
body = document.createElement('gui-list-view-body');
|
|
inner.appendChild(body);
|
|
}
|
|
body.setAttribute('role', 'group');
|
|
})();
|
|
(function _createHead() {
|
|
if ( head ) {
|
|
moveIntoInner(head);
|
|
} else {
|
|
head = document.createElement('gui-list-view-head');
|
|
inner.insertBefore(head, body);
|
|
}
|
|
head.setAttribute('role', 'group');
|
|
})();
|
|
el.setAttribute('role', 'list');
|
|
el.appendChild(fakeHead);
|
|
Utils.$bind(el, 'scroll', function(ev) {
|
|
fakeHead.style.top = el.scrollTop + 'px';
|
|
}, false);
|
|
var hcols = el.querySelectorAll('gui-list-view-head gui-list-view-column');
|
|
hcols.forEach(function(cel, idx) {
|
|
var vis = cel.getAttribute('data-visible');
|
|
var iter = {
|
|
visible: vis === null || vis === 'true',
|
|
size: cel.getAttribute('data-size')
|
|
};
|
|
if ( iter.size ) {
|
|
cel.style.width = iter.size;
|
|
}
|
|
el._columns.push(iter);
|
|
if ( !iter.visible ) {
|
|
cel.style.display = 'none';
|
|
}
|
|
});
|
|
createFakeHeader(el);
|
|
el.querySelectorAll('gui-list-view-body gui-list-view-row').forEach(function(row) {
|
|
initRow(el, row);
|
|
});
|
|
GUI.Elements._dataview.build(el, applyArgs);
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function createEntry(e) {
|
|
var entry = GUI.Helpers.createElement('gui-icon-view-entry', e);
|
|
return entry;
|
|
}
|
|
function initEntry(el, cel) {
|
|
var icon = cel.getAttribute('data-icon');
|
|
var label = GUI.Helpers.getLabel(cel);
|
|
var dicon = document.createElement('div');
|
|
var dimg = document.createElement('img');
|
|
dimg.src = icon;
|
|
dicon.appendChild(dimg);
|
|
var dlabel = document.createElement('div');
|
|
var dspan = document.createElement('span');
|
|
dspan.appendChild(document.createTextNode(label));
|
|
dlabel.appendChild(dspan);
|
|
GUI.Elements._dataview.bindEntryEvents(el, cel, 'gui-icon-view-entry');
|
|
cel.setAttribute('role', 'listitem');
|
|
cel.appendChild(dicon);
|
|
cel.appendChild(dlabel);
|
|
}
|
|
GUI.Elements['gui-icon-view'] = {
|
|
bind: GUI.Elements._dataview.bind,
|
|
values: function(el) {
|
|
return GUI.Elements._dataview.getSelected(el, el.querySelectorAll('gui-icon-view-entry'));
|
|
},
|
|
build: function(el, applyArgs) {
|
|
var body = el.querySelector('gui-icon-view-body');
|
|
var found = !!body;
|
|
if ( !body ) {
|
|
body = document.createElement('gui-icon-view-body');
|
|
el.appendChild(body);
|
|
}
|
|
el.querySelectorAll('gui-icon-view-entry').forEach(function(cel, idx) {
|
|
if ( !found ) {
|
|
body.appendChild(cel);
|
|
}
|
|
initEntry(el, cel);
|
|
});
|
|
el.setAttribute('role', 'list');
|
|
GUI.Elements._dataview.build(el, applyArgs);
|
|
},
|
|
get: function(el, param, value, arg, asValue) {
|
|
if ( param === 'entry' ) {
|
|
var body = el.querySelector('gui-icon-view-body');
|
|
var rows = body.querySelectorAll('gui-icon-view-entry');
|
|
return GUI.Elements._dataview.getEntry(el, rows, value, arg, asValue);
|
|
}
|
|
return GUI.Helpers.getProperty(el, param);
|
|
},
|
|
set: function(el, param, value, arg) {
|
|
var body = el.querySelector('gui-icon-view-body');
|
|
if ( param === 'selected' || param === 'value' ) {
|
|
GUI.Elements._dataview.setSelected(el, body, body.querySelectorAll('gui-icon-view-entry'), value, arg);
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
call: function(el, method, args) {
|
|
var body = el.querySelector('gui-icon-view-body');
|
|
if ( method === 'add' ) {
|
|
GUI.Elements._dataview.add(el, args, function(e) {
|
|
var entry = createEntry(e);
|
|
body.appendChild(entry);
|
|
initEntry(el, entry);
|
|
});
|
|
} else if ( method === 'remove' ) {
|
|
GUI.Elements._dataview.remove(el, args, 'gui-icon-view-entry');
|
|
} else if ( method === 'clear' ) {
|
|
GUI.Elements._dataview.clear(el, body);
|
|
} else if ( method === 'patch' ) {
|
|
GUI.Elements._dataview.patch(el, args, 'gui-icon-view-entry', body, createEntry, initEntry);
|
|
} else if ( method === 'focus' ) {
|
|
GUI.Elements._dataview.focus(el);
|
|
}
|
|
return this;
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
function getDocument(el, iframe) {
|
|
iframe = iframe || el.querySelector('iframe');
|
|
return iframe.contentDocument || iframe.contentWindow.document;
|
|
}
|
|
function getDocumentData(el) {
|
|
try {
|
|
var doc = getDocument(el);
|
|
return doc.body.innerHTML;
|
|
} catch ( error ) {
|
|
console.error('gui-richtext', 'getDocumentData()', error.stack, error);
|
|
}
|
|
return '';
|
|
}
|
|
function destroyFixInterval(el) {
|
|
el._fixTry = 0;
|
|
el._fixInterval = clearInterval(el._fixInterval);
|
|
}
|
|
function createFixInterval(el, doc, text) {
|
|
if ( el._fixTry > 10 ) {
|
|
el._fixTry = 0;
|
|
return;
|
|
}
|
|
el._fixInterval = setInterval(function() {
|
|
try {
|
|
if ( text ) {
|
|
doc.body.innerHTML = text;
|
|
}
|
|
destroyFixInterval(el);
|
|
} catch ( error ) {
|
|
console.warn('gui-richtext', 'setDocumentData()', error.stack, error, '... trying again');
|
|
}
|
|
el._fixTry++;
|
|
}, 100);
|
|
}
|
|
function setDocumentData(el, text) {
|
|
destroyFixInterval(el);
|
|
text = text || '';
|
|
var wm = OSjs.Core.getWindowManager();
|
|
var theme = (wm ? wm.getSetting('theme') : 'default') || 'default';
|
|
var themeSrc = OSjs.API.getThemeCSS(theme);
|
|
var editable = el.getAttribute('data-editable');
|
|
editable = editable === null || editable === 'true';
|
|
function onMouseDown(ev) {
|
|
function insertTextAtCursor(text) {
|
|
var sel, range;
|
|
if (window.getSelection) {
|
|
sel = window.getSelection();
|
|
if (sel.getRangeAt && sel.rangeCount) {
|
|
range = sel.getRangeAt(0);
|
|
range.deleteContents();
|
|
range.insertNode( document.createTextNode(text) );
|
|
}
|
|
} else if (document.selection && document.selection.createRange) {
|
|
document.selection.createRange().text = text;
|
|
}
|
|
}
|
|
if ( ev.keyCode === 9 ) {
|
|
insertTextAtCursor('\u00A0');
|
|
ev.preventDefault();
|
|
}
|
|
}
|
|
var script = onMouseDown.toString() + ';window.addEventListener("keydown", onMouseDown)';
|
|
var template = '<!DOCTYPE html><html><head><link rel="stylesheet" type="text/css" href="' + themeSrc + '" /><script>' + script + '</script></head><body contentEditable="true"></body></html>';
|
|
if ( !editable ) {
|
|
template = template.replace(' contentEditable="true"', '');
|
|
}
|
|
var doc = getDocument(el);
|
|
doc.open();
|
|
doc.write(template);
|
|
doc.close();
|
|
createFixInterval(el, doc, text);
|
|
}
|
|
GUI.Elements['gui-richtext'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( (['selection']).indexOf(evName) !== -1 ) {
|
|
evName = '_' + evName;
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var text = el.childNodes.length ? el.childNodes[0].nodeValue : '';
|
|
Utils.$empty(el);
|
|
var iframe = document.createElement('iframe');
|
|
iframe.setAttribute('border', 0);
|
|
iframe.onload = function() {
|
|
iframe.contentWindow.addEventListener('selectstart', function() {
|
|
el.dispatchEvent(new CustomEvent('_selection', {detail: {}}));
|
|
});
|
|
iframe.contentWindow.addEventListener('mouseup', function() {
|
|
el.dispatchEvent(new CustomEvent('_selection', {detail: {}}));
|
|
});
|
|
};
|
|
el.appendChild(iframe);
|
|
setTimeout(function() {
|
|
try {
|
|
setDocumentData(el, text);
|
|
} catch ( e ) {
|
|
console.warn('gui-richtext', 'build()', e);
|
|
}
|
|
}, 1);
|
|
},
|
|
call: function(el, method, args) {
|
|
var doc = getDocument(el);
|
|
try {
|
|
if ( method === 'command' ) {
|
|
if ( doc && doc.execCommand ) {
|
|
return doc.execCommand.apply(doc, args);
|
|
}
|
|
} else if ( method === 'query' ) {
|
|
if ( doc && doc.queryCommandValue ) {
|
|
return doc.queryCommandValue.apply(doc, args);
|
|
}
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('gui-richtext call() warning', e.stack, e);
|
|
}
|
|
return null;
|
|
},
|
|
get: function(el, param, value) {
|
|
if ( param === 'value' ) {
|
|
return getDocumentData(el);
|
|
}
|
|
return GUI.Helpers.getProperty(el, param);
|
|
},
|
|
set: function(el, param, value) {
|
|
if ( param === 'value' ) {
|
|
setDocumentData(el, value);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
};
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, VFS, GUI) {
|
|
'use strict';
|
|
GUI.Elements['gui-paned-view'] = {
|
|
bind: function(el, evName, callback, params) {
|
|
if ( evName === 'resize' ) {
|
|
evName = '_' + evName;
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var orient = el.getAttribute('data-orientation') || 'horizontal';
|
|
function bindResizer(resizer, idx, cel) {
|
|
var resizeEl = resizer.previousElementSibling;
|
|
if ( !resizeEl ) {
|
|
return;
|
|
}
|
|
var startWidth = resizeEl.offsetWidth;
|
|
var startHeight = resizeEl.offsetHeight;
|
|
var minSize = 16;
|
|
var maxSize = Number.MAX_VALUE;
|
|
GUI.Helpers.createDrag(resizer, function(ev) {
|
|
startWidth = resizeEl.offsetWidth;
|
|
startHeight = resizeEl.offsetHeight;
|
|
minSize = parseInt(cel.getAttribute('data-min-size'), 10) || minSize;
|
|
var max = parseInt(cel.getAttribute('data-max-size'), 10);
|
|
if ( !max ) {
|
|
var totalHeight = resizer.parentNode.offsetHeight;
|
|
var totalContainers = resizer.parentNode.querySelectorAll('gui-paned-view-container').length;
|
|
var totalSpacers = resizer.parentNode.querySelectorAll('gui-paned-view-handle').length;
|
|
maxSize = totalHeight - (totalContainers * 16) - (totalSpacers * 8);
|
|
}
|
|
}, function(ev, diff) {
|
|
var newWidth = startWidth + diff.x;
|
|
var newHeight = startHeight + diff.y;
|
|
var flex;
|
|
if ( orient === 'horizontal' ) {
|
|
if ( !isNaN(newWidth) && newWidth > 0 && newWidth >= minSize && newWidth <= maxSize ) {
|
|
flex = newWidth.toString() + 'px';
|
|
}
|
|
} else {
|
|
if ( !isNaN(newHeight) && newHeight > 0 && newHeight >= minSize && newHeight <= maxSize ) {
|
|
flex = newHeight.toString() + 'px';
|
|
}
|
|
}
|
|
if ( flex ) {
|
|
resizeEl.style.webkitFlexBasis = flex;
|
|
resizeEl.style.mozFflexBasis = flex;
|
|
resizeEl.style.msFflexBasis = flex;
|
|
resizeEl.style.oFlexBasis = flex;
|
|
resizeEl.style.flexBasis = flex;
|
|
}
|
|
}, function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_resize', {detail: {index: idx}}));
|
|
});
|
|
}
|
|
el.querySelectorAll('gui-paned-view-container').forEach(function(cel, idx) {
|
|
if ( idx % 2 ) {
|
|
var resizer = document.createElement('gui-paned-view-handle');
|
|
resizer.setAttribute('role', 'separator');
|
|
cel.parentNode.insertBefore(resizer, cel);
|
|
bindResizer(resizer, idx, cel);
|
|
}
|
|
});
|
|
}
|
|
};
|
|
GUI.Elements['gui-paned-view-container'] = {
|
|
build: function(el) {
|
|
GUI.Helpers.setFlexbox(el);
|
|
}
|
|
};
|
|
GUI.Elements['gui-button-bar'] = {
|
|
build: function(el) {
|
|
el.setAttribute('role', 'toolbar');
|
|
}
|
|
};
|
|
GUI.Elements['gui-toolbar'] = {
|
|
build: function(el) {
|
|
el.setAttribute('role', 'toolbar');
|
|
}
|
|
};
|
|
GUI.Elements['gui-grid'] = {
|
|
build: function(el) {
|
|
var rows = el.querySelectorAll('gui-grid-row');
|
|
var p = 100 / rows.length;
|
|
rows.forEach(function(r) {
|
|
r.style.height = String(p) + '%';
|
|
});
|
|
}
|
|
};
|
|
GUI.Elements['gui-grid-row'] = {
|
|
build: function(el) {
|
|
}
|
|
};
|
|
GUI.Elements['gui-grid-entry'] = {
|
|
build: function(el) {
|
|
}
|
|
};
|
|
GUI.Elements['gui-vbox'] = {
|
|
build: function(el) {
|
|
}
|
|
};
|
|
GUI.Elements['gui-vbox-container'] = {
|
|
build: function(el) {
|
|
GUI.Helpers.setFlexbox(el);
|
|
}
|
|
};
|
|
GUI.Elements['gui-hbox'] = {
|
|
build: function(el) {
|
|
}
|
|
};
|
|
GUI.Elements['gui-hbox-container'] = {
|
|
build: function(el) {
|
|
GUI.Helpers.setFlexbox(el);
|
|
}
|
|
};
|
|
GUI.Elements['gui-expander'] = (function() {
|
|
function toggleState(el, expanded) {
|
|
if ( typeof expanded === 'undefined' ) {
|
|
expanded = el.getAttribute('data-expanded') !== 'false';
|
|
expanded = !expanded;
|
|
}
|
|
el.setAttribute('aria-expanded', String(expanded));
|
|
el.setAttribute('data-expanded', String(expanded));
|
|
return expanded;
|
|
}
|
|
return {
|
|
set: function(el, param, value) {
|
|
if ( param === 'expanded' ) {
|
|
return toggleState(el, value === true);
|
|
}
|
|
return null;
|
|
},
|
|
bind: function(el, evName, callback, params) {
|
|
if ( (['change']).indexOf(evName) !== -1 ) {
|
|
evName = '_' + evName;
|
|
}
|
|
Utils.$bind(el, evName, callback.bind(new GUI.Element(el)), params);
|
|
},
|
|
build: function(el) {
|
|
var lbltxt = el.getAttribute('data-label') || '';
|
|
var label = document.createElement('gui-expander-label');
|
|
Utils.$bind(label, 'click', function(ev) {
|
|
el.dispatchEvent(new CustomEvent('_change', {detail: {expanded: toggleState(el)}}));
|
|
}, false);
|
|
label.appendChild(document.createTextNode(lbltxt));
|
|
el.setAttribute('role', 'toolbar');
|
|
el.setAttribute('aria-expanded', 'true');
|
|
el.setAttribute('data-expanded', 'true');
|
|
if ( el.children.length ) {
|
|
el.insertBefore(label, el.children[0]);
|
|
} else {
|
|
el.appendChild(label);
|
|
}
|
|
}
|
|
};
|
|
})();
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function AlertDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
DialogWindow.apply(this, ['AlertDialog', {
|
|
title: args.title || API._('DIALOG_ALERT_TITLE'),
|
|
icon: 'status/dialog-warning.png',
|
|
width: 400,
|
|
height: 100
|
|
}, args, callback]);
|
|
}
|
|
AlertDialog.prototype = Object.create(DialogWindow.prototype);
|
|
AlertDialog.constructor = DialogWindow;
|
|
AlertDialog.prototype.init = function() {
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
root.setAttribute('role', 'alertdialog');
|
|
this.scheme.find(this, 'Message').set('value', this.args.message, true);
|
|
return root;
|
|
};
|
|
OSjs.Dialogs.Alert = Object.seal(AlertDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function ApplicationChooserDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
DialogWindow.apply(this, ['ApplicationChooserDialog', {
|
|
title: args.title || API._('DIALOG_APPCHOOSER_TITLE'),
|
|
width: 400,
|
|
height: 400
|
|
}, args, callback]);
|
|
}
|
|
ApplicationChooserDialog.prototype = Object.create(DialogWindow.prototype);
|
|
ApplicationChooserDialog.constructor = DialogWindow;
|
|
ApplicationChooserDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var cols = [{label: API._('LBL_NAME')}];
|
|
var rows = [];
|
|
var metadata = OSjs.Core.getPackageManager().getPackages();
|
|
(this.args.list || []).forEach(function(name) {
|
|
var iter = metadata[name];
|
|
if ( iter && iter.type === 'application' ) {
|
|
var label = [iter.name];
|
|
if ( iter.description ) {
|
|
label.push(iter.description);
|
|
}
|
|
rows.push({
|
|
value: iter,
|
|
columns: [
|
|
{label: label.join(' - '), icon: API.getIcon(iter.icon, null, name), value: JSON.stringify(iter)}
|
|
]
|
|
});
|
|
}
|
|
});
|
|
this.scheme.find(this, 'ApplicationList').set('columns', cols).add(rows).on('activate', function(ev) {
|
|
self.onClose(ev, 'ok');
|
|
});
|
|
var file = '<unknown file>';
|
|
var label = '<unknown mime>';
|
|
if ( this.args.file ) {
|
|
file = Utils.format('{0} ({1})', this.args.file.filename, this.args.file.mime);
|
|
label = API._('DIALOG_APPCHOOSER_SET_DEFAULT', this.args.file.mime);
|
|
}
|
|
this.scheme.find(this, 'FileName').set('value', file);
|
|
this.scheme.find(this, 'SetDefault').set('label', label);
|
|
return root;
|
|
};
|
|
ApplicationChooserDialog.prototype.onClose = function(ev, button) {
|
|
var result = null;
|
|
if ( button === 'ok' ) {
|
|
var useDefault = this.scheme.find(this, 'SetDefault').get('value');
|
|
var selected = this.scheme.find(this, 'ApplicationList').get('value');
|
|
if ( selected && selected.length ) {
|
|
result = selected[0].data.className;
|
|
}
|
|
if ( !result ) {
|
|
OSjs.API.createDialog('Alert', {
|
|
message: API._('DIALOG_APPCHOOSER_NO_SELECTION')
|
|
}, null, this);
|
|
return;
|
|
}
|
|
result = {
|
|
name: result,
|
|
useDefault: useDefault
|
|
};
|
|
}
|
|
this.closeCallback(ev, button, result);
|
|
};
|
|
OSjs.Dialogs.ApplicationChooser = Object.seal(ApplicationChooserDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function ColorDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {
|
|
});
|
|
var rgb = args.color;
|
|
var hex = rgb;
|
|
if ( typeof rgb === 'string' ) {
|
|
hex = rgb;
|
|
rgb = Utils.convertToRGB(rgb);
|
|
rgb.a = null;
|
|
} else {
|
|
if ( typeof rgb.a === 'undefined' ) {
|
|
rgb.a = null;
|
|
} else {
|
|
if ( rgb.a > 1.0 ) {
|
|
rgb.a /= 100;
|
|
}
|
|
}
|
|
rgb = rgb || {r: 0, g: 0, b: 0, a: 100};
|
|
hex = Utils.convertToHEX(rgb.r, rgb.g, rgb.b);
|
|
}
|
|
DialogWindow.apply(this, ['ColorDialog', {
|
|
title: args.title || API._('DIALOG_COLOR_TITLE'),
|
|
icon: 'apps/gnome-settings-theme.png',
|
|
width: 400,
|
|
height: rgb.a !== null ? 300 : 220
|
|
}, args, callback]);
|
|
this.color = {r: rgb.r, g: rgb.g, b: rgb.b, a: rgb.a, hex: hex};
|
|
}
|
|
ColorDialog.prototype = Object.create(DialogWindow.prototype);
|
|
ColorDialog.constructor = DialogWindow;
|
|
ColorDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
function updateHex(update) {
|
|
self.scheme.find(self, 'LabelRed').set('value', API._('DIALOG_COLOR_R', self.color.r));
|
|
self.scheme.find(self, 'LabelGreen').set('value', API._('DIALOG_COLOR_G', self.color.g));
|
|
self.scheme.find(self, 'LabelBlue').set('value', API._('DIALOG_COLOR_B', self.color.b));
|
|
self.scheme.find(self, 'LabelAlpha').set('value', API._('DIALOG_COLOR_A', self.color.a));
|
|
if ( update ) {
|
|
self.color.hex = Utils.convertToHEX(self.color.r, self.color.g, self.color.b);
|
|
}
|
|
var value = self.color.hex;
|
|
if ( self.color.a !== null && !isNaN(self.color.a) ) {
|
|
value = Utils.format('rgba({0}, {1}, {2}, {3})', self.color.r, self.color.g, self.color.b, self.color.a);
|
|
}
|
|
self.scheme.find(self, 'ColorPreview').set('value', value);
|
|
}
|
|
this.scheme.find(this, 'ColorSelect').on('change', function(ev) {
|
|
self.color = ev.detail;
|
|
self.scheme.find(self, 'Red').set('value', self.color.r);
|
|
self.scheme.find(self, 'Green').set('value', self.color.g);
|
|
self.scheme.find(self, 'Blue').set('value', self.color.b);
|
|
updateHex(true);
|
|
});
|
|
this.scheme.find(this, 'Red').on('change', function(ev) {
|
|
self.color.r = parseInt(ev.detail, 10);
|
|
updateHex(true);
|
|
}).set('value', this.color.r);
|
|
this.scheme.find(this, 'Green').on('change', function(ev) {
|
|
self.color.g = parseInt(ev.detail, 10);
|
|
updateHex(true);
|
|
}).set('value', this.color.g);
|
|
this.scheme.find(this, 'Blue').on('change', function(ev) {
|
|
self.color.b = parseInt(ev.detail, 10);
|
|
updateHex(true);
|
|
}).set('value', this.color.b);
|
|
this.scheme.find(this, 'Alpha').on('change', function(ev) {
|
|
self.color.a = parseInt(ev.detail, 10) / 100;
|
|
updateHex(true);
|
|
}).set('value', this.color.a * 100);
|
|
if ( this.color.a === null ) {
|
|
this.scheme.find(this, 'AlphaContainer').hide();
|
|
this.scheme.find(this, 'AlphaLabelContainer').hide();
|
|
}
|
|
updateHex(false, this.color.a !== null);
|
|
return root;
|
|
};
|
|
ColorDialog.prototype.onClose = function(ev, button) {
|
|
this.closeCallback(ev, button, button === 'ok' ? this.color : null);
|
|
};
|
|
OSjs.Dialogs.Color = Object.seal(ColorDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function ConfirmDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {
|
|
buttons: ['yes', 'no', 'cancel']
|
|
});
|
|
DialogWindow.apply(this, ['ConfirmDialog', {
|
|
title: args.title || API._('DIALOG_CONFIRM_TITLE'),
|
|
icon: 'status/dialog-question.png',
|
|
width: 400,
|
|
height: 100
|
|
}, args, callback]);
|
|
}
|
|
ConfirmDialog.prototype = Object.create(DialogWindow.prototype);
|
|
ConfirmDialog.constructor = DialogWindow;
|
|
ConfirmDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var msg = DialogWindow.parseMessage(this.args.message);
|
|
this.scheme.find(this, 'Message').empty().append(msg);
|
|
var buttonMap = {
|
|
yes: 'ButtonYes',
|
|
no: 'ButtonNo',
|
|
cancel: 'ButtonCancel'
|
|
};
|
|
var hide = [];
|
|
(['yes', 'no', 'cancel']).forEach(function(b) {
|
|
if ( self.args.buttons.indexOf(b) < 0 ) {
|
|
hide.push(b);
|
|
}
|
|
});
|
|
hide.forEach(function(b) {
|
|
self.scheme.find(self, buttonMap[b]).hide();
|
|
});
|
|
return root;
|
|
};
|
|
OSjs.Dialogs.Confirm = Object.seal(ConfirmDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function ErrorDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
console.error('ErrorDialog::constructor()', args);
|
|
var exception = args.exception || {};
|
|
var error = '';
|
|
if ( exception.stack ) {
|
|
error = exception.stack;
|
|
} else {
|
|
if ( Object.keys(exception).length ) {
|
|
error = exception.name;
|
|
error += '\nFilename: ' + exception.fileName || '<unknown>';
|
|
error += '\nLine: ' + exception.lineNumber;
|
|
error += '\nMessage: ' + exception.message;
|
|
if ( exception.extMessage ) {
|
|
error += '\n' + exception.extMessage;
|
|
}
|
|
}
|
|
}
|
|
DialogWindow.apply(this, ['ErrorDialog', {
|
|
title: args.title || API._('DIALOG_CONFIRM_TITLE'),
|
|
icon: 'status/dialog-error.png',
|
|
width: 400,
|
|
height: error ? 400 : 200
|
|
}, args, callback]);
|
|
this._sound = 'ERROR';
|
|
this._soundVolume = 1.0;
|
|
this.traceMessage = error;
|
|
}
|
|
ErrorDialog.prototype = Object.create(DialogWindow.prototype);
|
|
ErrorDialog.constructor = DialogWindow;
|
|
ErrorDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
root.setAttribute('role', 'alertdialog');
|
|
var msg = DialogWindow.parseMessage(this.args.message);
|
|
this.scheme.find(this, 'Message').empty().append(msg);
|
|
this.scheme.find(this, 'Summary').set('value', this.args.error);
|
|
this.scheme.find(this, 'Trace').set('value', this.traceMessage);
|
|
if ( !this.traceMessage ) {
|
|
this.scheme.find(this, 'Trace').hide();
|
|
this.scheme.find(this, 'TraceLabel').hide();
|
|
}
|
|
if ( this.args.bugreport ) {
|
|
this.scheme.find(this, 'ButtonBugReport').on('click', function() {
|
|
var title = '';
|
|
var body = [];
|
|
if ( API.getConfig('BugReporting.options.issue') ) {
|
|
var obj = {};
|
|
var keys = ['userAgent', 'platform', 'language', 'appVersion'];
|
|
keys.forEach(function(k) {
|
|
obj[k] = navigator[k];
|
|
});
|
|
title = API.getConfig('BugReporting.options.title');
|
|
body = [
|
|
'**' + API.getConfig('BugReporting.options.message') + ':**',
|
|
'\n',
|
|
'> ' + self.args.message,
|
|
'\n',
|
|
'> ' + (self.args.error || 'Unknown error'),
|
|
'\n',
|
|
'## Expected behaviour',
|
|
'\n',
|
|
'## Actual behaviour',
|
|
'\n',
|
|
'## Steps to reproduce the error',
|
|
'\n',
|
|
'## (Optinal) Browser and OS information',
|
|
'\n',
|
|
'```\n' + JSON.stringify(obj) + '\n```'
|
|
];
|
|
if ( self.traceMessage ) {
|
|
body.push('\n## Stack Trace \n```\n' + self.traceMessage + '\n```\n');
|
|
}
|
|
}
|
|
var url = API.getConfig('BugReporting.url')
|
|
.replace('%TITLE%', encodeURIComponent(title))
|
|
.replace('%BODY%', encodeURIComponent(body.join('\n')));
|
|
window.open(url);
|
|
});
|
|
} else {
|
|
this.scheme.find(this, 'ButtonBugReport').hide();
|
|
}
|
|
return root;
|
|
};
|
|
OSjs.Dialogs.Error = Object.seal(ErrorDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, VFS, Utils, DialogWindow) {
|
|
'use strict';
|
|
function FileDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {
|
|
file: null,
|
|
type: 'open',
|
|
path: OSjs.API.getDefaultPath(),
|
|
filename: '',
|
|
filetypes: [],
|
|
extension: '',
|
|
mime: 'application/octet-stream',
|
|
filter: [],
|
|
mfilter: [],
|
|
select: null,
|
|
multiple: false
|
|
});
|
|
args.multiple = (args.type === 'save' ? false : args.multiple === true);
|
|
if ( args.path && args.path instanceof VFS.File ) {
|
|
args.path = Utils.dirname(args.path.path);
|
|
}
|
|
if ( args.file && args.file.path ) {
|
|
args.path = Utils.dirname(args.file.path);
|
|
args.filename = args.file.filename;
|
|
args.mime = args.file.mime;
|
|
if ( args.filetypes.length ) {
|
|
var setTo = args.filetypes[0];
|
|
args.filename = Utils.replaceFileExtension(args.filename, setTo.extension);
|
|
args.mime = setTo.mime;
|
|
}
|
|
}
|
|
var title = API._(args.type === 'save' ? 'DIALOG_FILE_SAVE' : 'DIALOG_FILE_OPEN');
|
|
var icon = args.type === 'open' ? 'actions/gtk-open.png' : 'actions/gtk-save-as.png';
|
|
DialogWindow.apply(this, ['FileDialog', {
|
|
title: title,
|
|
icon: icon,
|
|
width: 600,
|
|
height: 400
|
|
}, args, callback]);
|
|
this.selected = null;
|
|
this.path = args.path;
|
|
var self = this;
|
|
this.settingsWatch = OSjs.Core.getSettingsManager().watch('VFS', function() {
|
|
self.changePath();
|
|
});
|
|
}
|
|
FileDialog.prototype = Object.create(DialogWindow.prototype);
|
|
FileDialog.constructor = DialogWindow;
|
|
FileDialog.prototype.destroy = function() {
|
|
try {
|
|
OSjs.Core.getSettingsManager().unwatch(this.settingsWatch);
|
|
} catch ( e ) {}
|
|
return DialogWindow.prototype.destroy.apply(this, arguments);
|
|
};
|
|
FileDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var view = this.scheme.find(this, 'FileView');
|
|
view.set('filter', this.args.filter);
|
|
view.set('filetype', this.args.select || '');
|
|
view.set('defaultcolumns', 'true');
|
|
var filename = this.scheme.find(this, 'Filename');
|
|
var home = this.scheme.find(this, 'HomeButton');
|
|
var mlist = this.scheme.find(this, 'ModuleSelect');
|
|
function checkEmptyInput() {
|
|
var disable = false;
|
|
if ( self.args.select !== 'dir' ) {
|
|
disable = !filename.get('value').length;
|
|
}
|
|
self.scheme.find(self, 'ButtonOK').set('disabled', disable);
|
|
}
|
|
this._toggleLoading(true);
|
|
view.set('multiple', this.args.multiple);
|
|
filename.set('value', this.args.filename || '');
|
|
home.on('click', function() {
|
|
var dpath = API.getDefaultPath();
|
|
self.changePath(dpath);
|
|
});
|
|
view.on('activate', function(ev) {
|
|
self.selected = null;
|
|
if ( self.args.type !== 'save' ) {
|
|
filename.set('value', '');
|
|
}
|
|
if ( ev && ev.detail && ev.detail.entries ) {
|
|
var activated = ev.detail.entries[0];
|
|
if ( activated ) {
|
|
self.selected = new VFS.File(activated.data);
|
|
if ( self.selected.type !== 'dir' ) {
|
|
filename.set('value', self.selected.filename);
|
|
}
|
|
self.checkSelection(ev, true);
|
|
}
|
|
}
|
|
});
|
|
view.on('select', function(ev) {
|
|
self.selected = null;
|
|
if ( ev && ev.detail && ev.detail.entries ) {
|
|
var activated = ev.detail.entries[0];
|
|
if ( activated ) {
|
|
self.selected = new VFS.File(activated.data);
|
|
if ( self.selected.type !== 'dir' ) {
|
|
filename.set('value', self.selected.filename);
|
|
}
|
|
}
|
|
}
|
|
checkEmptyInput();
|
|
});
|
|
if ( this.args.type === 'save' ) {
|
|
var filetypes = [];
|
|
this.args.filetypes.forEach(function(f) {
|
|
filetypes.push({
|
|
label: Utils.format('{0} (.{1} {2})', f.label, f.extension, f.mime),
|
|
value: f.extension
|
|
});
|
|
});
|
|
var ft = this.scheme.find(this, 'Filetype').add(filetypes).on('change', function(ev) {
|
|
var newinput = Utils.replaceFileExtension(filename.get('value'), ev.detail);
|
|
filename.set('value', newinput);
|
|
});
|
|
if ( filetypes.length <= 1 ) {
|
|
new OSjs.GUI.Element(ft.$element.parentNode).hide();
|
|
}
|
|
filename.on('enter', function(ev) {
|
|
self.selected = null;
|
|
self.checkSelection(ev);
|
|
});
|
|
filename.on('change', function(ev) {
|
|
checkEmptyInput();
|
|
});
|
|
filename.on('keyup', function(ev) {
|
|
checkEmptyInput();
|
|
});
|
|
} else {
|
|
this.scheme.find(this, 'FileInput').hide();
|
|
}
|
|
var mm = OSjs.Core.getMountManager();
|
|
var rootPath = mm.getRootFromPath(this.path);
|
|
var modules = mm.getModules().filter(function(m) {
|
|
if ( self.args.mfilter.length ) {
|
|
var success = false;
|
|
self.args.mfilter.forEach(function(fn) {
|
|
if ( !success ) {
|
|
success = fn(m);
|
|
}
|
|
});
|
|
return success;
|
|
}
|
|
return true;
|
|
}).map(function(m) {
|
|
return {
|
|
label: m.name + (m.module.readOnly ? Utils.format(' ({0})', API._('LBL_READONLY')) : ''),
|
|
value: m.module.root
|
|
};
|
|
});
|
|
mlist.clear().add(modules).set('value', rootPath);
|
|
mlist.on('change', function(ev) {
|
|
self.changePath(ev.detail, true);
|
|
});
|
|
this.changePath();
|
|
checkEmptyInput();
|
|
return root;
|
|
};
|
|
FileDialog.prototype.changePath = function(dir, fromDropdown) {
|
|
var self = this;
|
|
var view = this.scheme.find(this, 'FileView');
|
|
var lastDir = this.path;
|
|
function resetLastSelected() {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var rootPath = mm.getRootFromPath(lastDir);
|
|
try {
|
|
self.scheme.find(self, 'ModuleSelect').set('value', rootPath);
|
|
} catch ( e ) {
|
|
console.warn('FileDialog::changePath()', 'resetLastSelection()', e);
|
|
}
|
|
}
|
|
this._toggleLoading(true);
|
|
view._call('chdir', {
|
|
path: dir || this.path,
|
|
done: function(error) {
|
|
if ( error ) {
|
|
if ( fromDropdown ) {
|
|
resetLastSelected();
|
|
}
|
|
} else {
|
|
if ( dir ) {
|
|
self.path = dir;
|
|
}
|
|
}
|
|
self.selected = null;
|
|
self._toggleLoading(false);
|
|
}
|
|
});
|
|
};
|
|
FileDialog.prototype.checkFileExtension = function() {
|
|
var filename = this.scheme.find(this, 'Filename');
|
|
var mime = this.args.mime;
|
|
var input = filename.get('value');
|
|
if ( this.args.filetypes.length ) {
|
|
if ( !input && this.args.filename ) {
|
|
input = this.args.filename;
|
|
}
|
|
if ( input.length ) {
|
|
var extension = input.split('.').pop();
|
|
var found = false;
|
|
this.args.filetypes.forEach(function(f) {
|
|
if ( f.extension === extension ) {
|
|
found = f;
|
|
}
|
|
return !!found;
|
|
});
|
|
found = found || this.args.filetypes[0];
|
|
input = Utils.replaceFileExtension(input, found.extension);
|
|
mime = found.mime;
|
|
}
|
|
}
|
|
return {
|
|
filename: input,
|
|
mime: mime
|
|
};
|
|
};
|
|
FileDialog.prototype.checkSelection = function(ev, wasActivated) {
|
|
var self = this;
|
|
if ( this.selected && this.selected.type === 'dir' ) {
|
|
if ( wasActivated ) {
|
|
this.changePath(this.selected.path);
|
|
return false;
|
|
}
|
|
}
|
|
if ( this.args.type === 'save' ) {
|
|
var check = this.checkFileExtension();
|
|
if ( !this.path || !check.filename ) {
|
|
API.error(API._('DIALOG_FILE_ERROR'), API._('DIALOG_FILE_MISSING_FILENAME'));
|
|
return;
|
|
}
|
|
this.selected = new VFS.File(this.path.replace(/^\//, '') + '/' + check.filename, check.mime);
|
|
this._toggleDisabled(true);
|
|
VFS.exists(this.selected, function(error, result) {
|
|
self._toggleDisabled(false);
|
|
if ( self._destroyed ) {
|
|
return;
|
|
}
|
|
if ( error ) {
|
|
API.error(API._('DIALOG_FILE_ERROR'), API._('DIALOG_FILE_MISSING_FILENAME'));
|
|
} else {
|
|
if ( result ) {
|
|
self._toggleDisabled(true);
|
|
if ( self.selected ) {
|
|
API.createDialog('Confirm', {
|
|
buttons: ['yes', 'no'],
|
|
message: API._('DIALOG_FILE_OVERWRITE', self.selected.filename)
|
|
}, function(ev, button) {
|
|
self._toggleDisabled(false);
|
|
if ( button === 'yes' || button === 'ok' ) {
|
|
self.closeCallback(ev, 'ok', self.selected);
|
|
}
|
|
}, self);
|
|
}
|
|
} else {
|
|
self.closeCallback(ev, 'ok', self.selected);
|
|
}
|
|
}
|
|
});
|
|
return false;
|
|
} else {
|
|
if ( !this.selected && this.args.select !== 'dir' ) {
|
|
API.error(API._('DIALOG_FILE_ERROR'), API._('DIALOG_FILE_MISSING_SELECTION'));
|
|
return false;
|
|
}
|
|
var res = this.selected;
|
|
if ( !res && this.args.select === 'dir' ) {
|
|
res = new VFS.File({
|
|
filename: Utils.filename(this.path),
|
|
path: this.path,
|
|
type: 'dir'
|
|
});
|
|
}
|
|
this.closeCallback(ev, 'ok', res);
|
|
}
|
|
return true;
|
|
};
|
|
FileDialog.prototype.onClose = function(ev, button) {
|
|
if ( button === 'ok' && !this.checkSelection(ev) ) {
|
|
return;
|
|
}
|
|
this.closeCallback(ev, button, this.selected);
|
|
};
|
|
OSjs.Dialogs.File = Object.seal(FileDialog);
|
|
})(OSjs.API, OSjs.VFS, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, VFS, DialogWindow) {
|
|
'use strict';
|
|
function FileInfoDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
DialogWindow.apply(this, ['FileInfoDialog', {
|
|
title: args.title || API._('DIALOG_FILEINFO_TITLE'),
|
|
width: 400,
|
|
height: 400
|
|
}, args, callback]);
|
|
if ( !this.args.file ) {
|
|
throw new Error('You have to select a file for FileInfo');
|
|
}
|
|
}
|
|
FileInfoDialog.prototype = Object.create(DialogWindow.prototype);
|
|
FileInfoDialog.constructor = DialogWindow;
|
|
FileInfoDialog.prototype.init = function() {
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var txt = this.scheme.find(this, 'Info').set('value', API._('LBL_LOADING'));
|
|
var file = this.args.file;
|
|
function _onError(error) {
|
|
if ( error ) {
|
|
txt.set('value', API._('DIALOG_FILEINFO_ERROR_LOOKUP_FMT', file.path));
|
|
}
|
|
}
|
|
function _onSuccess(data) {
|
|
var info = [];
|
|
Object.keys(data).forEach(function(i) {
|
|
if ( i === 'exif' ) {
|
|
info.push(i + ':\n\n' + data[i]);
|
|
} else {
|
|
info.push(i + ':\n\t' + data[i]);
|
|
}
|
|
});
|
|
txt.set('value', info.join('\n\n'));
|
|
}
|
|
VFS.fileinfo(file, function(error, result) {
|
|
if ( error ) {
|
|
_onError(error);
|
|
return;
|
|
}
|
|
_onSuccess(result || {});
|
|
});
|
|
return root;
|
|
};
|
|
OSjs.Dialogs.FileInfo = Object.seal(FileInfoDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function FileProgressDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
DialogWindow.apply(this, ['FileProgressDialog', {
|
|
title: args.title || API._('DIALOG_FILEPROGRESS_TITLE'),
|
|
icon: 'actions/document-send.png',
|
|
width: 400,
|
|
height: 100
|
|
}, args, callback]);
|
|
this.busy = !!args.filename;
|
|
}
|
|
FileProgressDialog.prototype = Object.create(DialogWindow.prototype);
|
|
FileProgressDialog.constructor = DialogWindow;
|
|
FileProgressDialog.prototype.init = function() {
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
if ( this.args.message ) {
|
|
this.scheme.find(this, 'Message').set('value', this.args.message, true);
|
|
}
|
|
return root;
|
|
};
|
|
FileProgressDialog.prototype.onClose = function(ev, button) {
|
|
this.closeCallback(ev, button, null);
|
|
};
|
|
FileProgressDialog.prototype.setProgress = function(p) {
|
|
this.scheme.find(this, 'Progress').set('progress', p);
|
|
};
|
|
FileProgressDialog.prototype._close = function(force) {
|
|
if ( !force && this.busy ) {
|
|
return false;
|
|
}
|
|
return DialogWindow.prototype._close.call(this);
|
|
};
|
|
FileProgressDialog.prototype._onKeyEvent = function(ev) {
|
|
if ( !this.busy ) {
|
|
DialogWindow.prototype._onKeyEvent.apply(this, arguments);
|
|
}
|
|
};
|
|
OSjs.Dialogs.FileProgress = Object.seal(FileProgressDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, VFS, Utils, DialogWindow) {
|
|
'use strict';
|
|
function FileUploadDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {
|
|
dest: API.getDefaultPath(),
|
|
progress: {},
|
|
file: null
|
|
});
|
|
DialogWindow.apply(this, ['FileUploadDialog', {
|
|
title: args.title || API._('DIALOG_UPLOAD_TITLE'),
|
|
icon: 'actions/filenew.png',
|
|
width: 400,
|
|
height: 100
|
|
}, args, callback]);
|
|
}
|
|
FileUploadDialog.prototype = Object.create(DialogWindow.prototype);
|
|
FileUploadDialog.constructor = DialogWindow;
|
|
FileUploadDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var message = this.scheme.find(this, 'Message');
|
|
var maxSize = API.getConfig('VFS.MaxUploadSize');
|
|
message.set('value', API._('DIALOG_UPLOAD_DESC', this.args.dest, maxSize), true);
|
|
var input = this.scheme.find(this, 'File');
|
|
if ( this.args.file ) {
|
|
this.setFile(this.args.file, input);
|
|
} else {
|
|
input.on('change', function(ev) {
|
|
self.setFile(ev.detail, input);
|
|
});
|
|
}
|
|
return root;
|
|
};
|
|
FileUploadDialog.prototype.setFile = function(file, input) {
|
|
var self = this;
|
|
var progressDialog;
|
|
function error(msg, ev) {
|
|
API.error(
|
|
OSjs.API._('DIALOG_UPLOAD_FAILED'),
|
|
OSjs.API._('DIALOG_UPLOAD_FAILED_MSG'),
|
|
msg || OSjs.API._('DIALOG_UPLOAD_FAILED_UNKNOWN')
|
|
);
|
|
progressDialog._close(true);
|
|
self.onClose(ev, 'cancel');
|
|
}
|
|
if ( file ) {
|
|
var fileSize = 0;
|
|
if ( file.size > 1024 * 1024 ) {
|
|
fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB';
|
|
} else {
|
|
fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
|
|
}
|
|
if ( input ) {
|
|
input.set('disabled', true);
|
|
}
|
|
this.scheme.find(this, 'ButtonCancel').set('disabled', true);
|
|
var desc = OSjs.API._('DIALOG_UPLOAD_MSG_FMT', file.name, file.type, fileSize, this.dest);
|
|
progressDialog = API.createDialog('FileProgress', {
|
|
message: desc,
|
|
dest: this.args.dest,
|
|
filename: file.name,
|
|
mime: file.type,
|
|
size: fileSize
|
|
}, function(ev, button) {
|
|
}, this);
|
|
if ( this._wmref ) {
|
|
this._wmref.createNotificationIcon(this.notificationId, {className: 'BusyNotification', tooltip: desc, image: false});
|
|
}
|
|
OSjs.VFS.upload({files: [file], destination: this.args.dest}, function(err, result, ev) {
|
|
if ( err ) {
|
|
error(err, ev);
|
|
return;
|
|
}
|
|
progressDialog._close();
|
|
self.onClose(ev, 'ok', file);
|
|
}, {
|
|
onprogress: function(ev) {
|
|
if ( ev.lengthComputable ) {
|
|
var p = Math.round(ev.loaded * 100 / ev.total);
|
|
progressDialog.setProgress(p);
|
|
}
|
|
}
|
|
});
|
|
setTimeout(function() {
|
|
if ( progressDialog ) {
|
|
progressDialog._focus();
|
|
}
|
|
}, 100);
|
|
}
|
|
};
|
|
FileUploadDialog.prototype.onClose = function(ev, button, result) {
|
|
result = result || null;
|
|
this.closeCallback(ev, button, result);
|
|
};
|
|
OSjs.Dialogs.FileUpload = Object.seal(FileUploadDialog);
|
|
})(OSjs.API, OSjs.VFS, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function FontDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {
|
|
fontName: API.getConfig('Fonts.default'),
|
|
fontSize: 12,
|
|
fontColor: '#000000',
|
|
backgroundColor: '#ffffff',
|
|
fonts: API.getConfig('Fonts.list'),
|
|
minSize: 6,
|
|
maxSize: 30,
|
|
text: 'The quick brown fox jumps over the lazy dog',
|
|
unit: 'px'
|
|
});
|
|
if ( args.unit === 'null' || args.unit === 'unit' ) {
|
|
args.unit = '';
|
|
}
|
|
DialogWindow.apply(this, ['FontDialog', {
|
|
title: args.title || API._('DIALOG_FONT_TITLE'),
|
|
width: 400,
|
|
height: 300
|
|
}, args, callback]);
|
|
this.selection = {
|
|
fontName: args.fontName,
|
|
fontSize: args.fontSize + args.unit
|
|
};
|
|
}
|
|
FontDialog.prototype = Object.create(DialogWindow.prototype);
|
|
FontDialog.constructor = DialogWindow;
|
|
FontDialog.prototype.init = function() {
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
var self = this;
|
|
var preview = this.scheme.find(this, 'FontPreview');
|
|
var sizes = [];
|
|
var fonts = [];
|
|
for ( var i = this.args.minSize; i < this.args.maxSize; i++ ) {
|
|
sizes.push({value: i, label: i});
|
|
}
|
|
for ( var j = 0; j < this.args.fonts.length; j++ ) {
|
|
fonts.push({value: this.args.fonts[j], label: this.args.fonts[j]});
|
|
}
|
|
function updatePreview() {
|
|
preview.querySelector('textarea').style.fontFamily = self.selection.fontName;
|
|
preview.querySelector('textarea').style.fontSize = self.selection.fontSize;
|
|
}
|
|
var listFonts = this.scheme.find(this, 'FontName');
|
|
listFonts.add(fonts).set('value', this.args.fontName);
|
|
listFonts.on('change', function(ev) {
|
|
self.selection.fontName = ev.detail;
|
|
updatePreview();
|
|
});
|
|
var listSizes = this.scheme.find(this, 'FontSize');
|
|
listSizes.add(sizes).set('value', this.args.fontSize);
|
|
listSizes.on('change', function(ev) {
|
|
self.selection.fontSize = ev.detail + self.args.unit;
|
|
updatePreview();
|
|
});
|
|
preview.$element.style.color = this.args.fontColor;
|
|
preview.$element.style.backgroundColor = this.args.backgroundColor;
|
|
preview.set('value', this.args.text);
|
|
if ( this.args.fontSize < 0 ) {
|
|
this.scheme.find(this, 'FontSizeContainer').hide();
|
|
}
|
|
updatePreview();
|
|
return root;
|
|
};
|
|
FontDialog.prototype.onClose = function(ev, button) {
|
|
var result = button === 'ok' ? this.selection : null;
|
|
this.closeCallback(ev, button, result);
|
|
};
|
|
OSjs.Dialogs.Font = Object.seal(FontDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils, DialogWindow) {
|
|
'use strict';
|
|
function InputDialog(args, callback) {
|
|
args = Utils.argumentDefaults(args, {});
|
|
DialogWindow.apply(this, ['InputDialog', {
|
|
title: args.title || API._('DIALOG_INPUT_TITLE'),
|
|
icon: 'status/dialog-information.png',
|
|
width: 400,
|
|
height: 120
|
|
}, args, callback]);
|
|
}
|
|
InputDialog.prototype = Object.create(DialogWindow.prototype);
|
|
InputDialog.constructor = DialogWindow;
|
|
InputDialog.prototype.init = function() {
|
|
var self = this;
|
|
var root = DialogWindow.prototype.init.apply(this, arguments);
|
|
if ( this.args.message ) {
|
|
var msg = DialogWindow.parseMessage(this.args.message);
|
|
this.scheme.find(this, 'Message').empty().append(msg);
|
|
}
|
|
var input = this.scheme.find(this, 'Input');
|
|
input.set('placeholder', this.args.placeholder || '');
|
|
input.set('value', this.args.value || '');
|
|
input.on('enter', function(ev) {
|
|
self.onClose(ev, 'ok');
|
|
});
|
|
return root;
|
|
};
|
|
InputDialog.prototype._focus = function() {
|
|
if ( DialogWindow.prototype._focus.apply(this, arguments) ) {
|
|
this.scheme.find(this, 'Input').focus();
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
InputDialog.prototype.onClose = function(ev, button) {
|
|
var result = this.scheme.find(this, 'Input').get('value');
|
|
this.closeCallback(ev, button, button === 'ok' ? result : null);
|
|
};
|
|
InputDialog.prototype.setRange = function(range) {
|
|
var input = this.scheme.find(this, 'Input');
|
|
if ( input.$element ) {
|
|
input.$element.querySelector('input').select(range);
|
|
}
|
|
};
|
|
OSjs.Dialogs.Input = Object.seal(InputDialog);
|
|
})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow);
|
|
|
|
(function(API, Utils) {
|
|
'use strict';
|
|
var _handlerInstance;
|
|
function appendRequestOptions(data, options) {
|
|
options = options || {};
|
|
var onprogress = options.onprogress || function() {};
|
|
var ignore = ['onsuccess', 'onerror', 'onprogress', 'oncanceled'];
|
|
Object.keys(options).forEach(function(key) {
|
|
if ( ignore.indexOf(key) === -1 ) {
|
|
data[key] = options[key];
|
|
}
|
|
});
|
|
data.onprogress = function(ev) {
|
|
if ( ev.lengthComputable ) {
|
|
onprogress(ev, ev.loaded / ev.total);
|
|
} else {
|
|
onprogress(ev, -1);
|
|
}
|
|
};
|
|
return data;
|
|
}
|
|
function HandlerConnection(handler) {
|
|
this.index = 0;
|
|
this.handler = handler;
|
|
this.nw = null;
|
|
this.ws = null;
|
|
if ( (API.getConfig('Connection.Type') === 'nw') ) {
|
|
this.nw = require('osjs').init({
|
|
root: process.cwd(),
|
|
settings: {
|
|
mimes: API.getConfig('MIME.mapping')
|
|
},
|
|
nw: true
|
|
});
|
|
}
|
|
this.wsqueue = {};
|
|
}
|
|
HandlerConnection.prototype.init = function(callback) {
|
|
var self = this;
|
|
if ( API.getConfig('Connection.Type') === 'ws' ) {
|
|
var url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host;
|
|
var connected = false;
|
|
this.ws = new WebSocket(url);
|
|
this.ws.onopen = function() {
|
|
connected = true;
|
|
callback();
|
|
};
|
|
this.ws.onmessage = function(ev) {
|
|
var data = JSON.parse(ev.data);
|
|
var idx = data._index;
|
|
if ( self.wsqueue[idx] ) {
|
|
delete data._index;
|
|
self.wsqueue[idx](data);
|
|
delete self.wsqueue[idx];
|
|
}
|
|
};
|
|
this.ws.onclose = function(ev) {
|
|
if ( !connected && ev.code !== 3001 ) {
|
|
callback('WebSocket connection error'); // FIXME: Locale
|
|
}
|
|
};
|
|
} else {
|
|
callback();
|
|
}
|
|
};
|
|
HandlerConnection.prototype.destroy = function() {
|
|
if ( this.ws ) {
|
|
this.ws.close();
|
|
}
|
|
this.nw = null;
|
|
this.ws = null;
|
|
this._wsRequest = {};
|
|
};
|
|
HandlerConnection.prototype.callPOST = function(form, options, onsuccess, onerror) {
|
|
onerror = onerror || function() {
|
|
console.warn('HandlerConnection::callPOST()', 'error', arguments);
|
|
};
|
|
Utils.ajax(appendRequestOptions({
|
|
url: OSjs.VFS.Transports.Internal.path(),
|
|
method: 'POST',
|
|
body: form,
|
|
onsuccess: function(result) {
|
|
onsuccess(false, result);
|
|
},
|
|
onerror: function(result) {
|
|
onerror('error', null, result);
|
|
},
|
|
oncanceled: function(evt) {
|
|
onerror('canceled', null, evt);
|
|
}
|
|
}, options));
|
|
return true;
|
|
};
|
|
HandlerConnection.prototype.callGET = function(args, options, onsuccess, onerror) {
|
|
onerror = onerror || function() {
|
|
console.warn('HandlerConnection::callGET()', 'error', arguments);
|
|
};
|
|
var self = this;
|
|
Utils.ajax(appendRequestOptions({
|
|
url: args.url || OSjs.VFS.Transports.Internal.path(args.path),
|
|
method: args.method || 'GET',
|
|
responseType: 'arraybuffer',
|
|
onsuccess: function(response, xhr) {
|
|
if ( !xhr || xhr.status === 404 || xhr.status === 500 ) {
|
|
onsuccess({error: xhr.statusText || response, result: null});
|
|
return;
|
|
}
|
|
onsuccess({error: false, result: response});
|
|
},
|
|
onerror: function() {
|
|
onerror.apply(self, arguments);
|
|
}
|
|
}, options));
|
|
return true;
|
|
};
|
|
HandlerConnection.prototype.callXHR = function(url, args, options, onsuccess, onerror) {
|
|
onerror = onerror || function() {
|
|
console.warn('HandlerConnection::callXHR()', 'error', arguments);
|
|
};
|
|
var self = this;
|
|
Utils.ajax(appendRequestOptions({
|
|
url: url,
|
|
method: 'POST',
|
|
json: true,
|
|
body: args,
|
|
onsuccess: function() {
|
|
onsuccess.apply(self.handler, arguments);
|
|
},
|
|
onerror: function() {
|
|
onerror.apply(self.handler, arguments);
|
|
}
|
|
}, options));
|
|
return true;
|
|
};
|
|
HandlerConnection.prototype.callWS = function(path, args, options, onsuccess, onerror) {
|
|
onerror = onerror || function() {
|
|
console.warn('HandlerConnection::callWS()', 'error', arguments);
|
|
};
|
|
var idx = this.index++;
|
|
try {
|
|
this.ws.send(JSON.stringify({
|
|
_index: idx,
|
|
sid: Utils.getCookie('session'),
|
|
path: '/' + path,
|
|
args: args
|
|
}));
|
|
this.wsqueue[idx] = onsuccess || function() {};
|
|
return true;
|
|
} catch ( e ) {
|
|
console.warn('callWS() Warning', e.stack, e);
|
|
onerror(e);
|
|
}
|
|
return false;
|
|
};
|
|
HandlerConnection.prototype.callNW = function(method, args, options, onsuccess, onerror) {
|
|
onerror = onerror || function() {
|
|
console.warn('HandlerConnection::callNW()', 'error', arguments);
|
|
};
|
|
try {
|
|
this.nw.request(method.match(/^FS\:/) !== null, method.replace(/^FS\:/, ''), args, function(err, res) {
|
|
onsuccess({error: err, result: res});
|
|
});
|
|
return true;
|
|
} catch ( e ) {
|
|
console.warn('callNW() Warning', e.stack, e);
|
|
onerror(e);
|
|
}
|
|
return false;
|
|
};
|
|
HandlerConnection.prototype.request = function(isVfs, method, args, options, onsuccess, onerror) {
|
|
if ( API.getConfig('Connection.Type') === 'nw' ) {
|
|
return this.callNW(method, args, options, onsuccess, onerror);
|
|
}
|
|
if ( isVfs ) {
|
|
if ( method === 'FS:get' ) {
|
|
return this.callGET(args, options, onsuccess, onerror);
|
|
} else if ( method === 'FS:upload' ) {
|
|
return this.callPOST(args, options, onsuccess, onerror);
|
|
}
|
|
}
|
|
var url = (function() {
|
|
if ( isVfs ) {
|
|
return API.getConfig('Connection.FSURI') + '/' + method.replace(/^FS\:/, '');
|
|
}
|
|
return API.getConfig('Connection.APIURI') + '/' + method;
|
|
})();
|
|
if ( API.getConfig('Connection.Type') === 'ws' ) {
|
|
return this.callWS(url, args, options, onsuccess, onerror);
|
|
}
|
|
return this.callXHR(url, args, options, onsuccess, onerror);
|
|
};
|
|
var _Handler = function() {
|
|
if ( _handlerInstance ) {
|
|
throw Error('Cannot create another Handler Instance');
|
|
}
|
|
this._saveTimeout = null;
|
|
this.loggedIn = false;
|
|
this.offline = false;
|
|
this.userData = {
|
|
id : 0,
|
|
username: 'root',
|
|
name : 'root user',
|
|
groups : ['admin']
|
|
};
|
|
this.connection = new HandlerConnection();
|
|
_handlerInstance = this;
|
|
};
|
|
_Handler.prototype.init = function(callback) {
|
|
var self = this;
|
|
API.setLocale(API.getConfig('Locale'));
|
|
if ( typeof navigator.onLine !== 'undefined' ) {
|
|
Utils.$bind(window, 'offline', function(ev) {
|
|
self.onOffline();
|
|
});
|
|
Utils.$bind(window, 'online', function(ev) {
|
|
self.onOnline();
|
|
});
|
|
}
|
|
this.connection.init(function(err, res) {
|
|
callback(err, res);
|
|
});
|
|
};
|
|
_Handler.prototype.destroy = function() {
|
|
Utils.$unbind(window, 'offline');
|
|
Utils.$unbind(window, 'online');
|
|
if ( this.connection ) {
|
|
this.connection.destroy();
|
|
}
|
|
this.connection = null;
|
|
_handlerInstance = null;
|
|
};
|
|
_Handler.prototype.login = function(username, password, callback) {
|
|
var opts = {username: username, password: password};
|
|
this.callAPI('login', opts, function(response) {
|
|
if ( response.result ) { // This contains an object with user data
|
|
callback(false, response.result);
|
|
} else {
|
|
var error = response.error || API._('ERR_LOGIN_INVALID');
|
|
callback(API._('ERR_LOGIN_FMT', error), false);
|
|
}
|
|
}, function(error) {
|
|
callback(API._('ERR_LOGIN_FMT', error), false);
|
|
});
|
|
};
|
|
_Handler.prototype.logout = function(save, callback) {
|
|
var self = this;
|
|
function _finished() {
|
|
var opts = {};
|
|
self.callAPI('logout', opts, function(response) {
|
|
if ( response.result ) {
|
|
self.loggedIn = false;
|
|
callback(true);
|
|
} else {
|
|
callback(false, 'An error occured: ' + (response.error || 'Unknown error'));
|
|
}
|
|
}, function(error) {
|
|
callback(false, 'Logout error: ' + error);
|
|
});
|
|
}
|
|
if ( save ) {
|
|
this.saveSession(function() {
|
|
_finished(true);
|
|
});
|
|
return;
|
|
}
|
|
_finished(true);
|
|
};
|
|
_Handler.prototype.saveSession = function(callback) {
|
|
var data = [];
|
|
API.getProcesses().forEach(function(proc, i) {
|
|
if ( proc && (proc instanceof OSjs.Core.Application) ) {
|
|
data.push(proc._getSessionData());
|
|
}
|
|
});
|
|
OSjs.Core.getSettingsManager().set('UserSession', null, data, callback);
|
|
};
|
|
_Handler.prototype.getLastSession = function(callback) {
|
|
callback = callback || function() {};
|
|
var res = OSjs.Core.getSettingsManager().get('UserSession');
|
|
var list = [];
|
|
(res || []).forEach(function(iter, i) {
|
|
var args = iter.args;
|
|
args.__resume__ = true;
|
|
args.__windows__ = iter.windows || [];
|
|
list.push({name: iter.name, args: args});
|
|
});
|
|
callback(false, list);
|
|
};
|
|
_Handler.prototype.loadSession = function(callback) {
|
|
callback = callback || function() {};
|
|
this.getLastSession(function(err, list) {
|
|
if ( err ) {
|
|
callback();
|
|
} else {
|
|
API.launchList(list, null, null, callback);
|
|
}
|
|
});
|
|
};
|
|
_Handler.prototype.saveSettings = function(pool, storage, callback) {
|
|
var self = this;
|
|
var opts = {settings: storage};
|
|
function _save() {
|
|
self.callAPI('settings', opts, function(response) {
|
|
callback.call(self, false, response.result);
|
|
}, function(error) {
|
|
callback.call(self, error, false);
|
|
});
|
|
}
|
|
if ( this._saveTimeout ) {
|
|
clearTimeout(this._saveTimeout);
|
|
this._saveTimeout = null;
|
|
}
|
|
setTimeout(_save, 250);
|
|
};
|
|
_Handler.prototype.getVFSPath = function(item) {
|
|
var base = API.getConfig('Connection.FSURI', '/');
|
|
if ( item ) {
|
|
return base + '/get/' + item.path;
|
|
}
|
|
return base + '/upload';
|
|
};
|
|
_Handler.prototype.getAPICallOptions = function() {
|
|
return {};
|
|
};
|
|
_Handler.prototype.callAPI = function(method, args, cbSuccess, cbError, options) {
|
|
args = args || {};
|
|
options = Utils.mergeObject(this.getAPICallOptions(), options || {});
|
|
cbSuccess = cbSuccess || function() {};
|
|
cbError = cbError || function() {};
|
|
if ( this.offline ) {
|
|
cbError('You are currently off-line and cannot perform this operation!');
|
|
} else if ( (API.getConfig('Connection.Type') === 'standalone') ) {
|
|
cbError('You are currently running locally and cannot perform this operation!');
|
|
} else {
|
|
if ( method.match(/^FS/) ) {
|
|
return this._callVFS(method, args, options, cbSuccess, cbError);
|
|
}
|
|
return this._callAPI(method, args, options, cbSuccess, cbError);
|
|
}
|
|
return false;
|
|
};
|
|
_Handler.prototype._callAPI = function(method, args, options, cbSuccess, cbError) {
|
|
return this.connection.request(false, method, args, options, cbSuccess, cbError);
|
|
};
|
|
_Handler.prototype._callVFS = function(method, args, options, cbSuccess, cbError) {
|
|
return this.connection.request(true, method, args, options, cbSuccess, cbError);
|
|
};
|
|
_Handler.prototype.onLogin = function(data, callback) {
|
|
callback = callback || function() {};
|
|
var userSettings = data.userSettings;
|
|
if ( !userSettings || userSettings instanceof Array ) {
|
|
userSettings = {};
|
|
}
|
|
this.userData = data.userData;
|
|
function getUserLocale() {
|
|
var curLocale = API.getConfig('Locale');
|
|
var detectedLocale = Utils.getUserLocale();
|
|
if ( API.getConfig('LocaleOptions.AutoDetect', true) && detectedLocale ) {
|
|
curLocale = detectedLocale;
|
|
}
|
|
var result = OSjs.Core.getSettingsManager().get('CoreWM');
|
|
if ( !result ) {
|
|
try {
|
|
result = userSettings.CoreWM;
|
|
} catch ( e ) {}
|
|
}
|
|
return result ? (result.language || curLocale) : curLocale;
|
|
}
|
|
document.getElementById('LoadingScreen').style.display = 'block';
|
|
API.setLocale(getUserLocale());
|
|
OSjs.Core.getSettingsManager().init(userSettings);
|
|
if ( data.blacklistedPackages ) {
|
|
OSjs.Core.getPackageManager().setBlacklist(data.blacklistedPackages);
|
|
}
|
|
this.loggedIn = true;
|
|
callback();
|
|
};
|
|
_Handler.prototype.onVFSRequest = function(vfsModule, vfsMethod, vfsArguments, callback) {
|
|
callback();
|
|
};
|
|
_Handler.prototype.onVFSRequestCompleted = function(vfsModule, vfsMethod, vfsArguments, vfsError, vfsResult, callback) {
|
|
callback();
|
|
};
|
|
_Handler.prototype.onOnline = function() {
|
|
console.warn('Handler::onOnline()', 'Going online...');
|
|
this.offline = false;
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.notification({title: 'Warning!', message: 'You are On-line!'});
|
|
}
|
|
};
|
|
_Handler.prototype.onOffline = function() {
|
|
console.warn('Handler::onOffline()', 'Going offline...');
|
|
this.offline = true;
|
|
var wm = OSjs.Core.getWindowManager();
|
|
if ( wm ) {
|
|
wm.notification({title: 'Warning!', message: 'You are Off-line!'});
|
|
}
|
|
};
|
|
_Handler.prototype.getUserData = function() {
|
|
return this.userData || {};
|
|
};
|
|
_Handler.prototype.initLoginScreen = function(callback) {
|
|
var self = this;
|
|
var container = document.getElementById('Login');
|
|
var login = document.getElementById('LoginForm');
|
|
var u = document.getElementById('LoginUsername');
|
|
var p = document.getElementById('LoginPassword');
|
|
var s = document.getElementById('LoginSubmit');
|
|
if ( !container ) {
|
|
throw new Error('Could not find Login Form Container');
|
|
}
|
|
function _restore() {
|
|
s.removeAttribute('disabled');
|
|
u.removeAttribute('disabled');
|
|
p.removeAttribute('disabled');
|
|
}
|
|
function _lock() {
|
|
s.setAttribute('disabled', 'disabled');
|
|
u.setAttribute('disabled', 'disabled');
|
|
p.setAttribute('disabled', 'disabled');
|
|
}
|
|
function _login(username, password) {
|
|
self.login(username, password, function(error, result) {
|
|
if ( error ) {
|
|
alert(error);
|
|
_restore();
|
|
return;
|
|
}
|
|
container.parentNode.removeChild(container);
|
|
self.onLogin(result, function() {
|
|
callback();
|
|
});
|
|
});
|
|
}
|
|
login.onsubmit = function(ev) {
|
|
_lock();
|
|
if ( ev ) {
|
|
ev.preventDefault();
|
|
}
|
|
_login(u.value, p.value);
|
|
};
|
|
container.style.display = 'block';
|
|
_restore();
|
|
};
|
|
_Handler.use = (function() {
|
|
var traits = {
|
|
init: function defaultInit(callback) {
|
|
var self = this;
|
|
return OSjs.Core._Handler.prototype.init.call(this, function() {
|
|
self.initLoginScreen(callback);
|
|
});
|
|
},
|
|
login: function defaultLogin(username, password, callback) {
|
|
return OSjs.Core._Handler.prototype.login.apply(this, arguments);
|
|
},
|
|
logout: function defaultLogout(save, callback) {
|
|
return OSjs.Core._Handler.prototype.logout.apply(this, arguments);
|
|
},
|
|
settings: function defaultSettings(pool, storage, callback) {
|
|
return OSjs.Core._Handler.prototype.saveSettings.apply(this, arguments);
|
|
}
|
|
};
|
|
function applyTraits(obj, add) {
|
|
add.forEach(function(fn) {
|
|
obj.prototype[fn] = traits[fn];
|
|
});
|
|
}
|
|
var exports = {
|
|
defaults: function(obj) {
|
|
applyTraits(obj, Object.keys(traits));
|
|
}
|
|
};
|
|
Object.keys(traits).forEach(function(k) {
|
|
exports[k] = function(obj) {
|
|
applyTraits(obj, [k]);
|
|
};
|
|
});
|
|
return exports;
|
|
})();
|
|
OSjs.Core._Handler = _Handler;
|
|
OSjs.Core.Handler = null;
|
|
OSjs.Core.getHandler = function() {
|
|
return _handlerInstance;
|
|
};
|
|
})(OSjs.API, OSjs.Utils);
|
|
|
|
(function(API, Utils, VFS) {
|
|
'use strict';
|
|
function getSettings() {
|
|
var result = {};
|
|
var key;
|
|
for ( var i = 0; i < localStorage.length; i++ ) {
|
|
key = localStorage.key(i);
|
|
if ( key.match(/^OSjs\//) ) {
|
|
try {
|
|
result[key.replace(/^OSjs\//, '')] = JSON.parse(localStorage.getItem(key));
|
|
} catch ( e ) {
|
|
console.warn('DemoHandler::getSetting()', 'exception', e, e.stack);
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
function DemoHandler() {
|
|
OSjs.Core._Handler.apply(this, arguments);
|
|
var curr = API.getConfig('Version');
|
|
var version = localStorage.getItem('__version__');
|
|
if ( curr !== version ) {
|
|
console.warn('DemoHandler()', 'You are running', version, 'version is', curr, 'flushing for compability!');
|
|
localStorage.clear();
|
|
}
|
|
localStorage.setItem('__version__', String(curr));
|
|
}
|
|
DemoHandler.prototype = Object.create(OSjs.Core._Handler.prototype);
|
|
DemoHandler.constructor = OSjs.Core._Handler;
|
|
DemoHandler.prototype.init = function(callback) {
|
|
var self = this;
|
|
OSjs.Core._Handler.prototype.init.call(this, function() {
|
|
function finished(result) {
|
|
result.userSettings = getSettings();
|
|
self.onLogin(result, function() {
|
|
callback();
|
|
});
|
|
}
|
|
if ( API.getConfig('Connection.Type') === 'standalone' || window.location.protocol === 'file:' ) {
|
|
finished({
|
|
userData: {
|
|
id: 0,
|
|
username: 'demo',
|
|
name: 'Local Server',
|
|
groups: ['admin']
|
|
}
|
|
});
|
|
} else {
|
|
self.login('demo', 'demo', function(error, result) {
|
|
if ( error ) {
|
|
callback(error);
|
|
} else {
|
|
finished(result);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
};
|
|
DemoHandler.prototype.saveSettings = function(pool, storage, callback) {
|
|
Object.keys(storage).forEach(function(key) {
|
|
if ( pool && key !== pool ) {
|
|
return;
|
|
}
|
|
try {
|
|
localStorage.setItem('OSjs/' + key, JSON.stringify(storage[key]));
|
|
} catch ( e ) {
|
|
console.warn('DemoHandler::_save()', 'exception', e, e.stack);
|
|
}
|
|
});
|
|
callback();
|
|
};
|
|
OSjs.Core.Handler = DemoHandler;
|
|
})(OSjs.API, OSjs.Utils, OSjs.VFS);
|
|
|
|
(function(Utils, API, VFS, Core) {
|
|
'use strict';
|
|
VFS.Helpers.filterScandir = function filterScandir(list, options) {
|
|
var defaultOptions = Utils.cloneObject(Core.getSettingsManager().get('VFS') || {});
|
|
options = Utils.argumentDefaults(options, defaultOptions.scandir || {});
|
|
options = Utils.argumentDefaults(options, {
|
|
typeFilter: null,
|
|
mimeFilter: [],
|
|
showHiddenFiles: true
|
|
}, true);
|
|
function filterFile(iter) {
|
|
if ( (options.typeFilter && iter.type !== options.typeFilter) || (!options.showHiddenFiles && iter.filename.match(/^\.\w/)) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
function validMime(iter) {
|
|
if ( options.mimeFilter && options.mimeFilter.length && iter.mime ) {
|
|
return options.mimeFilter.some(function(miter) {
|
|
if ( iter.mime.match(miter) ) {
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
}
|
|
return true;
|
|
}
|
|
var result = list.filter(function(iter) {
|
|
if ( (iter.filename === '..' && options.backlink === false) || !filterFile(iter) ) {
|
|
return false;
|
|
}
|
|
if ( iter.type === 'file' && !validMime(iter) ) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}).map(function(iter) {
|
|
if ( iter.mime === 'application/vnd.google-apps.folder' ) {
|
|
iter.type = 'dir';
|
|
}
|
|
return iter;
|
|
});
|
|
return result.filter(function(iter) {
|
|
return iter.type === 'dir';
|
|
}).concat(result.filter(function(iter) {
|
|
return iter.type !== 'dir';
|
|
}));
|
|
};
|
|
function _abToSomething(m, arrayBuffer, mime, callback) {
|
|
mime = mime || 'application/octet-stream';
|
|
try {
|
|
var blob = new Blob([arrayBuffer], {type: mime});
|
|
var r = new FileReader();
|
|
r.onerror = function(e) {
|
|
callback(e);
|
|
};
|
|
r.onloadend = function() {
|
|
callback(false, r.result);
|
|
};
|
|
r[m](blob);
|
|
} catch ( e ) {
|
|
console.warn(e, e.stack);
|
|
callback(e);
|
|
}
|
|
}
|
|
VFS.Helpers.addFormFile = function addFormFile(fd, key, data, file) {
|
|
if ( data instanceof window.File ) {
|
|
fd.append(key, data);
|
|
} else {
|
|
if ( file ) {
|
|
if ( data instanceof window.ArrayBuffer ) {
|
|
try {
|
|
data = new Blob([data], {type: file.mime});
|
|
} catch ( e ) {
|
|
data = null;
|
|
console.warn(e, e.stack);
|
|
}
|
|
}
|
|
fd.append(key, data, file.filename);
|
|
} else {
|
|
if ( data.data && data.filename ) { // In case user defines custom
|
|
fd.append(key, data.data, data.filename);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
VFS.Helpers.dataSourceToAb = function dataSourceToAb(data, mime, callback) {
|
|
var byteString = atob(data.split(',')[1]);
|
|
var ab = new ArrayBuffer(byteString.length);
|
|
var ia = new Uint8Array(ab);
|
|
for (var i = 0; i < byteString.length; i++) {
|
|
ia[i] = byteString.charCodeAt(i);
|
|
}
|
|
callback(false, ab);
|
|
};
|
|
VFS.Helpers.textToAb = function textToAb(data, mime, callback) {
|
|
_abToSomething('readAsArrayBuffer', data, mime, callback);
|
|
};
|
|
VFS.Helpers.abToDataSource = function abToDataSource(arrayBuffer, mime, callback) {
|
|
_abToSomething('readAsDataURL', arrayBuffer, mime, callback);
|
|
};
|
|
VFS.Helpers.abToText = function abToText(arrayBuffer, mime, callback) {
|
|
_abToSomething('readAsText', arrayBuffer, mime, callback);
|
|
};
|
|
VFS.Helpers.abToBinaryString = function abToBinaryString(arrayBuffer, mime, callback) {
|
|
_abToSomething('readAsBinaryString', arrayBuffer, mime, callback);
|
|
};
|
|
VFS.Helpers.abToBlob = function abToBlob(arrayBuffer, mime, callback) {
|
|
mime = mime || 'application/octet-stream';
|
|
try {
|
|
var blob = new Blob([arrayBuffer], {type: mime});
|
|
callback(false, blob);
|
|
} catch ( e ) {
|
|
console.warn(e, e.stack);
|
|
callback(e);
|
|
}
|
|
};
|
|
VFS.Helpers.blobToAb = function blobToAb(data, callback) {
|
|
try {
|
|
var r = new FileReader();
|
|
r.onerror = function(e) {
|
|
callback(e);
|
|
};
|
|
r.onloadend = function() {
|
|
callback(false, r.result);
|
|
};
|
|
r.readAsArrayBuffer(data);
|
|
} catch ( e ) {
|
|
console.warn(e, e.stack);
|
|
callback(e);
|
|
}
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.Core);
|
|
|
|
(function(Utils, API, VFS, Core) {
|
|
'use strict';
|
|
function request(test, method, args, callback, options) {
|
|
var mm = Core.getMountManager();
|
|
var d = mm.getModuleFromPath(test, false);
|
|
if ( !d ) {
|
|
throw new Error(API._('ERR_VFSMODULE_NOT_FOUND_FMT', test));
|
|
}
|
|
if ( typeof method !== 'string' ) {
|
|
throw new TypeError(API._('ERR_ARGUMENT_FMT', 'VFS::' + method, 'method', 'String', typeof method));
|
|
}
|
|
if ( !(args instanceof Object) ) {
|
|
throw new TypeError(API._('ERR_ARGUMENT_FMT', 'VFS::' + method, 'args', 'Object', typeof args));
|
|
}
|
|
if ( !(callback instanceof Function) ) {
|
|
throw new TypeError(API._('ERR_ARGUMENT_FMT', 'VFS::' + method, 'callback', 'Function', typeof callback));
|
|
}
|
|
if ( options && !(options instanceof Object) ) {
|
|
throw new TypeError(API._('ERR_ARGUMENT_FMT', 'VFS::' + method, 'options', 'Object', typeof options));
|
|
}
|
|
var h = Core.getHandler();
|
|
h.onVFSRequest(d, method, args, function vfsRequestCallback(err, response) {
|
|
if ( arguments.length === 2 ) {
|
|
console.warn('VFS::request()', 'Core::onVFSRequest hijacked the VFS request');
|
|
callback(err, response);
|
|
return;
|
|
}
|
|
try {
|
|
mm.getModule(d).request(method, args, function(err, res) {
|
|
h.onVFSRequestCompleted(d, method, args, err, res, function(e, r) {
|
|
if ( arguments.length === 2 ) {
|
|
console.warn('VFS::request()', 'Core::onVFSRequestCompleted hijacked the VFS request');
|
|
callback(e, r);
|
|
return;
|
|
} else {
|
|
callback(err, res);
|
|
}
|
|
});
|
|
}, options);
|
|
} catch ( e ) {
|
|
var msg = API._('ERR_VFSMODULE_EXCEPTION_FMT', e.toString());
|
|
callback(msg);
|
|
console.warn('VFS::request()', 'exception', e.stack, e);
|
|
}
|
|
});
|
|
}
|
|
function requestWrapper(args, errstr, callback, onfinished, options) {
|
|
function _finished(error, response) {
|
|
if ( error ) {
|
|
error = API._(errstr, error);
|
|
}
|
|
if ( onfinished ) {
|
|
response = onfinished(error, response);
|
|
}
|
|
callback(error, response);
|
|
}
|
|
args.push(_finished);
|
|
if ( typeof options !== 'undefined' ) {
|
|
args.push(options);
|
|
}
|
|
try {
|
|
request.apply(null, args);
|
|
} catch ( e ) {
|
|
_finished(e);
|
|
}
|
|
}
|
|
function hasAlias(item, retm) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var module = mm.getModuleFromPath(item.path, false, true);
|
|
if ( module && module.options && module.options.alias ) {
|
|
return retm ? module : item.path.replace(module.match, module.options.alias);
|
|
}
|
|
return false;
|
|
}
|
|
function findAlias(item) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var found = null;
|
|
mm.getModules().forEach(function(iter) {
|
|
if ( !found && iter.module.options && iter.module.options.alias ) {
|
|
var a = iter.module.options.alias;
|
|
if ( item.path.substr(0, a.length) === a ) {
|
|
found = iter.module;
|
|
}
|
|
}
|
|
});
|
|
return found;
|
|
}
|
|
function checkMetadataArgument(item, err) {
|
|
if ( typeof item === 'string' ) {
|
|
item = new VFS.File(item);
|
|
} else if ( typeof item === 'object' && item.path ) {
|
|
item = new VFS.File(item);
|
|
}
|
|
if ( !(item instanceof VFS.File) ) {
|
|
throw new TypeError(err || API._('ERR_VFS_EXPECT_FILE'));
|
|
}
|
|
var alias = hasAlias(item);
|
|
if ( alias ) {
|
|
item.path = alias;
|
|
}
|
|
if ( !Core.getMountManager().getModuleFromPath(item.path, false) ) {
|
|
throw new Error(API._('ERR_VFSMODULE_NOT_FOUND_FMT', item.path));
|
|
}
|
|
return item;
|
|
}
|
|
function hasSameTransport(src, dest) {
|
|
var mm = Core.getMountManager();
|
|
if ( mm.isInternal(src.path) && mm.isInternal(dest.path) ) {
|
|
return true;
|
|
}
|
|
var msrc = mm.getModuleFromPath(src.path, false, true) || {};
|
|
var mdst = mm.getModuleFromPath(dest.path, false, true) || {};
|
|
return (msrc.transport === mdst.transport) || (msrc.name === mdst.name);
|
|
}
|
|
function existsWrapper(item, callback, options) {
|
|
options = options || {};
|
|
try {
|
|
if ( typeof options.overwrite !== 'undefined' && options.overwrite === true ) {
|
|
callback();
|
|
} else {
|
|
VFS.exists(item, function(error, result) {
|
|
if ( error ) {
|
|
console.warn('existsWrapper() error', error);
|
|
}
|
|
if ( result ) {
|
|
callback(API._('ERR_VFS_FILE_EXISTS'));
|
|
} else {
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
} catch ( e ) {
|
|
callback(e);
|
|
}
|
|
}
|
|
function isReadOnly(item) {
|
|
var m = Core.getMountManager().getModuleFromPath(item.path, false, true) || {};
|
|
return m.readOnly === true;
|
|
}
|
|
function broadcastMessage(msg, item, appRef) {
|
|
API.message(msg, item, {source: appRef ? appRef.__pid : null});
|
|
var aliased = (function() {
|
|
function _transform(i) {
|
|
if ( i instanceof VFS.File ) {
|
|
var n = new VFS.File(i);
|
|
var alias = findAlias(n);
|
|
if ( alias ) {
|
|
n.path = n.path.replace(alias.options.alias, alias.root);
|
|
return n;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if ( item instanceof VFS.File ) {
|
|
return _transform(item);
|
|
} else if ( item && item.destination && item.source ) {
|
|
return {
|
|
source: _transform(item.source),
|
|
destination: _transform(item.destination)
|
|
};
|
|
}
|
|
return null;
|
|
})();
|
|
var tuple = aliased.source || aliased.destination;
|
|
if ( aliased && (aliased instanceof VFS.File || tuple) ) {
|
|
if ( tuple ) {
|
|
aliased.source = aliased.source || item.source;
|
|
aliased.destination = aliased.destination || item.destination;
|
|
}
|
|
API.message(msg, aliased, {source: appRef ? appRef.__pid : null});
|
|
}
|
|
}
|
|
function createBackLink(item, result, alias, oitem) {
|
|
var path = Utils.getPathProtocol(item.path);
|
|
var isOnRoot = path.replace(/\/+/, '/') === '/';
|
|
if ( alias ) {
|
|
isOnRoot = (oitem.path === alias.root);
|
|
}
|
|
if ( !isOnRoot ) {
|
|
var foundBack = result.some(function(iter) {
|
|
return iter.filename === '..';
|
|
});
|
|
if ( !foundBack ) {
|
|
return new VFS.File({
|
|
filename: '..',
|
|
path: Utils.dirname(item.path),
|
|
mime: null,
|
|
size: 0,
|
|
type: 'dir'
|
|
});
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
VFS.find = function(item, args, callback, options) {
|
|
if ( arguments.length < 3 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'find', [item, args]], 'ERR_VFSMODULE_FIND_FMT', callback, null, options);
|
|
};
|
|
VFS.scandir = function(item, callback, options) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
var oitem = new VFS.File(item);
|
|
var alias = hasAlias(oitem, true);
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'scandir', [item]], 'ERR_VFSMODULE_SCANDIR_FMT', function(error, result) {
|
|
if ( alias && result ) {
|
|
result = result.map(function(iter) {
|
|
var niter = new VFS.File(iter);
|
|
var str = iter.path.replace(/\/?$/, '');
|
|
var tmp = alias.options.alias.replace(/\/?$/, '');
|
|
niter.path = Utils.pathJoin(alias.root, str.replace(tmp, ''));
|
|
return niter;
|
|
});
|
|
}
|
|
if ( !error && result instanceof Array ) {
|
|
var back = createBackLink(item, result, alias, oitem);
|
|
if ( back ) {
|
|
result.unshift(back);
|
|
}
|
|
}
|
|
return callback(error, result);
|
|
}, null, options);
|
|
};
|
|
VFS.write = function(item, data, callback, options, appRef) {
|
|
if ( arguments.length < 3 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
function _finished(error, result) {
|
|
if ( error ) {
|
|
error = API._('ERR_VFSMODULE_WRITE_FMT', error);
|
|
} else {
|
|
broadcastMessage('vfs:write', item, appRef);
|
|
}
|
|
callback(error, result);
|
|
}
|
|
function _write(filedata) {
|
|
try {
|
|
request(item.path, 'write', [item, filedata], _finished, options);
|
|
} catch ( e ) {
|
|
_finished(e);
|
|
}
|
|
}
|
|
function _converted(error, response) {
|
|
if ( error ) {
|
|
_finished(error, null);
|
|
return;
|
|
}
|
|
_write(response);
|
|
}
|
|
try {
|
|
if ( typeof data === 'string' ) {
|
|
if ( data.length ) {
|
|
VFS.Helpers.textToAb(data, item.mime, function(error, response) {
|
|
_converted(error, response);
|
|
});
|
|
} else {
|
|
_converted(null, data);
|
|
}
|
|
} else {
|
|
if ( data instanceof VFS.FileDataURL ) {
|
|
VFS.Helpers.dataSourceToAb(data.toString(), item.mime, function(error, response) {
|
|
_converted(error, response);
|
|
});
|
|
return;
|
|
} else if ( window.Blob && data instanceof window.Blob ) {
|
|
VFS.Helpers.blobToAb(data, function(error, response) {
|
|
_converted(error, response);
|
|
});
|
|
return;
|
|
}
|
|
_write(data);
|
|
}
|
|
} catch ( e ) {
|
|
_finished(e);
|
|
}
|
|
};
|
|
VFS.read = function(item, callback, options) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
options = options || {};
|
|
function _finished(error, response) {
|
|
if ( error ) {
|
|
error = API._('ERR_VFSMODULE_READ_FMT', error);
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( options.type ) {
|
|
var types = {
|
|
datasource: function readToDataSource() {
|
|
VFS.Helpers.abToDataSource(response, item.mime, function(error, dataSource) {
|
|
callback(error, error ? null : dataSource);
|
|
});
|
|
},
|
|
text: function readToText() {
|
|
VFS.Helpers.abToText(response, item.mime, function(error, text) {
|
|
callback(error, error ? null : text);
|
|
});
|
|
},
|
|
blob: function readToBlob() {
|
|
VFS.Helpers.abToBlob(response, item.mime, function(error, blob) {
|
|
callback(error, error ? null : blob);
|
|
});
|
|
},
|
|
json: function readToJSON() {
|
|
VFS.Helpers.abToText(response, item.mime, function(error, text) {
|
|
var jsn;
|
|
if ( typeof text === 'string' ) {
|
|
try {
|
|
jsn = JSON.parse(text);
|
|
} catch ( e ) {
|
|
console.warn('VFS::read()', 'readToJSON', e.stack, e);
|
|
}
|
|
}
|
|
callback(error, error ? null : jsn);
|
|
});
|
|
}
|
|
};
|
|
var type = options.type.toLowerCase();
|
|
if ( types[type] ) {
|
|
types[type]();
|
|
return;
|
|
}
|
|
}
|
|
callback(error, error ? null : response);
|
|
}
|
|
try {
|
|
request(item.path, 'read', [item], function(error, response) {
|
|
_finished(error, error ? false : response);
|
|
}, options);
|
|
} catch ( e ) {
|
|
_finished(e);
|
|
}
|
|
};
|
|
VFS.copy = function(src, dest, callback, options, appRef) {
|
|
if ( arguments.length < 3 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
var mm = Core.getMountManager();
|
|
src = checkMetadataArgument(src, API._('ERR_VFS_EXPECT_SRC_FILE'));
|
|
dest = checkMetadataArgument(dest, API._('ERR_VFS_EXPECT_DST_FILE'));
|
|
if ( isReadOnly(dest) ) {
|
|
callback(API._('ERR_VFSMODULE_READONLY_FMT', mm.getModuleFromPath(dest.path)));
|
|
return;
|
|
}
|
|
options = Utils.argumentDefaults(options, {
|
|
type: 'binary',
|
|
dialog: null
|
|
});
|
|
options.arrayBuffer = true;
|
|
function dialogProgress(prog) {
|
|
if ( options.dialog ) {
|
|
options.dialog.setProgress(prog);
|
|
}
|
|
}
|
|
function doRequest() {
|
|
function _finished(error, result) {
|
|
if ( !error ) {
|
|
broadcastMessage('vfs:copy', dest, appRef);
|
|
}
|
|
callback(error, result);
|
|
}
|
|
if ( hasSameTransport(src, dest) ) {
|
|
request(src.path, 'copy', [src, dest], function(error, response) {
|
|
dialogProgress(100);
|
|
if ( error ) {
|
|
error = API._('ERR_VFSMODULE_COPY_FMT', error);
|
|
}
|
|
_finished(error, response);
|
|
}, options);
|
|
} else {
|
|
var msrc = mm.getModuleFromPath(src.path);
|
|
var mdst = mm.getModuleFromPath(dest.path);
|
|
if ( src.type === 'dir' ) {
|
|
_finished(API._('ERR_VFSMODULE_COPY_FMT', 'Copying folders between different transports is not yet supported!'));
|
|
return;
|
|
}
|
|
dest.mime = src.mime;
|
|
mm.getModule(msrc).request('read', [src], function(error, data) {
|
|
dialogProgress(50);
|
|
if ( error ) {
|
|
_finished(API._('ERR_VFS_TRANSFER_FMT', error));
|
|
return;
|
|
}
|
|
mm.getModule(mdst).request('write', [dest, data], function(error, result) {
|
|
dialogProgress(100);
|
|
if ( error ) {
|
|
error = API._('ERR_VFSMODULE_COPY_FMT', error);
|
|
}
|
|
_finished(error, result);
|
|
}, options);
|
|
}, options);
|
|
}
|
|
}
|
|
existsWrapper(dest, function(error) {
|
|
if ( error ) {
|
|
callback(API._('ERR_VFSMODULE_COPY_FMT', error));
|
|
} else {
|
|
try {
|
|
doRequest();
|
|
} catch ( e ) {
|
|
callback(API._('ERR_VFSMODULE_COPY_FMT', e));
|
|
}
|
|
}
|
|
});
|
|
};
|
|
VFS.move = function(src, dest, callback, options, appRef) {
|
|
var self = this;
|
|
if ( arguments.length < 3 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
var mm = Core.getMountManager();
|
|
src = checkMetadataArgument(src, API._('ERR_VFS_EXPECT_SRC_FILE'));
|
|
dest = checkMetadataArgument(dest, API._('ERR_VFS_EXPECT_DST_FILE'));
|
|
if ( isReadOnly(dest) ) {
|
|
callback(API._('ERR_VFSMODULE_READONLY_FMT', mm.getModuleFromPath(dest.path)));
|
|
return;
|
|
}
|
|
function doRequest() {
|
|
function _finished(error, result) {
|
|
if ( !error ) {
|
|
broadcastMessage('vfs:move', {source: src, destination: dest}, appRef);
|
|
}
|
|
callback(error, result);
|
|
}
|
|
if ( hasSameTransport(src, dest) ) {
|
|
request(src.path, 'move', [src, dest], function(error, response) {
|
|
if ( error ) {
|
|
error = API._('ERR_VFSMODULE_MOVE_FMT', error);
|
|
}
|
|
_finished(error, error ? null : response, dest);
|
|
}, options);
|
|
} else {
|
|
var msrc = mm.getModuleFromPath(src.path);
|
|
dest.mime = src.mime;
|
|
self.copy(src, dest, function(error, result) {
|
|
if ( error ) {
|
|
error = API._('ERR_VFS_TRANSFER_FMT', error);
|
|
return _finished(error);
|
|
}
|
|
mm.getModule(msrc).request('unlink', [src], function(error, result) {
|
|
if ( error ) {
|
|
error = API._('ERR_VFS_TRANSFER_FMT', error);
|
|
}
|
|
_finished(error, result, dest);
|
|
}, options);
|
|
});
|
|
}
|
|
}
|
|
existsWrapper(dest, function(error) {
|
|
if ( error ) {
|
|
callback(API._('ERR_VFSMODULE_MOVE_FMT', error));
|
|
} else {
|
|
try {
|
|
doRequest();
|
|
} catch ( e ) {
|
|
callback(API._('ERR_VFSMODULE_MOVE_FMT', e));
|
|
}
|
|
}
|
|
});
|
|
};
|
|
VFS.rename = function(src, dest, callback) {
|
|
VFS.move.apply(this, arguments);
|
|
};
|
|
VFS.unlink = function(item, callback, options, appRef) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
function _checkPath() {
|
|
var pkgdir = OSjs.Core.getSettingsManager().instance('PackageManager').get('PackagePaths', []);
|
|
var found = pkgdir.some(function(i) {
|
|
var chkdir = new VFS.File(i);
|
|
var idir = Utils.dirname(item.path);
|
|
return idir === chkdir.path;
|
|
});
|
|
if ( found ) {
|
|
Core.getPackageManager().generateUserMetadata(function() {});
|
|
}
|
|
}
|
|
requestWrapper([item.path, 'unlink', [item]], 'ERR_VFSMODULE_UNLINK_FMT', callback, function(error, response) {
|
|
if ( !error ) {
|
|
broadcastMessage('vfs:unlink', item, appRef);
|
|
_checkPath();
|
|
}
|
|
return response;
|
|
}, options);
|
|
};
|
|
(function() {
|
|
VFS['delete'] = function(item, callback) {
|
|
VFS.unlink.apply(this, arguments);
|
|
};
|
|
})();
|
|
VFS.mkdir = function(item, callback, options, appRef) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
existsWrapper(item, function(error) {
|
|
if ( error ) {
|
|
return callback(API._('ERR_VFSMODULE_MKDIR_FMT', error));
|
|
}
|
|
requestWrapper([item.path, 'mkdir', [item]], 'ERR_VFSMODULE_MKDIR_FMT', callback, function(error, response) {
|
|
if ( !error ) {
|
|
broadcastMessage('vfs:mkdir', item, appRef);
|
|
}
|
|
return response;
|
|
}, options);
|
|
});
|
|
};
|
|
VFS.exists = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'exists', [item]], 'ERR_VFSMODULE_EXISTS_FMT', callback);
|
|
};
|
|
VFS.fileinfo = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'fileinfo', [item]], 'ERR_VFSMODULE_FILEINFO_FMT', callback);
|
|
};
|
|
VFS.url = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'url', [item]], 'ERR_VFSMODULE_URL_FMT', callback, function(error, response) {
|
|
return error ? false : Utils.checkdir(response);
|
|
});
|
|
};
|
|
VFS.upload = function(args, callback, options, appRef) {
|
|
args = args || {};
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
if ( !args.files ) {
|
|
throw new Error(API._('ERR_VFS_UPLOAD_NO_FILES'));
|
|
}
|
|
if ( !args.destination ) {
|
|
throw new Error(API._('ERR_VFS_UPLOAD_NO_DEST'));
|
|
}
|
|
function _createFile(filename, mime, size) {
|
|
var npath = (args.destination + '/' + filename).replace(/\/\/\/\/+/, '///');
|
|
return new VFS.File({
|
|
filename: filename,
|
|
path: npath,
|
|
mime: mime || 'application/octet-stream',
|
|
size: size
|
|
});
|
|
}
|
|
function _dialogClose(ev, btn, ufile) {
|
|
if ( btn !== 'ok' && btn !== 'complete' ) {
|
|
callback(false, false);
|
|
return;
|
|
}
|
|
var file = _createFile(ufile.name, ufile.mime, ufile.size);
|
|
callback(false, file);
|
|
}
|
|
var mm = Core.getMountManager();
|
|
if ( !mm.isInternal(args.destination) ) {
|
|
args.files.forEach(function(f, i) {
|
|
request(args.destination, 'upload', [f, args.destination], callback, options);
|
|
});
|
|
return;
|
|
}
|
|
function doRequest(f, i) {
|
|
if ( args.app ) {
|
|
API.createDialog('FileUpload', {
|
|
dest: args.destination,
|
|
file: f
|
|
}, _dialogClose, args.win || args.app);
|
|
} else {
|
|
var realDest = new VFS.File(args.destination);
|
|
var tmpPath = hasAlias(realDest);
|
|
if ( tmpPath ) {
|
|
realDest = tmpPath;
|
|
}
|
|
VFS.Transports.Internal.upload(f, realDest, function(err, result, ev) {
|
|
if ( err ) {
|
|
if ( err === 'canceled' ) {
|
|
callback(API._('ERR_VFS_UPLOAD_CANCELLED'), null, ev);
|
|
} else {
|
|
var errstr = ev ? ev.toString() : 'Unknown reason';
|
|
var msg = API._('ERR_VFS_UPLOAD_FAIL_FMT', errstr);
|
|
callback(msg, null, ev);
|
|
}
|
|
} else {
|
|
var file = _createFile(f.name, f.type, f.size);
|
|
broadcastMessage('vfs:upload', file, args.app);
|
|
callback(false, file, ev);
|
|
}
|
|
}, options);
|
|
}
|
|
}
|
|
args.files.forEach(function(f, i) {
|
|
var filename = (f instanceof window.File) ? f.name : f.filename;
|
|
var dest = new VFS.File(args.destination + '/' + filename);
|
|
existsWrapper(dest, function(error) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
try {
|
|
doRequest(f, i);
|
|
} catch ( e ) {
|
|
callback(API._('ERR_VFS_UPLOAD_FAIL_FMT', e));
|
|
}
|
|
}, options);
|
|
});
|
|
};
|
|
VFS.download = (function download() {
|
|
var _didx = 1;
|
|
return function(args, callback) {
|
|
args = args || {};
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
if ( !args.path ) {
|
|
throw new Error(API._('ERR_VFS_DOWNLOAD_NO_FILE'));
|
|
}
|
|
args = checkMetadataArgument(args);
|
|
var lname = 'DownloadFile_' + _didx;
|
|
_didx++;
|
|
API.createLoading(lname, {className: 'BusyNotification', tooltip: API._('TOOLTIP_VFS_DOWNLOAD_NOTIFICATION')});
|
|
var mm = Core.getMountManager();
|
|
var dmodule = mm.getModuleFromPath(args.path);
|
|
if ( !mm.isInternal(args.path) ) {
|
|
var file = args;
|
|
if ( !(file instanceof VFS.File) ) {
|
|
file = new VFS.File(args.path);
|
|
if ( args.id ) {
|
|
file.id = args.id;
|
|
}
|
|
}
|
|
mm.getModule(dmodule).request('read', [file], function(error, result) {
|
|
API.destroyLoading(lname);
|
|
if ( error ) {
|
|
callback(API._('ERR_VFS_DOWNLOAD_FAILED', error));
|
|
return;
|
|
}
|
|
callback(false, result);
|
|
});
|
|
return;
|
|
}
|
|
VFS.url(args, function(error, url) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
Utils.ajax({
|
|
url: url,
|
|
method: 'GET',
|
|
responseType: 'arraybuffer',
|
|
onsuccess: function(result) {
|
|
API.destroyLoading(lname);
|
|
callback(false, result);
|
|
},
|
|
onerror: function(result) {
|
|
API.destroyLoading(lname);
|
|
callback(error);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
})();
|
|
VFS.trash = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'trash', [item]], 'ERR_VFSMODULE_TRASH_FMT', callback);
|
|
};
|
|
VFS.untrash = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
requestWrapper([item.path, 'untrash', [item]], 'ERR_VFSMODULE_UNTRASH_FMT', callback);
|
|
};
|
|
VFS.emptyTrash = function(callback) {
|
|
if ( arguments.length < 1 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
requestWrapper([null, 'emptyTrash', []], 'ERR_VFSMODULE_EMPTYTRASH_FMT', callback);
|
|
};
|
|
VFS.freeSpace = function(item, callback) {
|
|
if ( arguments.length < 2 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
item = checkMetadataArgument(item);
|
|
var m = Core.getMountManager().getModuleFromPath(item.path, false, true);
|
|
requestWrapper([item.path, 'freeSpace', [m.root]], 'ERR_VFSMODULE_FREESPACE_FMT', callback);
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.Core);
|
|
|
|
(function(Utils, API, VFS) {
|
|
'use strict';
|
|
function FileDataURL(dataURL) {
|
|
this.dataURL = dataURL;
|
|
}
|
|
FileDataURL.prototype.toBase64 = function() {
|
|
return this.data.split(',')[1];
|
|
};
|
|
FileDataURL.prototype.toString = function() {
|
|
return this.dataURL;
|
|
};
|
|
function FileMetadata(arg, mime) {
|
|
if ( !arg ) {
|
|
throw new Error(API._('ERR_VFS_FILE_ARGS'));
|
|
}
|
|
this.path = null;
|
|
this.filename = null;
|
|
this.type = null;
|
|
this.size = null;
|
|
this.mime = null;
|
|
this.id = null;
|
|
if ( typeof arg === 'object' ) {
|
|
this.setData(arg);
|
|
} else if ( typeof arg === 'string' ) {
|
|
this.path = arg;
|
|
this.setData();
|
|
}
|
|
if ( typeof mime === 'string' ) {
|
|
if ( mime.match(/\//) ) {
|
|
this.mime = mime;
|
|
} else {
|
|
this.type = mime;
|
|
}
|
|
}
|
|
this._guessMime();
|
|
}
|
|
FileMetadata.prototype.setData = function(o) {
|
|
var self = this;
|
|
if ( o ) {
|
|
Object.keys(o).forEach(function(k) {
|
|
if ( k !== '_element' ) {
|
|
self[k] = o[k];
|
|
}
|
|
});
|
|
}
|
|
if ( !this.filename ) {
|
|
this.filename = Utils.filename(this.path);
|
|
}
|
|
};
|
|
FileMetadata.prototype.getData = function() {
|
|
return {
|
|
path: this.path,
|
|
filename: this.filename,
|
|
type: this.type,
|
|
size: this.size,
|
|
mime: this.mime,
|
|
id: this.id
|
|
};
|
|
};
|
|
FileMetadata.prototype.copy = function(dest, callback, options, appRef) {
|
|
return VFS.copy(this, dest, callback, options, appRef);
|
|
};
|
|
FileMetadata.prototype.download = function(callback) {
|
|
return VFS.download(this, callback);
|
|
};
|
|
FileMetadata.prototype.delete = function() {
|
|
return this.unlink.apply(this, arguments);
|
|
};
|
|
FileMetadata.prototype.unlink = function(callback, options, appRef) {
|
|
return VFS.unlink(this, callback, options, appRef);
|
|
};
|
|
FileMetadata.prototype.exists = function(callback) {
|
|
return VFS.exists(this, callback);
|
|
};
|
|
FileMetadata.prototype.mkdir = function(callback, options, appRef) {
|
|
return VFS.mkdir(this, callback, options, appRef);
|
|
};
|
|
FileMetadata.prototype.move = function(dest, callback, options, appRef) {
|
|
var self = this;
|
|
return VFS.move(this, dest, function(err, res, newDest) {
|
|
if ( !err && newDest ) {
|
|
self.setData(newDest);
|
|
}
|
|
callback.apply(this, arguments);
|
|
}, options, appRef);
|
|
};
|
|
FileMetadata.prototype.read = function(callback, options) {
|
|
return VFS.read(this, callback, options);
|
|
};
|
|
FileMetadata.prototype.rename = function() {
|
|
return this.move.apply(this, arguments);
|
|
};
|
|
FileMetadata.prototype.scandir = function(callback, options) {
|
|
return VFS.scandir(this, callback, options);
|
|
};
|
|
FileMetadata.prototype.trash = function(callback) {
|
|
return VFS.trash(this, callback);
|
|
};
|
|
FileMetadata.prototype.untrash = function(callback) {
|
|
return VFS.untrash(this, callback);
|
|
};
|
|
FileMetadata.prototype.url = function(callback) {
|
|
return VFS.url(this, callback);
|
|
};
|
|
FileMetadata.prototype.write = function(data, callback, options, appRef) {
|
|
return VFS.write(this, data, callback, options, appRef);
|
|
};
|
|
FileMetadata.prototype._guessMime = function() {
|
|
if ( this.mime || this.type === 'dir' || (!this.path || this.path.match(/\/$/)) ) {
|
|
return;
|
|
}
|
|
var ext = Utils.filext(this.path);
|
|
this.mime = API.getConfig('MIME.mapping')['.' + ext] || 'application/octet-stream';
|
|
};
|
|
VFS.file = function createFileInstance(arg, mime) {
|
|
return new FileMetadata(arg, mime);
|
|
};
|
|
VFS.File = FileMetadata;
|
|
VFS.FileDataURL = FileDataURL;
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS);
|
|
|
|
(function(Utils, API, VFS) {
|
|
'use strict';
|
|
function makePath(item) {
|
|
if ( typeof item === 'string' ) {
|
|
item = new VFS.File(item);
|
|
}
|
|
return OSjs.Core.getHandler().getVFSPath(item);
|
|
}
|
|
function internalRequest(name, args, callback) {
|
|
API.call('FS:' + name, args, function(err, res) {
|
|
if ( !err && typeof res === 'undefined' ) {
|
|
err = API._('ERR_VFS_FATAL');
|
|
}
|
|
callback(err, res);
|
|
});
|
|
}
|
|
function internalUpload(file, dest, callback, options) {
|
|
options = options || {};
|
|
if ( dest instanceof VFS.File ) {
|
|
dest = dest.path;
|
|
}
|
|
if ( typeof file.size !== 'undefined' ) {
|
|
var maxSize = API.getConfig('VFS.MaxUploadSize');
|
|
if ( maxSize > 0 ) {
|
|
var bytes = file.size;
|
|
if ( bytes > maxSize ) {
|
|
var msg = API._('DIALOG_UPLOAD_TOO_BIG_FMT', Utils.humanFileSize(maxSize));
|
|
callback('error', null, msg);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
var fd = new FormData();
|
|
fd.append('upload', 1);
|
|
fd.append('path', dest);
|
|
if ( options ) {
|
|
Object.keys(options).forEach(function(key) {
|
|
fd.append(key, String(options[key]));
|
|
});
|
|
}
|
|
VFS.Helpers.addFormFile(fd, 'upload', file);
|
|
OSjs.Core.getHandler().callAPI('FS:upload', fd, callback, null, options);
|
|
}
|
|
function internalFetch(url, mime, callback, options) {
|
|
options = options || {};
|
|
options.type = options.type || 'binary';
|
|
mime = options.mime || 'application/octet-stream';
|
|
if ( arguments.length < 1 ) {
|
|
throw new Error(API._('ERR_VFS_NUM_ARGS'));
|
|
}
|
|
options = options || {};
|
|
API.curl({
|
|
url: url,
|
|
binary: true,
|
|
mime: mime
|
|
}, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !response.body ) {
|
|
callback(API._('ERR_VFS_REMOTEREAD_EMPTY'));
|
|
return;
|
|
}
|
|
if ( options.type.toLowerCase() === 'datasource' ) {
|
|
callback(false, response.body);
|
|
return;
|
|
}
|
|
VFS.Helpers.dataSourceToAb(response.body, mime, function(error, response) {
|
|
if ( options.type === 'text' ) {
|
|
VFS.Helpers.abToText(response, mime, function(error, text) {
|
|
callback(error, text);
|
|
});
|
|
return;
|
|
}
|
|
callback(error, response);
|
|
});
|
|
});
|
|
}
|
|
var Transport = {
|
|
scandir: function(item, callback, options) {
|
|
internalRequest('scandir', {path: item.path}, function(error, result) {
|
|
var list = [];
|
|
if ( result ) {
|
|
result = VFS.Helpers.filterScandir(result, options);
|
|
result.forEach(function(iter) {
|
|
list.push(new VFS.File(iter));
|
|
});
|
|
}
|
|
callback(error, list);
|
|
});
|
|
},
|
|
write: function(item, data, callback, options) {
|
|
options = options || {};
|
|
options.onprogress = options.onprogress || function() {};
|
|
function _write(dataSource) {
|
|
var wopts = {path: item.path, data: dataSource};
|
|
internalRequest('write', wopts, callback, options);
|
|
}
|
|
if ( typeof data === 'string' && !data.length ) {
|
|
_write(data);
|
|
return;
|
|
}
|
|
VFS.Helpers.abToDataSource(data, item.mime, function(error, dataSource) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
_write(dataSource);
|
|
});
|
|
},
|
|
read: function(item, callback, options) {
|
|
if ( API.getConfig('Connection.Type') === 'nw' ) {
|
|
OSjs.Core.getHandler().nw.request(true, 'read', {
|
|
path: item.path,
|
|
options: {raw: true}
|
|
}, function(err, res) {
|
|
callback(err, res);
|
|
});
|
|
return;
|
|
}
|
|
internalRequest('get', {path: item.path}, callback, options);
|
|
},
|
|
copy: function(src, dest, callback) {
|
|
internalRequest('copy', {src: src.path, dest: dest.path}, callback);
|
|
},
|
|
move: function(src, dest, callback) {
|
|
internalRequest('move', {src: src.path, dest: dest.path}, callback);
|
|
},
|
|
unlink: function(item, callback) {
|
|
internalRequest('delete', {path: item.path}, callback);
|
|
},
|
|
mkdir: function(item, callback) {
|
|
internalRequest('mkdir', {path: item.path}, callback);
|
|
},
|
|
exists: function(item, callback) {
|
|
internalRequest('exists', {path: item.path}, callback);
|
|
},
|
|
fileinfo: function(item, callback) {
|
|
internalRequest('fileinfo', {path: item.path}, callback);
|
|
},
|
|
find: function(item, args, callback) {
|
|
internalRequest('find', {path: item.path, args: args}, callback);
|
|
},
|
|
url: function(item, callback) {
|
|
callback(false, VFS.Transports.Internal.path(item));
|
|
},
|
|
freeSpace: function(root, callback) {
|
|
internalRequest('freeSpace', {root: root}, callback);
|
|
}
|
|
};
|
|
VFS.Transports.Internal = {
|
|
request: internalRequest,
|
|
upload: internalUpload,
|
|
fetch: internalFetch,
|
|
module: Transport,
|
|
path: makePath
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS);
|
|
|
|
(function(Utils, API, VFS) {
|
|
'use strict';
|
|
VFS.Transports.HTTP = {
|
|
module: {
|
|
read: function(item, callback, options) {
|
|
VFS.Transports.Internal.fetch(item.path, item.mime, callback, options);
|
|
}
|
|
}
|
|
};
|
|
OSjs.Core.getMountManager()._add({
|
|
readOnly: true,
|
|
name: 'HTTP',
|
|
transport: 'HTTP',
|
|
description: 'HTTP',
|
|
visible: false,
|
|
searchable: false,
|
|
unmount: function(cb) {
|
|
cb(false, false);
|
|
},
|
|
mounted: function() {
|
|
return true;
|
|
},
|
|
enabled: function() {
|
|
return true;
|
|
},
|
|
root: 'http:///',
|
|
icon: 'places/google-drive.png',
|
|
match: /^https?\:\/\//
|
|
});
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var Transport = {
|
|
url: function(item, callback) {
|
|
var root = window.location.pathname || '/';
|
|
if ( root === '/' || window.location.protocol === 'file:' ) {
|
|
root = '';
|
|
}
|
|
var mm = OSjs.Core.getMountManager();
|
|
var module = mm.getModuleFromPath(item.path, false, true);
|
|
var url = item.path.replace(module.match, root);
|
|
callback(false, url);
|
|
}
|
|
};
|
|
var restricted = ['write', 'move', 'unlink', 'mkdir', 'exists', 'fileinfo', 'trash', 'untrash', 'emptyTrash', 'freeSpace'];
|
|
var internal = OSjs.VFS.Transports.Internal.module;
|
|
Object.keys(internal).forEach(function(n) {
|
|
if ( restricted.indexOf(n) === -1 ) {
|
|
Transport[n] = internal[n];
|
|
}
|
|
});
|
|
OSjs.VFS.Transports.OSjs = {
|
|
module: Transport,
|
|
defaults: function(opts) {
|
|
opts.readOnly = true;
|
|
opts.searchable = true;
|
|
}
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
function makePath(file) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var rel = mm.getPathProtocol(file.path);
|
|
var module = mm.getModuleFromPath(file.path, false, true);
|
|
var base = (module.options || {}).url;
|
|
return base + rel.replace(/^\/+/, '/');
|
|
}
|
|
function httpCall(func, item, callback) {
|
|
var url = makePath(item);
|
|
if ( func === 'scandir' ) {
|
|
url += '/_scandir.json';
|
|
}
|
|
var args = {
|
|
method: func === 'exists' ? 'HEAD' : 'GET',
|
|
url: url,
|
|
onerror: function(error) {
|
|
callback(error);
|
|
},
|
|
onsuccess: function(response) {
|
|
callback(false, response);
|
|
}
|
|
};
|
|
if ( func === 'read' ) {
|
|
args.responseType = 'arraybuffer';
|
|
}
|
|
Utils.ajax(args);
|
|
}
|
|
var Transport = {
|
|
scandir: function(item, callback, options) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var root = mm.getRootFromPath(item.path);
|
|
httpCall('scandir', item, function(error, response) {
|
|
var list = null;
|
|
if ( !error ) {
|
|
var json = null;
|
|
try {
|
|
json = JSON.parse(response);
|
|
} catch ( e ) {}
|
|
if ( json === null ) {
|
|
error = 'Failed to parse directory JSON';
|
|
} else {
|
|
list = json.map(function(iter) {
|
|
iter.path = root + iter.path.replace(/^\//, '');
|
|
return iter;
|
|
});
|
|
var rel = Utils.getPathProtocol(item.path);
|
|
if ( rel !== '/' ) {
|
|
list.unshift({
|
|
filename: '..',
|
|
path: Utils.dirname(item.path),
|
|
type: 'dir',
|
|
size: 0
|
|
});
|
|
}
|
|
}
|
|
}
|
|
callback(error, list);
|
|
});
|
|
},
|
|
read: function(item, callback, options) {
|
|
options = options || {};
|
|
var mime = item.mime || 'application/octet-stream';
|
|
httpCall('read', item, function(error, response) {
|
|
if ( !error ) {
|
|
if ( options.type === 'text' ) {
|
|
OSjs.VFS.Helpers.abToText(response, mime, function(error, text) {
|
|
callback(error, text);
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
callback(error, response);
|
|
});
|
|
},
|
|
exists: function(item, callback) {
|
|
httpCall('exists', item, function(err) {
|
|
callback(err, err ? false : true);
|
|
});
|
|
},
|
|
url: function(item, callback, options) {
|
|
callback(false, makePath(item));
|
|
}
|
|
};
|
|
OSjs.VFS.Transports.Web = {
|
|
defaults: function(iter) {
|
|
iter.readOnly = true;
|
|
iter.match = /^https?\:\/\//;
|
|
},
|
|
module: Transport,
|
|
path: makePath
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
function getModule(item) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var module = mm.getModuleFromPath(item.path, false, true);
|
|
if ( !module ) {
|
|
throw new Error(API._('ERR_VFSMODULE_INVALID_FMT', item.path));
|
|
}
|
|
return module;
|
|
}
|
|
function getNamespace(item) {
|
|
var module = getModule(item);
|
|
return module.options.ns || 'DAV:';
|
|
}
|
|
function getCORSAllowed(item) {
|
|
var module = getModule(item);
|
|
var val = module.options.cors;
|
|
return typeof val === 'undefined' ? false : val === true;
|
|
}
|
|
function getURL(item) {
|
|
if ( typeof item === 'string' ) {
|
|
item = new OSjs.VFS.File(item);
|
|
}
|
|
var module = getModule(item);
|
|
var opts = module.options;
|
|
return Utils.parseurl(opts.host, {username: opts.username, password: opts.password}).url;
|
|
}
|
|
function getURI(item) {
|
|
var module = getModule(item);
|
|
return Utils.parseurl(module.options.host).path;
|
|
}
|
|
function resolvePath(item) {
|
|
var module = getModule(item);
|
|
return item.path.replace(module.match, '');
|
|
}
|
|
function davCall(method, args, callback, raw) {
|
|
function parseDocument(body) {
|
|
var parser = new DOMParser();
|
|
var doc = parser.parseFromString(body, 'application/xml');
|
|
return doc.firstChild;
|
|
}
|
|
function getUrl(p, f) {
|
|
var url = getURL(p);
|
|
url += resolvePath(f).replace(/^\//, '');
|
|
return url;
|
|
}
|
|
var mime = args.mime || 'application/octet-stream';
|
|
var headers = {};
|
|
var sourceFile = new OSjs.VFS.File(args.path, mime);
|
|
var sourceUrl = getUrl(args.path, sourceFile);
|
|
var destUrl = null;
|
|
if ( args.dest ) {
|
|
destUrl = getUrl(args.dest, new OSjs.VFS.File(args.dest, mime));
|
|
headers.Destination = destUrl;
|
|
}
|
|
function externalCall() {
|
|
var opts = {
|
|
url: sourceUrl,
|
|
method: method,
|
|
requestHeaders: headers
|
|
};
|
|
if ( raw ) {
|
|
opts.binary = true;
|
|
opts.mime = mime;
|
|
}
|
|
if ( typeof args.data !== 'undefined' ) {
|
|
opts.query = args.data;
|
|
}
|
|
API.call('curl', opts, function(error, result) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !result ) {
|
|
callback(API._('ERR_VFS_REMOTEREAD_EMPTY'));
|
|
return;
|
|
}
|
|
if ( ([200, 201, 203, 204, 205, 207]).indexOf(result.httpCode) < 0 ) {
|
|
callback(API._('ERR_VFSMODULE_XHR_ERROR') + ': ' + result.httpCode);
|
|
return;
|
|
}
|
|
if ( opts.binary ) {
|
|
OSjs.VFS.Helpers.dataSourceToAb(result.body, mime, callback);
|
|
} else {
|
|
var doc = parseDocument(result.body);
|
|
callback(false, doc);
|
|
}
|
|
});
|
|
}
|
|
if ( getCORSAllowed(sourceFile) ) {
|
|
OSjs.VFS.Transports.Internal.request('get', {url: sourceUrl, method: method}, callback);
|
|
} else {
|
|
externalCall();
|
|
}
|
|
}
|
|
var Transport = {
|
|
scandir: function(item, callback, options) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
function parse(doc) {
|
|
var ns = getNamespace(item);
|
|
var list = [];
|
|
var reqpath = resolvePath(item);
|
|
var root = mm.getRootFromPath(item.path);
|
|
doc.children.forEach(function(c) {
|
|
var type = 'file';
|
|
function getPath() {
|
|
var path = c.getElementsByTagNameNS(ns, 'href')[0].textContent;
|
|
return path.substr(getURI(item).length - 1, path.length);
|
|
}
|
|
function getId() {
|
|
var id = null;
|
|
try {
|
|
id = c.getElementsByTagNameNS(ns, 'getetag')[0].textContent;
|
|
} catch ( e ) {
|
|
}
|
|
return id;
|
|
}
|
|
function getMime() {
|
|
var mime = null;
|
|
if ( type === 'file' ) {
|
|
try {
|
|
mime = c.getElementsByTagNameNS(ns, 'getcontenttype')[0].textContent || 'application/octet-stream';
|
|
} catch ( e ) {
|
|
mime = 'application/octet-stream';
|
|
}
|
|
}
|
|
return mime;
|
|
}
|
|
function getSize() {
|
|
var size = 0;
|
|
if ( type === 'file' ) {
|
|
try {
|
|
size = parseInt(c.getElementsByTagNameNS(ns, 'getcontentlength')[0].textContent, 10) || 0;
|
|
} catch ( e ) {
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
try {
|
|
var path = getPath();
|
|
if ( path.match(/\/$/) ) {
|
|
type = 'dir';
|
|
path = path.replace(/\/$/, '') || '/';
|
|
}
|
|
if ( path !== reqpath ) {
|
|
list.push({
|
|
id: getId(),
|
|
path: root + path.replace(/^\//, ''),
|
|
filename: Utils.filename(path),
|
|
size: getSize(),
|
|
mime: getMime(),
|
|
type: type
|
|
});
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('scandir() exception', e, e.stack);
|
|
}
|
|
});
|
|
return OSjs.VFS.Helpers.filterScandir(list, options);
|
|
}
|
|
davCall('PROPFIND', {path: item.path}, function(error, doc) {
|
|
var list = [];
|
|
if ( !error && doc ) {
|
|
var result = parse(doc);
|
|
result.forEach(function(iter) {
|
|
list.push(new OSjs.VFS.File(iter));
|
|
});
|
|
}
|
|
callback(error, list);
|
|
});
|
|
},
|
|
write: function(item, data, callback, options) {
|
|
davCall('PUT', {path: item.path, mime: item.mime, data: data}, callback);
|
|
},
|
|
read: function(item, callback, options) {
|
|
davCall('GET', {path: item.path, mime: item.mime}, callback, true);
|
|
},
|
|
copy: function(src, dest, callback) {
|
|
davCall('COPY', {path: src.path, dest: dest.path}, callback);
|
|
},
|
|
move: function(src, dest, callback) {
|
|
davCall('MOVE', {path: src.path, dest: dest.path}, callback);
|
|
},
|
|
unlink: function(item, callback) {
|
|
davCall('DELETE', {path: item.path}, callback);
|
|
},
|
|
mkdir: function(item, callback) {
|
|
davCall('MKCOL', {path: item.path}, callback);
|
|
},
|
|
exists: function(item, callback) {
|
|
davCall('PROPFIND', {path: item.path}, function(error, doc) {
|
|
callback(false, !error);
|
|
});
|
|
},
|
|
url: function(item, callback, options) {
|
|
callback(false, OSjs.VFS.Transports.WebDAV.path(item));
|
|
},
|
|
freeSpace: function(root, callback) {
|
|
callback(false, -1);
|
|
}
|
|
};
|
|
function makePath(item) {
|
|
if ( typeof item === 'string' ) {
|
|
item = new OSjs.VFS.File(item);
|
|
}
|
|
var url = getURL(item);
|
|
var reqpath = resolvePath(item).replace(/^\//, '');
|
|
var fullpath = url + reqpath;
|
|
if ( !getCORSAllowed(item) ) {
|
|
fullpath = API.getConfig('Connection.FSURI') + '/get/' + fullpath;
|
|
}
|
|
return fullpath;
|
|
}
|
|
OSjs.VFS.Transports.WebDAV = {
|
|
module: Transport,
|
|
path: makePath
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API, VFS) {
|
|
'use strict';
|
|
var Transport = {
|
|
scandir: function(item, callback, options) {
|
|
var metadata = OSjs.Core.getPackageManager().getPackages();
|
|
var files = [];
|
|
Object.keys(metadata).forEach(function(m) {
|
|
var iter = metadata[m];
|
|
if ( iter.type !== 'extension' ) {
|
|
files.push(new OSjs.VFS.File({
|
|
filename: iter.name,
|
|
icon: {
|
|
filename: iter.icon,
|
|
application: m
|
|
},
|
|
type: 'application',
|
|
path: 'applications:///' + m,
|
|
mime: 'osjs/application'
|
|
}, 'osjs/application'));
|
|
}
|
|
});
|
|
callback(false, files);
|
|
}
|
|
};
|
|
VFS.Transports.Applications = {
|
|
module: Transport,
|
|
defaults: function(opts) {
|
|
opts.readOnly = true;
|
|
opts.special = true;
|
|
opts.searchable = true;
|
|
}
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var gapi = window.gapi = window.gapi || {};
|
|
var CACHE_CLEAR_TIMEOUT = 7000;
|
|
var _isMounted = false;
|
|
var _rootFolderId = null;
|
|
var _treeCache = null;
|
|
var _clearCacheTimeout;
|
|
function createBoundary(file, data, callback) {
|
|
var boundary = '-------314159265358979323846';
|
|
var delimiter = '\r\n--' + boundary + '\r\n';
|
|
var close_delim = '\r\n--' + boundary + '--';
|
|
var contentType = file.mime || 'text/plain'; //fileData.type || 'application/octet-stream';
|
|
function createBody(result) {
|
|
var metadata = {
|
|
title: file.filename,
|
|
mimeType: contentType
|
|
};
|
|
var base64Data = result;
|
|
var multipartRequestBody =
|
|
delimiter +
|
|
'Content-Type: application/json\r\n\r\n' +
|
|
JSON.stringify(metadata) +
|
|
delimiter +
|
|
'Content-Type: ' + contentType + '\r\n' +
|
|
'Content-Transfer-Encoding: base64\r\n' +
|
|
'\r\n' +
|
|
base64Data +
|
|
close_delim;
|
|
return multipartRequestBody;
|
|
}
|
|
var reqContentType = 'multipart/mixed; boundary=\'' + boundary + '\'';
|
|
if ( data instanceof OSjs.VFS.FileDataURL ) {
|
|
callback(false, {
|
|
contentType: reqContentType,
|
|
body: createBody(data.toBase64())
|
|
});
|
|
} else {
|
|
OSjs.VFS.Helpers.abToBinaryString(data, contentType, function(error, response) {
|
|
callback(error, error ? false : {
|
|
contentType: reqContentType,
|
|
body: createBody(btoa(response))
|
|
});
|
|
});
|
|
}
|
|
}
|
|
function getFileFromPath(dir, type, callback) {
|
|
if ( dir instanceof OSjs.VFS.File ) {
|
|
dir = dir.path;
|
|
}
|
|
var tmpItem = new OSjs.VFS.File({
|
|
filename: Utils.filename(dir),
|
|
type: 'dir',
|
|
path: Utils.dirname(dir)
|
|
});
|
|
getAllDirectoryFiles(tmpItem, function(error, list, ldir) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
var found = null;
|
|
list.forEach(function(iter) {
|
|
if ( iter.title === Utils.filename(dir) ) {
|
|
if ( type ) {
|
|
if ( iter.mimeType === type ) {
|
|
found = iter;
|
|
return false;
|
|
}
|
|
} else {
|
|
found = iter;
|
|
}
|
|
}
|
|
return true;
|
|
});
|
|
callback(false, found);
|
|
});
|
|
}
|
|
function getParentPathId(item, callback) {
|
|
var dir = Utils.dirname(item.path);
|
|
var type = 'application/vnd.google-apps.folder';
|
|
getFileFromPath(dir, type, function(error, item) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
callback(false, item ? item.id : null);
|
|
});
|
|
}
|
|
function createDirectoryList(dir, list, item, options) {
|
|
var result = [];
|
|
var rdir = dir.replace(/^google-drive\:\/+/, '/'); // FIXME
|
|
var isOnRoot = rdir === '/';
|
|
function createItem(iter, i) {
|
|
var path = dir;
|
|
if ( iter.title === '..' ) {
|
|
path = Utils.dirname(dir);
|
|
} else {
|
|
if ( !isOnRoot ) {
|
|
path += '/';
|
|
}
|
|
path += iter.title;
|
|
}
|
|
var fileType = iter.mimeType === 'application/vnd.google-apps.folder' ? 'dir' : (iter.kind === 'drive#file' ? 'file' : 'dir');
|
|
if ( iter.mimeType === 'application/vnd.google-apps.trash' ) {
|
|
fileType = 'trash';
|
|
}
|
|
return new OSjs.VFS.File({
|
|
filename: iter.title,
|
|
path: path,
|
|
id: iter.id,
|
|
size: iter.quotaBytesUsed || 0,
|
|
mime: iter.mimeType === 'application/vnd.google-apps.folder' ? null : iter.mimeType,
|
|
type: fileType
|
|
});
|
|
}
|
|
if ( list ) {
|
|
list.forEach(function(iter, i) {
|
|
if ( !iter ) {
|
|
return;
|
|
}
|
|
result.push(createItem(iter, i));
|
|
});
|
|
}
|
|
return result ? OSjs.VFS.Helpers.filterScandir(result, options) : [];
|
|
}
|
|
function getAllDirectoryFiles(item, callback) {
|
|
function retrieveAllFiles(cb) {
|
|
if ( _clearCacheTimeout ) {
|
|
clearTimeout(_clearCacheTimeout);
|
|
_clearCacheTimeout = null;
|
|
}
|
|
if ( _treeCache ) {
|
|
cb(false, _treeCache);
|
|
return;
|
|
}
|
|
var list = [];
|
|
function retrievePageOfFiles(request, result) {
|
|
request.execute(function(resp) {
|
|
if ( resp.error ) {
|
|
console.warn('GoogleDrive::getAllDirectoryFiles()', 'error', resp);
|
|
}
|
|
result = result.concat(resp.items);
|
|
var nextPageToken = resp.nextPageToken;
|
|
if (nextPageToken) {
|
|
request = gapi.client.drive.files.list({
|
|
pageToken: nextPageToken
|
|
});
|
|
retrievePageOfFiles(request, result);
|
|
} else {
|
|
_treeCache = result;
|
|
cb(false, result);
|
|
}
|
|
});
|
|
}
|
|
try {
|
|
var initialRequest = gapi.client.drive.files.list({});
|
|
retrievePageOfFiles(initialRequest, list);
|
|
} catch ( e ) {
|
|
console.warn('GoogleDrive::getAllDirectoryFiles() exception', e, e.stack);
|
|
console.warn('THIS ERROR OCCURS WHEN MULTIPLE REQUESTS FIRE AT ONCE ?!'); // FIXME
|
|
cb(false, list);
|
|
}
|
|
}
|
|
function getFilesBelongingTo(list, root, cb) {
|
|
var idList = {};
|
|
var parentList = {};
|
|
list.forEach(function(iter) {
|
|
if ( iter ) {
|
|
idList[iter.id] = iter;
|
|
var parents = [];
|
|
if ( iter.parents ) {
|
|
iter.parents.forEach(function(piter) {
|
|
if ( piter ) {
|
|
parents.push(piter.id);
|
|
}
|
|
});
|
|
}
|
|
parentList[iter.id] = parents;
|
|
}
|
|
});
|
|
var resolves = Utils.getPathProtocol(root).replace(/^\/+/, '').split('/');
|
|
resolves = resolves.filter(function(el) {
|
|
return el !== '';
|
|
});
|
|
var currentParentId = _rootFolderId;
|
|
var isOnRoot = !resolves.length;
|
|
function _getFileList(foundId) {
|
|
var result = [];
|
|
if ( !isOnRoot ) {
|
|
result.push({
|
|
title: '..',
|
|
path: Utils.dirname(root),
|
|
id: item.id,
|
|
quotaBytesUsed: 0,
|
|
mimeType: 'application/vnd.google-apps.folder'
|
|
});
|
|
}
|
|
list.forEach(function(iter) {
|
|
if ( iter && parentList[iter.id] && parentList[iter.id].indexOf(foundId) !== -1 ) {
|
|
result.push(iter);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
function _nextDir(completed) {
|
|
var current = resolves.shift();
|
|
var done = resolves.length <= 0;
|
|
var found;
|
|
if ( isOnRoot ) {
|
|
found = currentParentId;
|
|
} else {
|
|
if ( current ) {
|
|
list.forEach(function(iter) {
|
|
if ( iter ) {
|
|
if ( iter.title === current && parentList[iter.id] && parentList[iter.id].indexOf(currentParentId) !== -1 ) {
|
|
currentParentId = iter.id;
|
|
found = iter.id;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
if ( done ) {
|
|
completed(found);
|
|
} else {
|
|
_nextDir(completed);
|
|
}
|
|
}
|
|
_nextDir(function(foundId) {
|
|
if ( foundId && idList[foundId] ) {
|
|
cb(false, _getFileList(foundId));
|
|
return;
|
|
} else {
|
|
if ( isOnRoot ) {
|
|
cb(false, _getFileList(currentParentId));
|
|
return;
|
|
}
|
|
}
|
|
cb('Could not list directory');
|
|
});
|
|
}
|
|
function doRetrieve() {
|
|
retrieveAllFiles(function(error, list) {
|
|
var root = item.path;
|
|
if ( error ) {
|
|
callback(error, false, root);
|
|
return;
|
|
}
|
|
getFilesBelongingTo(list, root, function(error, response) {
|
|
_clearCacheTimeout = setTimeout(function() {
|
|
_treeCache = null;
|
|
}, CACHE_CLEAR_TIMEOUT);
|
|
callback(error, response, root);
|
|
});
|
|
});
|
|
}
|
|
if ( !_rootFolderId ) {
|
|
var request = gapi.client.drive.about.get();
|
|
request.execute(function(resp) {
|
|
if ( !resp || !resp.rootFolderId ) {
|
|
callback(API._('ERR_VFSMODULE_ROOT_ID'));
|
|
return;
|
|
}
|
|
_rootFolderId = resp.rootFolderId;
|
|
doRetrieve();
|
|
});
|
|
} else {
|
|
doRetrieve();
|
|
}
|
|
}
|
|
function setFolder(item, pid, callback) {
|
|
pid = pid || 'root';
|
|
function _clearFolders(cb) {
|
|
item.parents.forEach(function(p, i) {
|
|
var request = gapi.client.drive.children.delete({
|
|
folderId: p.id,
|
|
childId: item.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( i >= (item.parents.length - 1) ) {
|
|
cb();
|
|
}
|
|
});
|
|
});
|
|
}
|
|
function _setFolder(rootId, cb) {
|
|
var request = gapi.client.drive.children.insert({
|
|
folderId: pid,
|
|
resource: {id: item.id}
|
|
});
|
|
request.execute(function(resp) {
|
|
callback(false, true);
|
|
});
|
|
}
|
|
_clearFolders(function() {
|
|
_setFolder(pid, callback);
|
|
});
|
|
}
|
|
var GoogleDriveStorage = {};
|
|
GoogleDriveStorage.scandir = function(item, callback, options) {
|
|
getAllDirectoryFiles(item, function(error, list, dir) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
var result = createDirectoryList(dir, list, item, options);
|
|
callback(false, result, list);
|
|
});
|
|
};
|
|
GoogleDriveStorage.read = function(item, callback, options) {
|
|
function doRead() {
|
|
var request = gapi.client.drive.files.get({
|
|
fileId: item.id
|
|
});
|
|
request.execute(function(file) {
|
|
if ( file && file.id ) {
|
|
var accessToken = gapi.auth.getToken().access_token;
|
|
Utils.ajax({
|
|
url: file.downloadUrl,
|
|
method: 'GET',
|
|
responseType: 'arraybuffer',
|
|
requestHeaders: {'Authorization': 'Bearer ' + accessToken},
|
|
onsuccess: function(response) {
|
|
callback(false, response);
|
|
},
|
|
onerror: function(error) {
|
|
callback(API._('ERR_VFSMODULE_XHR_ERROR') + ' - ' + error);
|
|
}
|
|
});
|
|
} else {
|
|
callback(API._('ERR_VFSMODULE_NOSUCH'));
|
|
}
|
|
});
|
|
}
|
|
if ( item.downloadUrl ) {
|
|
doRead();
|
|
} else {
|
|
getFileFromPath(item.path, item.mime, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !response ) {
|
|
callback(API._('ERR_VFSMODULE_NOSUCH'));
|
|
return;
|
|
}
|
|
item = response;
|
|
doRead();
|
|
});
|
|
}
|
|
};
|
|
GoogleDriveStorage.write = function(file, data, callback) {
|
|
var self = this;
|
|
function doWrite(parentId, fileId) {
|
|
var uri = '/upload/drive/v2/files';
|
|
var method = 'POST';
|
|
if ( fileId ) {
|
|
uri = '/upload/drive/v2/files/' + fileId;
|
|
method = 'PUT';
|
|
}
|
|
createBoundary(file, data, function(error, fileData) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
var request = gapi.client.request({
|
|
path: uri,
|
|
method: method,
|
|
params: {uploadType: 'multipart'},
|
|
headers: {'Content-Type': fileData.contentType},
|
|
body: fileData.body
|
|
});
|
|
request.execute(function(resp) {
|
|
_treeCache = null; // Make sure we refetch any cached stuff
|
|
if ( resp && resp.id ) {
|
|
if ( parentId ) {
|
|
setFolder(resp, parentId, callback);
|
|
} else {
|
|
callback(false, true);
|
|
}
|
|
} else {
|
|
callback(API._('ERR_VFSMODULE_NOSUCH'));
|
|
}
|
|
});
|
|
});
|
|
}
|
|
getParentPathId(file, function(error, id) {
|
|
if ( error ) {
|
|
return callback(error);
|
|
}
|
|
if ( file.id ) {
|
|
doWrite(id, file.id);
|
|
} else {
|
|
self.exists(file, function(error, exists) {
|
|
var fileid = error ? null : (exists ? exists.id : null);
|
|
doWrite(id, fileid);
|
|
});
|
|
}
|
|
});
|
|
};
|
|
GoogleDriveStorage.copy = function(src, dest, callback) {
|
|
var request = gapi.client.drive.files.copy({
|
|
fileId: Utils.filename(src),
|
|
resource: {title: Utils.filename(dest)}
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp.id ) {
|
|
callback(false, true);
|
|
return;
|
|
}
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
});
|
|
};
|
|
GoogleDriveStorage.unlink = function(src, callback) {
|
|
function doDelete() {
|
|
_treeCache = null; // Make sure we refetch any cached stuff
|
|
var request = gapi.client.drive.files.delete({
|
|
fileId: src.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp && (typeof resp.result === 'object') ) {
|
|
callback(false, true);
|
|
} else {
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
}
|
|
});
|
|
}
|
|
if ( !src.id ) {
|
|
getFileFromPath(src.path, src.mime, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !response ) {
|
|
callback(API._('ERR_VFSMODULE_NOSUCH'));
|
|
return;
|
|
}
|
|
src = response;
|
|
doDelete();
|
|
});
|
|
} else {
|
|
doDelete();
|
|
}
|
|
};
|
|
GoogleDriveStorage.move = function(src, dest, callback) {
|
|
var request = gapi.client.drive.files.patch({
|
|
fileId: src.id,
|
|
resource: {
|
|
title: Utils.filename(dest.path)
|
|
}
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp && resp.id ) {
|
|
_treeCache = null; // Make sure we refetch any cached stuff
|
|
callback(false, true);
|
|
} else {
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
}
|
|
});
|
|
};
|
|
GoogleDriveStorage.exists = function(item, callback) {
|
|
var req = new OSjs.VFS.File(OSjs.Utils.dirname(item.path));
|
|
this.scandir(req, function(error, result) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
var found = false;
|
|
if ( result ) {
|
|
result.forEach(function(iter) {
|
|
if ( iter.path === item.path ) {
|
|
found = new OSjs.VFS.File(item.path, iter.mimeType);
|
|
found.id = iter.id;
|
|
found.title = iter.title;
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
callback(false, found);
|
|
});
|
|
};
|
|
GoogleDriveStorage.fileinfo = function(item, callback) {
|
|
var request = gapi.client.drive.files.get({
|
|
fileId: item.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp && resp.id ) {
|
|
var useKeys = ['createdDate', 'id', 'lastModifyingUser', 'lastViewedByMeDate', 'markedViewedByMeDate', 'mimeType', 'modifiedByMeDate', 'modifiedDate', 'title', 'alternateLink'];
|
|
var info = {};
|
|
useKeys.forEach(function(k) {
|
|
info[k] = resp[k];
|
|
});
|
|
return callback(false, info);
|
|
}
|
|
callback(API._('ERR_VFSMODULE_NOSUCH'));
|
|
});
|
|
};
|
|
GoogleDriveStorage.url = function(item, callback) {
|
|
if ( !item || !item.id ) {
|
|
throw new Error('url() expects a File ref with Id');
|
|
}
|
|
var request = gapi.client.drive.files.get({
|
|
fileId: item.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp && resp.webContentLink ) {
|
|
callback(false, resp.webContentLink);
|
|
} else {
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
}
|
|
});
|
|
};
|
|
GoogleDriveStorage.mkdir = function(dir, callback) {
|
|
function doMkdir(parents) {
|
|
var request = gapi.client.request({
|
|
'path': '/drive/v2/files',
|
|
'method': 'POST',
|
|
'body': JSON.stringify({
|
|
title: dir.filename,
|
|
parents: parents,
|
|
mimeType: 'application/vnd.google-apps.folder'
|
|
})
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp && resp.id ) {
|
|
_treeCache = null; // Make sure we refetch any cached stuff
|
|
callback(false, true);
|
|
} else {
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
}
|
|
});
|
|
}
|
|
var mm = OSjs.Core.getMountManager();
|
|
if ( Utils.dirname(dir.path) !== Utils.getPathProtocol(mm.getModuleProperty('GoogleDrive', 'root')) ) {
|
|
getParentPathId(dir, function(error, id) {
|
|
if ( error || !id ) {
|
|
error = error || API._('ERR_VFSMODULE_PARENT');
|
|
callback(API._('ERR_VFSMODULE_PARENT_FMT', error));
|
|
return;
|
|
}
|
|
doMkdir([{id: id}]);
|
|
});
|
|
return;
|
|
}
|
|
doMkdir(null);
|
|
};
|
|
GoogleDriveStorage.upload = function(file, dest, callback) {
|
|
var item = new OSjs.VFS.File({
|
|
filename: file.name,
|
|
path: Utils.pathJoin((new OSjs.VFS.File(dest)).path, file.name),
|
|
mime: file.type,
|
|
size: file.size
|
|
});
|
|
this.write(item, file, callback);
|
|
};
|
|
GoogleDriveStorage.trash = function(file, callback) {
|
|
var request = gapi.client.drive.files.trash({
|
|
fileId: file.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp.id ) {
|
|
callback(false, true);
|
|
return;
|
|
}
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
});
|
|
};
|
|
GoogleDriveStorage.untrash = function(file, callback) {
|
|
var request = gapi.client.drive.files.untrash({
|
|
fileId: file.id
|
|
});
|
|
request.execute(function(resp) {
|
|
if ( resp.id ) {
|
|
callback(false, true);
|
|
return;
|
|
}
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
});
|
|
};
|
|
GoogleDriveStorage.emptyTrash = function(callback) {
|
|
var request = gapi.client.drive.files.emptyTrash({});
|
|
request.execute(function(resp) {
|
|
if ( resp && resp.message ) {
|
|
var msg = resp && resp.message ? resp.message : API._('ERR_APP_UNKNOWN_ERROR');
|
|
callback(msg);
|
|
return;
|
|
}
|
|
callback(false, true);
|
|
});
|
|
};
|
|
GoogleDriveStorage.freeSpace = function(root, callback) {
|
|
callback(false, -1);
|
|
};
|
|
function getGoogleDrive(callback, onerror) {
|
|
callback = callback || function() {};
|
|
onerror = onerror || function() {};
|
|
if ( _isMounted ) {
|
|
var inst = OSjs.Helpers.GoogleAPI.getInstance();
|
|
if ( inst && !inst.authenticated ) {
|
|
_isMounted = false;
|
|
}
|
|
}
|
|
if ( !_isMounted ) {
|
|
var scopes = [
|
|
'https://www.googleapis.com/auth/drive.install',
|
|
'https://www.googleapis.com/auth/drive.file',
|
|
'openid'
|
|
];
|
|
var loads = [
|
|
'drive-realtime',
|
|
'drive-share'
|
|
];
|
|
var iargs = {load: loads, scope: scopes};
|
|
OSjs.Helpers.GoogleAPI.createInstance(iargs, function(error, result) {
|
|
if ( error ) {
|
|
return onerror(error);
|
|
}
|
|
gapi.client.load('drive', 'v2', function() {
|
|
_isMounted = true;
|
|
API.message('vfs:mount', 'GoogleDrive', {source: null});
|
|
callback(GoogleDriveStorage);
|
|
});
|
|
});
|
|
return;
|
|
}
|
|
callback(GoogleDriveStorage);
|
|
}
|
|
function makeRequest(name, args, callback, options) {
|
|
args = args || [];
|
|
callback = callback || function() {};
|
|
getGoogleDrive(function(instance) {
|
|
if ( !instance ) {
|
|
throw new Error('No GoogleDrive instance was created. Load error ?');
|
|
} else if ( !instance[name] ) {
|
|
throw new Error('Invalid GoogleDrive API call name');
|
|
}
|
|
var fargs = args;
|
|
fargs.push(callback);
|
|
fargs.push(options);
|
|
instance[name].apply(instance, fargs);
|
|
}, function(error) {
|
|
callback(error);
|
|
});
|
|
}
|
|
OSjs.Core.getMountManager()._add({
|
|
readOnly: false,
|
|
name: 'GoogleDrive',
|
|
transport: 'GoogleDrive',
|
|
description: 'Google Drive',
|
|
visible: true,
|
|
searchable: false,
|
|
unmount: function(cb) {
|
|
cb = cb || function() {};
|
|
_isMounted = false;
|
|
API.message('vfs:unmount', 'GoogleDrive', {source: null});
|
|
cb(false, true);
|
|
},
|
|
mounted: function() {
|
|
return _isMounted;
|
|
},
|
|
enabled: function() {
|
|
try {
|
|
if ( API.getConfig('VFS.GoogleDrive.Enabled') ) {
|
|
return true;
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('OSjs.VFS.Modules.GoogleDrive::enabled()', e, e.stack);
|
|
}
|
|
return false;
|
|
},
|
|
root: 'google-drive:///',
|
|
icon: 'places/google-drive.png',
|
|
match: /^google-drive\:\/\//,
|
|
request: makeRequest
|
|
});
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var _cachedClient;
|
|
var _isMounted = false;
|
|
function _getConfig(cfg, isVFS) {
|
|
var config = OSjs.Core.getConfig();
|
|
try {
|
|
return isVFS ? config.VFS.Dropbox[cfg] : config.DropboxAPI[cfg];
|
|
} catch ( e ) {
|
|
console.warn('OSjs.VFS.Modules.Dropbox::enabled()', e, e.stack);
|
|
}
|
|
return null;
|
|
}
|
|
function destroyRingNotification() {
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.remove('Dropbox.js');
|
|
}
|
|
}
|
|
function createRingNotification() {
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.add('Dropbox.js', [{
|
|
title: API._('DROPBOX_SIGN_OUT'),
|
|
onClick: function() {
|
|
signoutDropbox();
|
|
}
|
|
}]);
|
|
}
|
|
}
|
|
function DropboxVFS() {
|
|
var clientKey = _getConfig('ClientKey');
|
|
this.client = new window.Dropbox.Client({ key: clientKey });
|
|
if ( this.client ) {
|
|
var href = window.location.href;
|
|
if ( !href.match(/\/$/) ) {
|
|
href += '/';
|
|
}
|
|
href += 'vendor/dropboxOauthReceiver.html';
|
|
var authDriver = new window.Dropbox.AuthDriver.Popup({
|
|
receiverUrl: href
|
|
});
|
|
this.client.authDriver(authDriver);
|
|
}
|
|
}
|
|
DropboxVFS.prototype.init = function(callback) {
|
|
var timedOut = false;
|
|
var timeout = setTimeout(function() {
|
|
timedOut = true;
|
|
callback(API._('ERR_OPERATION_TIMEOUT_FMT', '60s'));
|
|
}, 60 * 1000);
|
|
this.client.authenticate(function(error, client) {
|
|
if ( !timedOut ) {
|
|
console.warn('DropboxVFS::construct()', error, client);
|
|
timeout = clearTimeout(timeout);
|
|
callback(error);
|
|
}
|
|
});
|
|
};
|
|
DropboxVFS.prototype.scandir = function(item, callback) {
|
|
var mm = OSjs.Core.getMountManager();
|
|
var path = Utils.getPathProtocol(item.path);
|
|
function _finish(entries) {
|
|
var result = entries.map(function(iter) {
|
|
return new OSjs.VFS.File({
|
|
filename: iter.name,
|
|
path: mm.getModuleProperty('Dropbox', 'root').replace(/\/$/, '') + iter.path,
|
|
size: iter.size,
|
|
mime: iter.isFolder ? null : iter.mimeType,
|
|
type: iter.isFolder ? 'dir' : 'file'
|
|
});
|
|
});
|
|
var list = OSjs.VFS.Helpers.filterScandir(result, item._opts);
|
|
callback(false, list);
|
|
}
|
|
this.client.readdir(path, {}, function(error, entries, stat, entry_stats) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
_finish(entry_stats);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.write = function(item, data, callback) {
|
|
var path = Utils.getPathProtocol(item.path);
|
|
this.client.writeFile(path, data, function(error, stat) {
|
|
callback(error, true);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.read = function(item, callback, options) {
|
|
options = options || {};
|
|
options.arrayBuffer = true;
|
|
var path = Utils.getPathProtocol(item.path);
|
|
this.client.readFile(path, options, function(error, entries) {
|
|
callback(error, (error ? false : (entries instanceof Array ? entries.join('\n') : entries)));
|
|
});
|
|
};
|
|
DropboxVFS.prototype.copy = function(src, dest, callback) {
|
|
var spath = Utils.getPathProtocol(src.path);
|
|
var dpath = Utils.getPathProtocol(dest.path);
|
|
this.client.copy(spath, dpath, function(error) {
|
|
callback(error, !error);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.move = function(src, dest, callback) {
|
|
var spath = Utils.getPathProtocol(src.path);
|
|
var dpath = Utils.getPathProtocol(dest.path);
|
|
this.client.move(spath, dpath, function(error) {
|
|
callback(error, !error);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.unlink = function(item, callback) {
|
|
var path = Utils.getPathProtocol(item.path);
|
|
this.client.unlink(path, function(error, stat) {
|
|
callback(error, !error);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.mkdir = function(item, callback) {
|
|
var path = Utils.getPathProtocol(item.path);
|
|
this.client.mkdir(path, function(error, stat) {
|
|
callback(error, !error);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.exists = function(item, callback) {
|
|
this.read(item, function(error, data) {
|
|
callback(error, !error);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.fileinfo = function(item, callback) {
|
|
var path = Utils.getPathProtocol(item.path);
|
|
this.client.stat(path, path, function(error, response) {
|
|
var fileinfo = null;
|
|
if ( !error && response ) {
|
|
fileinfo = {};
|
|
var useKeys = ['clientModifiedAt', 'humanSize', 'mimeType', 'modifiedAt', 'name', 'path', 'size', 'versionTag'];
|
|
useKeys.forEach(function(k) {
|
|
fileinfo[k] = response[k];
|
|
});
|
|
}
|
|
callback(error, fileinfo);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.url = function(item, callback) {
|
|
var path = (typeof item === 'string') ? Utils.getPathProtocol(item) : Utils.getPathProtocol(item.path);
|
|
this.client.makeUrl(path, {downloadHack: true}, function(error, url) {
|
|
callback(error, url ? url.url : false);
|
|
});
|
|
};
|
|
DropboxVFS.prototype.upload = function(file, dest, callback) {
|
|
var item = new OSjs.VFS.File({
|
|
filename: file.name,
|
|
path: Utils.pathJoin((new OSjs.VFS.File(dest)).path, file.name),
|
|
mime: file.type,
|
|
size: file.size
|
|
});
|
|
this.write(item, file, callback);
|
|
};
|
|
DropboxVFS.prototype.trash = function(item, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
DropboxVFS.prototype.untrash = function(item, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
DropboxVFS.prototype.emtpyTrash = function(item, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
DropboxVFS.freeSpace = function(root, callback) {
|
|
callback(false, -1);
|
|
};
|
|
function getDropbox(callback) {
|
|
if ( !_cachedClient ) {
|
|
_cachedClient = new DropboxVFS();
|
|
_cachedClient.init(function(error) {
|
|
if ( error ) {
|
|
console.error('Failed to initialize dropbox VFS', error);
|
|
callback(null, error);
|
|
return;
|
|
}
|
|
_isMounted = true;
|
|
createRingNotification();
|
|
API.message('vfs:mount', 'Dropbox', {source: null});
|
|
callback(_cachedClient);
|
|
});
|
|
return;
|
|
}
|
|
callback(_cachedClient);
|
|
}
|
|
function signoutDropbox(cb, options) {
|
|
cb = cb || function() {};
|
|
options = options || null;
|
|
function finished(client) {
|
|
if ( client ) {
|
|
client.reset();
|
|
}
|
|
_isMounted = false;
|
|
_cachedClient = null;
|
|
API.message('vfs:unmount', 'Dropbox', {source: null});
|
|
destroyRingNotification();
|
|
cb();
|
|
}
|
|
getDropbox(function(client) {
|
|
client = client ? client.client : null;
|
|
if ( client ) {
|
|
try {
|
|
client.signOut(options, function() {
|
|
finished(client);
|
|
});
|
|
} catch ( ex ) {
|
|
console.warn('DROPBOX SIGNOUT EXCEPTION', ex);
|
|
finished(client);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
function makeRequest(name, args, callback, options) {
|
|
args = args || [];
|
|
callback = callback || function() {};
|
|
getDropbox(function(instance, error) {
|
|
if ( !instance ) {
|
|
callback('No Dropbox VFS API Instance was ever created. Possible intialization error' + (error ? ': ' + error : ''));
|
|
return;
|
|
}
|
|
var fargs = args;
|
|
fargs.push(callback);
|
|
fargs.push(options);
|
|
instance[name].apply(instance, fargs);
|
|
});
|
|
}
|
|
OSjs.Core.getMountManager()._add({
|
|
readOnly: false,
|
|
name: 'Dropbox',
|
|
transport: 'Dropbox',
|
|
description: 'Dropbox',
|
|
visible: true,
|
|
searchable: false,
|
|
unmount: function(cb) {
|
|
cb = cb || function() {};
|
|
_isMounted = false;
|
|
API.message('vfs:unmount', 'Dropbox', {source: null});
|
|
cb(false, true);
|
|
},
|
|
mounted: function() {
|
|
return _isMounted;
|
|
},
|
|
enabled: function() {
|
|
if ( !window.Dropbox ) {
|
|
return false;
|
|
}
|
|
return _getConfig('Enabled', true) || false;
|
|
},
|
|
root: 'dropbox:///',
|
|
icon: 'places/dropbox.png',
|
|
match: /^dropbox\:\/\//,
|
|
request: makeRequest
|
|
});
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var _isMounted = false;
|
|
var _mimeCache;
|
|
function onedriveCall(args, callback) {
|
|
var WL = window.WL || {};
|
|
WL.api(args).then(
|
|
function(response) {
|
|
callback(false, response);
|
|
},
|
|
function(responseFailed) {
|
|
console.error('OneDrive::*onedriveCall()', 'error', responseFailed, args);
|
|
callback(responseFailed.error.message);
|
|
}
|
|
);
|
|
}
|
|
function getItemType(iter) {
|
|
var type = 'file';
|
|
if ( iter.type === 'folder' || iter.type === 'album' ) {
|
|
type = 'dir';
|
|
}
|
|
return type;
|
|
}
|
|
function getMetadataFromItem(dir, item) {
|
|
var path = 'onedrive://' + dir.replace(/^\/+/, '').replace(/\/+$/, '') + '/' + item.name; // FIXME
|
|
var itemFile = new OSjs.VFS.File({
|
|
id: item.id,
|
|
filename: item.name,
|
|
size: item.size || 0,
|
|
path: path,
|
|
mime: getItemMime(item),
|
|
type: getItemType(item)
|
|
});
|
|
return itemFile;
|
|
}
|
|
function getItemMime(iter) {
|
|
if ( !_mimeCache ) {
|
|
_mimeCache = API.getConfig('MIME.mapping', {});
|
|
}
|
|
var mime = null;
|
|
if ( getItemType(iter) !== 'dir' ) {
|
|
mime = 'application/octet-stream';
|
|
var ext = Utils.filext(iter.name);
|
|
if ( ext.length ) {
|
|
ext = '.' + ext;
|
|
if ( _mimeCache[ext] ) {
|
|
mime = _mimeCache[ext];
|
|
}
|
|
}
|
|
}
|
|
return mime;
|
|
}
|
|
function createDirectoryList(dir, list, item, options) {
|
|
var result = [];
|
|
if ( dir !== '/' ) {
|
|
result.push(new OSjs.VFS.File({
|
|
id: item.id,
|
|
filename: '..',
|
|
path: Utils.dirname(item.path),
|
|
size: 0,
|
|
type: 'dir'
|
|
}));
|
|
}
|
|
list.forEach(function(iter) {
|
|
result.push(getMetadataFromItem(dir, iter));
|
|
});
|
|
return result;
|
|
}
|
|
function getFilesInFolder(folderId, callback) {
|
|
onedriveCall({
|
|
path: folderId + '/files',
|
|
method: 'GET'
|
|
}, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
callback(false, response.data || []);
|
|
});
|
|
}
|
|
function resolvePath(item, callback, useParent) {
|
|
if ( !useParent ) {
|
|
if ( item.id ) {
|
|
callback(false, item.id);
|
|
return;
|
|
}
|
|
}
|
|
var path = Utils.getPathProtocol(item.path).replace(/\/+/, '/');
|
|
if ( useParent ) {
|
|
path = Utils.dirname(path);
|
|
}
|
|
if ( path === '/' ) {
|
|
callback(false, 'me/skydrive');
|
|
return;
|
|
}
|
|
var resolves = path.replace(/^\/+/, '').split('/');
|
|
var isOnRoot = !resolves.length;
|
|
var currentParentId = 'me/skydrive';
|
|
function _nextDir(completed) {
|
|
var current = resolves.shift();
|
|
var done = resolves.length <= 0;
|
|
var found;
|
|
if ( isOnRoot ) {
|
|
found = currentParentId;
|
|
} else {
|
|
if ( current ) {
|
|
getFilesInFolder(currentParentId, function(error, list) {
|
|
list = list || [];
|
|
var lfound;
|
|
if ( !error ) {
|
|
list.forEach(function(iter) { // FIXME: Not very precise
|
|
if ( iter ) {
|
|
if ( iter.name === current ) {
|
|
lfound = iter.id;
|
|
}
|
|
}
|
|
});
|
|
if ( lfound ) {
|
|
currentParentId = lfound;
|
|
}
|
|
} else {
|
|
console.warn('OneDrive', 'resolvePath()', 'getFilesInFolder() error', error);
|
|
}
|
|
if ( done ) {
|
|
completed(lfound);
|
|
} else {
|
|
_nextDir(completed);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
if ( done ) {
|
|
completed(found);
|
|
} else {
|
|
_nextDir(completed);
|
|
}
|
|
}
|
|
_nextDir(function(foundId) {
|
|
if ( foundId ) {
|
|
callback(false, foundId);
|
|
} else {
|
|
callback(API._('ONEDRIVE_ERR_RESOLVE'));
|
|
}
|
|
});
|
|
}
|
|
var OneDriveStorage = {};
|
|
OneDriveStorage.scandir = function(item, callback, options) {
|
|
var relativePath = Utils.getPathProtocol(item.path);
|
|
function _finished(error, result) {
|
|
callback(error, result);
|
|
}
|
|
function _scandir(drivePath) {
|
|
onedriveCall({
|
|
path: drivePath,
|
|
method: 'GET'
|
|
}, function(error, response) {
|
|
if ( error ) {
|
|
_finished(error);
|
|
return;
|
|
}
|
|
getFilesInFolder(response.id, function(error, list) {
|
|
if ( error ) {
|
|
_finished(error);
|
|
return;
|
|
}
|
|
var fileList = createDirectoryList(relativePath, list, item, options);
|
|
_finished(false, fileList);
|
|
});
|
|
});
|
|
}
|
|
resolvePath(item, function(error, drivePath) {
|
|
if ( error ) {
|
|
_finished(error);
|
|
return;
|
|
}
|
|
_scandir(drivePath);
|
|
});
|
|
};
|
|
OneDriveStorage.read = function(item, callback, options) {
|
|
options = options || {};
|
|
this.url(item, function(error, url) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
var file = new OSjs.VFS.File(url, item.mime);
|
|
OSjs.VFS.read(file, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
callback(false, response);
|
|
}, options);
|
|
});
|
|
};
|
|
OneDriveStorage.write = function(file, data, callback) {
|
|
var inst = OSjs.Helpers.WindowsLiveAPI.getInstance();
|
|
var url = 'https://apis.live.net/v5.0/me/skydrive/files?access_token=' + inst.accessToken;
|
|
var fd = new FormData();
|
|
OSjs.VFS.Helpers.addFormFile(fd, 'file', data, file);
|
|
OSjs.Utils.ajax({
|
|
url: url,
|
|
method: 'POST',
|
|
json: true,
|
|
body: fd,
|
|
onsuccess: function(result) {
|
|
if ( result && result.id ) {
|
|
callback(false, result.id);
|
|
return;
|
|
}
|
|
callback(API._('ERR_APP_UNKNOWN_ERROR'));
|
|
},
|
|
onerror: function(error, result) {
|
|
if ( result && result.error ) {
|
|
error += ' - ' + result.error.message;
|
|
}
|
|
callback(error);
|
|
}
|
|
});
|
|
};
|
|
OneDriveStorage.copy = function(src, dest, callback) {
|
|
resolvePath(src, function(error, srcDrivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
resolvePath(dest, function(error, dstDrivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: srcDrivePath,
|
|
method: 'COPY',
|
|
body: {
|
|
destination: dstDrivePath
|
|
}
|
|
}, function(error, response) {
|
|
callback(error, error ? null : true);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
OneDriveStorage.unlink = function(src, callback) {
|
|
resolvePath(src, function(error, drivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: drivePath,
|
|
method: 'DELETE'
|
|
}, function(error, response) {
|
|
callback(error, error ? null : true);
|
|
});
|
|
});
|
|
};
|
|
OneDriveStorage.move = function(src, dest, callback) {
|
|
resolvePath(src, function(error, srcDrivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
resolvePath(dest, function(error, dstDrivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: srcDrivePath,
|
|
method: 'MOVE',
|
|
body: {
|
|
destination: dstDrivePath
|
|
}
|
|
}, function(error, response) {
|
|
callback(error, error ? null : true);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
OneDriveStorage.exists = function(item, callback) {
|
|
this.fileinfo(item, function(error, response) {
|
|
if ( error ) {
|
|
callback(false, false);
|
|
return;
|
|
}
|
|
callback(false, response ? true : false);
|
|
});
|
|
};
|
|
OneDriveStorage.fileinfo = function(item, callback) {
|
|
resolvePath(item, function(error, drivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: drivePath,
|
|
method: 'GET'
|
|
}, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
var useKeys = ['created_time', 'id', 'link', 'name', 'type', 'updated_time', 'upload_location', 'description', 'client_updated_time'];
|
|
var info = {};
|
|
useKeys.forEach(function(k) {
|
|
info[k] = response[k];
|
|
});
|
|
callback(false, info);
|
|
});
|
|
});
|
|
};
|
|
OneDriveStorage.mkdir = function(dir, callback) {
|
|
resolvePath(dir, function(error, drivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: drivePath,
|
|
method: 'POST',
|
|
body: {
|
|
name: dir.filename
|
|
}
|
|
}, function(error, response) {
|
|
callback(error, error ? null : true);
|
|
});
|
|
}, true);
|
|
};
|
|
OneDriveStorage.upload = function(file, dest, callback) {
|
|
var item = new OSjs.VFS.File({
|
|
filename: file.name,
|
|
path: Utils.pathJoin((new OSjs.VFS.File(dest)).path, file.name),
|
|
mime: file.type,
|
|
size: file.size
|
|
});
|
|
this.write(item, file, callback);
|
|
};
|
|
OneDriveStorage.url = function(item, callback) {
|
|
resolvePath(item, function(error, drivePath) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
onedriveCall({
|
|
path: drivePath + '/content',
|
|
method: 'GET'
|
|
}, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
callback(false, response.location);
|
|
});
|
|
});
|
|
};
|
|
OneDriveStorage.trash = function(file, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
OneDriveStorage.untrash = function(file, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
OneDriveStorage.emptyTrash = function(callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
};
|
|
OneDriveStorage.freeSpace = function(root, callback) {
|
|
callback(false, -1);
|
|
};
|
|
function getOneDrive(callback, onerror) {
|
|
callback = callback || function() {};
|
|
onerror = onerror || function() {};
|
|
if ( _isMounted ) {
|
|
var inst = OSjs.Helpers.WindowsLiveAPI.getInstance();
|
|
if ( inst && !inst.authenticated ) {
|
|
_isMounted = false;
|
|
}
|
|
}
|
|
if ( !_isMounted ) {
|
|
var iargs = {scope: ['wl.signin', 'wl.skydrive', 'wl.skydrive_update']};
|
|
OSjs.Helpers.WindowsLiveAPI.createInstance(iargs, function(error, result) {
|
|
if ( error ) {
|
|
return onerror(error);
|
|
}
|
|
_isMounted = true;
|
|
API.message('vfs:mount', 'OneDrive', {source: null});
|
|
callback(OneDriveStorage);
|
|
});
|
|
return;
|
|
}
|
|
callback(OneDriveStorage);
|
|
}
|
|
function makeRequest(name, args, callback, options) {
|
|
args = args || [];
|
|
callback = callback || function() {};
|
|
getOneDrive(function(instance) {
|
|
if ( !instance ) {
|
|
throw new Error('No OneDrive instance was created. Load error ?');
|
|
} else if ( !instance[name] ) {
|
|
throw new Error('Invalid OneDrive API call name');
|
|
}
|
|
var fargs = args;
|
|
fargs.push(callback);
|
|
fargs.push(options);
|
|
instance[name].apply(instance, fargs);
|
|
}, function(error) {
|
|
callback(error);
|
|
});
|
|
}
|
|
OSjs.Core.getMountManager()._add({
|
|
readOnly: false,
|
|
name: 'OneDrive',
|
|
transport: 'OneDrive',
|
|
description: 'OneDrive',
|
|
visible: true,
|
|
searchable: false,
|
|
unmount: function(cb) {
|
|
cb = cb || function() {};
|
|
_isMounted = false;
|
|
API.message('vfs:unmount', 'OneDrive', {source: null});
|
|
cb(false, true);
|
|
},
|
|
mounted: function() {
|
|
return _isMounted;
|
|
},
|
|
enabled: function() {
|
|
try {
|
|
if ( API.getConfig('VFS.OneDrive.Enabled') ) {
|
|
return true;
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('OSjs.VFS.Modules.OneDrive::enabled()', e, e.stack);
|
|
}
|
|
return false;
|
|
},
|
|
root: 'onedrive:///',
|
|
icon: 'places/onedrive.png',
|
|
match: /^onedrive\:\/\//,
|
|
request: makeRequest
|
|
});
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var NAMESPACE = 'OSjs/VFS/LocalStorage';
|
|
var _isMounted = false;
|
|
var _cache = {};
|
|
var _fileCache = {};
|
|
function getRealPath(p, par) {
|
|
if ( typeof p !== 'string' || !p ) {
|
|
throw new TypeError('Expected p as String');
|
|
}
|
|
p = Utils.getPathProtocol(p).replace(/\/+/g, '/');
|
|
var path = par ? (Utils.dirname(p) || '/') : p;
|
|
if ( path !== '/' ) {
|
|
path = path.replace(/\/$/, '');
|
|
}
|
|
return path;
|
|
}
|
|
function createMetadata(i, path, p) {
|
|
i = Utils.cloneObject(i);
|
|
if ( !p.match(/(\/\/)?\/$/) ) {
|
|
p += '/';
|
|
}
|
|
i.path = p + i.filename;
|
|
return new OSjs.VFS.File(i);
|
|
}
|
|
function initStorage() {
|
|
if ( !_isMounted ) {
|
|
try {
|
|
_cache = JSON.parse(localStorage.getItem(NAMESPACE + '/tree')) || {};
|
|
} catch ( e ) {}
|
|
try {
|
|
_fileCache = JSON.parse(localStorage.getItem(NAMESPACE + '/data')) || {};
|
|
} catch ( e ) {}
|
|
if ( typeof _cache['/'] === 'undefined' ) {
|
|
_cache['/'] = [];
|
|
}
|
|
_isMounted = true;
|
|
API.message('vfs:mount', 'LocalStorage', {source: null});
|
|
}
|
|
}
|
|
function commitStorage() {
|
|
try {
|
|
localStorage.setItem(NAMESPACE + '/tree', JSON.stringify(_cache));
|
|
localStorage.setItem(NAMESPACE + '/data', JSON.stringify(_fileCache));
|
|
return true;
|
|
} catch ( e ) {}
|
|
return false;
|
|
}
|
|
function addToCache(iter, data, dab) {
|
|
var path = getRealPath(iter.path);
|
|
var dirname = Utils.dirname(path);
|
|
var type = typeof data === 'undefined' || data === null ? 'dir' : 'file';
|
|
var mimeConfig = API.getConfig('MIME.mapping');
|
|
var mime = (function(type) {
|
|
if ( type !== 'dir' ) {
|
|
if ( iter.mime ) {
|
|
return iter.mime;
|
|
} else {
|
|
var ext = Utils.filext(iter.filename);
|
|
return mimeConfig['.' + ext] || 'application/octet-stream';
|
|
}
|
|
}
|
|
return null;
|
|
})(iter.type);
|
|
var file = {
|
|
size: iter.size || (type === 'file' ? (dab.byteLength || dab.length || 0) : 0),
|
|
mime: mime,
|
|
type: type,
|
|
filename: iter.filename
|
|
};
|
|
if ( typeof _cache[dirname] === 'undefined' ) {
|
|
_cache[dirname] = [];
|
|
}
|
|
(function(found) {
|
|
if ( found !== false) {
|
|
_cache[dirname][found] = file;
|
|
} else {
|
|
_cache[dirname].push(file);
|
|
}
|
|
})(findInCache(iter));
|
|
if ( file.type === 'dir' ) {
|
|
if ( _fileCache[path] ) {
|
|
delete _fileCache[path];
|
|
}
|
|
_cache[path] = [];
|
|
} else {
|
|
var iof = data.indexOf(',');
|
|
_fileCache[path] = data.substr(iof + 1);
|
|
}
|
|
return true;
|
|
}
|
|
function removeFromCache(iter) {
|
|
function _removef(i) {
|
|
var path = getRealPath(i.path);
|
|
if ( _fileCache[path] ) {
|
|
delete _fileCache[path];
|
|
}
|
|
_removefromp(i);
|
|
}
|
|
function _removed(i) {
|
|
var path = getRealPath(i.path);
|
|
if ( path !== '/' ) {
|
|
_removefromp(i);
|
|
if ( _cache[path] ) {
|
|
delete _cache[path];
|
|
}
|
|
}
|
|
}
|
|
function _removefromp(i) {
|
|
var path = getRealPath(i.path);
|
|
var dirname = Utils.dirname(path);
|
|
if ( _cache[dirname] ) {
|
|
var found = -1;
|
|
_cache[dirname].forEach(function(ii, idx) {
|
|
if ( found === -1 && ii ) {
|
|
if ( ii.type === i.type && i.filename === i.filename ) {
|
|
found = idx;
|
|
}
|
|
}
|
|
});
|
|
if ( found >= 0 ) {
|
|
_cache[dirname].splice(found, 1);
|
|
}
|
|
}
|
|
}
|
|
function _op(i) {
|
|
if ( i ) {
|
|
if ( i.type === 'dir' ) {
|
|
scanStorage(i, false).forEach(function(ii) {
|
|
_op(ii);
|
|
});
|
|
_removed(i);
|
|
} else {
|
|
_removef(i);
|
|
}
|
|
}
|
|
}
|
|
_op(iter);
|
|
return true;
|
|
}
|
|
function findInCache(iter) {
|
|
var path = getRealPath(iter.path);
|
|
var dirname = Utils.dirname(path);
|
|
var found = false;
|
|
_cache[dirname].forEach(function(chk, idx) {
|
|
if ( found === false && chk.filename === iter.filename ) {
|
|
found = idx;
|
|
}
|
|
});
|
|
return found;
|
|
}
|
|
function getFromCache(pp) {
|
|
var path = Utils.dirname(pp);
|
|
var fname = Utils.filename(pp);
|
|
var result = null;
|
|
var tpath = path.replace(/^(.*)\:\/\//, '');
|
|
(_cache[tpath] || []).forEach(function(v) {
|
|
if ( !result && v.filename === fname ) {
|
|
result = createMetadata(v, null, path);
|
|
}
|
|
});
|
|
return result;
|
|
}
|
|
function scanStorage(item, ui) {
|
|
var path = getRealPath(item.path);
|
|
var data = _cache[path] || false;
|
|
var list = (data === false) ? false : data.filter(function(i) {
|
|
return !!i;
|
|
}).map(function(i) {
|
|
return createMetadata(i, path, item.path);
|
|
});
|
|
return list;
|
|
}
|
|
var LocalStorageStorage = {
|
|
scandir: function(item, callback, options) {
|
|
var list = scanStorage(item, true);
|
|
callback(list === false ? API._('ERR_VFSMODULE_NOSUCH') : false, list);
|
|
},
|
|
read: function(item, callback, options) {
|
|
options = options || {};
|
|
var path = getRealPath(item.path);
|
|
function readStorage(cb) {
|
|
var metadata = getFromCache(path);
|
|
if ( metadata ) {
|
|
var data = _fileCache[path];
|
|
if ( data ) {
|
|
var ds = 'data:' + metadata.mime + ',' + data;
|
|
OSjs.VFS.Helpers.dataSourceToAb(ds, metadata.mime, function(err, res) {
|
|
if ( err ) {
|
|
cb(err);
|
|
} else {
|
|
if ( options.url ) {
|
|
OSjs.VFS.Helpers.abToBlob(res, metadata.mime, function(err, blob) {
|
|
cb(err, URL.createObjectURL(blob));
|
|
});
|
|
} else {
|
|
cb(err, res);
|
|
}
|
|
}
|
|
});
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
if ( readStorage(callback) === false ) {
|
|
callback(API._('ERR_VFS_FATAL'), false);
|
|
}
|
|
},
|
|
write: function(file, data, callback, options) {
|
|
options = options || {};
|
|
var mime = file.mime || 'application/octet-stream';
|
|
function writeStorage(cb) {
|
|
if ( options.isds ) {
|
|
cb(false, data);
|
|
} else {
|
|
OSjs.VFS.Helpers.abToDataSource(data, mime, function(err, res) {
|
|
if ( err ) {
|
|
callback(err, false);
|
|
} else {
|
|
cb(false, res);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
writeStorage(function(err, res) {
|
|
try {
|
|
if ( addToCache(file, res, data) && commitStorage() ) {
|
|
callback(err, true);
|
|
} else {
|
|
callback(API._('ERR_VFS_FATAL'), false);
|
|
}
|
|
} catch ( e ) {
|
|
callback(e);
|
|
}
|
|
});
|
|
},
|
|
unlink: function(src, callback) {
|
|
try {
|
|
src = getFromCache(src.path) || src;
|
|
if ( removeFromCache(src) && commitStorage() ) {
|
|
callback(false, true);
|
|
} else {
|
|
callback(API._('ERR_VFS_FATAL'), false);
|
|
}
|
|
} catch ( e ) {
|
|
callback(e);
|
|
}
|
|
},
|
|
copy: function(src, dest, callback) {
|
|
function _write(s, d, cb) {
|
|
OSjs.VFS.read(s, function(err, data) {
|
|
if ( err ) {
|
|
cb(err);
|
|
} else {
|
|
OSjs.VFS.write(d, data, cb);
|
|
}
|
|
});
|
|
}
|
|
function _op(s, d, cb) {
|
|
if ( s.type === 'file' ) {
|
|
d.mime = s.mime;
|
|
}
|
|
d.size = s.size;
|
|
d.type = s.type;
|
|
if ( d.type === 'dir' ) {
|
|
OSjs.VFS.mkdir(d, function(err, res) {
|
|
if ( err ) {
|
|
cb(err);
|
|
} else {
|
|
var list = scanStorage(s, false);
|
|
if ( list && list.length ) {
|
|
Utils.asyncs(list, function(entry, idx, next) {
|
|
var rp = entry.path.substr(src.path.length);
|
|
var nd = new OSjs.VFS.File(dest.path + rp);
|
|
_op(entry, nd, next);
|
|
}, function() {
|
|
cb(false, true);
|
|
});
|
|
} else {
|
|
cb(false, true);
|
|
}
|
|
}
|
|
});
|
|
} else {
|
|
_write(s, d, cb);
|
|
}
|
|
}
|
|
src = getFromCache(src.path) || src;
|
|
var droot = getRealPath(Utils.dirname(dest.path));
|
|
if ( droot !== '/' && !getFromCache(droot) ) {
|
|
callback(API._('ERR_VFS_TARGET_NOT_EXISTS'));
|
|
return;
|
|
}
|
|
if ( src.type === 'dir' && src.path === Utils.dirname(dest.path) ) {
|
|
callback('You cannot copy a directory into itself'); // FIXME
|
|
return;
|
|
}
|
|
_op(src, dest, callback);
|
|
},
|
|
move: function(src, dest, callback) {
|
|
var spath = getRealPath(src.path);
|
|
var dpath = getRealPath(dest.path);
|
|
var sdirname = Utils.dirname(spath);
|
|
var ddirname = Utils.dirname(dpath);
|
|
if ( _fileCache[dpath] ) {
|
|
callback(API._('ERR_VFS_FILE_EXISTS'));
|
|
return;
|
|
}
|
|
if ( sdirname === ddirname ) {
|
|
if ( _fileCache[spath] ) {
|
|
var tmp = _fileCache[spath];
|
|
delete _fileCache[spath];
|
|
_fileCache[dpath] = tmp;
|
|
}
|
|
if ( _cache[sdirname] ) {
|
|
var found = -1;
|
|
_cache[sdirname].forEach(function(i, idx) {
|
|
if ( i && found === -1 ) {
|
|
if ( i.filename === src.filename && i.type === src.type ) {
|
|
found = idx;
|
|
}
|
|
}
|
|
});
|
|
if ( found >= 0 ) {
|
|
_cache[sdirname][found].filename = dest.filename;
|
|
}
|
|
}
|
|
callback(false, commitStorage());
|
|
} else {
|
|
OSjs.VSF.copy(src, dest, function(err) {
|
|
if ( err ) {
|
|
callback(err);
|
|
} else {
|
|
OSjs.VFS.unlink(src, callback);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
exists: function(item, callback) {
|
|
var data = getFromCache(getRealPath(item.path));
|
|
callback(false, !!data);
|
|
},
|
|
fileinfo: function(item, callback) {
|
|
var data = getFromCache(item.path);
|
|
callback(data ? false : API._('ERR_VFSMODULE_NOSUCH'), data);
|
|
},
|
|
mkdir: function(dir, callback) {
|
|
var dpath = getRealPath(dir.path);
|
|
if ( dpath !== '/' && getFromCache(dpath) ) {
|
|
callback(API._('ERR_VFS_FILE_EXISTS'));
|
|
return;
|
|
}
|
|
dir.mime = null;
|
|
dir.size = 0;
|
|
dir.type = 'dir';
|
|
try {
|
|
if ( addToCache(dir) && commitStorage() ) {
|
|
callback(false, true);
|
|
} else {
|
|
callback(API._('ERR_VFS_FATAL'));
|
|
}
|
|
} catch ( e ) {
|
|
callback(e);
|
|
}
|
|
},
|
|
upload: function(file, dest, callback) {
|
|
var check = new OSjs.VFS.File(Utils.pathJoin((new OSjs.VFS.File(dest)).path, file.name), file.type);
|
|
check.size = file.size;
|
|
check.type = 'file';
|
|
OSjs.VFS.exists(check, function(err, exists) {
|
|
if ( err || exists ) {
|
|
callback(err || API._('ERR_VFS_FILE_EXISTS'));
|
|
} else {
|
|
var reader = new FileReader();
|
|
reader.onerror = function(e) {
|
|
callback(e);
|
|
};
|
|
reader.onloadend = function() {
|
|
OSjs.VFS.write(check, reader.result, callback, {isds: true});
|
|
};
|
|
reader.readAsDataURL(file);
|
|
}
|
|
});
|
|
},
|
|
url: function(item, callback) {
|
|
OSjs.VFS.exists(item, function(err, exists) {
|
|
if ( err || !exists ) {
|
|
callback(err || API._('ERR_VFS_FILE_EXISTS'));
|
|
} else {
|
|
OSjs.VFS.read(item, callback, {url: true});
|
|
}
|
|
});
|
|
},
|
|
find: function(file, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
},
|
|
trash: function(file, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
},
|
|
untrash: function(file, callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
},
|
|
emptyTrash: function(callback) {
|
|
callback(API._('ERR_VFS_UNAVAILABLE'));
|
|
},
|
|
freeSpace: function(root, callback) {
|
|
var total = 5 * 1024 * 1024;
|
|
var used = JSON.stringify(_cache).length + JSON.stringify(_fileCache).length;
|
|
callback(false, total - used);
|
|
}
|
|
};
|
|
function makeRequest(name, args, callback, options) {
|
|
initStorage();
|
|
var ref = LocalStorageStorage[name];
|
|
var fargs = (args || []).slice(0);
|
|
fargs.push(callback || function() {});
|
|
fargs.push(options || {});
|
|
return ref.apply(ref, fargs);
|
|
}
|
|
OSjs.Core.getMountManager()._add({
|
|
readOnly: false,
|
|
name: 'LocalStorage',
|
|
transport: 'LocalStorage',
|
|
description: API.getConfig('VFS.LocalStorage.Options.description', 'LocalStorage'),
|
|
visible: true,
|
|
searchable: false,
|
|
unmount: function(cb) {
|
|
cb = cb || function() {};
|
|
_isMounted = false;
|
|
API.message('vfs:unmount', 'LocalStorage', {source: null});
|
|
cb(false, true);
|
|
},
|
|
mounted: function() {
|
|
return _isMounted;
|
|
},
|
|
enabled: function() {
|
|
try {
|
|
if ( API.getConfig('VFS.LocalStorage.Enabled') ) {
|
|
return true;
|
|
}
|
|
} catch ( e ) {
|
|
console.warn('OSjs.VFS.Modules.LocalStorage::enabled()', e, e.stack);
|
|
}
|
|
return false;
|
|
},
|
|
root: 'localstorage:///',
|
|
icon: API.getConfig('VFS.LocalStorage.Options.icon', 'apps/web-browser.png'),
|
|
match: /^localstorage\:\/\//,
|
|
request: makeRequest
|
|
});
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, VFS, API) {
|
|
'use strict';
|
|
function filter(from, index, shrt, toindex) {
|
|
var list = [];
|
|
for ( var i = (shrt ? 0 : toindex); i < from.length; i++ ) {
|
|
list.push(from[i]);
|
|
}
|
|
return list;
|
|
}
|
|
function format(fmt, date) {
|
|
var utc;
|
|
if ( typeof fmt === 'undefined' || !fmt ) {
|
|
fmt = ExtendedDate.config.defaultFormat;
|
|
} else {
|
|
if ( typeof fmt !== 'string' ) {
|
|
utc = fmt.utc;
|
|
fmt = fmt.format;
|
|
} else {
|
|
utc = ExtendedDate.config.utc;
|
|
}
|
|
}
|
|
return formatDate(date, fmt, utc);
|
|
}
|
|
function _now(now) {
|
|
return now ? (now instanceof ExtendedDate ? now.date : now) : new Date();
|
|
}
|
|
function _y(y, now) {
|
|
return (typeof y === 'undefined' || y === null || y < 0 ) ? now.getFullYear() : y;
|
|
}
|
|
function _m(m, now) {
|
|
return (typeof m === 'undefined' || m === null || m < 0 ) ? now.getMonth() : m;
|
|
}
|
|
function ExtendedDate(date) {
|
|
if ( date ) {
|
|
if ( date instanceof Date ) {
|
|
this.date = date;
|
|
} else if ( date instanceof ExtendedDate ) {
|
|
this.date = date.date;
|
|
} else if ( typeof date === 'string' ) {
|
|
this.date = new Date(date);
|
|
}
|
|
}
|
|
if ( !this.date ) {
|
|
this.date = new Date();
|
|
}
|
|
}
|
|
ExtendedDate.config = {
|
|
defaultFormat: 'isoDateTime'
|
|
};
|
|
ExtendedDate.dayNames = [
|
|
'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat',
|
|
'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
|
|
];
|
|
ExtendedDate.monthNames = [
|
|
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
|
|
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'
|
|
];
|
|
var methods = [
|
|
'UTC',
|
|
'toString',
|
|
'now',
|
|
'parse',
|
|
'getDate',
|
|
'getDay',
|
|
'getFullYear',
|
|
'getHours',
|
|
'getMilliseconds',
|
|
'getMinutes',
|
|
'getMonth',
|
|
'getSeconds',
|
|
'getTime',
|
|
'getTimezoneOffset',
|
|
'getUTCDate',
|
|
'getUTCDay',
|
|
'getUTCFullYear',
|
|
'getUTCHours',
|
|
'getUTCMilliseconds',
|
|
'getUTCMinutes',
|
|
'getUTCMonth',
|
|
'getUTCSeconds',
|
|
'getYear',
|
|
'setDate',
|
|
'setFullYear',
|
|
'setHours',
|
|
'setMilliseconds',
|
|
'setMinutes',
|
|
'setMonth',
|
|
'setSeconds',
|
|
'setTime',
|
|
'setUTCDate',
|
|
'setUTCFullYear',
|
|
'setUTCHours',
|
|
'setUTCMilliseconds',
|
|
'setUTCMinutes',
|
|
'setUTCMonth',
|
|
'setUTCSeconds',
|
|
'setYear',
|
|
'toDateString',
|
|
'toGMTString',
|
|
'toISOString',
|
|
'toJSON',
|
|
'toLocaleDateString',
|
|
'toLocaleFormat',
|
|
'toLocaleString',
|
|
'toLocaleTimeString',
|
|
'toSource',
|
|
'toString',
|
|
'toTimeString',
|
|
'toUTCString',
|
|
'valueOf'
|
|
];
|
|
methods.forEach(function(m) {
|
|
ExtendedDate.prototype[m] = function() {
|
|
return this.date[m].apply(this.date, arguments);
|
|
};
|
|
});
|
|
ExtendedDate.prototype.get = function() {
|
|
return this.date;
|
|
};
|
|
ExtendedDate.prototype.format = function(fmt) {
|
|
return ExtendedDate.format(this, fmt);
|
|
};
|
|
ExtendedDate.prototype.getFirstDayInMonth = function(fmt) {
|
|
return ExtendedDate.getFirstDayInMonth(fmt, null, null, this);
|
|
};
|
|
ExtendedDate.prototype.getLastDayInMonth = function(fmt) {
|
|
return ExtendedDate.getLastDayInMonth(fmt, null, null, this);
|
|
};
|
|
ExtendedDate.prototype.getDaysInMonth = function() {
|
|
return ExtendedDate.getDaysInMonth(null, null, this);
|
|
};
|
|
ExtendedDate.prototype.getWeekNumber = function() {
|
|
return ExtendedDate.getWeekNumber(this);
|
|
};
|
|
ExtendedDate.prototype.isWithinMonth = function(from, to) {
|
|
return ExtendedDate.isWithinMonth(this, from, to);
|
|
};
|
|
ExtendedDate.prototype.getDayOfTheYear = function() {
|
|
return ExtendedDate.getDayOfTheYear();
|
|
};
|
|
ExtendedDate.format = function(date, fmt) {
|
|
return format(fmt, date);
|
|
};
|
|
ExtendedDate.getPreviousMonth = function(now) {
|
|
now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date();
|
|
var current;
|
|
if (now.getMonth() === 0) {
|
|
current = new Date(now.getFullYear() - 1, 11, now.getDate());
|
|
} else {
|
|
current = new Date(now.getFullYear(), now.getMonth() - 1, now.getDate());
|
|
}
|
|
return new ExtendedDate(current);
|
|
};
|
|
ExtendedDate.getNextMonth = function(now) {
|
|
now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date();
|
|
var current;
|
|
if (now.getMonth() === 11) {
|
|
current = new Date(now.getFullYear() + 1, 0, now.getDate());
|
|
} else {
|
|
current = new Date(now.getFullYear(), now.getMonth() + 1, now.getDate());
|
|
}
|
|
return new ExtendedDate(current);
|
|
};
|
|
ExtendedDate.getFirstDayInMonth = function(fmt, y, m, now) {
|
|
now = _now(now);
|
|
y = _y(y, now);
|
|
m = _m(m, now);
|
|
var date = new Date();
|
|
date.setFullYear(y, m, 1);
|
|
if ( fmt === true ) {
|
|
return date.getDate();
|
|
}
|
|
return fmt ? format(fmt, date) : new ExtendedDate(date);
|
|
};
|
|
ExtendedDate.getLastDayInMonth = function(fmt, y, m, now) {
|
|
now = _now(now);
|
|
y = _y(y, now);
|
|
m = _m(m, now);
|
|
var date = new Date();
|
|
date.setFullYear(y, m, 0);
|
|
if ( fmt === true ) {
|
|
return date.getDate();
|
|
}
|
|
return fmt ? format(fmt, date) : new ExtendedDate(date);
|
|
};
|
|
ExtendedDate.getDaysInMonth = function(y, m, now) {
|
|
now = _now(now);
|
|
y = _y(y, now);
|
|
m = _m(m, now);
|
|
var date = new Date();
|
|
date.setFullYear(y, m, 0);
|
|
return parseInt(date.getDate(), 10);
|
|
};
|
|
ExtendedDate.getWeekNumber = function(now) {
|
|
now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date();
|
|
var d = new Date(+now);
|
|
d.setHours(0,0,0);
|
|
d.setDate(d.getDate() + 4 - (d.getDay() || 7));
|
|
return Math.ceil((((d - new Date(d.getFullYear(),0,1)) / 8.64e7) + 1) / 7);
|
|
};
|
|
ExtendedDate.getDayName = function(index, shrt) {
|
|
if ( index < 0 || index === null || typeof index === 'undefined' ) {
|
|
return filter(ExtendedDate.dayNames, index, shrt, 7);
|
|
}
|
|
shrt = shrt ? 0 : 1;
|
|
var idx = index + (shrt + 7);
|
|
return ExtendedDate.dayNames[idx];
|
|
};
|
|
ExtendedDate.getMonthName = function(index, shrt) {
|
|
if ( index < 0 || index === null || typeof index === 'undefined' ) {
|
|
return filter(ExtendedDate.monthNames, index, shrt, 12);
|
|
}
|
|
shrt = shrt ? 0 : 1;
|
|
var idx = index + (shrt + 12);
|
|
return ExtendedDate.monthNames[idx];
|
|
};
|
|
ExtendedDate.isWithinMonth = function(now, from, to) {
|
|
if ( now.getFullYear() >= from.getFullYear() && now.getMonth() >= from.getMonth() ) {
|
|
if ( now.getFullYear() <= to.getFullYear() && now.getMonth() <= to.getMonth() ) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
ExtendedDate.getDayOfTheYear = function() {
|
|
var now = new Date();
|
|
var start = new Date(now.getFullYear(), 0, 0);
|
|
var diff = now - start;
|
|
var oneDay = 1000 * 60 * 60 * 24;
|
|
return Math.floor(diff / oneDay);
|
|
};
|
|
function formatDate(date, format, utc) {
|
|
utc = utc === true;
|
|
function pad(val, len) {
|
|
val = String(val);
|
|
len = len || 2;
|
|
while (val.length < len) {
|
|
val = '0' + val;
|
|
}
|
|
return val;
|
|
}
|
|
var defaultFormats = {
|
|
'default': 'Y-m-d H:i:s',
|
|
shortDate: 'm/d/y',
|
|
mediumDate: 'M d, Y',
|
|
longDate: 'F d, Y',
|
|
fullDate: 'l, F d, Y',
|
|
shortTime: 'h:i A',
|
|
mediumTime: 'h:i:s A',
|
|
longTime: 'h:i:s A T',
|
|
isoDate: 'Y-m-d',
|
|
isoTime: 'H:i:s',
|
|
isoDateTime: 'Y-m-d H:i:s'
|
|
};
|
|
format = defaultFormats[format] || format;
|
|
if ( !(date instanceof ExtendedDate) ) {
|
|
date = new ExtendedDate(date);
|
|
}
|
|
var map = {
|
|
d: function(s) {
|
|
return pad(map.j(s));
|
|
},
|
|
D: function(s) {
|
|
return ExtendedDate.dayNames[utc ? date.getUTCDay() : date.getDay()];
|
|
},
|
|
j: function(s) {
|
|
return (utc ? date.getUTCDate() : date.getDate());
|
|
},
|
|
l: function(s) {
|
|
return ExtendedDate.dayNames[(utc ? date.getUTCDay() : date.getDay()) + 7];
|
|
},
|
|
w: function(s) {
|
|
return (utc ? date.getUTCDay() : date.getDay());
|
|
},
|
|
z: function(s) {
|
|
return date.getDayOfTheYear();
|
|
},
|
|
S: function(s) {
|
|
var d = utc ? date.getUTCDate() : date.getDate();
|
|
return ['th', 'st', 'nd', 'rd'][d % 10 > 3 ? 0 : (d % 100 - d % 10 !== 10) * d % 10];
|
|
},
|
|
W: function(s) {
|
|
return date.getWeekNumber();
|
|
},
|
|
F: function(s) {
|
|
return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth()) + 12];
|
|
},
|
|
m: function(s) {
|
|
return pad(map.n(s));
|
|
},
|
|
M: function(s) {
|
|
return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth())];
|
|
},
|
|
n: function(s) {
|
|
return (utc ? date.getUTCMonth() : date.getMonth()) + 1;
|
|
},
|
|
t: function(s) {
|
|
return date.getDaysInMonth();
|
|
},
|
|
Y: function(s) {
|
|
return (utc ? date.getUTCFullYear() : date.getFullYear());
|
|
},
|
|
y: function(s) {
|
|
return String(map.Y(s)).slice(2);
|
|
},
|
|
a: function(s) {
|
|
return map.G(s) < 12 ? 'am' : 'pm';
|
|
},
|
|
A: function(s) {
|
|
return map.a(s).toUpperCase();
|
|
},
|
|
g: function(s) {
|
|
return map.G(s) % 12 || 12;
|
|
},
|
|
G: function(s) {
|
|
return (utc ? date.getUTCHours() : date.getHours());
|
|
},
|
|
h: function(s) {
|
|
return pad(map.g(s));
|
|
},
|
|
H: function(s) {
|
|
return pad(map.G(s));
|
|
},
|
|
i: function(s) {
|
|
return pad(utc ? date.getUTCMinutes() : date.getMinutes());
|
|
},
|
|
s: function(s) {
|
|
return pad(utc ? date.getUTCSeconds() : date.getSeconds());
|
|
},
|
|
O: function(s) {
|
|
var tzo = -date.getTimezoneOffset();
|
|
var dif = tzo >= 0 ? '+' : '-';
|
|
function ppad(num) {
|
|
var norm = Math.abs(Math.floor(num));
|
|
return (norm < 10 ? '0' : '') + norm;
|
|
}
|
|
var str = dif + ppad(tzo / 60) + ':' + ppad(tzo % 60);
|
|
return str;
|
|
},
|
|
T: function(s) {
|
|
if ( utc ) {
|
|
return 'UTC';
|
|
}
|
|
var timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g;
|
|
var zones = String(date.date).match(timezone) || [''];
|
|
return zones.pop().replace(/(\+|\-)[0-9]+$/, '');
|
|
},
|
|
U: function(s) {
|
|
return date.getTime();
|
|
}
|
|
};
|
|
var result = [];
|
|
format.split('').forEach(function(s) {
|
|
result.push(map[s] ? map[s]() : s);
|
|
});
|
|
return result.join('');
|
|
}
|
|
OSjs.Helpers.Date = ExtendedDate;
|
|
})(OSjs.Utils, OSjs.VFS, OSjs.API);
|
|
|
|
(function(Utils, API, GUI, Window) {
|
|
'use strict';
|
|
function EventHandler(name, names) {
|
|
this.name = name;
|
|
this.events = {};
|
|
(names || []).forEach(function(n) {
|
|
this.events[n] = [];
|
|
}, this);
|
|
}
|
|
EventHandler.prototype.destroy = function() {
|
|
this.events = {};
|
|
};
|
|
EventHandler.prototype.on = function(name, cb, thisArg) {
|
|
thisArg = thisArg || this;
|
|
if ( !(cb instanceof Function) ) {
|
|
throw new TypeError('EventHandler::on() expects cb to be a Function');
|
|
}
|
|
var self = this;
|
|
var added = [];
|
|
function _register(n) {
|
|
if ( !(self.events[n] instanceof Array) ) {
|
|
self.events[n] = [];
|
|
}
|
|
added.push(self.events[n].push(function(args) {
|
|
return cb.apply(thisArg, args);
|
|
}));
|
|
}
|
|
if ( name instanceof RegExp ) {
|
|
Object.keys(this.events).forEach(function(n) {
|
|
if ( name.test(n) ) {
|
|
_register(n);
|
|
}
|
|
});
|
|
} else {
|
|
name.replace(/\s/g, '').split(',').forEach(function(n) {
|
|
_register(n);
|
|
});
|
|
}
|
|
return added.length === 1 ? added[0] : added;
|
|
};
|
|
EventHandler.prototype.off = function(name, index) {
|
|
if ( !(this.events[name] instanceof Array) ) {
|
|
throw new TypeError('Invalid event name');
|
|
}
|
|
if ( arguments.length > 1 && typeof index === 'number' ) {
|
|
this.events[name].splice(index, 1);
|
|
} else {
|
|
this.events[name] = [];
|
|
}
|
|
};
|
|
EventHandler.prototype.emit = function(name, args) {
|
|
args = args || [];
|
|
if ( !(this.events[name] instanceof Array) ) {
|
|
return true;
|
|
}
|
|
return (this.events[name]).every(function(fn) {
|
|
var result;
|
|
try {
|
|
result = fn(args);
|
|
} catch ( e ) {
|
|
console.warn('EventHandler::emit() exception', name, e);
|
|
console.warn(e.stack);
|
|
}
|
|
return typeof result === 'undefined' || result === true;
|
|
});
|
|
};
|
|
OSjs.Helpers.EventHandler = EventHandler;
|
|
})(OSjs.Utils, OSjs.API, OSjs.GUI, OSjs.Core.Window);
|
|
|
|
(function(Application, Window, Utils, VFS, GUI) {
|
|
'use strict';
|
|
var IFRAME_COUNT = 0;
|
|
var IFrameApplicationWindow = function(name, opts, app) {
|
|
opts = Utils.argumentDefaults(opts, {
|
|
src: 'about:blank',
|
|
focus: function() {},
|
|
blur: function() {},
|
|
icon: null,
|
|
title: 'IframeApplicationWindow',
|
|
width: 320,
|
|
height: 240,
|
|
allow_resize: false,
|
|
allow_restore: false,
|
|
allow_maximize: false
|
|
});
|
|
Window.apply(this, ['IFrameApplicationWindow', opts, app]);
|
|
this._iwin = null;
|
|
this._frame = null;
|
|
};
|
|
IFrameApplicationWindow.prototype = Object.create(Window.prototype);
|
|
IFrameApplicationWindow.prototype.destroy = function() {
|
|
this.postMessage('Window::destroy');
|
|
return Window.prototype.destroy.apply(this, arguments);
|
|
};
|
|
IFrameApplicationWindow.prototype.init = function(wmRef, app) {
|
|
var self = this;
|
|
var root = Window.prototype.init.apply(this, arguments);
|
|
root.style.overflow = 'visible';
|
|
var id = 'IframeApplicationWindow' + IFRAME_COUNT.toString();
|
|
var iframe = document.createElement('iframe');
|
|
iframe.setAttribute('border', 0);
|
|
iframe.id = id;
|
|
iframe.className = 'IframeApplicationFrame';
|
|
iframe.addEventListener('load', function() {
|
|
self._iwin = iframe.contentWindow;
|
|
self.postMessage('Window::init');
|
|
});
|
|
this.setLocation(this._opts.src, iframe);
|
|
root.appendChild(iframe);
|
|
this._frame = iframe;
|
|
try {
|
|
this._iwin = iframe.contentWindow;
|
|
} catch ( e ) {}
|
|
if ( this._iwin ) {
|
|
this._iwin.focus();
|
|
}
|
|
this._frame.focus();
|
|
this._opts.focus(this._frame, this._iwin);
|
|
IFRAME_COUNT++;
|
|
return root;
|
|
};
|
|
IFrameApplicationWindow.prototype._blur = function() {
|
|
if ( Window.prototype._blur.apply(this, arguments) ) {
|
|
if ( this._iwin ) {
|
|
this._iwin.blur();
|
|
}
|
|
if ( this._frame ) {
|
|
this._frame.blur();
|
|
}
|
|
this._opts.blur(this._frame, this._iwin);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
IFrameApplicationWindow.prototype._focus = function() {
|
|
if ( Window.prototype._focus.apply(this, arguments) ) {
|
|
if ( this._iwin ) {
|
|
this._iwin.focus();
|
|
}
|
|
if ( this._frame ) {
|
|
this._frame.focus();
|
|
}
|
|
this._opts.focus(this._frame, this._iwin);
|
|
return true;
|
|
}
|
|
return false;
|
|
};
|
|
IFrameApplicationWindow.prototype.postMessage = function(message) {
|
|
if ( this._iwin && this._app ) {
|
|
this._iwin.postMessage({
|
|
message: message,
|
|
pid: this._app.__pid,
|
|
wid: this._wid
|
|
}, window.location.href);
|
|
}
|
|
};
|
|
IFrameApplicationWindow.prototype.onPostMessage = function(message, ev) {
|
|
};
|
|
IFrameApplicationWindow.prototype.setLocation = function(src, iframe) {
|
|
iframe = iframe || this._frame;
|
|
var oldbefore = window.onbeforeunload;
|
|
window.onbeforeunload = null;
|
|
iframe.src = src;
|
|
window.onbeforeunload = oldbefore;
|
|
};
|
|
var IFrameApplication = function(name, args, metadata, opts) {
|
|
Application.call(this, name, args, metadata);
|
|
this.options = Utils.argumentDefaults(opts, {
|
|
icon: '',
|
|
title: 'IframeApplicationWindow'
|
|
});
|
|
this.options.src = OSjs.API.getApplicationResource(this, this.options.src);
|
|
};
|
|
IFrameApplication.prototype = Object.create(Application.prototype);
|
|
IFrameApplication.prototype.init = function(settings, metadata) {
|
|
Application.prototype.init.apply(this, arguments);
|
|
var name = this.__pname + 'Window';
|
|
this._addWindow(new IFrameApplicationWindow(name, this.options, this), null, true);
|
|
};
|
|
IFrameApplication.prototype.onPostMessage = function(message, ev) {
|
|
var self = this;
|
|
function _response(err, res) {
|
|
self.postMessage({
|
|
id: message.id,
|
|
method: message.method,
|
|
error: err,
|
|
result: Utils.cloneObject(res)
|
|
});
|
|
}
|
|
if ( typeof message.id === 'number' && message.method ) {
|
|
if ( this[message.method] ) {
|
|
this[message.method](message.args || {}, _response);
|
|
} else {
|
|
_response('No such method');
|
|
}
|
|
}
|
|
};
|
|
IFrameApplication.prototype.postMessage = function(message) {
|
|
var win = this._getMainWindow();
|
|
if ( win ) {
|
|
win.postMessage(message);
|
|
}
|
|
};
|
|
OSjs.Helpers.IFrameApplication = IFrameApplication;
|
|
OSjs.Helpers.IFrameApplicationWindow = IFrameApplicationWindow;
|
|
})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI);
|
|
|
|
(function(Application, Window, Utils, VFS, API, GUI) {
|
|
'use strict';
|
|
function DefaultApplication(name, args, metadata, opts) {
|
|
this.defaultOptions = Utils.argumentDefaults(opts, {
|
|
readData: true,
|
|
rawData: false,
|
|
extension: '',
|
|
mime: 'application/octet-stream',
|
|
filetypes: [],
|
|
filename: 'New file'
|
|
});
|
|
Application.apply(this, [name, args, metadata]);
|
|
}
|
|
DefaultApplication.prototype = Object.create(Application.prototype);
|
|
DefaultApplication.constructor = Application;
|
|
DefaultApplication.prototype.destroy = function() {
|
|
Application.prototype.destroy.apply(this, arguments);
|
|
};
|
|
DefaultApplication.prototype._onMessage = function(obj, msg, args) {
|
|
Application.prototype._onMessage.apply(this, arguments);
|
|
var self = this;
|
|
var current = this._getArgument('file');
|
|
var win = this._getWindow(this.__mainwindow);
|
|
if ( msg === 'vfs' && args.source !== null && args.source !== this.__pid && args.file ) {
|
|
if ( win && current && current.path === args.file.path ) {
|
|
win._toggleDisabled(true);
|
|
API.createDialog('Confirm', {
|
|
buttons: ['yes', 'no'],
|
|
message: API._('MSG_FILE_CHANGED')
|
|
}, function(ev, button) {
|
|
win._toggleDisabled(false);
|
|
if ( button === 'ok' || button === 'yes' ) {
|
|
self.openFile(new VFS.File(args.file), win);
|
|
}
|
|
}, win);
|
|
}
|
|
}
|
|
};
|
|
DefaultApplication.prototype.openFile = function(file, win) {
|
|
var self = this;
|
|
if ( !file ) {
|
|
return;
|
|
}
|
|
function onError(error) {
|
|
if ( error ) {
|
|
API.error(self.__label,
|
|
API._('ERR_FILE_APP_OPEN'),
|
|
API._('ERR_FILE_APP_OPEN_ALT_FMT',
|
|
file.path));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
function onDone(result) {
|
|
self._setArgument('file', file);
|
|
win.showFile(file, result);
|
|
}
|
|
var check = this.__metadata.mime || [];
|
|
if ( !Utils.checkAcceptMime(file.mime, check) ) {
|
|
API.error(this.__label,
|
|
API._('ERR_FILE_APP_OPEN'),
|
|
API._('ERR_FILE_APP_OPEN_FMT',
|
|
file.path, file.mime)
|
|
);
|
|
return false;
|
|
}
|
|
win._toggleLoading(true);
|
|
function CallbackVFS(error, result) {
|
|
win._toggleLoading(false);
|
|
if ( onError(error) ) {
|
|
return;
|
|
}
|
|
onDone(result);
|
|
}
|
|
if ( this.defaultOptions.readData ) {
|
|
VFS.read(file, CallbackVFS, {type: this.defaultOptions.rawData ? 'binary' : 'text'});
|
|
} else {
|
|
VFS.url(file, CallbackVFS);
|
|
}
|
|
return true;
|
|
};
|
|
DefaultApplication.prototype.saveFile = function(file, value, win) {
|
|
var self = this;
|
|
if ( !file ) {
|
|
return;
|
|
}
|
|
win._toggleLoading(true);
|
|
VFS.write(file, value || '', function(error, result) {
|
|
win._toggleLoading(false);
|
|
if ( error ) {
|
|
API.error(self.__label,
|
|
API._('ERR_FILE_APP_SAVE'),
|
|
API._('ERR_FILE_APP_SAVE_ALT_FMT',
|
|
file.path));
|
|
return;
|
|
}
|
|
self._setArgument('file', file);
|
|
win.updateFile(file);
|
|
}, {}, this);
|
|
};
|
|
DefaultApplication.prototype.saveDialog = function(file, win, saveAs) {
|
|
var self = this;
|
|
var value = win.getFileData();
|
|
if ( !saveAs ) {
|
|
this.saveFile(file, value, win);
|
|
return;
|
|
}
|
|
win._toggleDisabled(true);
|
|
API.createDialog('File', {
|
|
file: file,
|
|
filename: file ? file.filename : this.defaultOptions.filename,
|
|
filetypes: this.defaultOptions.filetypes,
|
|
filter: this.__metadata.mime,
|
|
extension: this.defaultOptions.extension,
|
|
mime: this.defaultOptions.mime,
|
|
type: 'save'
|
|
}, function(ev, button, result) {
|
|
win._toggleDisabled(false);
|
|
if ( button === 'ok' ) {
|
|
self.saveFile(result, value, win);
|
|
}
|
|
}, win);
|
|
};
|
|
DefaultApplication.prototype.openDialog = function(file, win) {
|
|
var self = this;
|
|
function openDialog() {
|
|
win._toggleDisabled(true);
|
|
API.createDialog('File', {
|
|
file: file,
|
|
filter: self.__metadata.mime
|
|
}, function(ev, button, result) {
|
|
win._toggleDisabled(false);
|
|
if ( button === 'ok' && result ) {
|
|
self.openFile(new VFS.File(result), win);
|
|
}
|
|
}, win);
|
|
}
|
|
win.checkHasChanged(function(discard) {
|
|
if ( discard ) {
|
|
openDialog();
|
|
}
|
|
});
|
|
};
|
|
DefaultApplication.prototype.newDialog = function(path, win) {
|
|
var self = this;
|
|
win.checkHasChanged(function(discard) {
|
|
if ( discard ) {
|
|
self._setArgument('file', null);
|
|
win.showFile(null, null);
|
|
}
|
|
});
|
|
};
|
|
OSjs.Helpers.DefaultApplication = DefaultApplication;
|
|
})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.API, OSjs.GUI);
|
|
|
|
(function(Application, Window, Utils, VFS, API, GUI) {
|
|
'use strict';
|
|
function DefaultApplicationWindow(name, app, args, scheme, file) {
|
|
Window.apply(this, arguments);
|
|
this.hasClosingDialog = false;
|
|
this.currentFile = file ? new VFS.File(file) : null;
|
|
this.hasChanged = false;
|
|
}
|
|
DefaultApplicationWindow.prototype = Object.create(Window.prototype);
|
|
DefaultApplicationWindow.constructor = Window;
|
|
DefaultApplicationWindow.prototype.destroy = function() {
|
|
Window.prototype.destroy.apply(this, arguments);
|
|
this.currentFile = null;
|
|
};
|
|
DefaultApplicationWindow.prototype.init = function(wm, app, scheme) {
|
|
var root = Window.prototype.init.apply(this, arguments);
|
|
return root;
|
|
};
|
|
DefaultApplicationWindow.prototype._inited = function() {
|
|
var result = Window.prototype._inited.apply(this, arguments);
|
|
var self = this;
|
|
var app = this._app;
|
|
var menuMap = {
|
|
MenuNew: function() {
|
|
app.newDialog(self.currentFile, self);
|
|
},
|
|
MenuSave: function() {
|
|
app.saveDialog(self.currentFile, self);
|
|
},
|
|
MenuSaveAs: function() {
|
|
app.saveDialog(self.currentFile, self, true);
|
|
},
|
|
MenuOpen: function() {
|
|
app.openDialog(self.currentFile, self);
|
|
},
|
|
MenuClose: function() {
|
|
self._close();
|
|
}
|
|
};
|
|
this._scheme.find(this, 'SubmenuFile').on('select', function(ev) {
|
|
if ( menuMap[ev.detail.id] ) {
|
|
menuMap[ev.detail.id]();
|
|
}
|
|
});
|
|
this._scheme.find(this, 'MenuSave').set('disabled', true);
|
|
if ( this.currentFile ) {
|
|
if ( !this._app.openFile(this.currentFile, this) ) {
|
|
this.currentFile = null;
|
|
}
|
|
}
|
|
return result;
|
|
};
|
|
DefaultApplicationWindow.prototype._onDndEvent = function(ev, type, item, args) {
|
|
if ( !Window.prototype._onDndEvent.apply(this, arguments) ) {
|
|
return;
|
|
}
|
|
if ( type === 'itemDrop' && item ) {
|
|
var data = item.data;
|
|
if ( data && data.type === 'file' && data.mime ) {
|
|
this._app.openFile(new VFS.File(data), this);
|
|
}
|
|
}
|
|
};
|
|
DefaultApplicationWindow.prototype._close = function() {
|
|
var self = this;
|
|
if ( this.hasClosingDialog ) {
|
|
return;
|
|
}
|
|
if ( this.hasChanged ) {
|
|
this.hasClosingDialog = true;
|
|
this.checkHasChanged(function(discard) {
|
|
self.hasClosingDialog = false;
|
|
if ( discard ) {
|
|
self.hasChanged = false; // IMPORTANT
|
|
self._close();
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
Window.prototype._close.apply(this, arguments);
|
|
};
|
|
DefaultApplicationWindow.prototype.checkHasChanged = function(cb) {
|
|
var self = this;
|
|
if ( this.hasChanged ) {
|
|
this._toggleDisabled(true);
|
|
API.createDialog('Confirm', {
|
|
buttons: ['yes', 'no'],
|
|
message: API._('MSG_GENERIC_APP_DISCARD')
|
|
}, function(ev, button) {
|
|
self._toggleDisabled(false);
|
|
cb(button === 'ok' || button === 'yes');
|
|
});
|
|
return;
|
|
}
|
|
cb(true);
|
|
};
|
|
DefaultApplicationWindow.prototype.showFile = function(file, content) {
|
|
this.updateFile(file);
|
|
};
|
|
DefaultApplicationWindow.prototype.updateFile = function(file) {
|
|
this.currentFile = file || null;
|
|
this.hasChanged = false;
|
|
if ( this._scheme && (this._scheme instanceof GUI.Scheme) ) {
|
|
this._scheme.find(this, 'MenuSave').set('disabled', !file);
|
|
}
|
|
if ( file ) {
|
|
this._setTitle(file.filename, true);
|
|
} else {
|
|
this._setTitle();
|
|
}
|
|
};
|
|
DefaultApplicationWindow.prototype.getFileData = function() {
|
|
return null;
|
|
};
|
|
DefaultApplicationWindow.prototype._onKeyEvent = function(ev, type, shortcut) {
|
|
if ( shortcut === 'SAVE' ) {
|
|
this._app.saveDialog(this.currentFile, this, !this.currentFile);
|
|
return false;
|
|
} else if ( shortcut === 'SAVEAS' ) {
|
|
this._app.saveDialog(this.currentFile, this, true);
|
|
return false;
|
|
} else if ( shortcut === 'OPEN' ) {
|
|
this._app.openDialog(this.currentFile, this);
|
|
return false;
|
|
}
|
|
return Window.prototype._onKeyEvent.apply(this, arguments);
|
|
};
|
|
OSjs.Helpers.DefaultApplicationWindow = DefaultApplicationWindow;
|
|
})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.API, OSjs.GUI);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var gapi = window.gapi = window.gapi || {};
|
|
var SingletonInstance = null;
|
|
function GoogleAPI(clientId) {
|
|
this.clientId = clientId;
|
|
this.accessToken = null;
|
|
this.userId = null;
|
|
this.preloaded = false;
|
|
this.authenticated = false;
|
|
this.loaded = [];
|
|
this.preloads = [
|
|
{
|
|
type: 'javascript',
|
|
src: 'https://apis.google.com/js/api.js'
|
|
}
|
|
];
|
|
}
|
|
GoogleAPI.prototype.destroy = function() {
|
|
};
|
|
GoogleAPI.prototype.init = function(callback) {
|
|
var self = this;
|
|
callback = callback || function() {};
|
|
if ( this.preloaded ) {
|
|
callback(false, true);
|
|
} else {
|
|
Utils.preload(this.preloads, function(total, failed) {
|
|
if ( !failed.length ) {
|
|
self.preloaded = true;
|
|
}
|
|
callback(failed.join('\n'));
|
|
});
|
|
}
|
|
};
|
|
GoogleAPI.prototype.load = function(load, scope, client, callback) {
|
|
var self = this;
|
|
function auth(cb) {
|
|
self.authenticate(scope, function(error, result) {
|
|
if ( error ) {
|
|
return cb(error);
|
|
}
|
|
if ( !self.authenticated ) {
|
|
return cb(API._('GAPI_AUTH_FAILURE'));
|
|
}
|
|
cb(false, result);
|
|
});
|
|
}
|
|
function loadAll(finished) {
|
|
var lload = [];
|
|
load.forEach(function(i) {
|
|
if ( self.loaded.indexOf(i) === -1 ) {
|
|
lload.push(i);
|
|
}
|
|
});
|
|
var current = 0;
|
|
var total = lload.length;
|
|
function _load(iter, cb) {
|
|
var args = [];
|
|
var name = null;
|
|
if ( iter instanceof Array ) {
|
|
if ( iter.length > 0 && iter.length < 3 ) {
|
|
args = args.concat(iter);
|
|
name = iter[0];
|
|
}
|
|
} else {
|
|
args.push(iter);
|
|
name = iter;
|
|
}
|
|
args.push(function() {
|
|
self.loaded.push(name);
|
|
cb.apply(this, arguments);
|
|
});
|
|
if ( client ) {
|
|
gapi.client.load.apply(gapi, args);
|
|
} else {
|
|
gapi.load.apply(gapi, args);
|
|
}
|
|
}
|
|
function _next() {
|
|
if ( current >= total ) {
|
|
finished();
|
|
} else {
|
|
_load(lload[current], function() {
|
|
_next();
|
|
});
|
|
current++;
|
|
}
|
|
}
|
|
_next();
|
|
}
|
|
this.init(function(error) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !window.gapi || !gapi.load ) {
|
|
callback(API._('GAPI_LOAD_FAILURE'));
|
|
return;
|
|
}
|
|
auth(function(error) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
loadAll(function(error, result) {
|
|
callback(error, result, SingletonInstance);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
GoogleAPI.prototype.signOut = function(cb) {
|
|
cb = cb || function() {};
|
|
if ( this.authenticated ) {
|
|
try {
|
|
gapi.auth.signOut();
|
|
} catch ( e ) {
|
|
console.warn('GoogleAPI::signOut()', 'failed', e);
|
|
console.warn(e.stack);
|
|
}
|
|
this.authenticated = false;
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.remove('Google API');
|
|
}
|
|
}
|
|
OSjs.Core.getMountManager().remove('GoogleDrive');
|
|
cb(false, true);
|
|
};
|
|
GoogleAPI.prototype.revoke = function(callback) {
|
|
if ( !this.accessToken ) {
|
|
return callback(false);
|
|
}
|
|
var url = 'https://accounts.google.com/o/oauth2/revoke?token=' + this.accessToken;
|
|
Utils.ajax({
|
|
url: url,
|
|
jsonp: true,
|
|
onsuccess: function() {
|
|
callback(true);
|
|
},
|
|
onerror: function() {
|
|
callback(false);
|
|
}
|
|
});
|
|
};
|
|
GoogleAPI.prototype.authenticate = function(scope, callback) {
|
|
callback = callback || function() {};
|
|
var self = this;
|
|
function getUserId(cb) {
|
|
cb = cb || function() {};
|
|
gapi.client.load('oauth2', 'v2', function() {
|
|
gapi.client.oauth2.userinfo.get().execute(function(resp) {
|
|
cb(resp.id);
|
|
});
|
|
});
|
|
}
|
|
function login(immediate, cb) {
|
|
cb = cb || function() {};
|
|
gapi.auth.authorize({
|
|
client_id: self.clientId,
|
|
scope: scope,
|
|
user_id: self.userId,
|
|
immediate: immediate
|
|
}, cb);
|
|
}
|
|
function createRingNotification() {
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.remove('Google API');
|
|
ring.add('Google API', [{
|
|
title: API._('GAPI_SIGN_OUT'),
|
|
onClick: function() {
|
|
self.signOut();
|
|
}
|
|
}, {
|
|
title: API._('GAPI_REVOKE'),
|
|
onClick: function() {
|
|
self.revoke(function() {
|
|
self.signOut();
|
|
});
|
|
}
|
|
}]);
|
|
}
|
|
}
|
|
var handleAuthResult = function(authResult, immediate) {
|
|
if ( authResult.error ) {
|
|
if ( authResult.error_subtype === 'origin_mismatch' || (authResult.error_subtype === 'access_denied' && !immediate) ) {
|
|
var msg = API._('GAPI_AUTH_FAILURE_FMT', authResult.error, authResult.error_subtype);
|
|
callback(msg);
|
|
return;
|
|
}
|
|
}
|
|
if ( authResult && !authResult.error ) {
|
|
getUserId(function(id) {
|
|
self.userId = id;
|
|
if ( id ) {
|
|
createRingNotification();
|
|
self.authenticated = true;
|
|
self.accessToken = authResult.access_token || null;
|
|
callback(false, true);
|
|
} else {
|
|
callback(false, false);
|
|
}
|
|
});
|
|
} else {
|
|
login(false, function(res) {
|
|
handleAuthResult(res, false);
|
|
});
|
|
}
|
|
};
|
|
gapi.load('auth:client', function(result) {
|
|
if ( result && result.error ) {
|
|
var msg = API._('GAPI_AUTH_FAILURE_FMT', result.error, result.error_subtype);
|
|
callback(msg);
|
|
return;
|
|
}
|
|
login(true, function(res) {
|
|
handleAuthResult(res, true);
|
|
});
|
|
});
|
|
};
|
|
OSjs.Helpers.GoogleAPI = OSjs.Helpers.GoogleAPI || {};
|
|
OSjs.Helpers.GoogleAPI.getInstance = function() {
|
|
return SingletonInstance;
|
|
};
|
|
OSjs.Helpers.GoogleAPI.createInstance = function(args, callback) {
|
|
var load = args.load || [];
|
|
var scope = args.scope || [];
|
|
var client = args.client === true;
|
|
function _run() {
|
|
SingletonInstance.load(load, scope, client, callback);
|
|
}
|
|
if ( SingletonInstance ) {
|
|
return _run();
|
|
}
|
|
var clientId = null;
|
|
try {
|
|
clientId = API.getConfig('GoogleAPI.ClientId');
|
|
} catch ( e ) {
|
|
console.warn('getGoogleAPI()', e, e.stack);
|
|
}
|
|
if ( !clientId ) {
|
|
callback(API._('GAPI_DISABLED'));
|
|
return;
|
|
}
|
|
SingletonInstance = new GoogleAPI(clientId);
|
|
_run();
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API) {
|
|
'use strict';
|
|
var redirectURI = window.location.href.replace(/\/$/, '') + '/vendor/wlOauthReceiver.html';
|
|
var SingletonInstance = null;
|
|
function WindowsLiveAPI(clientId) {
|
|
this.hasSession = false;
|
|
this.clientId = clientId;
|
|
this.loaded = false;
|
|
this.inited = false;
|
|
this.accessToken = null;
|
|
this.lastScope = null;
|
|
this.preloads = [{
|
|
type: 'javascript',
|
|
src: '//js.live.net/v5.0/wl.js'
|
|
}];
|
|
}
|
|
WindowsLiveAPI.prototype.destroy = function() {
|
|
};
|
|
WindowsLiveAPI.prototype.init = function(callback) {
|
|
callback = callback || function() {};
|
|
var self = this;
|
|
if ( this.loaded ) {
|
|
callback(false, true);
|
|
} else {
|
|
Utils.preload(this.preloads, function(total, failed) {
|
|
if ( !failed.length ) {
|
|
self.loaded = true;
|
|
}
|
|
callback(failed.join('\n'));
|
|
});
|
|
}
|
|
};
|
|
WindowsLiveAPI.prototype.load = function(scope, callback) {
|
|
var self = this;
|
|
var WL = window.WL || {};
|
|
function _login() {
|
|
var lastScope = (self.lastScope || []).sort();
|
|
var currScope = (scope || []).sort();
|
|
if ( self.hasSession && (lastScope.toString() === currScope.toString()) ) {
|
|
callback(false, true);
|
|
return;
|
|
}
|
|
self.login(scope, function(error, response) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
setTimeout(function() {
|
|
callback(false, true);
|
|
}, 10);
|
|
});
|
|
}
|
|
this.init(function(error) {
|
|
if ( error ) {
|
|
callback(error);
|
|
return;
|
|
}
|
|
if ( !window.WL ) {
|
|
callback(API._('WLAPI_LOAD_FAILURE'));
|
|
return;
|
|
}
|
|
WL = window.WL || {};
|
|
if ( self.inited ) {
|
|
_login();
|
|
} else {
|
|
self.inited = true;
|
|
WL.Event.subscribe('auth.login', function() {
|
|
self.onLogin.apply(self, arguments);
|
|
});
|
|
WL.Event.subscribe('auth.logout', function() {
|
|
self.onLogout.apply(self, arguments);
|
|
});
|
|
WL.Event.subscribe('wl.log', function() {
|
|
self.onLog.apply(self, arguments);
|
|
});
|
|
WL.Event.subscribe('auth.sessionChange', function() {
|
|
self.onSessionChange.apply(self, arguments);
|
|
});
|
|
WL.init({
|
|
client_id: self.clientId,
|
|
display: 'popup',
|
|
redirect_uri: redirectURI
|
|
}).then(function(result) {
|
|
if ( result.session ) {
|
|
self.accessToken = result.session.access_token || null;
|
|
}
|
|
if ( result.status === 'connected' ) {
|
|
callback(false, true);
|
|
} else if ( result.status === 'success' ) {
|
|
_login();
|
|
} else {
|
|
callback(API._('WLAPI_INIT_FAILED_FMT', result.status.toString()));
|
|
}
|
|
}, function(result) {
|
|
console.error('WindowsLiveAPI::load()', 'init() error', result);
|
|
callback(result.error_description);
|
|
});
|
|
}
|
|
});
|
|
};
|
|
WindowsLiveAPI.prototype._removeRing = function() {
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.remove('Windows Live API');
|
|
}
|
|
};
|
|
WindowsLiveAPI.prototype.logout = function(callback) {
|
|
callback = callback || function() {};
|
|
var self = this;
|
|
var WL = window.WL || {};
|
|
if ( this.hasSession ) {
|
|
callback(false, false);
|
|
}
|
|
WL.Event.unsubscribe('auth.logout');
|
|
WL.Event.subscribe('auth.logout', function() {
|
|
self._removeRing();
|
|
WL.Event.unsubscribe('auth.logout');
|
|
callback(false, true);
|
|
});
|
|
WL.logout();
|
|
OSjs.Core.getMountManager().remove('OneDrive');
|
|
};
|
|
WindowsLiveAPI.prototype.login = function(scope, callback) {
|
|
var WL = window.WL || {};
|
|
if ( this.hasSession ) {
|
|
callback(false, true);
|
|
return;
|
|
}
|
|
WL.login({
|
|
scope: scope,
|
|
redirect_uri: redirectURI
|
|
}).then(function(result) {
|
|
if ( result.status === 'connected' ) {
|
|
callback(false, true);
|
|
} else {
|
|
callback(API._('WLAPI_LOGIN_FAILED'));
|
|
}
|
|
}, function(result) {
|
|
callback(API._('WLAPI_LOGIN_FAILED_FMT', result.error_description));
|
|
});
|
|
};
|
|
WindowsLiveAPI.prototype.onSessionChange = function() {
|
|
console.warn('WindowsLiveAPI::onSessionChange()', arguments);
|
|
var WL = window.WL || {};
|
|
var session = WL.getSession();
|
|
if ( session ) {
|
|
this.hasSession = true;
|
|
} else {
|
|
this.hasSession = false;
|
|
}
|
|
};
|
|
WindowsLiveAPI.prototype.onLogin = function() {
|
|
console.warn('WindowsLiveAPI::onLogin()', arguments);
|
|
this.hasSession = true;
|
|
var self = this;
|
|
var ring = API.getServiceNotificationIcon();
|
|
if ( ring ) {
|
|
ring.add('Windows Live API', [{
|
|
title: API._('WLAPI_SIGN_OUT'),
|
|
onClick: function() {
|
|
self.logout();
|
|
}
|
|
}]);
|
|
}
|
|
};
|
|
WindowsLiveAPI.prototype.onLogout = function() {
|
|
console.warn('WindowsLiveAPI::onLogout()', arguments);
|
|
this.hasSession = false;
|
|
this._removeRing();
|
|
};
|
|
WindowsLiveAPI.prototype.onLog = function() {
|
|
};
|
|
OSjs.Helpers.WindowsLiveAPI = OSjs.Helpers.WindowsLiveAPI || {};
|
|
OSjs.Helpers.WindowsLiveAPI.getInstance = function() {
|
|
return SingletonInstance;
|
|
};
|
|
OSjs.Helpers.WindowsLiveAPI.createInstance = function(args, callback) {
|
|
args = args || {};
|
|
function _run() {
|
|
var scope = args.scope;
|
|
SingletonInstance.load(scope, function(error) {
|
|
callback(error ? error : false, SingletonInstance);
|
|
});
|
|
}
|
|
if ( SingletonInstance ) {
|
|
_run();
|
|
return;
|
|
}
|
|
var clientId = null;
|
|
try {
|
|
clientId = API.getConfig('WindowsLiveAPI.ClientId');
|
|
} catch ( e ) {
|
|
console.warn('getWindowsLiveAPI()', e, e.stack);
|
|
}
|
|
if ( !clientId ) {
|
|
callback(API._('WLAPI_DISABLED'));
|
|
return;
|
|
}
|
|
SingletonInstance = new WindowsLiveAPI(clientId);
|
|
_run();
|
|
};
|
|
})(OSjs.Utils, OSjs.API);
|
|
|
|
(function(Utils, API, VFS) {
|
|
'use strict';
|
|
function getEntries(file, callback) {
|
|
zip.createReader(new zip.BlobReader(file), function(zipReader) {
|
|
zipReader.getEntries(function(entries) {
|
|
callback(false, entries);
|
|
});
|
|
}, function(message) {
|
|
callback(message);
|
|
});
|
|
}
|
|
function getEntryFile(entry, onend, onprogress) {
|
|
var writer = new zip.BlobWriter();
|
|
entry.getData(writer, function(blob) {
|
|
onend(blob);
|
|
writer = null;
|
|
}, onprogress);
|
|
}
|
|
function openFile(file, done) {
|
|
VFS.download(file, function(error, data) {
|
|
if ( error ) {
|
|
console.warning('An error while opening zip', error);
|
|
done(error);
|
|
return;
|
|
}
|
|
var blob = new Blob([data], {type: file.mime});
|
|
getEntries(blob, function(error, result) {
|
|
done(error, result || []);
|
|
});
|
|
});
|
|
}
|
|
function importFiles(writer, entries, pr, done, ignore) {
|
|
ignore = ignore || [];
|
|
function _next(index) {
|
|
if ( !entries.length || index >= entries.length ) {
|
|
done(false);
|
|
return;
|
|
}
|
|
var current = entries[index];
|
|
if ( ignore.indexOf(current.filename) >= 0 ) {
|
|
console.warn('Ignoring', index, current);
|
|
pr('ignored', index, current);
|
|
_next(index + 1);
|
|
return;
|
|
}
|
|
getEntryFile(current, function(blob) {
|
|
writer.add(current.filename, new zip.BlobReader(blob), function() {
|
|
pr('added', index, current);
|
|
_next(index + 1);
|
|
}, function(current, total) {
|
|
pr('reading', index, total, current);
|
|
}, {
|
|
directory: current.directory,
|
|
lastModDate: current.lastModDate,
|
|
version: current.version
|
|
});
|
|
});
|
|
}
|
|
_next(0);
|
|
}
|
|
function createZip(done) {
|
|
var writer = new zip.BlobWriter();
|
|
zip.createWriter(writer, function(writer) {
|
|
done(false, writer);
|
|
}, function(error) {
|
|
done(error);
|
|
});
|
|
}
|
|
function saveZip(writer, file, ccb) {
|
|
writer.close(function(blob) {
|
|
VFS.upload({
|
|
destination: Utils.dirname(file.path),
|
|
files: [{filename: Utils.filename(file.path), data: blob}]
|
|
}, function(type, ev) {
|
|
var error = (type === 'error') ? ev : false;
|
|
ccb(error, !!error);
|
|
}, {overwrite: true});
|
|
});
|
|
}
|
|
var SingletonInstance = null;
|
|
function ZipArchiver(opts) {
|
|
this.opts = opts;
|
|
this.inited = false;
|
|
this.preloads = [{
|
|
type: 'javascript',
|
|
src: '/vendor/zip.js/WebContent/zip.js'
|
|
}];
|
|
}
|
|
ZipArchiver.prototype.init = function(cb) {
|
|
cb = cb || function() {};
|
|
if ( this.inited ) {
|
|
cb();
|
|
return;
|
|
}
|
|
var self = this;
|
|
Utils.preload(this.preloads, function(total, failed) {
|
|
if ( failed.length ) {
|
|
cb(API._('ZIP_PRELOAD_FAIL'), failed);
|
|
return;
|
|
}
|
|
if ( window.zip ) {
|
|
zip.workerScriptsPath = '/vendor/zip.js/WebContent/';
|
|
self.inited = true;
|
|
}
|
|
cb();
|
|
});
|
|
};
|
|
ZipArchiver.prototype.list = function(file, cb) {
|
|
VFS.download(file, function(error, result) {
|
|
if ( error ) {
|
|
alert(error);
|
|
cb(error, null);
|
|
return;
|
|
}
|
|
var blob = new Blob([result], {type: 'application/zip'});
|
|
getEntries(blob, function(error, entries) {
|
|
cb(error, entries);
|
|
});
|
|
});
|
|
};
|
|
ZipArchiver.prototype.create = function(file, cb, appRef) {
|
|
var writer = new zip.BlobWriter();
|
|
zip.createWriter(writer, function(writer) {
|
|
writer.close(function(blob) {
|
|
VFS.upload({
|
|
destination: Utils.dirname(file.path),
|
|
files: [
|
|
{filename: Utils.filename(file.path), data: blob}
|
|
]
|
|
}, function(type, ev) {
|
|
if ( type === 'error' ) {
|
|
console.warn('Error creating blank zip', ev);
|
|
}
|
|
writer = null;
|
|
if ( type !== 'error' ) {
|
|
API.message('vfs:upload', file, {source: appRef ? appRef.__pid : null});
|
|
}
|
|
cb(type === 'error' ? ev : false, type !== 'error');
|
|
}, {overwrite: true});
|
|
});
|
|
});
|
|
};
|
|
ZipArchiver.prototype.add = function(file, add, args) {
|
|
var cb = args.oncomplete || function() {};
|
|
var pr = args.onprogress || function() {};
|
|
var currentDir = args.path || '/';
|
|
function finished(err, res) {
|
|
cb(err, res);
|
|
}
|
|
function checkIfExists(entries, done) {
|
|
var found = false;
|
|
var chk = Utils.filename(add.path);
|
|
entries.forEach(function(i) {
|
|
if ( i.filename === chk ) {
|
|
if ( !i.directory || (i.directory && add.type === 'dir') ) {
|
|
found = true;
|
|
}
|
|
}
|
|
return !found;
|
|
});
|
|
done(found ? 'File is already in archive' : false);
|
|
}
|
|
function addFile(writer, done) {
|
|
var filename = add instanceof window.File ? add.name : add.filename;
|
|
var type = add instanceof window.File ? 'file' : (add.type || 'file');
|
|
filename = ((currentDir || '/').replace(/\/$/, '') + '/' + filename).replace(/^\//, '');
|
|
function _addBlob(blob) {
|
|
writer.add(filename, new zip.BlobReader(blob), function() {
|
|
saveZip(writer, file, done);
|
|
}, function(current, total) {
|
|
pr('compressing', current);
|
|
});
|
|
}
|
|
function _addFolder() {
|
|
writer.add(filename, null, function() {
|
|
saveZip(writer, file, done);
|
|
}, null, {directory: true});
|
|
}
|
|
if ( type === 'dir' ) {
|
|
_addFolder();
|
|
} else {
|
|
if ( add instanceof window.File ) {
|
|
_addBlob(add);
|
|
} else {
|
|
VFS.download(add, function(error, data) {
|
|
if ( error ) {
|
|
done(error);
|
|
return;
|
|
}
|
|
var blob = new Blob([data], {type: add.mime});
|
|
_addBlob(blob);
|
|
});
|
|
}
|
|
}
|
|
}
|
|
openFile(file, function(err, entries) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
checkIfExists(entries, function(err) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
createZip(function(err, writer) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
importFiles(writer, entries, pr, function(err) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
addFile(writer, function(err) {
|
|
finished(err, !!err);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
};
|
|
ZipArchiver.prototype.remove = function(file, path, cb) {
|
|
function finished(err, res, writer) {
|
|
if ( err || !writer ) {
|
|
cb(err || API._('ZIP_NO_RESOURCE'));
|
|
return;
|
|
}
|
|
saveZip(writer, file, function(eer, rees) {
|
|
cb(eer, rees);
|
|
});
|
|
}
|
|
if ( !path ) {
|
|
finished(API._('ZIP_NO_PATH'));
|
|
return;
|
|
}
|
|
openFile(file, function(err, entries) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
createZip(function(err, writer) {
|
|
if ( err ) {
|
|
finished(err); return;
|
|
}
|
|
importFiles(writer, entries, function() {
|
|
}, function(err) {
|
|
finished(err, !!err, writer);
|
|
}, [path]);
|
|
});
|
|
});
|
|
};
|
|
ZipArchiver.prototype.extract = function(file, destination, args) {
|
|
args = args || {};
|
|
args.onprogress = args.onprogress || function() {};
|
|
args.oncomplete = args.oncomplete || function() {};
|
|
function finished(error, warnings, result) {
|
|
if ( !error ) {
|
|
API.message('vfs:update', destination, {source: args.app ? args.app.__pid : null});
|
|
}
|
|
args.oncomplete(error, warnings, result);
|
|
}
|
|
var extracted = [];
|
|
var warnings = [];
|
|
var total = 0;
|
|
function _extractList(list, destination) {
|
|
total = list.length;
|
|
var index = 0;
|
|
function _extract(item, cb) {
|
|
args.onprogress(item.filename, index, total);
|
|
var dest = destination;
|
|
if ( item.filename.match(/\//) ) {
|
|
if ( item.directory ) {
|
|
dest += '/' + item.filename;
|
|
} else {
|
|
dest += '/' + Utils.dirname(item.filename);
|
|
}
|
|
}
|
|
if ( item.directory ) {
|
|
VFS.mkdir(new VFS.File(dest), function(error, result) {
|
|
if ( error ) {
|
|
warnings.push(Utils.format('Could not create directory "{0}": {1}', item.filename, error));
|
|
} else {
|
|
extracted.push(item.filename);
|
|
}
|
|
cb();
|
|
});
|
|
return;
|
|
}
|
|
getEntryFile(item, function(blob) {
|
|
VFS.upload({
|
|
destination: dest,
|
|
files: [{filename: Utils.filename(item.filename), data: blob}]
|
|
}, function(type, ev) { // error, result, ev
|
|
console.warn('ZipArchiver::extract()', '_extract()', 'upload', type, ev);
|
|
if ( type === 'error' ) {
|
|
warnings.push(Utils.format('Could not extract "{0}": {1}', item.filename, ev));
|
|
} else {
|
|
extracted.push(item.filename);
|
|
}
|
|
cb();
|
|
});
|
|
}, function() {
|
|
});
|
|
}
|
|
function _finished() {
|
|
finished(false, warnings, true);
|
|
}
|
|
function _next() {
|
|
if ( !list.length || index >= list.length ) {
|
|
return _finished();
|
|
}
|
|
_extract(list[index], function() {
|
|
index++;
|
|
_next();
|
|
});
|
|
}
|
|
_next();
|
|
}
|
|
function _checkDirectory(destination, cb) {
|
|
var dst = new VFS.File({path: destination, type: 'dir'});
|
|
VFS.mkdir(dst, function(error, result) {
|
|
if ( error ) {
|
|
console.warn('ZipArchiver::extract()', '_checkDirectory()', 'VFS::mkdir()', error);
|
|
}
|
|
VFS.exists(dst, function(err, result) {
|
|
if ( err ) {
|
|
console.warn('ZipArchiver::extract()', '_checkDirectory()', 'VFS::exists()', err);
|
|
}
|
|
if ( result ) {
|
|
cb(false);
|
|
} else {
|
|
cb('Destination directory was not created or does not exist');
|
|
}
|
|
});
|
|
});
|
|
}
|
|
VFS.download(file, function(error, result) {
|
|
if ( error ) {
|
|
finished(error, warnings, false);
|
|
return;
|
|
}
|
|
var blob = new Blob([result], {type: 'application/zip'});
|
|
_checkDirectory(destination, function(err) {
|
|
if ( err ) {
|
|
finished(error, warnings, false);
|
|
return;
|
|
}
|
|
getEntries(blob, function(error, entries) {
|
|
if ( error ) {
|
|
finished(error, warnings, false);
|
|
return;
|
|
}
|
|
_extractList(entries, destination);
|
|
});
|
|
});
|
|
});
|
|
};
|
|
OSjs.Helpers.ZipArchiver = OSjs.Helpers.ZipArchiver || {};
|
|
OSjs.Helpers.ZipArchiver.getInstance = function() {
|
|
return SingletonInstance;
|
|
};
|
|
OSjs.Helpers.ZipArchiver.createInstance = function(args, callback) {
|
|
args = args || {};
|
|
if ( !SingletonInstance ) {
|
|
SingletonInstance = new ZipArchiver(args);
|
|
}
|
|
SingletonInstance.init(function(error) {
|
|
if ( !error ) {
|
|
if ( !window.zip ) {
|
|
error = API._('ZIP_VENDOR_FAIL');
|
|
}
|
|
}
|
|
callback(error, error ? false : SingletonInstance);
|
|
});
|
|
};
|
|
})(OSjs.Utils, OSjs.API, OSjs.VFS);
|
|
|
|
(function(Utils) {
|
|
'use strict';
|
|
function SettingsFragment(obj, poolName) {
|
|
this._pool = poolName;
|
|
if ( obj.constructor !== {}.constructor ) {
|
|
throw new Error('SettingsFragment will not work unless you give it a object to manage.');
|
|
}
|
|
this._settings = obj;
|
|
}
|
|
SettingsFragment.prototype.get = function(key, defaultValue) {
|
|
var ret = key ? this._settings[key] : this._settings;
|
|
return (typeof ret === 'undefined') ? defaultValue : ret;
|
|
};
|
|
SettingsFragment.prototype.set = function(key, value, save, triggerWatch) {
|
|
if ( key === null ) {
|
|
Utils.mergeObject(this._settings, value);
|
|
} else {
|
|
if ( (['number', 'string']).indexOf(typeof key) >= 0 ) {
|
|
this._settings[key] = value;
|
|
} else {
|
|
console.warn('SettingsFragment::set()', 'expects key to be a valid iter, not', key);
|
|
}
|
|
}
|
|
if (save) {
|
|
OSjs.Core.getSettingsManager().save(this._pool, save);
|
|
}
|
|
if ( typeof triggerWatch === 'undefined' || triggerWatch === true ) {
|
|
OSjs.Core.getSettingsManager().changed(this._pool);
|
|
}
|
|
return this;
|
|
};
|
|
SettingsFragment.prototype.save = function(callback) {
|
|
return OSjs.Core.getSettingsManager().save(this._pool, callback);
|
|
};
|
|
SettingsFragment.prototype.getChained = function() {
|
|
var nestedSetting = this._settings;
|
|
arguments.every(function(key) {
|
|
if (nestedSetting[key]) {
|
|
nestedSetting = nestedSetting[key];
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
return nestedSetting;
|
|
};
|
|
SettingsFragment.prototype.mergeDefaults = function(defaults) {
|
|
Utils.mergeObject(this._settings, defaults, {overwrite: false});
|
|
return this;
|
|
};
|
|
SettingsFragment.prototype.instance = function(key) {
|
|
if (typeof this._settings[key] === 'undefined') {
|
|
throw new Error('The object doesn\'t contain that key. SettingsFragment will not work.');
|
|
}
|
|
return new OSjs.Helpers.SettingsFragment(this._settings[key], this._pool);
|
|
};
|
|
OSjs.Helpers.SettingsFragment = SettingsFragment;
|
|
})(OSjs.Utils);
|