From abc7c56a0e6ecf884f2ebe2e9e894a62a52b1730 Mon Sep 17 00:00:00 2001 From: Anders Evenrud Date: Sun, 13 Aug 2017 19:58:09 +0200 Subject: [PATCH] Version bump (#617) Rewritten to ES6 (Babel), Webpack and Express. Many of these are **breaking** changes, but you can easily migrate to the new style. For a full writeup of changes etc, see links below. Relevant: * https://community.os-js.org/t/update-version-bump-2-1-0/142 * https://community.os-js.org/t/road-to-es6-es2015/131/8 * https://github.com/os-js/OS.js/issues/617 Digest: * Core: Rewritten to ES6 * Core: Callbacks replaced with Promise * Core: Now using imports * Core: Deprecated all marked methods * Core: Removed global namespace (available as BC module) * Core: Removed support for "simple" packages * Core: Removed support for "dummy" packages * Core: Removed support for "old" packages * Core: Detached Scheme files from applications * Core: Changed in namespaces (code separation) * API: Now using axios for XHR * API: Now using bluebird for better promises * VFS: Removed 'delete' operation (use 'unlink') * GUI: Schemes now embed in bundles if used * Packages: Default packages refactored * build: Now using Ygor as task system * build: Rewritten * build: Now using Webpack for themes * build: Now using Webpack for packages * build: Now using Webpack for core * build: Removed grunt entirely * build: Split up into separate package * build: Changed templating generation * build: Simplified configuration capabilities * build: Better overlay support * server-node: Rewritten to ES6 * server-node: Now using Express * server-node: Changed how modules look * server-node: Better module APIs * server-node: Better user handling * conf: Changed overlay layouts * conf: Overlays now support themes * conf: Overlays now support configuration includes * conf: Changed vfs configuration * misc: Added some new `bin/` scripts * misc: Removed the `Zip` helper. This will be replaced with something newer. * misc: The `Database` handler now uses separate tables * misc: Added `OSjs.require()` for externals * misc: Moved src/client/themes to src/themes * misc: Bugfixes and general cleanups * misc: Performance improvements * misc: No more 'dist/vendor' by default * misc: Removed automated installers from repo * misc: Separated graphics sources to own repo * misc: Separated x11 sources to own repo * misc: Separated Broadway (will be replaced with Xpra) * misc: Updated documentation * misc: Now using esdoc --- .bithoundrc | 1 + .csslintrc | 12 - .eslintignore | 1 - .eslintrc | 10 +- .gitignore | 10 +- .travis.yml | 4 - CHANGELOG.md | 123 +- CONTRIBUTING.md | 40 +- Dockerfile | 2 +- Gruntfile.js | 141 -- INSTALL.md | 6 +- README.md | 12 +- Vagrantfile | 2 +- bin/add-package-repo.sh | 31 + bin/add-package.sh | 34 + bin/add-user.js | 146 +- bin/build-electron.sh | 1 - bin/make-packaged.sh | 17 +- dist/.gitignore | 1 + dist/vendor/.gitignore | 0 dist/vendor/chai.js | 1 - dist/vendor/dropbox.js | 1 - dist/vendor/dropbox.min.map | 1 - dist/vendor/html2canvas | 1 - dist/vendor/mocha.css | 1 - dist/vendor/mocha.js | 1 - dist/vendor/zip.js | 1 - dist/vendor/zlib.js | 1 - osjs | 14 +- package.json | 37 +- src/build/.eslintrc | 19 - src/build/config.js | 582 ----- src/build/core.js | 161 -- src/build/dist.js | 258 -- src/build/generate.js | 228 -- src/build/help.txt | 53 - src/build/index.js | 351 --- src/build/manifest.js | 389 --- src/build/packages.js | 389 --- src/build/themes.js | 364 --- src/build/utils.js | 373 --- src/build/watcher.js | 228 -- src/client/javascript/boot.js | 71 + src/client/javascript/broadway/broadway.js | 1116 --------- src/client/javascript/broadway/connection.js | 361 --- src/client/javascript/broadway/unicode.js | 1306 ---------- src/client/javascript/broadway/window.js | 205 -- src/client/javascript/core/api.js | 1926 --------------- src/client/javascript/core/application.js | 403 ++- src/client/javascript/core/auth/database.js | 18 +- src/client/javascript/core/auth/demo.js | 68 +- src/client/javascript/core/auth/pam.js | 19 +- .../javascript/core/auth/standalone.js} | 29 +- src/client/javascript/core/authenticator.js | 277 +-- src/client/javascript/core/boot.js | 874 ------- src/client/javascript/core/config.js | 104 + src/client/javascript/core/connection.js | 499 ++-- .../javascript/core/connections/http.js | 63 +- .../core/connections/standalone.js} | 29 +- src/client/javascript/core/connections/ws.js | 164 +- src/client/javascript/core/dialog.js | 276 ++- src/client/javascript/core/init.js | 630 +++++ src/client/javascript/core/locales.js | 172 ++ src/client/javascript/core/mount-manager.js | 633 ++--- src/client/javascript/core/package-manager.js | 836 +++---- src/client/javascript/core/process.js | 837 ++++--- src/client/javascript/core/search-engine.js | 500 ++-- src/client/javascript/core/service.js | 65 +- .../javascript/core/settings-manager.js | 199 +- src/client/javascript/core/storage.js | 185 +- .../javascript/core/storage/database.js | 23 +- src/client/javascript/core/storage/demo.js | 41 +- .../javascript/core/storage/standalone.js} | 14 +- src/client/javascript/core/storage/system.js | 24 +- src/client/javascript/core/theme.js | 485 ++++ src/client/javascript/core/window-manager.js | 893 +++++++ src/client/javascript/core/window.js | 2160 ++++++++--------- src/client/javascript/core/windowmanager.js | 1188 --------- src/client/{ => javascript}/dialogs.html | 0 src/client/javascript/dialogs/alert.js | 49 +- .../javascript/dialogs/applicationchooser.js | 92 +- src/client/javascript/dialogs/color.js | 148 +- src/client/javascript/dialogs/confirm.js | 65 +- src/client/javascript/dialogs/error.js | 87 +- src/client/javascript/dialogs/file.js | 355 ++- src/client/javascript/dialogs/fileinfo.js | 78 +- src/client/javascript/dialogs/fileprogress.js | 81 +- src/client/javascript/dialogs/fileupload.js | 126 +- src/client/javascript/dialogs/font.js | 91 +- src/client/javascript/dialogs/input.js | 74 +- src/client/javascript/gui/dataview.js | 1252 +++++----- src/client/javascript/gui/element.js | 528 ++-- .../javascript/gui/elements/containers.js | 741 +++--- .../javascript/gui/elements/fileview.js | 936 +++---- .../javascript/gui/elements/iconview.js | 231 +- src/client/javascript/gui/elements/inputs.js | 1624 ++++++------- .../javascript/gui/elements/listview.js | 647 ++--- src/client/javascript/gui/elements/menus.js | 625 ++--- src/client/javascript/gui/elements/misc.js | 575 +++-- .../javascript/gui/elements/richtext.js | 344 +-- src/client/javascript/gui/elements/tabs.js | 316 +-- .../javascript/gui/elements/treeview.js | 451 ++-- src/client/javascript/gui/elements/visual.js | 347 ++- src/client/javascript/gui/helpers.js | 1016 -------- src/client/javascript/gui/menu.js | 215 ++ src/client/javascript/gui/notification.js | 234 ++ src/client/javascript/gui/scheme.js | 576 ++--- .../{vfs/transports/http.js => gui/splash.js} | 94 +- src/client/javascript/helpers/date.js | 877 ++++--- .../helpers/default-application-window.js | 163 +- .../javascript/helpers/default-application.js | 236 +- .../javascript/helpers/event-handler.js | 71 +- src/client/javascript/helpers/google-api.js | 335 ++- .../javascript/helpers/hooks.js} | 114 +- .../helpers/iframe-application-window.js | 189 ++ .../javascript/helpers/iframe-application.js | 275 +-- .../javascript/helpers/loader.js} | 93 +- .../helpers/service-notification-icon.js | 125 + .../javascript/helpers/settings-fragment.js | 131 +- .../javascript/helpers/window-behaviour.js | 387 +++ .../javascript/helpers/windows-live-api.js | 298 +-- src/client/javascript/helpers/zip-archiver.js | 639 ----- src/client/javascript/locales/ar_DZ.js | 846 ++++--- src/client/javascript/locales/bg_BG.js | 712 +++--- src/client/javascript/locales/de_DE.js | 460 ++-- src/client/javascript/locales/en_EN.js | 927 ++++--- src/client/javascript/locales/es_ES.js | 683 +++--- src/client/javascript/locales/fa_FA.js | 752 +++--- src/client/javascript/locales/fr_FR.js | 919 ++++--- src/client/javascript/locales/it_IT.js | 911 ++++--- src/client/javascript/locales/ko_KR.js | 811 +++---- src/client/javascript/locales/nl_NL.js | 787 +++--- src/client/javascript/locales/no_NO.js | 880 ++++--- src/client/javascript/locales/pl_PL.js | 739 +++--- src/client/javascript/locales/pt_BR.js | 697 +++--- src/client/javascript/locales/ru_RU.js | 463 ++-- src/client/javascript/locales/sk_SK.js | 699 +++--- src/client/javascript/locales/tr_TR.js | 711 +++--- src/client/javascript/locales/vi_VN.js | 863 ++++--- src/client/javascript/locales/zh_CN.js | 541 ++--- src/client/javascript/polyfill.js | 125 +- .../javascript/utils/clipboard.js} | 34 +- src/client/javascript/utils/compability.js | 524 ++-- src/client/javascript/utils/dom.js | 942 ++++--- src/client/javascript/utils/events.js | 939 ++++--- src/client/javascript/utils/fs.js | 878 ++++--- src/client/javascript/utils/gui.js | 779 ++++++ src/client/javascript/utils/keycodes.js | 87 + src/client/javascript/utils/misc.js | 682 ++---- src/client/javascript/utils/preloader.js | 230 ++ src/client/javascript/utils/xhr.js | 482 ---- src/client/javascript/vfs/file.js | 325 +-- .../javascript/vfs/filedataurl.js} | 55 +- src/client/javascript/vfs/fs.js | 2099 +++++++--------- src/client/javascript/vfs/helpers.js | 450 ---- src/client/javascript/vfs/mountpoint.js | 198 ++ src/client/javascript/vfs/mounts/dropbox.js | 379 --- .../javascript/vfs/mounts/googledrive.js | 934 ------- .../javascript/vfs/mounts/localstorage.js | 681 ------ src/client/javascript/vfs/mounts/onedrive.js | 681 ------ src/client/javascript/vfs/transport.js | 142 ++ .../javascript/vfs/transports/applications.js | 88 +- src/client/javascript/vfs/transports/dist.js | 74 +- .../javascript/vfs/transports/google-drive.js | 837 +++++++ .../javascript/vfs/transports/onedrive.js | 534 ++++ src/client/javascript/vfs/transports/osjs.js | 328 +-- src/client/javascript/vfs/transports/web.js | 230 +- .../javascript/vfs/transports/webdav.js | 453 ++-- src/client/stylesheets/animations.less | 232 ++ src/client/stylesheets/core.css | 120 +- src/client/stylesheets/gui.css | 2 +- src/client/test/test.js | 1588 ++++++------ src/client/themes/fonts/Karla/style.css | 57 - src/client/themes/fonts/Roboto/style.css | 140 -- src/client/themes/styles/dark/style.less | 101 - src/client/themes/styles/dark/theme.js | 27 - src/client/themes/styles/default/style.less | 77 - src/client/themes/styles/default/theme.js | 27 - src/client/themes/styles/glass/style.less | 63 - src/client/themes/styles/glass/theme.js | 27 - src/client/themes/styles/material/style.less | 365 --- src/client/themes/styles/material/theme.js | 41 - src/client/themes/styles/windows8/style.less | 110 - src/client/themes/styles/windows8/theme.js | 27 - src/client/webpack.config.js | 7 + src/conf/000-base.json | 3 +- src/conf/100-client.json | 8 +- src/conf/120-themes.json | 1 - src/conf/130-vfs.json | 78 +- src/conf/140-windowmanager.json | 15 +- src/conf/200-server.json | 20 +- src/conf/500-build.json | 176 +- src/gfx/logo-big.png | Bin 19496 -> 0 bytes src/gfx/logo-blue.svg | 848 ------- src/gfx/logo-footer.png | Bin 9570 -> 0 bytes src/gfx/logo-header-big.png | Bin 11981 -> 0 bytes src/gfx/logo-header-small.png | Bin 6301 -> 0 bytes src/gfx/logo-splash.png | Bin 10170 -> 0 bytes src/gfx/logo-white.svg | 851 ------- src/gfx/logo.svg | 169 -- src/gfx/screenshot.png | Bin 139204 -> 0 bytes src/gfx/symbol.svg | 247 -- src/gfx/symbol_backup.svg | 247 -- src/installer/installer.nsi | 32 - src/installer/installer.ps1 | Bin 5468 -> 0 bytes src/installer/installer.sh | 59 - src/packages/default/About/main.js | 60 +- src/packages/default/About/metadata.json | 4 - src/packages/default/About/scheme.html | 2 +- src/packages/default/About/webpack.config.js | 10 + src/packages/default/Calculator/main.css | 2 +- src/packages/default/Calculator/main.js | 168 +- src/packages/default/Calculator/metadata.json | 5 +- .../default/Calculator/webpack.config.js | 10 + src/packages/default/CoreWM/animations.css | 225 -- src/packages/default/CoreWM/iconview.js | 331 ++- src/packages/default/CoreWM/locales.js | 548 ++--- src/packages/default/CoreWM/main.css | 2 + src/packages/default/CoreWM/main.js | 977 +++----- src/packages/default/CoreWM/menu.js | 160 +- src/packages/default/CoreWM/metadata.json | 64 - src/packages/default/CoreWM/panel.js | 303 +-- src/packages/default/CoreWM/panelitem.js | 99 + .../default/CoreWM/panelitemdialog.js | 42 + .../default/CoreWM/panelitems/appmenu.js | 69 +- .../default/CoreWM/panelitems/buttons.js | 189 +- .../default/CoreWM/panelitems/clock.js | 136 +- .../CoreWM/panelitems/notificationarea.js | 133 +- .../default/CoreWM/panelitems/search.js | 262 +- .../default/CoreWM/panelitems/weather.js | 115 +- .../default/CoreWM/panelitems/windowlist.js | 106 +- src/packages/default/CoreWM/server/main.js | 21 +- src/packages/default/CoreWM/webpack.config.js | 10 + src/packages/default/CoreWM/widget.js | 468 ++-- .../default/CoreWM/widgets/analogclock.js | 66 +- .../default/CoreWM/widgets/digitalclock.js | 70 +- .../default/CoreWM/widgets/weather.js | 50 +- src/packages/default/CoreWM/windowswitcher.js | 40 +- src/packages/default/Draw/locales.js | 1361 +++++------ src/packages/default/Draw/main.css | 2 +- src/packages/default/Draw/main.js | 410 ++-- src/packages/default/Draw/metadata.json | 4 +- src/packages/default/Draw/scheme.html | 18 +- src/packages/default/Draw/webpack.config.js | 10 + src/packages/default/FileManager/locales.js | 299 ++- src/packages/default/FileManager/main.js | 442 ++-- .../default/FileManager/metadata.json | 8 - .../default/FileManager/webpack.config.js | 10 + src/packages/default/HTMLViewer/main.js | 65 +- src/packages/default/HTMLViewer/metadata.json | 6 +- .../default/HTMLViewer/webpack.config.js | 10 + src/packages/default/MusicPlayer/locales.js | 444 ++-- src/packages/default/MusicPlayer/main.css | 5 +- src/packages/default/MusicPlayer/main.js | 142 +- .../default/MusicPlayer/metadata.json | 8 - .../default/MusicPlayer/webpack.config.js | 10 + src/packages/default/Preview/main.js | 120 +- src/packages/default/Preview/metadata.json | 4 - .../default/Preview/webpack.config.js | 10 + src/packages/default/ProcessViewer/main.js | 73 +- .../default/ProcessViewer/metadata.json | 4 - .../default/ProcessViewer/webpack.config.js | 10 + src/packages/default/Settings/locale.js | 350 --- src/packages/default/Settings/locales.js | 328 +++ src/packages/default/Settings/main.js | 365 +-- src/packages/default/Settings/metadata.json | 16 +- .../default/Settings/module-broadway.js | 1 - .../default/Settings/module-desktop.js | 264 +- src/packages/default/Settings/module-input.js | 139 +- .../default/Settings/module-locale.js | 75 +- src/packages/default/Settings/module-panel.js | 398 ++- src/packages/default/Settings/module-pm.js | 402 ++- .../default/Settings/module-search.js | 220 +- src/packages/default/Settings/module-sound.js | 153 +- src/packages/default/Settings/module-store.js | 193 +- src/packages/default/Settings/module-theme.js | 204 +- src/packages/default/Settings/module-user.js | 57 +- .../default/Settings/module-users.html | 1 + src/packages/default/Settings/module-users.js | 305 ++- src/packages/default/Settings/module-vfs.js | 412 ++-- src/packages/default/Settings/scheme.html | 2 +- src/packages/default/Settings/server/main.js | 20 +- .../default/Settings/webpack.config.js | 10 + src/packages/default/Textpad/main.js | 91 +- src/packages/default/Textpad/metadata.json | 4 - .../default/Textpad/webpack.config.js | 10 + src/packages/default/Writer/locales.js | 109 +- src/packages/default/Writer/main.js | 129 +- src/packages/default/Writer/metadata.json | 8 - src/packages/default/Writer/webpack.config.js | 10 + src/server/node/.eslintrc | 19 - src/server/node/core/api.js | 140 -- src/server/node/core/auth.js | 286 --- src/server/node/core/env.js | 128 - src/server/node/core/http.js | 589 ----- src/server/node/core/instance.js | 420 ---- src/server/node/core/middleware.js | 120 - src/server/node/core/packagemanager.js | 311 --- src/server/node/core/responder.js | 295 --- src/server/node/core/session.js | 272 --- src/server/node/core/settings.js | 133 - src/server/node/core/vfs.js | 445 ---- src/server/node/lib/evhandler.js | 119 - src/server/node/lib/logger.js | 232 -- src/server/node/lib/utils.js | 220 -- src/server/node/modules.js | 521 ++++ src/server/node/modules/api/application.js | 126 - src/server/node/modules/api/auth.js | 106 - src/server/node/modules/api/users.js | 51 - src/server/node/modules/auth/database.js | 343 +-- src/server/node/modules/auth/demo.js | 88 +- src/server/node/modules/auth/example.js | 145 -- src/server/node/modules/auth/pam.js | 128 +- src/server/node/modules/auth/shadow.js | 134 +- src/server/node/modules/auth/test.js | 133 +- src/server/node/modules/authenticator.js | 244 ++ src/server/node/modules/connection.js | 271 +++ src/server/node/modules/connections/http.js | 89 + src/server/node/modules/connections/ws.js | 243 ++ src/server/node/{lib => modules}/database.js | 18 +- src/server/node/modules/middleware/example.js | 48 - .../node/modules/middleware/user-package.js | 34 +- src/server/node/modules/services/broadway.js | 116 - src/server/node/modules/services/example.js | 46 - src/server/node/modules/services/vfswatch.js | 21 +- src/server/node/modules/session/file.js | 44 - src/server/node/modules/session/memory.js | 44 - .../modules/{api/packages.js => storage.js} | 67 +- src/server/node/modules/storage/database.js | 93 +- src/server/node/modules/storage/demo.js | 22 +- src/server/node/modules/storage/example.js | 72 - src/server/node/modules/storage/system.js | 67 +- src/server/node/modules/storage/test.js | 22 +- src/server/node/modules/vfs/example.js | 142 -- src/server/node/modules/vfs/filesystem.js | 177 +- src/server/node/modules/vfs/http.js | 100 +- src/server/node/packagemanager.js | 261 ++ src/server/node/routes/api.js | 165 ++ .../node/{core/metadata.js => routes/fs.js} | 66 +- .../node/routes/internal.js} | 88 +- .../{modules/api/curl.js => routes/misc.js} | 39 +- src/server/node/server.js | 106 +- src/server/node/settings.js | 169 ++ src/server/node/user.js | 145 ++ src/server/node/vfs.js | 399 +++ src/server/php/Core/Instance.php | 16 +- src/server/php/Modules/VFS/Filesystem.php | 5 +- src/server/test/node/test.js | 966 ++------ src/templates/dist/{default => }/api.php | 0 src/templates/dist/{default => }/blank.css | 0 src/templates/dist/default/favicon.ico | Bin 15086 -> 0 bytes src/templates/dist/default/favicon.png | Bin 623 -> 7625 bytes .../dist/default/{index.html => index.ejs} | 35 +- .../default.html => default/login.html} | 0 src/templates/dist/default/splash.html | 48 + src/templates/dist/default/test.html | 65 - .../templates/dist/dropbox-oauth.html | 2 +- src/templates/dist/header.css | 31 - src/templates/dist/header.js | 32 - src/templates/dist/packages.js | 3 +- src/templates/dist/settings.js | 11 +- src/templates/dist/splash/default.html | 61 - .../templates/dist/windows-live-oauth.html | 0 src/templates/misc/authstorage.sql | 36 +- src/templates/misc/authstorage.sqlite | Bin 12288 -> 20480 bytes src/templates/package/application/main.css | 2 +- src/templates/package/application/main.js | 77 +- .../package/application/metadata.json | 7 +- .../package/application/server/main.js | 37 +- .../package/application/webpack.config.js | 10 + src/templates/package/dummy/metadata.json | 11 - src/templates/package/extension/main.js | 59 +- src/templates/package/extension/metadata.json | 9 +- .../package/extension/server/main.js | 21 +- .../package/extension/webpack.config.js | 10 + .../iframe-application/data/index.html | 27 + .../package/iframe-application/data/osjs.js | 140 ++ .../package/iframe-application/main.js | 34 +- .../package/iframe-application/metadata.json | 18 +- .../iframe-application/webpack.config.js | 12 + src/templates/package/service/main.js | 42 +- src/templates/package/service/metadata.json | 8 +- src/templates/package/service/server/main.js | 5 +- .../package/service/webpack.config.js | 10 + .../package/simple-application/main.css | 33 - .../package/simple-application/metadata.json | 19 - .../package/simple-application/scheme.html | 3 - .../simple-application/server/main.php | 17 - .../themes/fonts/Karla/LICENSE.txt | 0 .../fonts/Karla/fonts}/Bold.eot | Bin .../fonts/Karla/fonts}/Bold.svg | 0 .../fonts/Karla/fonts}/Bold.ttf | Bin .../fonts/Karla/fonts}/Bold.woff | Bin .../fonts/Karla/fonts}/BoldItalic.eot | Bin .../fonts/Karla/fonts}/BoldItalic.svg | 0 .../fonts/Karla/fonts}/BoldItalic.ttf | Bin .../fonts/Karla/fonts}/BoldItalic.woff | Bin .../fonts/Karla/fonts}/Italic.eot | Bin .../fonts/Karla/fonts}/Italic.svg | 0 .../fonts/Karla/fonts}/Italic.ttf | Bin .../fonts/Karla/fonts}/Italic.woff | Bin .../fonts/Karla/fonts}/Regular.eot | Bin .../fonts/Karla/fonts}/Regular.svg | 0 .../fonts/Karla/fonts}/Regular.ttf | Bin .../fonts/Karla/fonts}/Regular.woff | Bin src/themes/fonts/Karla/style.css | 57 + .../fonts/Roboto/fonts/Roboto-100/LICENSE.txt | 0 .../Roboto/fonts/Roboto-100/Roboto-100.eot | Bin .../Roboto/fonts/Roboto-100/Roboto-100.svg | 0 .../Roboto/fonts/Roboto-100/Roboto-100.ttf | Bin .../Roboto/fonts/Roboto-100/Roboto-100.woff | Bin .../Roboto/fonts/Roboto-100/Roboto-100.woff2 | Bin .../Roboto/fonts/Roboto-100italic/LICENSE.txt | 0 .../Roboto-100italic/Roboto-100italic.eot | Bin .../Roboto-100italic/Roboto-100italic.svg | 0 .../Roboto-100italic/Roboto-100italic.ttf | Bin .../Roboto-100italic/Roboto-100italic.woff | Bin .../Roboto-100italic/Roboto-100italic.woff2 | Bin .../fonts/Roboto/fonts/Roboto-300/LICENSE.txt | 0 .../Roboto/fonts/Roboto-300/Roboto-300.eot | Bin .../Roboto/fonts/Roboto-300/Roboto-300.svg | 0 .../Roboto/fonts/Roboto-300/Roboto-300.ttf | Bin .../Roboto/fonts/Roboto-300/Roboto-300.woff | Bin .../Roboto/fonts/Roboto-300/Roboto-300.woff2 | Bin .../Roboto/fonts/Roboto-300italic/LICENSE.txt | 0 .../Roboto-300italic/Roboto-300italic.eot | Bin .../Roboto-300italic/Roboto-300italic.svg | 0 .../Roboto-300italic/Roboto-300italic.ttf | Bin .../Roboto-300italic/Roboto-300italic.woff | Bin .../Roboto-300italic/Roboto-300italic.woff2 | Bin .../fonts/Roboto/fonts/Roboto-500/LICENSE.txt | 0 .../Roboto/fonts/Roboto-500/Roboto-500.eot | Bin .../Roboto/fonts/Roboto-500/Roboto-500.svg | 0 .../Roboto/fonts/Roboto-500/Roboto-500.ttf | Bin .../Roboto/fonts/Roboto-500/Roboto-500.woff | Bin .../Roboto/fonts/Roboto-500/Roboto-500.woff2 | Bin .../Roboto/fonts/Roboto-500italic/LICENSE.txt | 0 .../Roboto-500italic/Roboto-500italic.eot | Bin .../Roboto-500italic/Roboto-500italic.svg | 0 .../Roboto-500italic/Roboto-500italic.ttf | Bin .../Roboto-500italic/Roboto-500italic.woff | Bin .../Roboto-500italic/Roboto-500italic.woff2 | Bin .../fonts/Roboto/fonts/Roboto-700/LICENSE.txt | 0 .../Roboto/fonts/Roboto-700/Roboto-700.eot | Bin .../Roboto/fonts/Roboto-700/Roboto-700.svg | 0 .../Roboto/fonts/Roboto-700/Roboto-700.ttf | Bin .../Roboto/fonts/Roboto-700/Roboto-700.woff | Bin .../Roboto/fonts/Roboto-700/Roboto-700.woff2 | Bin .../Roboto/fonts/Roboto-700italic/LICENSE.txt | 0 .../Roboto-700italic/Roboto-700italic.eot | Bin .../Roboto-700italic/Roboto-700italic.svg | 0 .../Roboto-700italic/Roboto-700italic.ttf | Bin .../Roboto-700italic/Roboto-700italic.woff | Bin .../Roboto-700italic/Roboto-700italic.woff2 | Bin .../Roboto/fonts/Roboto-italic/LICENSE.txt | 0 .../fonts/Roboto-italic/Roboto-italic.eot | Bin .../fonts/Roboto-italic/Roboto-italic.svg | 0 .../fonts/Roboto-italic/Roboto-italic.ttf | Bin .../fonts/Roboto-italic/Roboto-italic.woff | Bin .../fonts/Roboto-italic/Roboto-italic.woff2 | Bin .../Roboto/fonts/Roboto-regular/LICENSE.txt | 0 .../fonts/Roboto-regular/Roboto-regular.eot | Bin .../fonts/Roboto-regular/Roboto-regular.svg | 0 .../fonts/Roboto-regular/Roboto-regular.ttf | Bin .../fonts/Roboto-regular/Roboto-regular.woff | Bin .../fonts/Roboto-regular/Roboto-regular.woff2 | Bin src/themes/fonts/Roboto/style.css | 140 ++ .../16x16/actions/address-book-new.png | Bin .../16x16/actions/application-exit.png | Bin .../default/16x16/actions/appointment-new.png | Bin .../default/16x16/actions/bookmark-new.png | Bin .../default/16x16/actions/call-start.png | Bin .../icons/default/16x16/actions/call-stop.png | Bin .../default/16x16/actions/contact-new.png | Bin .../default/16x16/actions/document-new.png | Bin .../16x16/actions/document-open-recent.png | Bin .../default/16x16/actions/document-open.png | Bin .../16x16/actions/document-page-setup.png | Bin .../16x16/actions/document-print-preview.png | Bin .../default/16x16/actions/document-print.png | Bin .../16x16/actions/document-properties.png | Bin .../default/16x16/actions/document-revert.png | Bin .../16x16/actions/document-save-as.png | Bin .../default/16x16/actions/document-save.png | Bin .../default/16x16/actions/document-send.png | Bin .../default/16x16/actions/edit-clear.png | Bin .../icons/default/16x16/actions/edit-copy.png | Bin .../icons/default/16x16/actions/edit-cut.png | Bin .../default/16x16/actions/edit-delete.png | Bin .../16x16/actions/edit-find-replace.png | Bin .../icons/default/16x16/actions/edit-find.png | Bin .../default/16x16/actions/edit-paste.png | Bin .../icons/default/16x16/actions/edit-redo.png | Bin .../default/16x16/actions/edit-select-all.png | Bin .../icons/default/16x16/actions/edit-undo.png | Bin .../default/16x16/actions/folder-new.png | Bin .../16x16/actions/format-indent-less.png | Bin .../16x16/actions/format-indent-more.png | Bin .../16x16/actions/format-justify-center.png | Bin .../16x16/actions/format-justify-fill.png | Bin .../16x16/actions/format-justify-left.png | Bin .../16x16/actions/format-justify-right.png | Bin .../16x16/actions/format-text-bold.png | Bin .../actions/format-text-direction-ltr.png | Bin .../actions/format-text-direction-rtl.png | Bin .../16x16/actions/format-text-italic.png | Bin .../actions/format-text-strikethrough.png | Bin .../16x16/actions/format-text-underline.png | Bin .../icons/default/16x16/actions/go-bottom.png | Bin .../icons/default/16x16/actions/go-down.png | Bin .../icons/default/16x16/actions/go-first.png | Bin .../icons/default/16x16/actions/go-home.png | Bin .../icons/default/16x16/actions/go-jump.png | Bin .../icons/default/16x16/actions/go-last.png | Bin .../icons/default/16x16/actions/go-next.png | Bin .../default/16x16/actions/go-previous.png | Bin .../icons/default/16x16/actions/go-top.png | Bin .../icons/default/16x16/actions/go-up.png | Bin .../default/16x16/actions/help-about.png | Bin .../default/16x16/actions/help-contents.png | Bin .../icons/default/16x16/actions/help-faq.png | Bin .../default/16x16/actions/insert-image.png | Bin .../default/16x16/actions/insert-link.png | Bin .../default/16x16/actions/insert-object.png | Bin .../default/16x16/actions/insert-text.png | Bin .../icons/default/16x16/actions/list-add.png | Bin .../default/16x16/actions/list-remove.png | Bin .../default/16x16/actions/mail-forward.png | Bin .../16x16/actions/mail-mark-important.png | Bin .../default/16x16/actions/mail-mark-junk.png | Bin .../16x16/actions/mail-mark-notjunk.png | Bin .../default/16x16/actions/mail-mark-read.png | Bin .../16x16/actions/mail-mark-unread.png | Bin .../16x16/actions/mail-message-new.png | Bin .../default/16x16/actions/mail-reply-all.png | Bin .../16x16/actions/mail-reply-sender.png | Bin .../16x16/actions/mail-send-receive.png | Bin .../icons/default/16x16/actions/mail-send.png | Bin .../default/16x16/actions/media-eject.png | Bin .../16x16/actions/media-playback-pause.png | Bin .../16x16/actions/media-playback-start.png | Bin .../16x16/actions/media-playback-stop.png | Bin .../default/16x16/actions/media-record.png | Bin .../16x16/actions/media-seek-backward.png | Bin .../16x16/actions/media-seek-forward.png | Bin .../16x16/actions/media-skip-backward.png | Bin .../16x16/actions/media-skip-forward.png | Bin .../16x16/actions/object-flip-horizontal.png | Bin .../16x16/actions/object-flip-vertical.png | Bin .../16x16/actions/object-rotate-left.png | Bin .../16x16/actions/object-rotate-right.png | Bin .../default/16x16/actions/process-stop.png | Bin .../16x16/actions/system-lock-screen.png | Bin .../default/16x16/actions/system-log-out.png | Bin .../default/16x16/actions/system-run.png | Bin .../default/16x16/actions/system-search.png | Bin .../default/16x16/actions/system-shutdown.png | Bin .../icons/default/16x16/actions/tab-new.png | Bin .../16x16/actions/tools-check-spelling.png | Bin .../default/16x16/actions/view-fullscreen.png | Bin .../default/16x16/actions/view-refresh.png | Bin .../default/16x16/actions/view-restore.png | Bin .../16x16/actions/view-sort-ascending.png | Bin .../16x16/actions/view-sort-descending.png | Bin .../default/16x16/actions/window-close.png | Bin .../default/16x16/actions/window-new.png | Bin .../default/16x16/actions/zoom-fit-best.png | Bin .../icons/default/16x16/actions/zoom-in.png | Bin .../default/16x16/actions/zoom-original.png | Bin .../icons/default/16x16/actions/zoom-out.png | Bin .../16x16/apps/accessories-calculator.png | Bin .../16x16/apps/accessories-character-map.png | Bin .../16x16/apps/accessories-dictionary.png | Bin .../16x16/apps/accessories-text-editor.png | Bin .../16x16/apps/applets-screenshooter.png | Bin .../apps/gnome-panel-notification-area.png | Bin .../icons/default/16x16/apps/gnome-panel.png | Bin .../icons/default/16x16/apps/help-browser.png | Bin .../default/16x16/apps/libreoffice34-base.png | Bin .../default/16x16/apps/libreoffice34-calc.png | Bin .../default/16x16/apps/libreoffice34-draw.png | Bin .../16x16/apps/libreoffice34-impress.png | Bin .../default/16x16/apps/libreoffice34-main.png | Bin .../default/16x16/apps/libreoffice34-math.png | Bin .../16x16/apps/libreoffice34-printeradmin.png | Bin .../16x16/apps/libreoffice34-startcenter.png | Bin .../16x16/apps/libreoffice34-writer.png | Bin .../icons/default/16x16/apps/logviewer.png | Bin .../16x16/apps/multimedia-volume-control.png | Bin .../preferences-desktop-accessibility.png | Bin .../apps/preferences-desktop-display.png | Bin .../16x16/apps/preferences-desktop-font.png | Bin ...preferences-desktop-keyboard-shortcuts.png | Bin .../apps/preferences-desktop-keyboard.png | Bin .../16x16/apps/preferences-desktop-locale.png | Bin .../preferences-desktop-remote-desktop.png | Bin .../apps/preferences-desktop-screensaver.png | Bin .../16x16/apps/preferences-desktop-theme.png | Bin .../apps/preferences-desktop-wallpaper.png | Bin .../16x16/apps/preferences-system-windows.png | Bin .../16x16/apps/system-file-manager.png | Bin .../16x16/apps/system-software-install.png | Bin .../16x16/apps/system-software-update.png | Bin .../icons/default/16x16/apps/system-users.png | Bin .../icons/default/16x16/apps/user-info.png | Bin .../16x16/apps/utilities-system-monitor.png | Bin .../default/16x16/apps/utilities-terminal.png | Bin .../icons/default/16x16/apps/web-browser.png | Bin .../categories/applications-accessories.png | Bin .../categories/applications-development.png | Bin .../categories/applications-engineering.png | Bin .../16x16/categories/applications-games.png | Bin .../categories/applications-graphics.png | Bin .../categories/applications-internet.png | Bin .../categories/applications-multimedia.png | Bin .../16x16/categories/applications-office.png | Bin .../16x16/categories/applications-other.png | Bin .../16x16/categories/applications-science.png | Bin .../16x16/categories/applications-system.png | Bin .../categories/applications-utilities.png | Bin .../preferences-desktop-peripherals.png | Bin .../preferences-desktop-personal.png | Bin .../16x16/categories/preferences-desktop.png | Bin .../16x16/categories/preferences-other.png | Bin .../categories/preferences-system-network.png | Bin .../16x16/categories/preferences-system.png | Bin .../default/16x16/categories/system-help.png | Bin .../default/16x16/devices/ac-adapter.png | Bin .../default/16x16/devices/audio-card.png | Bin .../16x16/devices/audio-input-microphone.png | Bin .../icons/default/16x16/devices/battery.png | Bin .../default/16x16/devices/camera-photo.png | Bin .../default/16x16/devices/camera-video.png | Bin .../default/16x16/devices/camera-web.png | Bin .../icons/default/16x16/devices/computer.png | Bin .../default/16x16/devices/drive-harddisk.png | Bin .../default/16x16/devices/drive-optical.png | Bin .../16x16/devices/drive-removable-media.png | Bin .../default/16x16/devices/input-gaming.png | Bin .../default/16x16/devices/input-keyboard.png | Bin .../default/16x16/devices/input-mouse.png | Bin .../default/16x16/devices/input-tablet.png | Bin .../default/16x16/devices/input-touchpad.png | Bin .../default/16x16/devices/media-flash.png | Bin .../default/16x16/devices/media-floppy.png | Bin .../default/16x16/devices/media-optical.png | Bin .../default/16x16/devices/media-tape.png | Bin .../icons/default/16x16/devices/modem.png | Bin .../16x16/devices/multimedia-player.png | Bin .../default/16x16/devices/network-wired.png | Bin .../16x16/devices/network-wireless.png | Bin .../icons/default/16x16/devices/pda.png | Bin .../icons/default/16x16/devices/phone.png | Bin .../icons/default/16x16/devices/printer.png | Bin .../icons/default/16x16/devices/scanner.png | Bin .../default/16x16/devices/video-display.png | Bin .../default/16x16/emblems/emblem-default.png | Bin .../16x16/emblems/emblem-documents.png | Bin .../16x16/emblems/emblem-downloads.png | Bin .../default/16x16/emblems/emblem-favorite.png | Bin .../default/16x16/emblems/emblem-generic.png | Bin .../16x16/emblems/emblem-important.png | Bin .../default/16x16/emblems/emblem-mail.png | Bin .../default/16x16/emblems/emblem-new.png | Bin .../default/16x16/emblems/emblem-package.png | Bin .../default/16x16/emblems/emblem-photos.png | Bin .../default/16x16/emblems/emblem-readonly.png | Bin .../default/16x16/emblems/emblem-shared.png | Bin .../16x16/emblems/emblem-symbolic-link.png | Bin .../16x16/emblems/emblem-synchronizing.png | Bin .../default/16x16/emblems/emblem-system.png | Bin .../16x16/emblems/emblem-unreadable.png | Bin .../default/16x16/emblems/emblem-urgent.png | Bin .../default/16x16/emblems/emblem-web.png | Bin .../icons/default/16x16/emotes/face-angel.png | Bin .../icons/default/16x16/emotes/face-angry.png | Bin .../icons/default/16x16/emotes/face-cool.png | Bin .../default/16x16/emotes/face-crying.png | Bin .../default/16x16/emotes/face-devilish.png | Bin .../default/16x16/emotes/face-embarrassed.png | Bin .../default/16x16/emotes/face-glasses.png | Bin .../icons/default/16x16/emotes/face-kiss.png | Bin .../icons/default/16x16/emotes/face-laugh.png | Bin .../default/16x16/emotes/face-monkey.png | Bin .../icons/default/16x16/emotes/face-plain.png | Bin .../default/16x16/emotes/face-raspberry.png | Bin .../icons/default/16x16/emotes/face-sad.png | Bin .../icons/default/16x16/emotes/face-sick.png | Bin .../default/16x16/emotes/face-smile-big.png | Bin .../icons/default/16x16/emotes/face-smile.png | Bin .../icons/default/16x16/emotes/face-smirk.png | Bin .../default/16x16/emotes/face-surprise.png | Bin .../icons/default/16x16/emotes/face-tired.png | Bin .../default/16x16/emotes/face-uncertain.png | Bin .../icons/default/16x16/emotes/face-wink.png | Bin .../default/16x16/emotes/face-worried.png | Bin .../themes/icons/default/16x16/gtk.png | Bin .../mimetypes/application-certificate.png | Bin .../mimetypes/application-x-executable.png | Bin .../16x16/mimetypes/audio-x-generic.png | Bin .../16x16/mimetypes/font-x-generic.png | Bin .../16x16/mimetypes/image-x-generic.png | Bin .../16x16/mimetypes/package-x-generic.png | Bin .../default/16x16/mimetypes/text-html.png | Bin .../mimetypes/text-x-generic-template.png | Bin .../16x16/mimetypes/text-x-generic.png | Bin .../16x16/mimetypes/text-x-preview.png | Bin .../default/16x16/mimetypes/text-x-script.png | Bin .../16x16/mimetypes/video-x-generic.png | Bin .../16x16/mimetypes/x-office-address-book.png | Bin .../16x16/mimetypes/x-office-calendar.png | Bin .../mimetypes/x-office-document-template.png | Bin .../16x16/mimetypes/x-office-document.png | Bin .../mimetypes/x-office-drawing-template.png | Bin .../16x16/mimetypes/x-office-drawing.png | Bin .../x-office-presentation-template.png | Bin .../16x16/mimetypes/x-office-presentation.png | Bin .../x-office-spreadsheet-template.png | Bin .../16x16/mimetypes/x-office-spreadsheet.png | Bin .../themes/icons/default/16x16/osjs-white.png | Bin .../themes/icons/default/16x16/osjs.png | Bin .../icons/default/16x16/places/dropbox.png | Bin .../default/16x16/places/folder-documents.png | Bin .../default/16x16/places/folder-download.png | Bin .../default/16x16/places/folder-music.png | Bin .../default/16x16/places/folder-pictures.png | Bin .../16x16/places/folder-publicshare.png | Bin .../default/16x16/places/folder-remote.png | Bin .../16x16/places/folder-saved-search.png | Bin .../default/16x16/places/folder-templates.png | Bin .../default/16x16/places/folder-videos.png | Bin .../icons/default/16x16/places/folder.png | Bin .../default/16x16/places/google-drive.png | Bin .../default/16x16/places/network-server.png | Bin .../16x16/places/network-workgroup.png | Bin .../icons/default/16x16/places/onedrive.png | Bin .../icons/default/16x16/places/start-here.png | Bin .../default/16x16/places/user-bookmarks.png | Bin .../default/16x16/places/user-desktop.png | Bin .../icons/default/16x16/places/user-home.png | Bin .../icons/default/16x16/places/user-trash.png | Bin .../16x16/status/appointment-missed.png | Bin .../default/16x16/status/appointment-soon.png | Bin .../16x16/status/audio-volume-high.png | Bin .../default/16x16/status/audio-volume-low.png | Bin .../16x16/status/audio-volume-medium.png | Bin .../16x16/status/audio-volume-muted.png | Bin .../default/16x16/status/avatar-default.png | Bin .../16x16/status/battery-caution-charging.png | Bin .../default/16x16/status/battery-caution.png | Bin .../default/16x16/status/battery-empty.png | Bin .../16x16/status/battery-full-charged.png | Bin .../16x16/status/battery-full-charging.png | Bin .../default/16x16/status/battery-full.png | Bin .../16x16/status/battery-good-charging.png | Bin .../default/16x16/status/battery-good.png | Bin .../16x16/status/battery-low-charging.png | Bin .../default/16x16/status/battery-low.png | Bin .../default/16x16/status/battery-missing.png | Bin .../default/16x16/status/changes-allow.png | Bin .../default/16x16/status/changes-prevent.png | Bin .../default/16x16/status/dialog-error.png | Bin .../16x16/status/dialog-information.png | Bin .../default/16x16/status/dialog-password.png | Bin .../default/16x16/status/dialog-question.png | Bin .../default/16x16/status/dialog-warning.png | Bin .../16x16/status/folder-drag-accept.png | Bin .../default/16x16/status/folder-open.png | Bin .../default/16x16/status/folder-visiting.png | Bin .../default/16x16/status/image-loading.png | Bin .../default/16x16/status/image-missing.png | Bin .../default/16x16/status/mail-attachment.png | Bin .../icons/default/16x16/status/mail-read.png | Bin .../default/16x16/status/mail-replied.png | Bin .../16x16/status/mail-signed-verified.png | Bin .../default/16x16/status/mail-signed.png | Bin .../default/16x16/status/mail-unread.png | Bin .../16x16/status/media-playlist-repeat.png | Bin .../16x16/status/media-playlist-shuffle.png | Bin .../status/microphone-sensitivity-high.png | Bin .../status/microphone-sensitivity-low.png | Bin .../status/microphone-sensitivity-medium.png | Bin .../status/microphone-sensitivity-muted.png | Bin .../default/16x16/status/network-error.png | Bin .../default/16x16/status/network-idle.png | Bin .../default/16x16/status/network-offline.png | Bin .../default/16x16/status/network-receive.png | Bin .../16x16/status/network-transmit-receive.png | Bin .../default/16x16/status/network-transmit.png | Bin .../status/network-wireless-encrypted.png | Bin .../default/16x16/status/printer-error.png | Bin .../default/16x16/status/printer-printing.png | Bin .../default/16x16/status/security-high.png | Bin .../default/16x16/status/security-low.png | Bin .../default/16x16/status/security-medium.png | Bin .../status/software-update-available.png | Bin .../16x16/status/software-update-urgent.png | Bin .../icons/default/16x16/status/task-due.png | Bin .../default/16x16/status/task-past-due.png | Bin .../default/16x16/status/user-available.png | Bin .../icons/default/16x16/status/user-away.png | Bin .../icons/default/16x16/status/user-busy.png | Bin .../icons/default/16x16/status/user-idle.png | Bin .../default/16x16/status/user-invisible.png | Bin .../default/16x16/status/user-offline.png | Bin .../default/16x16/status/user-trash-full.png | Bin .../16x16/status/weather-clear-night.png | Bin .../default/16x16/status/weather-clear.png | Bin .../16x16/status/weather-few-clouds-night.png | Bin .../16x16/status/weather-few-clouds.png | Bin .../default/16x16/status/weather-fog.png | Bin .../default/16x16/status/weather-overcast.png | Bin .../16x16/status/weather-severe-alert.png | Bin .../status/weather-showers-scattered.png | Bin .../default/16x16/status/weather-showers.png | Bin .../default/16x16/status/weather-snow.png | Bin .../default/16x16/status/weather-storm.png | Bin .../32x32/actions/address-book-new.png | Bin .../32x32/actions/application-exit.png | Bin .../default/32x32/actions/appointment-new.png | Bin .../default/32x32/actions/bookmark-new.png | Bin .../default/32x32/actions/call-start.png | Bin .../icons/default/32x32/actions/call-stop.png | Bin .../default/32x32/actions/contact-new.png | Bin .../default/32x32/actions/document-new.png | Bin .../32x32/actions/document-open-recent.png | Bin .../default/32x32/actions/document-open.png | Bin .../32x32/actions/document-page-setup.png | Bin .../32x32/actions/document-print-preview.png | Bin .../default/32x32/actions/document-print.png | Bin .../32x32/actions/document-properties.png | Bin .../default/32x32/actions/document-revert.png | Bin .../32x32/actions/document-save-as.png | Bin .../default/32x32/actions/document-save.png | Bin .../default/32x32/actions/document-send.png | Bin .../default/32x32/actions/edit-clear.png | Bin .../icons/default/32x32/actions/edit-copy.png | Bin .../icons/default/32x32/actions/edit-cut.png | Bin .../default/32x32/actions/edit-delete.png | Bin .../32x32/actions/edit-find-replace.png | Bin .../icons/default/32x32/actions/edit-find.png | Bin .../default/32x32/actions/edit-paste.png | Bin .../icons/default/32x32/actions/edit-redo.png | Bin .../default/32x32/actions/edit-select-all.png | Bin .../icons/default/32x32/actions/edit-undo.png | Bin .../default/32x32/actions/folder-new.png | Bin .../32x32/actions/format-indent-less.png | Bin .../32x32/actions/format-indent-more.png | Bin .../32x32/actions/format-justify-center.png | Bin .../32x32/actions/format-justify-fill.png | Bin .../32x32/actions/format-justify-left.png | Bin .../32x32/actions/format-justify-right.png | Bin .../32x32/actions/format-text-bold.png | Bin .../actions/format-text-direction-ltr.png | Bin .../actions/format-text-direction-rtl.png | Bin .../32x32/actions/format-text-italic.png | Bin .../actions/format-text-strikethrough.png | Bin .../32x32/actions/format-text-underline.png | Bin .../icons/default/32x32/actions/go-bottom.png | Bin .../icons/default/32x32/actions/go-down.png | Bin .../icons/default/32x32/actions/go-first.png | Bin .../icons/default/32x32/actions/go-home.png | Bin .../icons/default/32x32/actions/go-jump.png | Bin .../icons/default/32x32/actions/go-last.png | Bin .../icons/default/32x32/actions/go-next.png | Bin .../default/32x32/actions/go-previous.png | Bin .../icons/default/32x32/actions/go-top.png | Bin .../icons/default/32x32/actions/go-up.png | Bin .../default/32x32/actions/help-about.png | Bin .../default/32x32/actions/help-contents.png | Bin .../icons/default/32x32/actions/help-faq.png | Bin .../default/32x32/actions/insert-image.png | Bin .../default/32x32/actions/insert-link.png | Bin .../default/32x32/actions/insert-object.png | Bin .../default/32x32/actions/insert-text.png | Bin .../icons/default/32x32/actions/list-add.png | Bin .../default/32x32/actions/list-remove.png | Bin .../default/32x32/actions/mail-forward.png | Bin .../32x32/actions/mail-mark-important.png | Bin .../default/32x32/actions/mail-mark-junk.png | Bin .../32x32/actions/mail-mark-notjunk.png | Bin .../default/32x32/actions/mail-mark-read.png | Bin .../32x32/actions/mail-mark-unread.png | Bin .../32x32/actions/mail-message-new.png | Bin .../default/32x32/actions/mail-reply-all.png | Bin .../32x32/actions/mail-reply-sender.png | Bin .../32x32/actions/mail-send-receive.png | Bin .../icons/default/32x32/actions/mail-send.png | Bin .../default/32x32/actions/media-eject.png | Bin .../32x32/actions/media-playback-pause.png | Bin .../32x32/actions/media-playback-start.png | Bin .../32x32/actions/media-playback-stop.png | Bin .../default/32x32/actions/media-record.png | Bin .../32x32/actions/media-seek-backward.png | Bin .../32x32/actions/media-seek-forward.png | Bin .../32x32/actions/media-skip-backward.png | Bin .../32x32/actions/media-skip-forward.png | Bin .../32x32/actions/object-flip-horizontal.png | Bin .../32x32/actions/object-flip-vertical.png | Bin .../32x32/actions/object-rotate-left.png | Bin .../32x32/actions/object-rotate-right.png | Bin .../default/32x32/actions/process-stop.png | Bin .../32x32/actions/system-lock-screen.png | Bin .../default/32x32/actions/system-log-out.png | Bin .../default/32x32/actions/system-run.png | Bin .../default/32x32/actions/system-search.png | Bin .../default/32x32/actions/system-shutdown.png | Bin .../32x32/actions/tools-check-spelling.png | Bin .../default/32x32/actions/view-fullscreen.png | Bin .../default/32x32/actions/view-refresh.png | Bin .../default/32x32/actions/view-restore.png | Bin .../32x32/actions/view-sort-ascending.png | Bin .../32x32/actions/view-sort-descending.png | Bin .../default/32x32/actions/window-close.png | Bin .../default/32x32/actions/window-new.png | Bin .../default/32x32/actions/zoom-fit-best.png | Bin .../icons/default/32x32/actions/zoom-in.png | Bin .../default/32x32/actions/zoom-original.png | Bin .../icons/default/32x32/actions/zoom-out.png | Bin .../32x32/apps/accessories-calculator.png | Bin .../32x32/apps/accessories-character-map.png | Bin .../32x32/apps/accessories-dictionary.png | Bin .../32x32/apps/accessories-text-editor.png | Bin .../32x32/apps/applets-screenshooter.png | Bin .../apps/gnome-panel-notification-area.png | Bin .../icons/default/32x32/apps/gnome-panel.png | Bin .../icons/default/32x32/apps/help-browser.png | Bin .../default/32x32/apps/libreoffice34-base.png | Bin .../default/32x32/apps/libreoffice34-calc.png | Bin .../default/32x32/apps/libreoffice34-draw.png | Bin .../32x32/apps/libreoffice34-impress.png | Bin .../default/32x32/apps/libreoffice34-main.png | Bin .../default/32x32/apps/libreoffice34-math.png | Bin .../32x32/apps/libreoffice34-printeradmin.png | Bin .../32x32/apps/libreoffice34-startcenter.png | Bin .../32x32/apps/libreoffice34-writer.png | Bin .../icons/default/32x32/apps/logviewer.png | Bin .../32x32/apps/multimedia-volume-control.png | Bin .../preferences-desktop-accessibility.png | Bin .../apps/preferences-desktop-display.png | Bin .../32x32/apps/preferences-desktop-font.png | Bin ...preferences-desktop-keyboard-shortcuts.png | Bin .../apps/preferences-desktop-keyboard.png | Bin .../32x32/apps/preferences-desktop-locale.png | Bin .../preferences-desktop-remote-desktop.png | Bin .../apps/preferences-desktop-screensaver.png | Bin .../32x32/apps/preferences-desktop-theme.png | Bin .../apps/preferences-desktop-wallpaper.png | Bin .../32x32/apps/preferences-system-windows.png | Bin .../32x32/apps/system-file-manager.png | Bin .../32x32/apps/system-software-install.png | Bin .../32x32/apps/system-software-update.png | Bin .../icons/default/32x32/apps/system-users.png | Bin .../icons/default/32x32/apps/user-info.png | Bin .../32x32/apps/utilities-system-monitor.png | Bin .../default/32x32/apps/utilities-terminal.png | Bin .../icons/default/32x32/apps/web-browser.png | Bin .../categories/applications-accessories.png | Bin .../categories/applications-development.png | Bin .../categories/applications-engineering.png | Bin .../32x32/categories/applications-games.png | Bin .../categories/applications-graphics.png | Bin .../categories/applications-internet.png | Bin .../categories/applications-multimedia.png | Bin .../32x32/categories/applications-office.png | Bin .../32x32/categories/applications-other.png | Bin .../32x32/categories/applications-science.png | Bin .../32x32/categories/applications-system.png | Bin .../categories/applications-utilities.png | Bin .../preferences-desktop-peripherals.png | Bin .../preferences-desktop-personal.png | Bin .../32x32/categories/preferences-desktop.png | Bin .../32x32/categories/preferences-other.png | Bin .../categories/preferences-system-network.png | Bin .../32x32/categories/preferences-system.png | Bin .../default/32x32/categories/system-help.png | Bin .../default/32x32/devices/ac-adapter.png | Bin .../default/32x32/devices/audio-card.png | Bin .../32x32/devices/audio-input-microphone.png | Bin .../icons/default/32x32/devices/battery.png | Bin .../default/32x32/devices/camera-photo.png | Bin .../default/32x32/devices/camera-video.png | Bin .../default/32x32/devices/camera-web.png | Bin .../icons/default/32x32/devices/computer.png | Bin .../default/32x32/devices/drive-harddisk.png | Bin .../default/32x32/devices/drive-optical.png | Bin .../32x32/devices/drive-removable-media.png | Bin .../default/32x32/devices/input-gaming.png | Bin .../default/32x32/devices/input-keyboard.png | Bin .../default/32x32/devices/input-mouse.png | Bin .../default/32x32/devices/input-tablet.png | Bin .../default/32x32/devices/input-touchpad.png | Bin .../default/32x32/devices/media-flash.png | Bin .../default/32x32/devices/media-floppy.png | Bin .../default/32x32/devices/media-optical.png | Bin .../default/32x32/devices/media-tape.png | Bin .../icons/default/32x32/devices/modem.png | Bin .../32x32/devices/multimedia-player.png | Bin .../default/32x32/devices/network-wired.png | Bin .../32x32/devices/network-wireless.png | Bin .../icons/default/32x32/devices/pda.png | Bin .../icons/default/32x32/devices/phone.png | Bin .../icons/default/32x32/devices/printer.png | Bin .../icons/default/32x32/devices/scanner.png | Bin .../default/32x32/devices/video-display.png | Bin .../default/32x32/emblems/emblem-default.png | Bin .../32x32/emblems/emblem-documents.png | Bin .../32x32/emblems/emblem-downloads.png | Bin .../default/32x32/emblems/emblem-favorite.png | Bin .../default/32x32/emblems/emblem-generic.png | Bin .../32x32/emblems/emblem-important.png | Bin .../default/32x32/emblems/emblem-mail.png | Bin .../default/32x32/emblems/emblem-new.png | Bin .../default/32x32/emblems/emblem-package.png | Bin .../default/32x32/emblems/emblem-photos.png | Bin .../default/32x32/emblems/emblem-readonly.png | Bin .../default/32x32/emblems/emblem-shared.png | Bin .../32x32/emblems/emblem-symbolic-link.png | Bin .../32x32/emblems/emblem-synchronizing.png | Bin .../default/32x32/emblems/emblem-system.png | Bin .../32x32/emblems/emblem-unreadable.png | Bin .../default/32x32/emblems/emblem-urgent.png | Bin .../default/32x32/emblems/emblem-web.png | Bin .../icons/default/32x32/emotes/face-angel.png | Bin .../icons/default/32x32/emotes/face-angry.png | Bin .../icons/default/32x32/emotes/face-cool.png | Bin .../default/32x32/emotes/face-crying.png | Bin .../default/32x32/emotes/face-devilish.png | Bin .../default/32x32/emotes/face-embarrassed.png | Bin .../default/32x32/emotes/face-glasses.png | Bin .../icons/default/32x32/emotes/face-kiss.png | Bin .../icons/default/32x32/emotes/face-laugh.png | Bin .../default/32x32/emotes/face-monkey.png | Bin .../icons/default/32x32/emotes/face-plain.png | Bin .../default/32x32/emotes/face-raspberry.png | Bin .../icons/default/32x32/emotes/face-sad.png | Bin .../icons/default/32x32/emotes/face-sick.png | Bin .../default/32x32/emotes/face-smile-big.png | Bin .../icons/default/32x32/emotes/face-smile.png | Bin .../icons/default/32x32/emotes/face-smirk.png | Bin .../default/32x32/emotes/face-surprise.png | Bin .../icons/default/32x32/emotes/face-tired.png | Bin .../default/32x32/emotes/face-uncertain.png | Bin .../icons/default/32x32/emotes/face-wink.png | Bin .../default/32x32/emotes/face-worried.png | Bin .../themes/icons/default/32x32/gtk.png | Bin .../mimetypes/application-certificate.png | Bin .../mimetypes/application-x-executable.png | Bin .../32x32/mimetypes/audio-x-generic.png | Bin .../32x32/mimetypes/font-x-generic.png | Bin .../32x32/mimetypes/image-x-generic.png | Bin .../32x32/mimetypes/package-x-generic.png | Bin .../default/32x32/mimetypes/text-html.png | Bin .../mimetypes/text-x-generic-template.png | Bin .../32x32/mimetypes/text-x-generic.png | Bin .../32x32/mimetypes/text-x-preview.png | Bin .../default/32x32/mimetypes/text-x-script.png | Bin .../32x32/mimetypes/video-x-generic.png | Bin .../32x32/mimetypes/x-office-address-book.png | Bin .../32x32/mimetypes/x-office-calendar.png | Bin .../mimetypes/x-office-document-template.png | Bin .../32x32/mimetypes/x-office-document.png | Bin .../mimetypes/x-office-drawing-template.png | Bin .../32x32/mimetypes/x-office-drawing.png | Bin .../x-office-presentation-template.png | Bin .../32x32/mimetypes/x-office-presentation.png | Bin .../x-office-spreadsheet-template.png | Bin .../32x32/mimetypes/x-office-spreadsheet.png | Bin .../themes/icons/default/32x32/osjs-white.png | Bin .../themes/icons/default/32x32/osjs.png | Bin .../icons/default/32x32/places/dropbox.png | Bin .../default/32x32/places/folder-documents.png | Bin .../default/32x32/places/folder-download.png | Bin .../default/32x32/places/folder-music.png | Bin .../default/32x32/places/folder-pictures.png | Bin .../32x32/places/folder-publicshare.png | Bin .../default/32x32/places/folder-remote.png | Bin .../32x32/places/folder-saved-search.png | Bin .../default/32x32/places/folder-templates.png | Bin .../default/32x32/places/folder-videos.png | Bin .../icons/default/32x32/places/folder.png | Bin .../default/32x32/places/google-drive.png | Bin .../default/32x32/places/network-server.png | Bin .../32x32/places/network-workgroup.png | Bin .../icons/default/32x32/places/start-here.png | Bin .../default/32x32/places/user-bookmarks.png | Bin .../default/32x32/places/user-desktop.png | Bin .../icons/default/32x32/places/user-home.png | Bin .../icons/default/32x32/places/user-trash.png | Bin .../32x32/status/appointment-missed.png | Bin .../default/32x32/status/appointment-soon.png | Bin .../32x32/status/audio-volume-high.png | Bin .../default/32x32/status/audio-volume-low.png | Bin .../32x32/status/audio-volume-medium.png | Bin .../32x32/status/audio-volume-muted.png | Bin .../default/32x32/status/avatar-default.png | Bin .../32x32/status/battery-caution-charging.png | Bin .../default/32x32/status/battery-caution.png | Bin .../default/32x32/status/battery-empty.png | Bin .../32x32/status/battery-full-charged.png | Bin .../32x32/status/battery-full-charging.png | Bin .../default/32x32/status/battery-full.png | Bin .../32x32/status/battery-good-charging.png | Bin .../default/32x32/status/battery-good.png | Bin .../32x32/status/battery-low-charging.png | Bin .../default/32x32/status/battery-low.png | Bin .../default/32x32/status/battery-missing.png | Bin .../default/32x32/status/changes-allow.png | Bin .../default/32x32/status/changes-prevent.png | Bin .../default/32x32/status/dialog-error.png | Bin .../32x32/status/dialog-information.png | Bin .../default/32x32/status/dialog-password.png | Bin .../default/32x32/status/dialog-question.png | Bin .../default/32x32/status/dialog-warning.png | Bin .../32x32/status/folder-drag-accept.png | Bin .../default/32x32/status/folder-open.png | Bin .../default/32x32/status/folder-visiting.png | Bin .../default/32x32/status/image-loading.png | Bin .../default/32x32/status/image-missing.png | Bin .../default/32x32/status/mail-attachment.png | Bin .../icons/default/32x32/status/mail-read.png | Bin .../default/32x32/status/mail-replied.png | Bin .../default/32x32/status/mail-unread.png | Bin .../32x32/status/media-playlist-repeat.png | Bin .../32x32/status/media-playlist-shuffle.png | Bin .../status/microphone-sensitivity-high.png | Bin .../status/microphone-sensitivity-low.png | Bin .../status/microphone-sensitivity-medium.png | Bin .../status/microphone-sensitivity-muted.png | Bin .../default/32x32/status/network-error.png | Bin .../default/32x32/status/network-idle.png | Bin .../default/32x32/status/network-offline.png | Bin .../default/32x32/status/network-receive.png | Bin .../32x32/status/network-transmit-receive.png | Bin .../default/32x32/status/network-transmit.png | Bin .../default/32x32/status/printer-error.png | Bin .../default/32x32/status/printer-printing.png | Bin .../default/32x32/status/security-high.png | Bin .../default/32x32/status/security-low.png | Bin .../default/32x32/status/security-medium.png | Bin .../status/software-update-available.png | Bin .../32x32/status/software-update-urgent.png | Bin .../icons/default/32x32/status/task-due.png | Bin .../default/32x32/status/task-past-due.png | Bin .../default/32x32/status/user-available.png | Bin .../icons/default/32x32/status/user-away.png | Bin .../icons/default/32x32/status/user-busy.png | Bin .../icons/default/32x32/status/user-idle.png | Bin .../default/32x32/status/user-invisible.png | Bin .../default/32x32/status/user-offline.png | Bin .../default/32x32/status/user-trash-full.png | Bin .../32x32/status/weather-clear-night.png | Bin .../default/32x32/status/weather-clear.png | Bin .../32x32/status/weather-few-clouds-night.png | Bin .../32x32/status/weather-few-clouds.png | Bin .../default/32x32/status/weather-fog.png | Bin .../default/32x32/status/weather-overcast.png | Bin .../32x32/status/weather-severe-alert.png | Bin .../status/weather-showers-scattered.png | Bin .../default/32x32/status/weather-showers.png | Bin .../default/32x32/status/weather-snow.png | Bin .../default/32x32/status/weather-storm.png | Bin src/{client => }/themes/icons/default/LICENSE | 0 .../themes/icons/default/metadata.json | 0 .../themes/sounds/default/LICENSE | 0 .../sounds/default/alarm-clock-elapsed.mp3 | Bin .../sounds/default/alarm-clock-elapsed.oga | Bin .../sounds/default/audio-volume-change.mp3 | Bin .../sounds/default/audio-volume-change.oga | Bin .../themes/sounds/default/bell.mp3 | Bin .../themes/sounds/default/bell.oga | Bin .../themes/sounds/default/camera-shutter.mp3 | Bin .../themes/sounds/default/camera-shutter.oga | Bin .../themes/sounds/default/complete.mp3 | Bin .../themes/sounds/default/complete.oga | Bin .../themes/sounds/default/device-added.mp3 | Bin .../themes/sounds/default/device-added.oga | Bin .../themes/sounds/default/device-removed.mp3 | Bin .../themes/sounds/default/device-removed.oga | Bin .../sounds/default/dialog-information.mp3 | Bin .../sounds/default/dialog-information.oga | Bin .../themes/sounds/default/dialog-warning.mp3 | Bin .../themes/sounds/default/dialog-warning.oga | Bin .../sounds/default/message-new-instant.mp3 | Bin .../sounds/default/message-new-instant.oga | Bin .../themes/sounds/default/message.mp3 | Bin .../themes/sounds/default/message.oga | Bin .../themes/sounds/default/metadata.json | 0 .../network-connectivity-established.mp3 | Bin .../network-connectivity-established.oga | Bin .../default/network-connectivity-lost.mp3 | Bin .../default/network-connectivity-lost.oga | Bin .../sounds/default/phone-incoming-call.mp3 | Bin .../sounds/default/phone-incoming-call.oga | Bin .../sounds/default/phone-outgoing-busy.mp3 | Bin .../sounds/default/phone-outgoing-busy.oga | Bin .../sounds/default/phone-outgoing-calling.mp3 | Bin .../sounds/default/phone-outgoing-calling.oga | Bin .../themes/sounds/default/power-plug.mp3 | Bin .../themes/sounds/default/power-plug.oga | Bin .../themes/sounds/default/power-unplug.mp3 | Bin .../themes/sounds/default/power-unplug.oga | Bin .../themes/sounds/default/screen-capture.mp3 | Bin .../themes/sounds/default/screen-capture.oga | Bin .../themes/sounds/default/service-login.mp3 | Bin .../themes/sounds/default/service-login.oga | Bin .../themes/sounds/default/service-logout.mp3 | Bin .../themes/sounds/default/service-logout.oga | Bin .../themes/sounds/default/suspend-error.mp3 | Bin .../themes/sounds/default/suspend-error.oga | Bin .../themes/sounds/default/trash-empty.mp3 | Bin .../themes/sounds/default/trash-empty.oga | Bin .../themes/styles/dark/gui/progressbar.png | Bin .../themes/styles/dark/metadata.json | 0 src/themes/styles/dark/style.less | 107 + src/themes/styles/dark/theme.js | 9 + src/{client => }/themes/styles/dark/wm/wm.png | Bin .../themes/styles/default/gui/progressbar.png | Bin .../themes/styles/default/metadata.json | 0 src/themes/styles/default/style.less | 83 + src/themes/styles/default/theme.js | 9 + .../themes/styles/default/wm/close.png | Bin .../default/wm/close_focused_normal.png | Bin .../default/wm/close_focused_prelight.png | Bin .../default/wm/close_focused_pressed.png | Bin .../styles/default/wm/close_unfocused.png | Bin .../default/wm/close_unfocused_prelight.png | Bin .../default/wm/close_unfocused_pressed.png | Bin .../themes/styles/default/wm/maximize.png | Bin .../default/wm/maximize_focused_normal.png | Bin .../default/wm/maximize_focused_prelight.png | Bin .../default/wm/maximize_focused_pressed.png | Bin .../styles/default/wm/maximize_unfocused.png | Bin .../wm/maximize_unfocused_prelight.png | Bin .../default/wm/maximize_unfocused_pressed.png | Bin .../themes/styles/default/wm/minimize.png | Bin .../default/wm/minimize_focused_normal.png | Bin .../default/wm/minimize_focused_prelight.png | Bin .../default/wm/minimize_focused_pressed.png | Bin .../styles/default/wm/minimize_unfocused.png | Bin .../wm/minimize_unfocused_prelight.png | Bin .../default/wm/minimize_unfocused_pressed.png | Bin .../themes/styles/default/wm/unmaximize.png | Bin .../default/wm/unmaximize_focused_normal.png | Bin .../wm/unmaximize_focused_prelight.png | Bin .../default/wm/unmaximize_focused_pressed.png | Bin .../default/wm/unmaximize_unfocused.png | Bin .../wm/unmaximize_unfocused_prelight.png | Bin .../wm/unmaximize_unfocused_pressed.png | Bin .../themes/styles/default/wm/wm.png | Bin .../themes/styles/default/wm/wm/wm.png | Bin .../themes/styles/glass/gui/progressbar.png | Bin .../themes/styles/glass/metadata.json | 0 src/themes/styles/glass/style.less | 70 + src/themes/styles/glass/theme.js | 9 + .../themes/styles/glass/wm/close.png | Bin .../themes/styles/glass/wm/maximize.png | Bin .../themes/styles/glass/wm/minimize.png | Bin .../themes/styles/glass/wm/wm.png | Bin .../styles/material/materialColors.less | 0 .../themes/styles/material/metadata.json | 0 src/themes/styles/material/style.less | 370 +++ src/themes/styles/material/theme.js | 38 + .../themes/styles/windows8/metadata.json | 0 src/themes/styles/windows8/style.less | 113 + src/themes/styles/windows8/theme.js | 9 + .../themes/styles/windows8/wm/close.png | Bin .../themes/styles/windows8/wm/maximize.png | Bin .../themes/styles/windows8/wm/minimize.png | Bin .../themes/styles/windows8/wm/wm.png | Bin .../themes/wallpapers/wallpaper.png | Bin src/themes/webpack.config.js | 8 + src/x11-launcher/Makefile | 55 - src/x11-launcher/main.c | 138 -- 1274 files changed, 38100 insertions(+), 56485 deletions(-) delete mode 100644 .csslintrc delete mode 100644 Gruntfile.js create mode 100755 bin/add-package-repo.sh create mode 100755 bin/add-package.sh create mode 100644 dist/.gitignore delete mode 100644 dist/vendor/.gitignore delete mode 120000 dist/vendor/chai.js delete mode 120000 dist/vendor/dropbox.js delete mode 120000 dist/vendor/dropbox.min.map delete mode 120000 dist/vendor/html2canvas delete mode 120000 dist/vendor/mocha.css delete mode 120000 dist/vendor/mocha.js delete mode 120000 dist/vendor/zip.js delete mode 120000 dist/vendor/zlib.js delete mode 100644 src/build/.eslintrc delete mode 100644 src/build/config.js delete mode 100644 src/build/core.js delete mode 100644 src/build/dist.js delete mode 100644 src/build/generate.js delete mode 100644 src/build/help.txt delete mode 100644 src/build/index.js delete mode 100644 src/build/manifest.js delete mode 100644 src/build/packages.js delete mode 100644 src/build/themes.js delete mode 100644 src/build/utils.js delete mode 100644 src/build/watcher.js create mode 100644 src/client/javascript/boot.js delete mode 100644 src/client/javascript/broadway/broadway.js delete mode 100644 src/client/javascript/broadway/connection.js delete mode 100644 src/client/javascript/broadway/unicode.js delete mode 100644 src/client/javascript/broadway/window.js delete mode 100644 src/client/javascript/core/api.js rename src/{templates/package/dummy/main.js => client/javascript/core/auth/standalone.js} (76%) delete mode 100644 src/client/javascript/core/boot.js create mode 100644 src/client/javascript/core/config.js rename src/{templates/package/simple-application/server/main.js => client/javascript/core/connections/standalone.js} (77%) create mode 100644 src/client/javascript/core/init.js create mode 100644 src/client/javascript/core/locales.js rename src/{server/node/modules/generic/example.js => client/javascript/core/storage/standalone.js} (87%) create mode 100644 src/client/javascript/core/theme.js create mode 100644 src/client/javascript/core/window-manager.js delete mode 100644 src/client/javascript/core/windowmanager.js rename src/client/{ => javascript}/dialogs.html (100%) delete mode 100644 src/client/javascript/gui/helpers.js create mode 100644 src/client/javascript/gui/menu.js create mode 100644 src/client/javascript/gui/notification.js rename src/client/javascript/{vfs/transports/http.js => gui/splash.js} (55%) rename src/{server/node/core/storage.js => client/javascript/helpers/hooks.js} (50%) create mode 100644 src/client/javascript/helpers/iframe-application-window.js rename src/{build/cli.js => client/javascript/helpers/loader.js} (55%) create mode 100644 src/client/javascript/helpers/service-notification-icon.js create mode 100644 src/client/javascript/helpers/window-behaviour.js delete mode 100644 src/client/javascript/helpers/zip-archiver.js rename src/{build/modules/example.js => client/javascript/utils/clipboard.js} (74%) create mode 100644 src/client/javascript/utils/gui.js create mode 100644 src/client/javascript/utils/keycodes.js create mode 100644 src/client/javascript/utils/preloader.js delete mode 100644 src/client/javascript/utils/xhr.js rename src/{server/node/modules/api/storage.js => client/javascript/vfs/filedataurl.js} (69%) delete mode 100644 src/client/javascript/vfs/helpers.js create mode 100644 src/client/javascript/vfs/mountpoint.js delete mode 100644 src/client/javascript/vfs/mounts/dropbox.js delete mode 100644 src/client/javascript/vfs/mounts/googledrive.js delete mode 100644 src/client/javascript/vfs/mounts/localstorage.js delete mode 100644 src/client/javascript/vfs/mounts/onedrive.js create mode 100644 src/client/javascript/vfs/transport.js create mode 100644 src/client/javascript/vfs/transports/google-drive.js create mode 100644 src/client/javascript/vfs/transports/onedrive.js create mode 100644 src/client/stylesheets/animations.less delete mode 100644 src/client/themes/fonts/Karla/style.css delete mode 100644 src/client/themes/fonts/Roboto/style.css delete mode 100644 src/client/themes/styles/dark/style.less delete mode 100644 src/client/themes/styles/dark/theme.js delete mode 100644 src/client/themes/styles/default/style.less delete mode 100644 src/client/themes/styles/default/theme.js delete mode 100644 src/client/themes/styles/glass/style.less delete mode 100644 src/client/themes/styles/glass/theme.js delete mode 100644 src/client/themes/styles/material/style.less delete mode 100644 src/client/themes/styles/material/theme.js delete mode 100644 src/client/themes/styles/windows8/style.less delete mode 100644 src/client/themes/styles/windows8/theme.js create mode 100644 src/client/webpack.config.js delete mode 100644 src/gfx/logo-big.png delete mode 100644 src/gfx/logo-blue.svg delete mode 100644 src/gfx/logo-footer.png delete mode 100644 src/gfx/logo-header-big.png delete mode 100644 src/gfx/logo-header-small.png delete mode 100644 src/gfx/logo-splash.png delete mode 100644 src/gfx/logo-white.svg delete mode 100644 src/gfx/logo.svg delete mode 100644 src/gfx/screenshot.png delete mode 100644 src/gfx/symbol.svg delete mode 100644 src/gfx/symbol_backup.svg delete mode 100644 src/installer/installer.nsi delete mode 100644 src/installer/installer.ps1 delete mode 100644 src/installer/installer.sh create mode 100644 src/packages/default/About/webpack.config.js create mode 100644 src/packages/default/Calculator/webpack.config.js delete mode 100644 src/packages/default/CoreWM/animations.css create mode 100644 src/packages/default/CoreWM/panelitem.js create mode 100644 src/packages/default/CoreWM/panelitemdialog.js create mode 100644 src/packages/default/CoreWM/webpack.config.js create mode 100644 src/packages/default/Draw/webpack.config.js create mode 100644 src/packages/default/FileManager/webpack.config.js create mode 100644 src/packages/default/HTMLViewer/webpack.config.js create mode 100644 src/packages/default/MusicPlayer/webpack.config.js create mode 100644 src/packages/default/Preview/webpack.config.js create mode 100644 src/packages/default/ProcessViewer/webpack.config.js delete mode 100644 src/packages/default/Settings/locale.js create mode 100644 src/packages/default/Settings/locales.js create mode 100644 src/packages/default/Settings/webpack.config.js create mode 100644 src/packages/default/Textpad/webpack.config.js create mode 100644 src/packages/default/Writer/webpack.config.js delete mode 100644 src/server/node/.eslintrc delete mode 100644 src/server/node/core/api.js delete mode 100644 src/server/node/core/auth.js delete mode 100644 src/server/node/core/env.js delete mode 100644 src/server/node/core/http.js delete mode 100644 src/server/node/core/instance.js delete mode 100644 src/server/node/core/middleware.js delete mode 100644 src/server/node/core/packagemanager.js delete mode 100644 src/server/node/core/responder.js delete mode 100644 src/server/node/core/session.js delete mode 100644 src/server/node/core/settings.js delete mode 100644 src/server/node/core/vfs.js delete mode 100644 src/server/node/lib/evhandler.js delete mode 100644 src/server/node/lib/logger.js delete mode 100644 src/server/node/lib/utils.js create mode 100644 src/server/node/modules.js delete mode 100644 src/server/node/modules/api/application.js delete mode 100644 src/server/node/modules/api/auth.js delete mode 100644 src/server/node/modules/api/users.js delete mode 100644 src/server/node/modules/auth/example.js create mode 100644 src/server/node/modules/authenticator.js create mode 100644 src/server/node/modules/connection.js create mode 100644 src/server/node/modules/connections/http.js create mode 100644 src/server/node/modules/connections/ws.js rename src/server/node/{lib => modules}/database.js (93%) delete mode 100644 src/server/node/modules/middleware/example.js delete mode 100644 src/server/node/modules/services/broadway.js delete mode 100644 src/server/node/modules/services/example.js delete mode 100644 src/server/node/modules/session/file.js delete mode 100644 src/server/node/modules/session/memory.js rename src/server/node/modules/{api/packages.js => storage.js} (65%) delete mode 100644 src/server/node/modules/storage/example.js delete mode 100644 src/server/node/modules/vfs/example.js create mode 100644 src/server/node/packagemanager.js create mode 100644 src/server/node/routes/api.js rename src/server/node/{core/metadata.js => routes/fs.js} (61%) rename src/{templates/package/simple-application/main.js => server/node/routes/internal.js} (52%) rename src/server/node/{modules/api/curl.js => routes/misc.js} (87%) create mode 100644 src/server/node/settings.js create mode 100644 src/server/node/user.js create mode 100644 src/server/node/vfs.js rename src/templates/dist/{default => }/api.php (100%) rename src/templates/dist/{default => }/blank.css (100%) delete mode 100644 src/templates/dist/default/favicon.ico rename src/templates/dist/default/{index.html => index.ejs} (74%) rename src/templates/dist/{login/default.html => default/login.html} (100%) create mode 100644 src/templates/dist/default/splash.html delete mode 100644 src/templates/dist/default/test.html rename dist/vendor/dropboxOauthReceiver.html => src/templates/dist/dropbox-oauth.html (80%) delete mode 100644 src/templates/dist/header.css delete mode 100644 src/templates/dist/header.js delete mode 100644 src/templates/dist/splash/default.html rename dist/vendor/wlOauthReceiver.html => src/templates/dist/windows-live-oauth.html (100%) create mode 100644 src/templates/package/application/webpack.config.js delete mode 100644 src/templates/package/dummy/metadata.json create mode 100644 src/templates/package/extension/webpack.config.js create mode 100644 src/templates/package/iframe-application/data/index.html create mode 100644 src/templates/package/iframe-application/data/osjs.js create mode 100644 src/templates/package/iframe-application/webpack.config.js create mode 100644 src/templates/package/service/webpack.config.js delete mode 100644 src/templates/package/simple-application/main.css delete mode 100644 src/templates/package/simple-application/metadata.json delete mode 100644 src/templates/package/simple-application/scheme.html delete mode 100644 src/templates/package/simple-application/server/main.php rename src/{client => }/themes/fonts/Karla/LICENSE.txt (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Bold.eot (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Bold.svg (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Bold.ttf (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Bold.woff (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/BoldItalic.eot (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/BoldItalic.svg (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/BoldItalic.ttf (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/BoldItalic.woff (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Italic.eot (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Italic.svg (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Italic.ttf (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Italic.woff (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Regular.eot (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Regular.svg (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Regular.ttf (100%) rename src/{client/themes/fonts/Karla => themes/fonts/Karla/fonts}/Regular.woff (100%) create mode 100644 src/themes/fonts/Karla/style.css rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/Roboto-100.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/Roboto-100.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/Roboto-100.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/Roboto-100.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100/Roboto-100.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/Roboto-100italic.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/Roboto-100italic.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/Roboto-100italic.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/Roboto-100italic.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-100italic/Roboto-100italic.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/Roboto-300.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/Roboto-300.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/Roboto-300.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/Roboto-300.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300/Roboto-300.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/Roboto-300italic.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/Roboto-300italic.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/Roboto-300italic.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/Roboto-300italic.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-300italic/Roboto-300italic.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/Roboto-500.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/Roboto-500.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/Roboto-500.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/Roboto-500.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500/Roboto-500.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/Roboto-500italic.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/Roboto-500italic.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/Roboto-500italic.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/Roboto-500italic.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-500italic/Roboto-500italic.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/Roboto-700.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/Roboto-700.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/Roboto-700.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/Roboto-700.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700/Roboto-700.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/Roboto-700italic.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/Roboto-700italic.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/Roboto-700italic.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/Roboto-700italic.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-700italic/Roboto-700italic.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/Roboto-italic.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/Roboto-italic.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/Roboto-italic.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/Roboto-italic.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-italic/Roboto-italic.woff2 (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/LICENSE.txt (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/Roboto-regular.eot (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/Roboto-regular.svg (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/Roboto-regular.ttf (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/Roboto-regular.woff (100%) rename src/{client => }/themes/fonts/Roboto/fonts/Roboto-regular/Roboto-regular.woff2 (100%) create mode 100644 src/themes/fonts/Roboto/style.css rename src/{client => }/themes/icons/default/16x16/actions/address-book-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/application-exit.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/appointment-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/bookmark-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/call-start.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/call-stop.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/contact-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-open-recent.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-open.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-page-setup.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-print-preview.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-print.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-properties.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-revert.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-save-as.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-save.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/document-send.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-clear.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-copy.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-cut.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-delete.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-find-replace.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-find.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-paste.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-redo.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-select-all.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/edit-undo.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/folder-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-indent-less.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-indent-more.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-justify-center.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-justify-fill.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-justify-left.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-justify-right.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-bold.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-direction-ltr.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-direction-rtl.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-italic.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-strikethrough.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/format-text-underline.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-bottom.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-down.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-first.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-home.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-jump.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-last.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-next.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-previous.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-top.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/go-up.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/help-about.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/help-contents.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/help-faq.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/insert-image.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/insert-link.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/insert-object.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/insert-text.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/list-add.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/list-remove.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-forward.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-mark-important.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-mark-junk.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-mark-notjunk.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-mark-read.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-mark-unread.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-message-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-reply-all.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-reply-sender.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-send-receive.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/mail-send.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-eject.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-playback-pause.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-playback-start.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-playback-stop.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-record.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-seek-backward.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-seek-forward.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-skip-backward.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/media-skip-forward.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/object-flip-horizontal.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/object-flip-vertical.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/object-rotate-left.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/object-rotate-right.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/process-stop.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/system-lock-screen.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/system-log-out.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/system-run.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/system-search.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/system-shutdown.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/tab-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/tools-check-spelling.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/view-fullscreen.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/view-refresh.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/view-restore.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/view-sort-ascending.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/view-sort-descending.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/window-close.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/window-new.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/zoom-fit-best.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/zoom-in.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/zoom-original.png (100%) rename src/{client => }/themes/icons/default/16x16/actions/zoom-out.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/accessories-calculator.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/accessories-character-map.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/accessories-dictionary.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/accessories-text-editor.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/applets-screenshooter.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/gnome-panel-notification-area.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/gnome-panel.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/help-browser.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-base.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-calc.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-draw.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-impress.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-main.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-math.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-printeradmin.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-startcenter.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/libreoffice34-writer.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/logviewer.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/multimedia-volume-control.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-accessibility.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-display.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-font.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-keyboard-shortcuts.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-keyboard.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-locale.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-remote-desktop.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-screensaver.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-theme.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-desktop-wallpaper.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/preferences-system-windows.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/system-file-manager.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/system-software-install.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/system-software-update.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/system-users.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/user-info.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/utilities-system-monitor.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/utilities-terminal.png (100%) rename src/{client => }/themes/icons/default/16x16/apps/web-browser.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-accessories.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-development.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-engineering.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-games.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-graphics.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-internet.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-multimedia.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-office.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-other.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-science.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-system.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/applications-utilities.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-desktop-peripherals.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-desktop-personal.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-desktop.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-other.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-system-network.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/preferences-system.png (100%) rename src/{client => }/themes/icons/default/16x16/categories/system-help.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/ac-adapter.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/audio-card.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/audio-input-microphone.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/battery.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/camera-photo.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/camera-video.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/camera-web.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/computer.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/drive-harddisk.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/drive-optical.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/drive-removable-media.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/input-gaming.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/input-keyboard.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/input-mouse.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/input-tablet.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/input-touchpad.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/media-flash.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/media-floppy.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/media-optical.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/media-tape.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/modem.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/multimedia-player.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/network-wired.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/network-wireless.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/pda.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/phone.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/printer.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/scanner.png (100%) rename src/{client => }/themes/icons/default/16x16/devices/video-display.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-default.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-documents.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-downloads.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-favorite.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-important.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-mail.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-new.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-package.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-photos.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-readonly.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-shared.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-symbolic-link.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-synchronizing.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-system.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-unreadable.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-urgent.png (100%) rename src/{client => }/themes/icons/default/16x16/emblems/emblem-web.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-angel.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-angry.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-cool.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-crying.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-devilish.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-embarrassed.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-glasses.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-kiss.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-laugh.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-monkey.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-plain.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-raspberry.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-sad.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-sick.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-smile-big.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-smile.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-smirk.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-surprise.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-tired.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-uncertain.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-wink.png (100%) rename src/{client => }/themes/icons/default/16x16/emotes/face-worried.png (100%) rename src/{client => }/themes/icons/default/16x16/gtk.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/application-certificate.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/application-x-executable.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/audio-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/font-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/image-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/package-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/text-html.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/text-x-generic-template.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/text-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/text-x-preview.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/text-x-script.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/video-x-generic.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-address-book.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-calendar.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-document-template.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-document.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-drawing-template.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-drawing.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-presentation-template.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-presentation.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-spreadsheet-template.png (100%) rename src/{client => }/themes/icons/default/16x16/mimetypes/x-office-spreadsheet.png (100%) rename src/{client => }/themes/icons/default/16x16/osjs-white.png (100%) rename src/{client => }/themes/icons/default/16x16/osjs.png (100%) rename src/{client => }/themes/icons/default/16x16/places/dropbox.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-documents.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-download.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-music.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-pictures.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-publicshare.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-remote.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-saved-search.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-templates.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder-videos.png (100%) rename src/{client => }/themes/icons/default/16x16/places/folder.png (100%) rename src/{client => }/themes/icons/default/16x16/places/google-drive.png (100%) rename src/{client => }/themes/icons/default/16x16/places/network-server.png (100%) rename src/{client => }/themes/icons/default/16x16/places/network-workgroup.png (100%) rename src/{client => }/themes/icons/default/16x16/places/onedrive.png (100%) rename src/{client => }/themes/icons/default/16x16/places/start-here.png (100%) rename src/{client => }/themes/icons/default/16x16/places/user-bookmarks.png (100%) rename src/{client => }/themes/icons/default/16x16/places/user-desktop.png (100%) rename src/{client => }/themes/icons/default/16x16/places/user-home.png (100%) rename src/{client => }/themes/icons/default/16x16/places/user-trash.png (100%) rename src/{client => }/themes/icons/default/16x16/status/appointment-missed.png (100%) rename src/{client => }/themes/icons/default/16x16/status/appointment-soon.png (100%) rename src/{client => }/themes/icons/default/16x16/status/audio-volume-high.png (100%) rename src/{client => }/themes/icons/default/16x16/status/audio-volume-low.png (100%) rename src/{client => }/themes/icons/default/16x16/status/audio-volume-medium.png (100%) rename src/{client => }/themes/icons/default/16x16/status/audio-volume-muted.png (100%) rename src/{client => }/themes/icons/default/16x16/status/avatar-default.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-caution-charging.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-caution.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-empty.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-full-charged.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-full-charging.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-full.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-good-charging.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-good.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-low-charging.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-low.png (100%) rename src/{client => }/themes/icons/default/16x16/status/battery-missing.png (100%) rename src/{client => }/themes/icons/default/16x16/status/changes-allow.png (100%) rename src/{client => }/themes/icons/default/16x16/status/changes-prevent.png (100%) rename src/{client => }/themes/icons/default/16x16/status/dialog-error.png (100%) rename src/{client => }/themes/icons/default/16x16/status/dialog-information.png (100%) rename src/{client => }/themes/icons/default/16x16/status/dialog-password.png (100%) rename src/{client => }/themes/icons/default/16x16/status/dialog-question.png (100%) rename src/{client => }/themes/icons/default/16x16/status/dialog-warning.png (100%) rename src/{client => }/themes/icons/default/16x16/status/folder-drag-accept.png (100%) rename src/{client => }/themes/icons/default/16x16/status/folder-open.png (100%) rename src/{client => }/themes/icons/default/16x16/status/folder-visiting.png (100%) rename src/{client => }/themes/icons/default/16x16/status/image-loading.png (100%) rename src/{client => }/themes/icons/default/16x16/status/image-missing.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-attachment.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-read.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-replied.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-signed-verified.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-signed.png (100%) rename src/{client => }/themes/icons/default/16x16/status/mail-unread.png (100%) rename src/{client => }/themes/icons/default/16x16/status/media-playlist-repeat.png (100%) rename src/{client => }/themes/icons/default/16x16/status/media-playlist-shuffle.png (100%) rename src/{client => }/themes/icons/default/16x16/status/microphone-sensitivity-high.png (100%) rename src/{client => }/themes/icons/default/16x16/status/microphone-sensitivity-low.png (100%) rename src/{client => }/themes/icons/default/16x16/status/microphone-sensitivity-medium.png (100%) rename src/{client => }/themes/icons/default/16x16/status/microphone-sensitivity-muted.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-error.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-idle.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-offline.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-receive.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-transmit-receive.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-transmit.png (100%) rename src/{client => }/themes/icons/default/16x16/status/network-wireless-encrypted.png (100%) rename src/{client => }/themes/icons/default/16x16/status/printer-error.png (100%) rename src/{client => }/themes/icons/default/16x16/status/printer-printing.png (100%) rename src/{client => }/themes/icons/default/16x16/status/security-high.png (100%) rename src/{client => }/themes/icons/default/16x16/status/security-low.png (100%) rename src/{client => }/themes/icons/default/16x16/status/security-medium.png (100%) rename src/{client => }/themes/icons/default/16x16/status/software-update-available.png (100%) rename src/{client => }/themes/icons/default/16x16/status/software-update-urgent.png (100%) rename src/{client => }/themes/icons/default/16x16/status/task-due.png (100%) rename src/{client => }/themes/icons/default/16x16/status/task-past-due.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-available.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-away.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-busy.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-idle.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-invisible.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-offline.png (100%) rename src/{client => }/themes/icons/default/16x16/status/user-trash-full.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-clear-night.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-clear.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-few-clouds-night.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-few-clouds.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-fog.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-overcast.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-severe-alert.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-showers-scattered.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-showers.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-snow.png (100%) rename src/{client => }/themes/icons/default/16x16/status/weather-storm.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/address-book-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/application-exit.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/appointment-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/bookmark-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/call-start.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/call-stop.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/contact-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-open-recent.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-open.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-page-setup.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-print-preview.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-print.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-properties.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-revert.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-save-as.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-save.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/document-send.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-clear.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-copy.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-cut.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-delete.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-find-replace.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-find.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-paste.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-redo.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-select-all.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/edit-undo.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/folder-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-indent-less.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-indent-more.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-justify-center.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-justify-fill.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-justify-left.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-justify-right.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-bold.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-direction-ltr.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-direction-rtl.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-italic.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-strikethrough.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/format-text-underline.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-bottom.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-down.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-first.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-home.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-jump.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-last.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-next.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-previous.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-top.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/go-up.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/help-about.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/help-contents.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/help-faq.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/insert-image.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/insert-link.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/insert-object.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/insert-text.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/list-add.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/list-remove.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-forward.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-mark-important.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-mark-junk.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-mark-notjunk.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-mark-read.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-mark-unread.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-message-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-reply-all.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-reply-sender.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-send-receive.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/mail-send.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-eject.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-playback-pause.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-playback-start.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-playback-stop.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-record.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-seek-backward.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-seek-forward.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-skip-backward.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/media-skip-forward.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/object-flip-horizontal.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/object-flip-vertical.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/object-rotate-left.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/object-rotate-right.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/process-stop.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/system-lock-screen.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/system-log-out.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/system-run.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/system-search.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/system-shutdown.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/tools-check-spelling.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/view-fullscreen.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/view-refresh.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/view-restore.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/view-sort-ascending.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/view-sort-descending.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/window-close.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/window-new.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/zoom-fit-best.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/zoom-in.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/zoom-original.png (100%) rename src/{client => }/themes/icons/default/32x32/actions/zoom-out.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/accessories-calculator.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/accessories-character-map.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/accessories-dictionary.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/accessories-text-editor.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/applets-screenshooter.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/gnome-panel-notification-area.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/gnome-panel.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/help-browser.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-base.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-calc.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-draw.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-impress.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-main.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-math.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-printeradmin.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-startcenter.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/libreoffice34-writer.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/logviewer.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/multimedia-volume-control.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-accessibility.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-display.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-font.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-keyboard-shortcuts.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-keyboard.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-locale.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-remote-desktop.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-screensaver.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-theme.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-desktop-wallpaper.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/preferences-system-windows.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/system-file-manager.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/system-software-install.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/system-software-update.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/system-users.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/user-info.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/utilities-system-monitor.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/utilities-terminal.png (100%) rename src/{client => }/themes/icons/default/32x32/apps/web-browser.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-accessories.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-development.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-engineering.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-games.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-graphics.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-internet.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-multimedia.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-office.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-other.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-science.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-system.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/applications-utilities.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-desktop-peripherals.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-desktop-personal.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-desktop.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-other.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-system-network.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/preferences-system.png (100%) rename src/{client => }/themes/icons/default/32x32/categories/system-help.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/ac-adapter.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/audio-card.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/audio-input-microphone.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/battery.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/camera-photo.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/camera-video.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/camera-web.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/computer.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/drive-harddisk.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/drive-optical.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/drive-removable-media.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/input-gaming.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/input-keyboard.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/input-mouse.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/input-tablet.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/input-touchpad.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/media-flash.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/media-floppy.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/media-optical.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/media-tape.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/modem.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/multimedia-player.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/network-wired.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/network-wireless.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/pda.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/phone.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/printer.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/scanner.png (100%) rename src/{client => }/themes/icons/default/32x32/devices/video-display.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-default.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-documents.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-downloads.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-favorite.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-important.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-mail.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-new.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-package.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-photos.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-readonly.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-shared.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-symbolic-link.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-synchronizing.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-system.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-unreadable.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-urgent.png (100%) rename src/{client => }/themes/icons/default/32x32/emblems/emblem-web.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-angel.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-angry.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-cool.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-crying.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-devilish.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-embarrassed.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-glasses.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-kiss.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-laugh.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-monkey.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-plain.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-raspberry.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-sad.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-sick.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-smile-big.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-smile.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-smirk.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-surprise.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-tired.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-uncertain.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-wink.png (100%) rename src/{client => }/themes/icons/default/32x32/emotes/face-worried.png (100%) rename src/{client => }/themes/icons/default/32x32/gtk.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/application-certificate.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/application-x-executable.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/audio-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/font-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/image-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/package-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/text-html.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/text-x-generic-template.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/text-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/text-x-preview.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/text-x-script.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/video-x-generic.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-address-book.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-calendar.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-document-template.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-document.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-drawing-template.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-drawing.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-presentation-template.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-presentation.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-spreadsheet-template.png (100%) rename src/{client => }/themes/icons/default/32x32/mimetypes/x-office-spreadsheet.png (100%) rename src/{client => }/themes/icons/default/32x32/osjs-white.png (100%) rename src/{client => }/themes/icons/default/32x32/osjs.png (100%) rename src/{client => }/themes/icons/default/32x32/places/dropbox.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-documents.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-download.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-music.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-pictures.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-publicshare.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-remote.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-saved-search.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-templates.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder-videos.png (100%) rename src/{client => }/themes/icons/default/32x32/places/folder.png (100%) rename src/{client => }/themes/icons/default/32x32/places/google-drive.png (100%) rename src/{client => }/themes/icons/default/32x32/places/network-server.png (100%) rename src/{client => }/themes/icons/default/32x32/places/network-workgroup.png (100%) rename src/{client => }/themes/icons/default/32x32/places/start-here.png (100%) rename src/{client => }/themes/icons/default/32x32/places/user-bookmarks.png (100%) rename src/{client => }/themes/icons/default/32x32/places/user-desktop.png (100%) rename src/{client => }/themes/icons/default/32x32/places/user-home.png (100%) rename src/{client => }/themes/icons/default/32x32/places/user-trash.png (100%) rename src/{client => }/themes/icons/default/32x32/status/appointment-missed.png (100%) rename src/{client => }/themes/icons/default/32x32/status/appointment-soon.png (100%) rename src/{client => }/themes/icons/default/32x32/status/audio-volume-high.png (100%) rename src/{client => }/themes/icons/default/32x32/status/audio-volume-low.png (100%) rename src/{client => }/themes/icons/default/32x32/status/audio-volume-medium.png (100%) rename src/{client => }/themes/icons/default/32x32/status/audio-volume-muted.png (100%) rename src/{client => }/themes/icons/default/32x32/status/avatar-default.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-caution-charging.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-caution.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-empty.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-full-charged.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-full-charging.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-full.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-good-charging.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-good.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-low-charging.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-low.png (100%) rename src/{client => }/themes/icons/default/32x32/status/battery-missing.png (100%) rename src/{client => }/themes/icons/default/32x32/status/changes-allow.png (100%) rename src/{client => }/themes/icons/default/32x32/status/changes-prevent.png (100%) rename src/{client => }/themes/icons/default/32x32/status/dialog-error.png (100%) rename src/{client => }/themes/icons/default/32x32/status/dialog-information.png (100%) rename src/{client => }/themes/icons/default/32x32/status/dialog-password.png (100%) rename src/{client => }/themes/icons/default/32x32/status/dialog-question.png (100%) rename src/{client => }/themes/icons/default/32x32/status/dialog-warning.png (100%) rename src/{client => }/themes/icons/default/32x32/status/folder-drag-accept.png (100%) rename src/{client => }/themes/icons/default/32x32/status/folder-open.png (100%) rename src/{client => }/themes/icons/default/32x32/status/folder-visiting.png (100%) rename src/{client => }/themes/icons/default/32x32/status/image-loading.png (100%) rename src/{client => }/themes/icons/default/32x32/status/image-missing.png (100%) rename src/{client => }/themes/icons/default/32x32/status/mail-attachment.png (100%) rename src/{client => }/themes/icons/default/32x32/status/mail-read.png (100%) rename src/{client => }/themes/icons/default/32x32/status/mail-replied.png (100%) rename src/{client => }/themes/icons/default/32x32/status/mail-unread.png (100%) rename src/{client => }/themes/icons/default/32x32/status/media-playlist-repeat.png (100%) rename src/{client => }/themes/icons/default/32x32/status/media-playlist-shuffle.png (100%) rename src/{client => }/themes/icons/default/32x32/status/microphone-sensitivity-high.png (100%) rename src/{client => }/themes/icons/default/32x32/status/microphone-sensitivity-low.png (100%) rename src/{client => }/themes/icons/default/32x32/status/microphone-sensitivity-medium.png (100%) rename src/{client => }/themes/icons/default/32x32/status/microphone-sensitivity-muted.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-error.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-idle.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-offline.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-receive.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-transmit-receive.png (100%) rename src/{client => }/themes/icons/default/32x32/status/network-transmit.png (100%) rename src/{client => }/themes/icons/default/32x32/status/printer-error.png (100%) rename src/{client => }/themes/icons/default/32x32/status/printer-printing.png (100%) rename src/{client => }/themes/icons/default/32x32/status/security-high.png (100%) rename src/{client => }/themes/icons/default/32x32/status/security-low.png (100%) rename src/{client => }/themes/icons/default/32x32/status/security-medium.png (100%) rename src/{client => }/themes/icons/default/32x32/status/software-update-available.png (100%) rename src/{client => }/themes/icons/default/32x32/status/software-update-urgent.png (100%) rename src/{client => }/themes/icons/default/32x32/status/task-due.png (100%) rename src/{client => }/themes/icons/default/32x32/status/task-past-due.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-available.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-away.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-busy.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-idle.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-invisible.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-offline.png (100%) rename src/{client => }/themes/icons/default/32x32/status/user-trash-full.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-clear-night.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-clear.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-few-clouds-night.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-few-clouds.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-fog.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-overcast.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-severe-alert.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-showers-scattered.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-showers.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-snow.png (100%) rename src/{client => }/themes/icons/default/32x32/status/weather-storm.png (100%) rename src/{client => }/themes/icons/default/LICENSE (100%) rename src/{client => }/themes/icons/default/metadata.json (100%) rename src/{client => }/themes/sounds/default/LICENSE (100%) rename src/{client => }/themes/sounds/default/alarm-clock-elapsed.mp3 (100%) rename src/{client => }/themes/sounds/default/alarm-clock-elapsed.oga (100%) rename src/{client => }/themes/sounds/default/audio-volume-change.mp3 (100%) rename src/{client => }/themes/sounds/default/audio-volume-change.oga (100%) rename src/{client => }/themes/sounds/default/bell.mp3 (100%) rename src/{client => }/themes/sounds/default/bell.oga (100%) rename src/{client => }/themes/sounds/default/camera-shutter.mp3 (100%) rename src/{client => }/themes/sounds/default/camera-shutter.oga (100%) rename src/{client => }/themes/sounds/default/complete.mp3 (100%) rename src/{client => }/themes/sounds/default/complete.oga (100%) rename src/{client => }/themes/sounds/default/device-added.mp3 (100%) rename src/{client => }/themes/sounds/default/device-added.oga (100%) rename src/{client => }/themes/sounds/default/device-removed.mp3 (100%) rename src/{client => }/themes/sounds/default/device-removed.oga (100%) rename src/{client => }/themes/sounds/default/dialog-information.mp3 (100%) rename src/{client => }/themes/sounds/default/dialog-information.oga (100%) rename src/{client => }/themes/sounds/default/dialog-warning.mp3 (100%) rename src/{client => }/themes/sounds/default/dialog-warning.oga (100%) rename src/{client => }/themes/sounds/default/message-new-instant.mp3 (100%) rename src/{client => }/themes/sounds/default/message-new-instant.oga (100%) rename src/{client => }/themes/sounds/default/message.mp3 (100%) rename src/{client => }/themes/sounds/default/message.oga (100%) rename src/{client => }/themes/sounds/default/metadata.json (100%) rename src/{client => }/themes/sounds/default/network-connectivity-established.mp3 (100%) rename src/{client => }/themes/sounds/default/network-connectivity-established.oga (100%) rename src/{client => }/themes/sounds/default/network-connectivity-lost.mp3 (100%) rename src/{client => }/themes/sounds/default/network-connectivity-lost.oga (100%) rename src/{client => }/themes/sounds/default/phone-incoming-call.mp3 (100%) rename src/{client => }/themes/sounds/default/phone-incoming-call.oga (100%) rename src/{client => }/themes/sounds/default/phone-outgoing-busy.mp3 (100%) rename src/{client => }/themes/sounds/default/phone-outgoing-busy.oga (100%) rename src/{client => }/themes/sounds/default/phone-outgoing-calling.mp3 (100%) rename src/{client => }/themes/sounds/default/phone-outgoing-calling.oga (100%) rename src/{client => }/themes/sounds/default/power-plug.mp3 (100%) rename src/{client => }/themes/sounds/default/power-plug.oga (100%) rename src/{client => }/themes/sounds/default/power-unplug.mp3 (100%) rename src/{client => }/themes/sounds/default/power-unplug.oga (100%) rename src/{client => }/themes/sounds/default/screen-capture.mp3 (100%) rename src/{client => }/themes/sounds/default/screen-capture.oga (100%) rename src/{client => }/themes/sounds/default/service-login.mp3 (100%) rename src/{client => }/themes/sounds/default/service-login.oga (100%) rename src/{client => }/themes/sounds/default/service-logout.mp3 (100%) rename src/{client => }/themes/sounds/default/service-logout.oga (100%) rename src/{client => }/themes/sounds/default/suspend-error.mp3 (100%) rename src/{client => }/themes/sounds/default/suspend-error.oga (100%) rename src/{client => }/themes/sounds/default/trash-empty.mp3 (100%) rename src/{client => }/themes/sounds/default/trash-empty.oga (100%) rename src/{client => }/themes/styles/dark/gui/progressbar.png (100%) rename src/{client => }/themes/styles/dark/metadata.json (100%) create mode 100644 src/themes/styles/dark/style.less create mode 100644 src/themes/styles/dark/theme.js rename src/{client => }/themes/styles/dark/wm/wm.png (100%) rename src/{client => }/themes/styles/default/gui/progressbar.png (100%) rename src/{client => }/themes/styles/default/metadata.json (100%) create mode 100644 src/themes/styles/default/style.less create mode 100644 src/themes/styles/default/theme.js rename src/{client => }/themes/styles/default/wm/close.png (100%) rename src/{client => }/themes/styles/default/wm/close_focused_normal.png (100%) rename src/{client => }/themes/styles/default/wm/close_focused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/close_focused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/close_unfocused.png (100%) rename src/{client => }/themes/styles/default/wm/close_unfocused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/close_unfocused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/maximize.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_focused_normal.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_focused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_focused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_unfocused.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_unfocused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/maximize_unfocused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/minimize.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_focused_normal.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_focused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_focused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_unfocused.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_unfocused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/minimize_unfocused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_focused_normal.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_focused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_focused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_unfocused.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_unfocused_prelight.png (100%) rename src/{client => }/themes/styles/default/wm/unmaximize_unfocused_pressed.png (100%) rename src/{client => }/themes/styles/default/wm/wm.png (100%) rename src/{client => }/themes/styles/default/wm/wm/wm.png (100%) rename src/{client => }/themes/styles/glass/gui/progressbar.png (100%) rename src/{client => }/themes/styles/glass/metadata.json (100%) create mode 100644 src/themes/styles/glass/style.less create mode 100644 src/themes/styles/glass/theme.js rename src/{client => }/themes/styles/glass/wm/close.png (100%) rename src/{client => }/themes/styles/glass/wm/maximize.png (100%) rename src/{client => }/themes/styles/glass/wm/minimize.png (100%) rename src/{client => }/themes/styles/glass/wm/wm.png (100%) rename src/{client => }/themes/styles/material/materialColors.less (100%) rename src/{client => }/themes/styles/material/metadata.json (100%) create mode 100644 src/themes/styles/material/style.less create mode 100644 src/themes/styles/material/theme.js rename src/{client => }/themes/styles/windows8/metadata.json (100%) create mode 100644 src/themes/styles/windows8/style.less create mode 100644 src/themes/styles/windows8/theme.js rename src/{client => }/themes/styles/windows8/wm/close.png (100%) rename src/{client => }/themes/styles/windows8/wm/maximize.png (100%) rename src/{client => }/themes/styles/windows8/wm/minimize.png (100%) rename src/{client => }/themes/styles/windows8/wm/wm.png (100%) rename src/{client => }/themes/wallpapers/wallpaper.png (100%) create mode 100644 src/themes/webpack.config.js delete mode 100644 src/x11-launcher/Makefile delete mode 100644 src/x11-launcher/main.c diff --git a/.bithoundrc b/.bithoundrc index 978a089c20..5ddd90ab85 100644 --- a/.bithoundrc +++ b/.bithoundrc @@ -5,6 +5,7 @@ } }, "ignore": [ + "src/client/javascript/compability.js", "src/client/stylesheets/**", "src/client/themes/**", "src/server/node/modules/*/example.js", diff --git a/.csslintrc b/.csslintrc deleted file mode 100644 index 8b6e1bcd2e..0000000000 --- a/.csslintrc +++ /dev/null @@ -1,12 +0,0 @@ -{ - "ids": false, - "important": false, - "box-sizing": false, - "fallback-colors": false, - "universal-selector": false, - "adjoining-classes": false, - "qualified-headings": false, - "font-faces": false, - "outline-none": false, - "order-alphabetical": false -} diff --git a/.eslintignore b/.eslintignore index 7e9de66f6c..f4abb5021a 100644 --- a/.eslintignore +++ b/.eslintignore @@ -13,4 +13,3 @@ vendor/* dist/** vfs/** doc/** -bin/** diff --git a/.eslintrc b/.eslintrc index e7a09fe722..2be8b530d2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -6,6 +6,7 @@ }, "globals": { "OSjs": true, + "OSJS_DEBUG": true, "zip": true, "alert": true, "confirm": true, @@ -14,7 +15,12 @@ "EventTarget": true, "Uint8Array": true, "ArrayBuffer": true, - "Promise": true + "Promise": true, + "gapi": true + }, + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" }, "rules": { "valid-jsdoc": [ @@ -97,7 +103,7 @@ "no-eq-null": 2, "strict": [ 1, - "function" + "global" ], "no-unused-expressions": 2, "no-use-before-define": 1, diff --git a/.gitignore b/.gitignore index 70727b6119..89a2abb505 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ twistd.* *.bak *.o .tern-project +.happypack +.external-ecmascript.js # Misc .nightly @@ -29,19 +31,17 @@ src/server/settings.json src/server/packages.json src/server/*.key src/server/*.crt -src/installer/installer.exe +src/overlays # Builds +doc/ dist/* -dist-electron doc/jsdoc src/server/*.sqlite src/x11-launcher/session-launch # Vendor -vendor/dropbox* -vendor/zip.js -vendor/html2canvas +vendor src/server/php/vendor src/packages/* !src/packages/default diff --git a/.travis.yml b/.travis.yml index c82e834e53..316b0a8171 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,11 +2,7 @@ language: node_js node_js: - 7 - 6 - - 5 - - 4 install: - npm install - - npm install mocha - - npm install grunt-cli -g before_script: - node osjs build diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f5154576f..71dd82eba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,75 @@ +# 2.1.0 + +Rewritten to ES6 (Babel), Webpack and Express. + +Many of these are **breaking** changes, but you can easily migrate to the new style. + +For a full writeup of changes etc, see links below. + +Relevant: + +* https://community.os-js.org/t/update-version-bump-2-1-0/142 +* https://community.os-js.org/t/road-to-es6-es2015/131/8 +* https://github.com/os-js/OS.js/issues/617 + +Digest: + +* Core: Rewritten to ES6 +* Core: Callbacks replaced with Promise +* Core: Now using imports +* Core: Deprecated all marked methods +* Core: Removed global namespace (available as BC module) +* Core: Removed support for "simple" packages +* Core: Removed support for "dummy" packages +* Core: Removed support for "old" packages +* Core: Detached Scheme files from applications +* Core: Changed in namespaces (code separation) +* API: Now using axios for XHR +* API: Now using bluebird for better promises +* VFS: Removed 'delete' operation (use 'unlink') +* GUI: Schemes now embed in bundles if used +* Packages: Default packages refactored +* build: Now using Ygor as task system +* build: Rewritten +* build: Now using Webpack for themes +* build: Now using Webpack for packages +* build: Now using Webpack for core +* build: Removed grunt entirely +* build: Split up into separate package +* build: Changed templating generation +* build: Simplified configuration capabilities +* build: Better overlay support +* server-node: Rewritten to ES6 +* server-node: Now using Express +* server-node: Changed how modules look +* server-node: Better module APIs +* server-node: Better user handling +* conf: Changed overlay layouts +* conf: Overlays now support themes +* conf: Overlays now support configuration includes +* conf: Changed vfs configuration +* misc: Added some new `bin/` scripts +* misc: Removed the `Zip` helper. This will be replaced with something newer. +* misc: The `Database` handler now uses separate tables +* misc: Added `OSjs.require()` for externals +* misc: Moved src/client/themes to src/themes +* misc: Bugfixes and general cleanups +* misc: Performance improvements +* misc: No more 'dist/vendor' by default +* misc: Removed automated installers from repo +* misc: Separated graphics sources to own repo +* misc: Separated x11 sources to own repo +* misc: Separated Broadway (will be replaced with Xpra) +* misc: Updated documentation +* misc: Now using esdoc + # 2.0.0-97 Bugfixes, updated dependencies, build system updates and moved some methods from Storage to Authenticator module Relevant: -* http://community.os.js.org/t/update-version-bump-alpha97/136 +* https://community.os-js.org/t/update-version-bump-alpha97/136 Digest: @@ -32,7 +97,7 @@ Mostly bugfixes and sortable shortcut buttons in panel. Relevant: -* http://community.os.js.org/t/update-version-bump-alpha96/130 +* https://community.os-js.org/t/update-version-bump-alpha96/130 Digest: @@ -60,7 +125,7 @@ Also updated mouse/pointer handling in some cases for better compability. Relevant: -* http://community.os.js.org/t/update-version-bump-alpha94/129 +* https://community.os-js.org/t/update-version-bump-alpha94/129 Digest: @@ -87,7 +152,7 @@ your package metadata file (see included). Relevant: -* http://community.os.js.org/t/update-version-bump-alpha93/128 +* https://community.os-js.org/t/update-version-bump-alpha93/128 Digest: @@ -230,7 +295,7 @@ add a small snippet in the bottom of your file(s) Relevant: -* http://community.os.js.org/t/update-version-bump-alpha86/122 +* https://community.os-js.org/t/update-version-bump-alpha86/122 Digest: @@ -267,7 +332,7 @@ handling has been updated. Relevant: -* http://community.os.js.org/t/update-version-bump-alpha85/ +* https://community.os-js.org/t/update-version-bump-alpha85/ Digest: @@ -297,7 +362,7 @@ Updates to mobile UI and handling, VFS improvements, bugfixes and a new 'osjs wa Relevant: -* http://community.os.js.org/t/update-version-bump-alpha84/118 +* https://community.os-js.org/t/update-version-bump-alpha84/118 * https://www.os-js.org/manual/gui/elements/#create-javascript Digest: @@ -340,7 +405,7 @@ bunch of bugfixes and compability updates. Relevant: -* http://community.os.js.org/t/update-version-bump-alpha83/114 +* https://community.os-js.org/t/update-version-bump-alpha83/114 Digest: @@ -388,8 +453,8 @@ server and build system improvements and lots of bugfixes. Relevant: -- http://community.os.js.org/t/update-version-bump-alpha82/110 -- http://community.os.js.org/t/feature-http-middleware/107/1 +- https://community.os-js.org/t/update-version-bump-alpha82/110 +- https://community.os-js.org/t/feature-http-middleware/107/1 Digest: @@ -455,10 +520,10 @@ The official documentation (manual) has also been completely reworked. It now ex Relevant: -- http://community.os.js.org/t/update-version-bump-alpha81/104 +- https://community.os-js.org/t/update-version-bump-alpha81/104 - https://gitter.im/os-js/topics/topic/5818ce090b10738c73fe24e0/new-server-codebase-and-handler-abstraction -- http://community.os.js.org/t/notice-upcoming-server-api-changes/104/2 -- http://community.os.js.org/t/feature-widgets/90 +- https://community.os-js.org/t/notice-upcoming-server-api-changes/104/2 +- https://community.os-js.org/t/feature-widgets/90 - https://github.com/os-js/OS.js/issues/527 - https://os.js.org/manual/ @@ -527,11 +592,11 @@ New Settings application, package management and user management subsystem, deve Relevant: -- http://community.os.js.org/t/update-version-bump-alpha80/101 -- http://community.os.js.org/t/notice-upcoming-grunt-and-build-system-changes/99 -- http://community.os.js.org/t/feature-create-applications-without-prototype-chain/96 -- http://community.os.js.org/t/feature-import-files-in-your-schemes/95 -- http://community.os.js.org/t/feature-scheme-loading-via-metadata-json/94 +- https://community.os-js.org/t/update-version-bump-alpha80/101 +- https://community.os-js.org/t/notice-upcoming-grunt-and-build-system-changes/99 +- https://community.os-js.org/t/feature-create-applications-without-prototype-chain/96 +- https://community.os-js.org/t/feature-import-files-in-your-schemes/95 +- https://community.os-js.org/t/feature-scheme-loading-via-metadata-json/94 Digest: @@ -584,9 +649,9 @@ Core API WebSocket support, Desktop now uses VFS mount, New touch menu, Bugfixes Relevant: -- http://community.os.js.org/t/update-version-bump-alpha79/92 -- http://community.os.js.org/t/feature-api-over-websocket/91 -- http://community.os.js.org/t/feature-widgets/90 +- https://community.os-js.org/t/update-version-bump-alpha79/92 +- https://community.os-js.org/t/feature-api-over-websocket/91 +- https://community.os-js.org/t/feature-widgets/90 Digest: @@ -680,9 +745,9 @@ to documentation and developer features. Relevant: -- http://community.os.js.org/t/features-extending-base-css/65 -- http://community.os.js.org/t/notice-node-server-api-changes/73 -- http://community.os.js.org/t/features-package-less-and-custom-script-support/72 +- https://community.os-js.org/t/features-extending-base-css/65 +- https://community.os-js.org/t/notice-node-server-api-changes/73 +- https://community.os-js.org/t/features-package-less-and-custom-script-support/72 Digest: @@ -748,9 +813,9 @@ Digest: Search Engine, HTTP/2 support, bugfixes, improvements -- http://community.os.js.org/t/quick-tips-window-events/47/1 -- http://community.os.js.org/t/feature-search-engine/43 -- http://community.os.js.org/t/feature-http-v2/44/2 +- https://community.os-js.org/t/quick-tips-window-events/47/1 +- https://community.os-js.org/t/feature-search-engine/43 +- https://community.os-js.org/t/feature-http-v2/44/2 This update brings you a new Search Engine implementation, HTTP/2 support, lots of bugfixes and general impreovements. Also a new HTML Viewer application. @@ -841,9 +906,9 @@ Bugfixes, Locale updates, Security and general improvements. New wallpaper, UI improvements, bugfixes and many improvements to the build system(s). Also new developer features! -**API CHANGE**: http://community.os.js.org/t/notice-updated-gui-methods/33 +**API CHANGE**: https://community.os-js.org/t/notice-updated-gui-methods/33 -**API CHANGE**: http://community.os.js.org/t/notice-recent-api-changes/31 +**API CHANGE**: https://community.os-js.org/t/notice-recent-api-changes/31 * UI: New Wallpaper * UI: Added loading bar to boot diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b12cf55ceb..272198d0db 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,38 +1,28 @@ # Contributing -These are some of the ways you can contribute to OS.js: +Follow the guide on https://manual.os-js.org/development/ for how to work with a development environment and a list of repositories to work with. -* **Open issues** You can post any issues/bugs/requests to [Github](https://github.com/os-js/OS.js/issues). -* **Code** Create a [pull request](https://github.com/os-js/OS.js/pulls) to contribute to the codebase -* **Translating** Language support is a bit lacking, so any help is appreciated! -* **Testing** Things are always changing, and automated tests are not enough to ensure everything is working 100%. -* **Documentation** Found something in the [homepage or documentation](https://github.com/andersevenrud/os-js.org) that does not seem right? -* **Chat** Join in our [Gitter](https://gitter.im/os-js/OS.js) chat room for fun and tech talk! -* **Community** Join our [community](http://community.os.js.org/) where you can post your ideas and questions etc (that does not fit into Github Issues) -* **Anonymous tips** Donate/tip anonymously with [Gratipay](https://gratipay.com/os-js/) -* **Donate** Donate via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=andersevenrud%40gmail%2ecom&lc=NO¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) -* **Support** by becoming a [Patreon](https://www.patreon.com/user?u=2978551&ty=h&u=2978551) +If you want to contribute, but not sure what to do, here's a list of things that I always need help with: -You can also submit patches and questions directly to me via [email](mailto:andersevenrud@gmail.com), but using GitHub is preferred. +* Translations +* Bug-hunting +* Finding security problems +* Themes and general graphics +* Website design (like the homepage and manuals) +* Documentation -## Information +If you need help, or just up for some general discussion, head into the [community forums](https://community.os-js.org/) or [community chat](https://gitter.im/os-js/OS.js). -You can find information about development here: https://os-js.org/manual/development/ +You can also donate or become a patreon, which helps out covering server costs and potentially make it possible to put out bounties: -## Resources +* Donate/tip anonymously with [Gratipay](https://gratipay.com/os-js/) +* Donate via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=andersevenrud%40gmail%2ecom&lc=NO¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) +* Become a [Patreon](https://www.patreon.com/user?u=2978551&ty=h&u=2978551) -* [Homepage](https://os-js.org/) -* [Manual](https://os-js.org/manual/) -* [FAQ and discussion](https://github.com/os-js/OS.js/issues/49) -* [Chat room](https://gitter.im/os-js/OS.js) -* [Subreddit](https://www.reddit.com/r/osjs) -* [OS.js Core Source](https://github.com/os-js/OS.js) -* [OS.js Homepage Source](https://github.com/andersevenrud/os-js.org) - -# For OS.js Team Members +# Team Members If you are a member of the official OS.js developer Team: -* [Discussions](http://community.os.js.org/c/team) +* [Discussions](http://community.os-js.org/c/team) * [Tasks](https://trello.com/osjs) * [Chat](https://gitter.im/os-js/OS.js/teams) diff --git a/Dockerfile b/Dockerfile index ef911d55eb..fdf9cbe202 100644 --- a/Dockerfile +++ b/Dockerfile @@ -41,7 +41,7 @@ RUN cd OS.js/ # Install OS.js WORKDIR OS.js/ -RUN npm install --production +RUN npm install RUN node osjs build # Run OS.js diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 9dfa306633..0000000000 --- a/Gruntfile.js +++ /dev/null @@ -1,141 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -module.exports = function(grunt) { - 'use strict'; - - grunt.file.defaultEncoding = 'utf-8'; - - grunt.loadNpmTasks('grunt-eslint'); - grunt.loadNpmTasks('grunt-mocha-test'); - grunt.loadNpmTasks('grunt-mocha'); - grunt.loadNpmTasks('grunt-contrib-csslint'); - grunt.loadNpmTasks('grunt-contrib-validate-xml'); - - grunt.registerTask('testBuild', 'Tests the build', function() { - var files = [ - 'src/server/settings.json', - 'src/server/packages.json', - 'dist/themes/fonts.min.css', - 'dist/themes/styles/default.min.css', - 'dist/themes/sounds/default/message.mp3', - 'dist/themes/sounds/default/message.oga', - 'dist/themes/icons/default/metadata.json', - 'dist/packages/default/CoreWM/_app.min.js', - 'dist/packages/default/CoreWM/_app.min.css', - 'dist/index.html', - 'dist/favicon.ico', - 'dist/dialogs.html', - 'dist/locales.min.js', - 'dist/osjs.min.js', - 'dist/osjs.min.css', - 'dist/settings.js', - 'dist/splash.png' - ]; - - var result = files.every(function(filename) { - if ( !grunt.file.exists(filename) ) { - grunt.log.error('Missing file from build: ' + filename); - return false; - } - return true; - }); - - return result; - }); - - grunt.registerTask('test', ['eslint', 'csslint', 'validate_xml', 'mochaTest'/*, 'mocha'*/, 'testBuild']); - - grunt.initConfig({ - pkg: grunt.file.readJSON('package.json'), - eslint: { - options: { - configFile: '.eslintrc' - }, - target: [ - 'Gruntfile.js', - 'src/*.js', - 'src/build/*.js', - 'src/server/node/*.js', - 'src/server/node/**/*.js', - 'src/client/javascript/*.js', - 'src/client/javascript/**/*.js', - 'src/packages/default/**/*.js', - '!src/packages/default/**/locales.js', - '!src/packages/default/**/locale.js' - ] - }, - csslint: { - options: { - csslintrc: '.csslintrc' - }, - strict: { - src: [ - 'src/client/stylesheets/*.css', - '!src/client/stylesheets/gui.css', - '!src/client/stylesheets/debug.css', - 'src/client/themes/fonts/*/*.css', - 'src/client/themes/styles/*/*.css', - 'src/packages/default/*/*.css', - '!src/packages/default/CoreWM/animations.css' - ] - }, - lax: { - options: { - 'known-properties': false, - 'compatible-vendor-prefixes': false - }, - src: [ - 'src/client/stylesheets/gui.css', - 'src/client/stylesheets/debug.css' - ] - } - }, - mochaTest: { - test: { - src: ['src/server/test/node/*.js'] - } - }, - mocha: { - test: { - options: { - urls: ['http://localhost:8000/test.html'] - } - } - }, - validate_xml: { - all: { - src: [ - 'src/client/dialogs.html', - 'src/packages/default/*/scheme.html' - ] - } - } - }); -}; diff --git a/INSTALL.md b/INSTALL.md index 6abad22dfc..021a7d2140 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -6,7 +6,7 @@ It is highly recommended that you use `git` to install instead of downloading an ## Dependencies -The only requirement is that you have `node` and `npm` installed (v4 or newer). +The only requirement is that you have `node` and `npm` installed (v6 or newer). *Note for Debian/Ubuntu users*: You might need to install the `nodejs-legacy` package. @@ -15,9 +15,9 @@ The only requirement is that you have `node` and `npm` installed (v4 or newer). Inside the OS.js directory: ``` -$ npm install --production +$ npm install $ node osjs build $ node osjs run ``` -For more information, see the [Installation Manual](https://os-js.org/manual/installation/). +For more information, see the [Installation Manual](https://manual.os-js.org/installation/). diff --git a/README.md b/README.md index 70f79f49ff..ab990ee505 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- OS.js Logo + OS.js Logo

[OS.js](https://www.os-js.org/) is an [open-source](https://raw.githubusercontent.com/os-js/OS.js/master/LICENSE) desktop implementation for your browser with a fully-fledged window manager, Application APIs, GUI toolkits and filesystem abstraction. @@ -7,7 +7,7 @@ [![bitHound Score](https://www.bithound.io/github/os-js/OS.js/badges/score.svg)](https://www.bithound.io/github/os-js/OS.js) [![Travis CI Build Status](https://travis-ci.org/os-js/OS.js.svg?branch=master)](https://travis-ci.org/os-js/OS.js) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/bcb06aa267d5433db95a581237c23453)](https://www.codacy.com/app/andersevenrud/OS-js?utm_source=github.com&utm_medium=referral&utm_content=os-js/OS.js&utm_campaign=Badge_Grade) -[![Community](https://img.shields.io/badge/join-community-green.svg)](http://community.os.js.org/) +[![Community](https://img.shields.io/badge/join-community-green.svg)](https://community.os-js.org/) [![JS.ORG](https://img.shields.io/badge/js.org-os-ffb400.svg)](http://js.org) [![Tips](https://img.shields.io/gratipay/os-js.svg)](https://gratipay.com/os-js/) [![Donate](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=andersevenrud%40gmail%2ecom&lc=NO¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) @@ -17,7 +17,7 @@ Visit the [official demo](https://demo.os-js.org) for a preview version. Please note that some features are disabled and might be outdated or unavailable at times. -![ScreenShot](https://raw.githubusercontent.com/os-js/OS.js/master/src/gfx/screenshot.png) +![ScreenShot](https://www.os-js.org/screenshot.png) ## Installation @@ -25,14 +25,14 @@ You can find the quick setup guide in the [INSTALL.md file](https://github.com/o ## Documentation -* [Manuals](https://os-js.org/manual/) -* [API Documentation](https://os-js.org/doc/) +* [Manuals](https://manual.os-js.org/) +* [API Documentation](https://api.os-js.org/) * [Contribution Guide](https://github.com/os-js/OS.js/blob/master/CONTRIBUTING.md) ## Links * [Official Chat](https://gitter.im/os-js/OS.js) -* [Community Forums and Announcements](http://community.os.js.org/) +* [Community Forums and Announcements](https://community.os-js.org/) * [Homepage](https://os-js.org/) * [Twitter](https://twitter.com/osjsorg) ([author](https://twitter.com/andersevenrud)) * [Google+](https://plus.google.com/b/113399210633478618934/113399210633478618934) diff --git a/Vagrantfile b/Vagrantfile index 8c97950501..a3d7a91a1d 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -36,7 +36,7 @@ Vagrant.configure(2) do |config| echo "Installing OS.js" git clone https://github.com/os-js/OS.js.git >/dev/null pushd OS.js - npm install --production >/dev/null + npm install >/dev/null node osjs build >/dev/null SHELL end diff --git a/bin/add-package-repo.sh b/bin/add-package-repo.sh new file mode 100755 index 0000000000..b4cb89cb3a --- /dev/null +++ b/bin/add-package-repo.sh @@ -0,0 +1,31 @@ +#!/bin/sh +# Usage: ./bin/add-package-repo.sh namespace http://git-repository +repo=$1 +src=$2 + +if [ -z "$repo" ]; then + echo "You need to supply a repository name" + exit 1 +fi + +if [ -z "$src" ]; then + echo "You need to supply a source" + exit 1 +fi + +if [ -d "src/packages/$repo" ]; then + echo "Repo already installed" + exit 1 +fi + +git clone --recursive $src src/packages/$repo + +for d in "src/packages/$repo/*/"; do + pushd $d + npm install + popd +done + +node osjs config:add --name=repositories --value=$repo +node osjs build:manifest +node osjs build:packages -repositories=$reoo diff --git a/bin/add-package.sh b/bin/add-package.sh new file mode 100755 index 0000000000..ec2ebbb6d5 --- /dev/null +++ b/bin/add-package.sh @@ -0,0 +1,34 @@ +#!/bin/sh +# Usage: ./bin/add-package.sh namespace PackageName http://git-repository +repo=$1 +name=$2 +src=$3 + +if [ -z "$repo" ]; then + echo "You need to supply a repository name" + exit 1 +fi + +if [ -z "$name" ]; then + echo "You need to supply a package name" + exit 1 +fi + +if [ -z "$src" ]; then + echo "You need to supply a source" + exit 1 +fi + +if [ -d "src/packages/$repo/$name" ]; then + echo "Package already installed" + exit 1 +fi + +mkdir src/packages/$repo +git clone --recursive $src src/packages/$repo/$name --branch +pushd src/packages/$repo/$name +npm install +popd +node osjs config:add --name=repositories --value=$repo +node osjs build:manifest +node osjs build:package --name=$reoo/$name diff --git a/bin/add-user.js b/bin/add-user.js index 7b1a1b6315..a6af9cfd2a 100755 --- a/bin/add-user.js +++ b/bin/add-user.js @@ -29,27 +29,18 @@ * @licence Simplified BSD License */ -/*eslint strict:["error", "global"]*/ -'use strict'; +const fs = require('fs-extra'); +const path = require('path'); -const _bcrypt = require('bcrypt'); -const _path = require('path'); -const _fs = require('fs'); - -const ROOT = _path.join(__dirname, '/../'); +const ROOT = path.join(__dirname, '/../'); const ARGS = process.argv; -const _db = require(_path.join(ROOT, 'src/server/node/lib/database.js')); - -const config = JSON.parse(_fs.readFileSync(_path.join(ROOT, 'src', 'server', 'settings.json'))); - +const config = JSON.parse(fs.readFileSync(path.resolve(ROOT, 'src', 'server', 'settings.json'))); +const auther = config.authenticator; +const command = ARGS[2]; const username = ARGS[3]; -const name = ARGS[3]; const groups = String(ARGS[4] || 'admin').replace(/\s/g, '').split(','); -const auther = config.authenticator; -const cfg = config.modules.auth[auther]; - function createPassword() { return new Promise(function(resolve, reject) { var password = ''; @@ -62,33 +53,27 @@ function createPassword() { stdin.setEncoding('utf8'); process.stdin.on('data', function(ch) { - ch = String(ch); - - switch (ch) { - case '\n': - case '\r': - case '\u0004': - process.stdout.write('\n'); - stdin.setRawMode(false); - stdin.pause(); - - const salt = _bcrypt.genSaltSync(10); - const hash = _bcrypt.hashSync(password, salt); - if ( hash ) { - resolve(hash); - } else { - reject('Empty password'); - } - break; - - case '\u0003': - reject('Aborted...'); - break; - - default: - process.stdout.write('*'); - password += ch; - break; + ch = String(ch); + + switch (ch) { + case '\n': + case '\r': + case '\u0004': + process.stdout.write('\n'); + stdin.setRawMode(false); + stdin.pause(); + + resolve(password); + break; + + case '\u0003': + reject('Aborted...'); + break; + + default: + process.stdout.write('*'); + password += ch; + break; } }); }); @@ -96,7 +81,7 @@ function createPassword() { if ( auther !== 'database' ) { console.error('You have to add users via your system for this authenticator.'); - return; + process.exit(1); } if ( ARGS.length < 4 ) { @@ -104,44 +89,61 @@ if ( ARGS.length < 4 ) { console.log(' add - Add a user (ex: anders api,fs,curl)'); console.log(' pwd - Change a user password'); console.log(' grp - Change a users group(s)'); - return; + process.exit(1); } -console.log('Using authenticator', auther); - -(new Promise(function(resolve, reject) { - _db.instance('cli', cfg.driver, cfg[cfg.driver]).then(function(db) { - switch ( ARGS[2] ) { - case 'add' : - createPassword().then(function(password) { - db.query('INSERT INTO `users` (`username`, `password`, `groups`, `name`) VALUES(?, ?, ?, ?);', [username, password, JSON.stringify(groups), username]) - .then(resolve).catch(reject); - }).catch(reject); +const filename = path.resolve(ROOT, 'src/server/node/modules/auth', auther); +console.log('Using authenticator', auther, 'at', filename); + +const instance = require(filename); +instance.register(config.modules.auth[auther]).then(() => { + let promise; + switch ( command ) { + case 'add': + promise = instance.manage('add', { + username: username, + name: username, + groups: groups + }); break; - case 'pwd' : - createPassword().then(function(password) { - db.query('UPDATE `users` SET `password` = ? WHERE `username` = ?;', [password, username]) - .then(resolve).catch(reject); - }).catch(reject); + case 'pwd': + promise = new Promise((yes, no) => { + instance.manager().then((manager) => { + manager.getUserFromUsername(username).then((user) => { + createPassword().then((input) => { + instance.manage('passwd', { + id: user.id, + password: input + }).then(yes).catch(no); + }); + }).catch(no); + }).catch(no); + }); break; - case 'grp' : - db.query('UPDATE `users` SET `groups` = ? WHERE `username` = ?;', [JSON.stringify(groups), username]) - .then(resolve).catch(reject); + case 'grp': + promise = new Promise((yes, no) => { + instance.manager().then((manager) => { + manager.getUserFromUsername(username).then((user) => { + return manager.setGroups(user.id, groups).then(yes).catch(no); + }).catch(no); + }).catch(no); + }); break; - default: - reject('Invalid command' + ARGS[2]); + default: + promise = Promise.reject('No such command'); break; + } + + promise.then((result) => { + if ( result ) { + console.log(result); } + process.exit(0); + }).catch((error) => { + console.error(error); + process.exit(1); }); -})).then(function(result) { - if ( result ) { - console.log(result); - } - process.exit(0); -}).catch(function(error) { - console.error(error); - process.exit(1); }); diff --git a/bin/build-electron.sh b/bin/build-electron.sh index 09d2aad964..91921eafad 100755 --- a/bin/build-electron.sh +++ b/bin/build-electron.sh @@ -10,7 +10,6 @@ rm -rf ${DIR} mkdir -p ${DIST} # OS.js client -node osjs clean node osjs build cp -r dist/* ${DIST} diff --git a/bin/make-packaged.sh b/bin/make-packaged.sh index 3bb7d7970b..7d44596d32 100755 --- a/bin/make-packaged.sh +++ b/bin/make-packaged.sh @@ -47,7 +47,8 @@ echo "[image] Updating sources..." rm -rf node_modules git checkout -- dist &>/dev/null -npm install --production &>/dev/null +rm -rf dist/*.* +npm install &>/dev/null if [ "$TEMPLATE" == "intel-edison" ]; then # npm install mraa @@ -61,7 +62,7 @@ echo "[image] Building..." # Build and copy required files # -grunt all &>/dev/null +node osjs build &>/dev/null mkdir -p $OUTDIR/bin mkdir -p $OUTDIR/server @@ -101,8 +102,6 @@ else fi cp -r src/server/node/* $OUTDIR/server/ cp -r node_modules $OUTDIR/ - rm -rf $OUTDIR/node_modules/grunt* - rm -rf $OUTDIR/node_modules/*grunt modclean -p $OUTDIR -d -r -n safe fi @@ -152,22 +151,12 @@ if [ "$TEMPLATE" != "deb" ]; then rm -rf $OUTDIR/dist/themes/wallpapers/* fi -rm $OUTDIR/dist/*.min.* 2>/dev/null rm $OUTDIR/dist/.htaccess 2>/dev/null rm $OUTDIR/dist/.gitignore 2>/dev/null rm $OUTDIR/dist/vendor/.gitignore 2>/dev/null rm $OUTDIR/dist/themes/.gitignore 2>/dev/null rm $OUTDIR/dist/packages/.gitignore 2>/dev/null rm $OUTDIR/dist/api.php 2>/dev/null -rm $OUTDIR/dist/packages/*/*/package.json 2>/dev/null -rm $OUTDIR/dist/packages/*/*/api.php 2>/dev/null -rm $OUTDIR/dist/packages/*/*/server.lua 2>/dev/null -if [ "$TEMPLATE" == "arduino" ]; then - rm $OUTDIR/dist/packages/*/*/api.js 2>/dev/null - rm $OUTDIR/dist/packages/target/CodeMirror/vendor 2>/dev/null -fi -rm $OUTDIR/dist/packages/target/CoreWM/panelitems 2>/dev/null -rm $OUTDIR/build/dist/themes/styles/*/*.less 2>/dev/null echo "[image] Done :)" exit 0 diff --git a/dist/.gitignore b/dist/.gitignore new file mode 100644 index 0000000000..72e8ffc0db --- /dev/null +++ b/dist/.gitignore @@ -0,0 +1 @@ +* diff --git a/dist/vendor/.gitignore b/dist/vendor/.gitignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/dist/vendor/chai.js b/dist/vendor/chai.js deleted file mode 120000 index a7b75aa705..0000000000 --- a/dist/vendor/chai.js +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/chai/chai.js \ No newline at end of file diff --git a/dist/vendor/dropbox.js b/dist/vendor/dropbox.js deleted file mode 120000 index 09e8a48a32..0000000000 --- a/dist/vendor/dropbox.js +++ /dev/null @@ -1 +0,0 @@ -../../vendor/dropbox-js/lib/dropbox.js \ No newline at end of file diff --git a/dist/vendor/dropbox.min.map b/dist/vendor/dropbox.min.map deleted file mode 120000 index bbaff7d949..0000000000 --- a/dist/vendor/dropbox.min.map +++ /dev/null @@ -1 +0,0 @@ -../../vendor/dropbox-js/lib/dropbox.min.map \ No newline at end of file diff --git a/dist/vendor/html2canvas b/dist/vendor/html2canvas deleted file mode 120000 index fa1fbb7703..0000000000 --- a/dist/vendor/html2canvas +++ /dev/null @@ -1 +0,0 @@ -../../vendor/html2canvas/dist \ No newline at end of file diff --git a/dist/vendor/mocha.css b/dist/vendor/mocha.css deleted file mode 120000 index bcb345a4ed..0000000000 --- a/dist/vendor/mocha.css +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/mocha/mocha.css \ No newline at end of file diff --git a/dist/vendor/mocha.js b/dist/vendor/mocha.js deleted file mode 120000 index 78251a9c7b..0000000000 --- a/dist/vendor/mocha.js +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/mocha/mocha.js \ No newline at end of file diff --git a/dist/vendor/zip.js b/dist/vendor/zip.js deleted file mode 120000 index e3e2067661..0000000000 --- a/dist/vendor/zip.js +++ /dev/null @@ -1 +0,0 @@ -../../vendor/zip.js \ No newline at end of file diff --git a/dist/vendor/zlib.js b/dist/vendor/zlib.js deleted file mode 120000 index 4941204ac3..0000000000 --- a/dist/vendor/zlib.js +++ /dev/null @@ -1 +0,0 @@ -../../node_modules/zlibjs/bin/rawinflate.min.js \ No newline at end of file diff --git a/osjs b/osjs index 3b4722eaca..2722592d67 100755 --- a/osjs +++ b/osjs @@ -1,13 +1,3 @@ #!/usr/bin/env node -(function(_path) { - - var ver = process.version.substr(1).split(/\./g); - if ( parseInt(ver[0], 10) < 4 ) { - console.warn('You need Node v4 or above to run OS.js', 'yellow'); - } - - require(_path.join(__dirname, 'src/build/cli.js')).run(process.argv.slice(2), function(err) { - process.exit(err ? 1 : 0); - }); - -})(require('path')); +process.env.OSJS_ROOT = __dirname; +require('osjs-build').cli(); diff --git a/package.json b/package.json index c07600b18b..0d8a57dd44 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "OS.js", - "version": "2.0.0-97", + "version": "2.1.0", "description": "JavaScript Cloud/Web Desktop Platform", "url": "https://www.os-js.org", "email": "andersevenrud@gmail.com", @@ -24,41 +24,46 @@ "url": "https://github.com/os-js/OS.js.git" }, "scripts": { - "test": "grunt test", + "test": "node osjs test", "build": "node osjs build", "run": "node osjs run" }, "dependencies": { + "app-module-path": "^2.2.0", + "bluebird": "^3.5.0", + "body-parser": "^1.17.2", "chokidar": "^1.7.0", - "clean-css": "^4.1.3", "colors": "^1.1.2", "compression": "^1.6.2", "cookie": "^0.3.1", "cookie-parser": "^1.4.3", "diskspace": "^2.0.0", - "express-session": "^1.15.3", + "express": "^4.15.4", + "express-json-transform": "^1.0.0", + "express-session": "^1.15.4", "findit": ">=2.0.0", "formidable": ">=1.0.17", - "fs-extra": "^2.1.2", + "fs-extra": "^4.0.1", "glob": "^7.1.2", "glob-promise": "^3.1.0", "http-proxy": "^1.16.2", - "less": ">=2.7.1", "minimist": "^1.2.0", + "morgan": "^1.8.2", + "osjs-scheme-loader": "^1.0.9", "request": "^2.81.0", - "simplejsonconf": "^1.0.5", - "uglify-js": "^2.8.28", + "session-file-store": "^1.1.2", + "simplejsonconf": "^1.0.7", "unzip-stream": "^0.1.2", - "ws": "^3.0.0", - "zlibjs": "^0.3.0" + "ws": "^3.1.0" }, "devDependencies": { + "axios": "^0.16.2", + "babel-polyfill": "^6.23.0", "chai": "^4.0.2", - "grunt": ">=1.0.1", - "grunt-contrib-csslint": "2.0.0", - "grunt-contrib-validate-xml": ">=0.0.1", - "grunt-eslint": ">=19.0.0", - "grunt-mocha": "^1.0.2", - "grunt-mocha-test": ">=0.13.2" + "chai-as-promised": "^7.1.1", + "mocha": "^3.5.0", + "osjs-build": "^1.0.4", + "promise-limit": "^2.4.0", + "then-jsonp": "^1.0.3" } } diff --git a/src/build/.eslintrc b/src/build/.eslintrc deleted file mode 100644 index be8ee4d3d1..0000000000 --- a/src/build/.eslintrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "extends": [ - "../../.eslintrc" - ], - "parserOptions": { - "ecmaVersion": 6 - }, - "env": { - "browser": true, - "node": true, - "mocha": true - }, - "rules": { - "strict": [ - 1, - "global" - ] - } -} diff --git a/src/build/config.js b/src/build/config.js deleted file mode 100644 index ed4ca2b954..0000000000 --- a/src/build/config.js +++ /dev/null @@ -1,582 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _glob = require('glob-promise'); -const _fs = require('fs-extra'); -const _sjc = require('simplejsonconf'); - -const _themes = require('./themes.js'); -const _metadata = require('./manifest.js'); -const _utils = require('./utils.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Generates a client-side config file - */ -function generateClientConfiguration(cli, cfg) { - return new Promise((resolve, reject) => { - let settings = Object.assign({}, cfg.client); - - const preloads = Object.keys(settings.Preloads || {}).map((k) => { - return settings.Preloads[k]; - }); - - if ( !(settings.AutoStart instanceof Array) ) { - settings.AutoStart = []; - } - - if ( cli.option('standalone') ) { - settings.Connection.Type = 'standalone'; - settings.VFS.GoogleDrive.Enabled = false; - settings.VFS.OneDrive.Enabled = false; - settings.VFS.Dropbox.Enabled = false; - settings.VFS.LocalStorage.Enabled = false; - - const valid = ['applications', 'home', 'osjs']; - Object.keys(settings.VFS.Mountpoints).forEach((k) => { - if ( valid.indexOf(k) === -1 ) { - delete settings.VFS.Mountpoints[k]; - } - }); - } - - settings.Debug = cli.option('debug') === true; - settings.Broadway = cfg.broadway; - - if ( cfg.broadway.enabled ) { - preloads.push({ - 'type': 'javascript', - 'src': '/vendor/zlib.js' - }); - } - - _themes.readMetadata(cfg).then((themes) => { - settings.Fonts.list = themes.fonts.concat(settings.Fonts.list); - settings.Styles = themes.styles; - settings.Sounds = _utils.makedict(themes.sounds, (iter) => { - return [iter.name, iter.title]; - }); - settings.Icons = _utils.makedict(themes.icons, (iter) => { - return [iter.name, iter.title]; - }); - - _metadata.getPackages(cfg.repositories, (pkg) => { - return pkg && pkg.autostart === true; - }).then((list) => { - settings.AutoStart = settings.AutoStart.concat(Object.keys(list).map((k) => { - return list[k].className; - })); - settings.MIME = cfg.mime; - settings.Preloads = preloads; - - resolve(settings); - }); - }).catch(reject); - }); -} - -/* - * Generates a server-side config file - */ -function generateServerConfiguration(cli, cfg) { - let settings = Object.assign({}, cfg.server); - - return new Promise((resolve, reject) => { - _metadata.getPackages(cfg.repositories, (pkg) => { - return pkg && pkg.type === 'extension'; - }).then((extensions) => { - const src = _path.join(ROOT, 'src'); - Object.keys(extensions).forEach((e) => { - - if ( extensions[e].conf && extensions[e].conf instanceof Array ) { - extensions[e].conf.forEach((c) => { - try { - const p = _path.join(src, 'packages', extensions[e].path, c); - try { - const s = _fs.readJsonSync(p); - settings = _utils.mergeObject(settings, s); - } catch ( e ) { - _utils.log(_logger.color('Failed reading:', 'yellow'), p); - } - } catch ( e ) { - _logger.warn('createConfigurationFiles()', e, e.stack); - } - }); - } - }); - - settings.mimes = cfg.mime.mapping; - settings.broadway = cfg.broadway; - settings.vfs.maxuploadsize = cfg.client.VFS.MaxUploadSize; - - resolve(settings); - }); - }); -} - -/* - * Get a configuration value by path - */ -function getConfigPath(config, path, defaultValue) { - return _sjc.getJSON(config, path, defaultValue); -} - -/* - * Sets a config value - */ -function setConfigPath(key, value, isTree, outputFile) { - let path = _path.join(ROOT, 'src', 'conf', '900-custom.json'); - if ( outputFile ) { - const confDir = _path.join(ROOT, 'src', 'conf'); - path = _path.resolve(confDir, outputFile); - } - - let conf = {}; - try { - conf = _fs.readJsonSync(path); - } catch ( e ) {} - - try { - const result = _sjc.setJSON(conf, isTree ? null : key, value, { - prune: true, - guess: true - }); - - _fs.writeFileSync(path, JSON.stringify(result, null, 2)); - } catch ( e ) { - console.error(e.stack, e); - return; - } - - _logger.info('Changes written to: ' + path.replace(ROOT, '')); - _logger.warn(_logger.color('Remember to run \'osjs build:config\' to update your build(s)...', 'green')); -} - -/* - * Toggles package enable state - */ -function _togglePackage(config, packageName, enable) { - const currentEnabled = getConfigPath(config, 'packages.ForceEnable') || []; - const currentDisabled = getConfigPath(config, 'packages.ForceDisable') || []; - - let idx; - if ( enable ) { - if ( currentEnabled.indexOf(packageName) < 0 ) { - currentEnabled.push(packageName); - } - - idx = currentDisabled.indexOf(packageName); - if ( idx >= 0 ) { - currentDisabled.splice(idx, 1); - } - } else { - idx = currentEnabled.indexOf(packageName); - if ( idx >= 0 ) { - currentEnabled.splice(idx, 1); - } - - idx = currentDisabled.indexOf(packageName); - if ( idx < 0 ) { - currentDisabled.push(packageName); - } - } - - setConfigPath('packages', { - packages: { - ForceEnable: currentEnabled, - ForceDisable: currentDisabled - } - }, true); -} - -/////////////////////////////////////////////////////////////////////////////// -// API -/////////////////////////////////////////////////////////////////////////////// - -/* - * Gets currenct configuration(s) - */ -function getConfiguration() { - const safeWords = [ - '%VERSION%', - '%DIST%', - '%DROOT%', - '%UID%', - '%USERNAME%' - ]; - - return new Promise((resolve, reject) => { - const path = _path.join(ROOT, 'src', 'conf'); - - let object = {}; - _glob(path + '/*.json').then((files) => { - - files.forEach((file) => { - try { - const json = _fs.readJsonSync(file); - object = _utils.mergeObject(object, json); - } catch ( e ) { - _logger.warn('Failed to read JSON file', _path.basename(file), 'Syntax error ?', e); - } - }); - - // Resolves all "%something%" config entries - let tmpFile = JSON.stringify(object).replace(/%ROOT%/g, _utils.fixWinPath(ROOT)); - const tmpConfig = JSON.parse(tmpFile); - - const words = tmpFile.match(/%([A-z0-9_\-\.]+)%/g).filter((() => { - let seen = {}; - return function(element, index, array) { - return !(element in seen) && (seen[element] = 1); - }; - })()); - - words.forEach((w) => { - const p = w.replace(/%/g, ''); - const u = /^[A-Z]*$/.test(p); - if ( safeWords.indexOf(w) === -1 ) { - const value = (u ? process.env[p] : null) || getConfigPath(tmpConfig, p); - - if ( typeof value === 'object' && value.constructor === Object ) { - const re = w.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '$1'); - tmpFile = tmpFile.replace(new RegExp('"' + re + '"', 'g'), JSON.stringify(value)); - } else { - const re = w.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '$1'); - tmpFile = tmpFile.replace(new RegExp(re, 'g'), String(value)); - } - } - }); - resolve(Object.freeze(JSON.parse(tmpFile))); - }).catch(reject); - - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -function _writeClientConfig(cli, cfg) { - return new Promise((resolve, reject) => { - const src = _path.join(ROOT, 'src', 'templates', 'dist', 'settings.js'); - const tpl = _fs.readFileSync(src).toString(); - const dest = _path.join(ROOT, 'dist', 'settings.js'); - - generateClientConfiguration(cli, cfg).then((settings) => { - const data = tpl.replace('%CONFIG%', JSON.stringify(settings, null, 4)); - resolve(_fs.writeFileSync(dest, data)); - }).catch(reject); - }); -} - -function _writeServerConfig(cli, cfg) { - return new Promise((resolve, reject) => { - const dest = _path.join(ROOT, 'src', 'server', 'settings.json'); - - generateServerConfiguration(cli, cfg).then((settings) => { - const data = JSON.stringify(settings, null, 4); - resolve(_fs.writeFileSync(dest, data)); - }).catch(reject); - }); -} - -/* - * Writes given configuration file(s) - */ -function writeConfiguration(cli, cfg) { - return new Promise((resolve, reject) => { - _writeClientConfig(cli, cfg).then(() => { - _writeServerConfig(cli, cfg).then(resolve).catch(reject); - }).catch(reject); - }); -} - -/* - * Gets a configuration option - */ -function getConfig(config, key) { - let dump = getConfigPath(config, key); - try { - dump = JSON.stringify(dump, null, 4); - } catch ( e ) {} - return Promise.resolve(dump); -} - -/* - * Sets a configuration option - */ -function setConfig(config, key, value, importFile, outputFile) { - key = key || ''; - - function getNewTree(k, v) { - let resulted = {}; - - if ( k.length ) { - const queue = k.split(/\./); - let ns = resulted; - queue.forEach((k, i) => { - if ( i >= queue.length - 1 ) { - ns[k] = v; - } else { - if ( typeof ns[k] === 'undefined' ) { - ns[k] = {}; - } - ns = ns[k]; - } - }); - } - - return resulted; - } - - if ( importFile ) { - const importJson = _fs.readJsonSync(importFile); - const importTree = key.length ? getNewTree(key, importJson) : importJson; - return Promise.resolve(setConfigPath(null, importTree, true)); - } - - if ( typeof value === 'undefined' ) { - return Promise.resolve(value); - } - - return Promise.resolve(setConfigPath(key, value, false, outputFile)); -} - -/* - * Add a force enable package to config files - */ -function enablePackage(config, name) { - return Promise.resolve(_togglePackage(config, name, true)); -} - -/* - * Add a force disable package to config files - */ -function disablePackage(config, name) { - return Promise.resolve(_togglePackage(config, name, false)); -} - -/* - * Adds a file to an overlay - */ -function addOverlayFile(config, type, path, overlay) { - const play = 'build.overlays.' + overlay; - - let overlays = getConfigPath(config, 'build.overlays'); - if ( typeof overlays !== 'object' ) { - overlays = {}; - } - - if ( typeof overlays[overlay] !== 'object' ) { - overlays[overlay] = {}; - } - - const files = overlays[overlay][type] || []; - if ( files.indexOf(path) === -1 ) { - files.push(path); - } - overlays[overlay][type] = files; - - setConfigPath('build.overlays', {build: {overlays: overlays}}, true); - return Promise.resolve(getConfigPath(config, play)); -} - -/* - * Add a mountpoint to config files - */ -function addMount(config, name, description, path, transport, ro) { - if ( typeof transport !== 'string' ) { - transport = null; - } - - if ( !path || !name ) { - return Promise.reject('You have to define a path and name for a mountpoint'); - } - - let iter = path; - if ( transport || ro ) { - iter = {destination: path}; - if ( transport ) { - iter.transport = transport; - } - if ( ro ) { - iter.ro = ro === true; - } - } - - let current = getConfigPath(config, 'client.VFS.Mountpoints') || {}; - current[name] = {description: description || name}; - setConfigPath('client.VFS.Mountpoints', {client: {VFS: {Mountpoints: current}}}, true); - - current = getConfigPath(config, 'server.vfs.mounts') || {}; - current[name] = iter; - setConfigPath('server.vfs.mounts', {server: {vfs: {mounts: current}}}, true); - - return Promise.resolve(getConfigPath(config, 'server.vfs.mounts')); -} - -/* - * Add a preload to config files - */ -function addPreload(config, name, path, type) { - type = type || 'javascript'; - - let current = getConfigPath(config, 'client.Preloads') || {}; - current[name] = {type: type, src: path}; - - setConfigPath('client.Preloads', {client: {Preloads: current}}, true); - - return Promise.resolve(getConfigPath(config, 'client.Preloads')); -} - -/* - * Add a repository to config files - */ -function addRepository(config, name) { - let current = getConfigPath(config, 'repositories') || []; - if ( current.indexOf(name) === -1 ) { - current.push(name); - } - setConfigPath('repositories', {repositories: current}, true); - - return Promise.resolve(getConfigPath(config, 'repositories')); -} - -/* - * Removes a repository from config files - */ -function removeRepository(config, name) { - let current = getConfigPath(config, 'repositories') || []; - let found = current.indexOf(name); - if ( found >= 0 ) { - current.splice(found, 1); - } - if ( current.length === 1 && current[0] === 'default' ) { - current = null; - } - - setConfigPath('repositories', {repositories: current}, true); - - return Promise.resolve(getConfigPath(config, 'repositories')); -} - -/* - * Lists all packages - */ -function listPackages(config) { - return new Promise((resolve) => { - _metadata.getPackages(config.repositories, null, true).then((packages) => { - const currentEnabled = getConfigPath(config, 'packages.ForceEnable') || []; - const currentDisabled = getConfigPath(config, 'packages.ForceDisable') || []; - - function pl(str, s) { - if ( str.length > s ) { - str = str.substr(0, s - 3) + '...'; - } - - while ( str.length <= s ) { - str += ' '; - } - - return str; - } - - if ( packages ) { - Object.keys(packages).forEach((pn) => { - const p = packages[pn]; - - let es = String(p.enabled) !== 'false'; - let esc = es ? 'green' : 'red'; - - if ( es ) { - if ( !_metadata.checkEnabledState(currentEnabled, currentDisabled, p) ) { - es = false; - esc = 'yellow'; - } - } else { - if ( _metadata.checkEnabledState(currentEnabled, currentDisabled, p) ) { - es = true; - esc = 'blue'; - } - } - - const prn = pn.split('/', 2)[1]; - const lblenabled = (es ? 'Enabled' : 'Disabled')[esc]; - const lblname = prn[es ? 'white' : 'grey']; - const lblrepo = p.repo[es ? 'white' : 'grey']; - const lbltype = p.type[es ? 'white' : 'grey']; - - _logger.log(pl(lblenabled, 20), pl(lblrepo, 30), pl(lbltype, 25), lblname); - }); - } - - resolve(); - }); - }); -} - -/* - * Cleans up build files - */ -function cleanFiles() { - _utils.removeSilent(_path.join(ROOT, 'dist', 'settings.js')); - _utils.removeSilent(_path.join(ROOT, 'src', 'server', 'settings.json')); - return Promise.resolve(); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.getConfiguration = getConfiguration; -module.exports.writeConfiguration = writeConfiguration; -module.exports.getConfigPath = getConfigPath; -module.exports.enablePackage = enablePackage; -module.exports.disablePackage = disablePackage; -module.exports.addOverlayFile = addOverlayFile; -module.exports.addMount = addMount; -module.exports.addPreload = addPreload; -module.exports.addRepository = addRepository; -module.exports.removeRepository = removeRepository; -module.exports.listPackages = listPackages; -module.exports.get = getConfig; -module.exports.set = setConfig; -module.exports._set = setConfigPath; -module.exports.clean = cleanFiles; diff --git a/src/build/core.js b/src/build/core.js deleted file mode 100644 index dedfd4971e..0000000000 --- a/src/build/core.js +++ /dev/null @@ -1,161 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _fs = require('fs-extra'); -const _glob = require('glob-promise'); - -const _utils = require('./utils.js'); - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Get build files - */ -function getBuildFiles(opts) { - let javascripts = opts.javascript; - let stylesheets = opts.stylesheets; - let locales = opts.locales; - - if ( opts.overlays ) { - Object.keys(opts.overlays).forEach((k) => { - const a = opts.overlays[k]; - if ( a ) { - if ( a.javascript instanceof Array ) { - javascripts = javascripts.concat(a.javascript); - } - if ( a.stylesheets instanceof Array ) { - stylesheets = stylesheets.concat(a.stylesheets); - } - if ( a.locales instanceof Array ) { - locales = locales.concat(a.locales); - } - } - }); - } - - return { - javascript: javascripts, - stylesheets: stylesheets, - locales: locales - }; -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Cleans core build files - */ -function cleanFiles(cli, cfg) { - return new Promise((done, errored) => { - let globs = [ - 'dist/dialogs.html', - 'dist/_dialogs.js', - 'dist/locales.js', - 'dist/test.js', - 'dist/osjs.*', - 'dist/*.min.*' - ]; - - const tpldir = _path.join(ROOT, 'src', 'templates', 'dist', cfg.build.dist.template); - globs = globs.concat(_fs.readdirSync(tpldir).map((f) => { - return 'dist/' + f; - })); - - Promise.all(globs.map((g) => { - return new Promise((ok) => { - _glob(g).then((list) => { - list.forEach((file) => { - _utils.removeSilent(file); - }); - ok(); - }).catch(ok); - }); - })).then(done).catch(errored); - }); -} - -/* - * Builds core files - */ -function buildFiles(cli, cfg) { - const verbose = cli.option('verbose', false); - const debug = cli.option('debug', false); - const optimization = cli.option('optimization', false); - const build = getBuildFiles(cfg.build); - - const only = cli.option('only'); - - if ( !only || only === 'javascript' ) { - _utils.writeScripts({ - dest: _path.join(ROOT, 'dist', 'osjs.min.js'), - sources: build.javascript, - debug: debug, - verbose: verbose, - optimizations: optimization - }); - } - if ( !only || only === 'locale' ) { - _utils.writeScripts({ - dest: _path.join(ROOT, 'dist', 'locales.min.js'), - sources: build.locales, - debug: debug, - verbose: verbose, - optimizations: optimization - }); - } - if ( !only || only === 'css' ) { - _utils.writeStyles({ - dest: _path.join(ROOT, 'dist', 'osjs.min.css'), - sources: build.stylesheets, - debug: debug, - verbose: verbose, - optimizations: optimization - }); - } - - return Promise.resolve(); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.clean = cleanFiles; -module.exports.buildFiles = buildFiles; diff --git a/src/build/dist.js b/src/build/dist.js deleted file mode 100644 index 3069ef2d91..0000000000 --- a/src/build/dist.js +++ /dev/null @@ -1,258 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _fs = require('fs-extra'); -const _glob = require('glob-promise'); - -const _utils = require('./utils.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Gets the correct template directory - */ -function getTemplatePath(cfg, category) { - const paths = [ - _path.join.apply(_path.join, [ROOT, 'src', 'templates'].concat(category)) - ]; - - _utils.enumOverlayPaths(cfg, 'templates', (p) => { - const rel = _path.resolve(ROOT, p); - paths.push(_path.join.apply(_path.join, [rel].concat(category))); - }); - - return paths.filter((p) => { - return _fs.existsSync(p); - })[0]; -} - -/* - * Create a 'index.html' file - */ -function createIndex(debug, verbose, standalone, cfg) { - const tpldir = getTemplatePath(cfg, ['dist', cfg.build.dist.template]); - const outdir = _path.join(ROOT, 'dist'); - - function _write(fileName) { - const inputScripts = [ - 'osjs.min.js', - 'locales.min.js' - ]; - - if ( standalone ) { - inputScripts.push('_dialogs.js'); - } - - const inputStylesheets = [ - 'osjs.min.css' - ]; - - let appendString = ''; - if ( cfg.client.Connection.AppendVersion ) { - appendString = '?ver=' + cfg.client.Connection.AppendVersion; - } - - const scripts = inputScripts.map((i) => { - if ( verbose ) { - _utils.log('- including:', i); - } - return ' '; - }); - const styles = inputStylesheets.map((i) => { - if ( verbose ) { - _utils.log('- including:', i); - } - return ' '; - }); - - const loginName = cfg.build.dist.login || 'default'; - const loginFile = getTemplatePath(cfg, ['dist', 'login', loginName + '.html']); - const loginHTML = _fs.readFileSync(loginFile).toString(); - - const splashName = cfg.build.dist.splash || 'default'; - const splashFile = getTemplatePath(cfg, ['dist', 'splash', splashName + '.html']); - const splashHTML = _fs.readFileSync(splashFile).toString(); - - const replace = { - '%STYLES%': styles.join('\n'), - '%SCRIPTS%': scripts.join('\n'), - '%LOGIN%': loginHTML, - '%SPLASH%': splashHTML, - '%VERSION%': cfg.client.Version - }; - - let tpl = _fs.readFileSync(_path.join(tpldir, fileName), 'utf8'); - Object.keys(replace).forEach((s) => { - tpl = _utils.replaceAll(tpl, s, replace[s]); - }); - - _fs.writeFileSync(_path.join(outdir, fileName), tpl); - } - - _write('index.html'); - if ( debug ) { - _write('test.html'); - } -} - -/* - * Copies a templates resources - */ -function copyResources(verbose, cfg) { - const tpldir = getTemplatePath(cfg, ['dist', cfg.build.dist.template]); - const dest = _path.join(ROOT, 'dist'); - - return new Promise((resolve) => { - _glob(_path.join(tpldir, '/**/*'), { - }).then((list) => { - list.forEach((path) => { - if ( ['index.html', 'test.html'].indexOf(_path.basename(path)) === -1 ) { - if ( verbose ) { - _utils.log('- copying:', path); - } - - _fs.copySync(path, _path.join(dest, path.replace(_utils.fixWinPath(tpldir), ''))); - } - }); - - Object.keys(cfg.build.statics).forEach((f) => { - const dst = _path.join(ROOT, cfg.build.statics[f]); - - let path = f; - let skip = false; - try { - if ( f.substr(0, 1) === '?' ) { - path = path.substr(1); - if ( _fs.existsSync(dst) ) { - skip = true; - } else { - _fs.mkdirSync(_path.dirname(dst)); - } - } - } catch ( e ) { - _utils.log(_logger.color('Warning:', 'yellow'), e); - } - - if ( !skip ) { - const src = _path.join(ROOT, path); - if ( verbose ) { - _utils.log('- included:', dst); - } - - try { - _fs.copySync(src, dst); - } catch ( e ) { - _utils.log(_logger.color('Warning:', 'yellow'), e); - } - } - }); - - resolve(); - }); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Cleans core build files - */ -function cleanFiles(cli, cfg) { - return new Promise((done, errored) => { - let globs = [ - 'dist/dialogs.html', - 'dist/_dialogs.js', - 'dist/test.js', - 'dist/test.js' - ]; - - const tpldir = getTemplatePath(cfg, ['dist', cfg.build.dist.template]); - globs = globs.concat(_fs.readdirSync(tpldir).map((f) => { - return 'dist/' + f; - })); - - Promise.all(globs.map((g) => { - return new Promise((ok) => { - _glob(g).then((list) => { - list.forEach((file) => { - _utils.removeSilent(file); - }); - ok(); - }).catch(ok); - }); - })).then(done).catch(errored); - }); -} - -/* - * Builds core files - */ -function buildFiles(cli, cfg) { - return new Promise((resolve, reject) => { - const verbose = cli.option('verbose', false); - const standalone = cli.option('standalone', false); - const debug = cli.option('debug', false); - - createIndex(debug, verbose, standalone, cfg); - - if ( debug ) { - try { - const s = _path.join(ROOT, 'src/client/test/test.js'); - const d = _path.join(ROOT, 'dist', 'test.js'); - _fs.symlinkSync(s, d, 'file'); - } catch ( e ) {} - } - - if ( standalone ) { - const src = _path.join(ROOT, 'src', 'client', 'dialogs.html'); - _utils.createStandaloneScheme(src, '/dialogs.html', _path.join(ROOT, 'dist', '_dialogs.js')); - } - - copyResources(verbose, cfg).then(resolve).catch(reject); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.clean = cleanFiles; -module.exports.buildFiles = buildFiles; diff --git a/src/build/generate.js b/src/build/generate.js deleted file mode 100644 index 1bd06f78a0..0000000000 --- a/src/build/generate.js +++ /dev/null @@ -1,228 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _fs = require('fs-extra'); - -const _utils = require('./utils.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Reads given config template and replaces any required strings - */ -function _createWebserverConfig(cfg, src, mimecb) { - const mimes = mimecb(cfg.mime); - - let tpl = _fs.readFileSync(src).toString(); - tpl = tpl.replace(/%DISTDIR%/, _path.join(ROOT, 'dist')); - tpl = tpl.replace(/%MIMES%/, mimes); - tpl = tpl.replace(/%PORT%/, cfg.server.http.port); - return tpl; -} - -/* - * Reads given template file and replaces example strings - */ -function _replaceInExample(name, file, dest) { - dest = dest ? dest : file; - - let c = _fs.readFileSync(file).toString(); - c = _utils.replaceAll(c, 'EXAMPLE', name); - _fs.writeFileSync(dest, c); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -const TASKS = { - 'apache_vhost': function(cli, cfg) { - const src = _path.join(ROOT, 'src', 'templates', 'webserver', 'apache_vhost.conf'); - - return Promise.resolve(_createWebserverConfig(cfg, src, (mime) => { - return ''; - })); - }, - - 'apache_htaccess': function(cli, cfg) { - const mimes = []; - const proxies = []; - - Object.keys(cfg.mime.mapping).forEach((i) => { - if ( i.match(/^\./) ) { - mimes.push(' AddType ' + cfg.mime.mapping[i] + ' ' + i); - } - }); - - Object.keys(cfg.server.proxies).forEach((k) => { - if ( k.substr(0, 1) !== '/' && typeof cfg.server.proxies[k] === 'string' ) { - proxies.push(' RewriteRule ' + k + ' ' + cfg.server.proxies[k] + ' [P]'); - } - }); - - function generate_htaccess(t) { - const src = _path.join(ROOT, 'src', 'templates', t); - const dst = _path.join(ROOT, 'dist', '.htaccess'); - - let tpl = _fs.readFileSync(src).toString(); - tpl = tpl.replace(/%MIMES%/, mimes.join('\n')); - tpl = tpl.replace(/%PROXIES%/, proxies.join('\n')); - _fs.writeFileSync(dst, tpl); - } - - if ( cli.option('debug') ) { - generate_htaccess('webserver/dev-htaccess.conf'); - } else { - generate_htaccess('webserver/prod-htaccess.conf'); - } - - return Promise.resolve(); - }, - - 'apache_proxy': function(cli, cfg) { - const src = _path.join(ROOT, 'src', 'templates', 'webserver', 'apache-proxy.conf'); - - return Promise.resolve(_createWebserverConfig(cfg, '', src, function() {})); - }, - - 'lighttpd_config': function(cli, cfg) { - const src = _path.join(ROOT, 'src', 'templates', 'webserver', 'lighttpd.conf'); - - return Promise.resolve(_createWebserverConfig(cfg, src, (mime) => { - return Object.keys(mime.mapping).map((i) => { - return i.match(/^\./) ? ' "' + i + '" => "' + mime.mapping[i] + '"' : null; - }).filter((i) => { - return !!i; - }).join(',\n'); - })); - }, - - 'nginx_config': function(cli, cfg) { - const src = _path.join(ROOT, 'src', 'templates', 'webserver', 'nginx.conf'); - - return Promise.resolve(_createWebserverConfig(cfg, src, (mime) => { - return Object.keys(mime.mapping).map((i) => { - return i.match(/^\./) ? (' ' + mime.mapping[i] + ' ' + i.replace(/^\./, '') + ';') : null; - }).filter((i) => { - return !!i; - }).join('\n'); - })); - }, - - 'nginx_proxy': function(cli, cfg) { - const src = _path.join(ROOT, 'src', 'templates', 'webserver', 'nginx-proxy.conf'); - - return Promise.resolve(_createWebserverConfig(cfg, src, function() {})); - }, - - 'package': function(cli, cfg) { - let name = cli.option('name', ''); - const type = cli.option('type', 'application'); - - const tmp = name.split('/'); - const repo = tmp.length > 1 ? tmp[0] : 'default'; - name = tmp.length > 1 ? tmp[1] : name; - - const words = name.replace(/[^A-z0-9\._]/g, '').replace(/\s+/g, ' ').split(' '); - name = [words[0]].concat(words.splice(1).map((w) => { - return w.replace(/\b\w/g, (l) => l.toUpperCase()); - })).join(''); - - const typemap = { - iframe: { - src: 'iframe-application', - cpy: ['main.js', 'metadata.json'] - }, - dummy: { - src: 'dummy', - cpy: ['main.js', 'metadata.json'] - }, - application: { - src: 'application', - cpy: ['server/main.php', 'server/main.js', 'main.js', 'main.css', 'metadata.json', 'scheme.html'] - }, - simple: { - src: 'simple-application', - cpy: ['server/main.php', 'server/main.js', 'main.js', 'main.css', 'metadata.json', 'scheme.html'] - }, - service: { - src: 'service', - cpy: ['server/main.php', 'server/main.js', 'main.js', 'metadata.json'] - }, - extension: { - src: 'extension', - cpy: ['server/main.php', 'server/main.js', 'main.js', 'metadata.json'] - } - }; - - if ( !name ) { - throw new Error('You have to specify a name'); - } - - const src = _path.join(ROOT, 'src', 'templates', 'package', typemap[type].src); - const dst = _path.join(ROOT, 'src', 'packages', repo, name); - - if ( !_fs.existsSync(src) ) { - throw new Error('Template not found'); - } - - if ( _fs.existsSync(dst) ) { - throw new Error('Package already exists'); - } - - _fs.copySync(src, dst); - - typemap[type].cpy.forEach((c) => { - _replaceInExample(name, _path.join(dst, c), false); - }); - - if ( (cfg.repositories || []).indexOf(repo) < 0 ) { - _logger.warn(_logger.color('The repository \'' + repo + '\' is not active.', 'yellow')); - } - - return Promise.resolve(); - } - -}; - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports = TASKS; diff --git a/src/build/help.txt b/src/build/help.txt deleted file mode 100644 index 948b1d5931..0000000000 --- a/src/build/help.txt +++ /dev/null @@ -1,53 +0,0 @@ -OS.js build system and task runner - -More information: https://os.js.org/manual/build/cli/ - -Use the --verbose argument to get detailed information in build output. - -The --debug flag enables full source map (inline) support in build files. For the server, -this disables any HTTP caching etc. - -You can also pass the --optimization= argument to change the optimization level, -where 'all' is slower/smaller, 'none' is quick/big and any other value uses defaults. - -Loglevels: INFO: 1, WARN: 2, WARNING: 2, ERROR: 3, VERBOSE: 8 (default: 7) - -Building: - clean - watch [--debug] - build [--debug] - build:config - build:manifest - build:dist [--debug] - build:core [--debug] - build:packages [--debug] - build:themes [--debug] [--only=] - build:package --name=REPO/NAME [--debug] - build:theme [--style] [--icons] [--fonts] [--static] [--sounds] - -Configuration: - config:get --name=KEY - config:set --name=KEY --value=VALUE [--out=FILE] - config:set [--name=KEY] --import=FILE - config:add-repository --name=NAME - config:remove-repository --name=NAME - config:list-packages - config:enable-package --name=REPO/NAME - config:disable-package --name=REPO/NAME - config:add-script --path=PATH [--overlay=NAME] - config:add-style --path=PATH [--overlay=NAME] - config:add-locale --path=PATH [--overlay=NAME] - config:add-preload --name=NAME --path=PATH - config:add-mount --name=NAME --desc=DESC --path=PATH - -Generators: - generate:apache-htaccess [--debug] - generate:apache-vhost [--out=FILENAME] - generate:apache-proxy [--out=FILENAME] - generate:nginx-config [--out=FILENAME] - generate:nginx-proxy [--out=FILENAME] - generate:lighttpd-config [--out=FILENAME] - generate:package --name=REPO/NAME [--type=TYPE] - -Server: - run [--port=N] [--loglevel=N] [--debug] diff --git a/src/build/index.js b/src/build/index.js deleted file mode 100644 index 566d51a6fe..0000000000 --- a/src/build/index.js +++ /dev/null @@ -1,351 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _fs = require('fs-extra'); -const _glob = require('glob'); - -const _config = require('./config.js'); -const _manifest = require('./manifest.js'); -const _themes = require('./themes.js'); -const _packages = require('./packages.js'); -const _core = require('./core.js'); -const _dist = require('./dist.js'); -const _generate = require('./generate.js'); -const _utils = require('./utils.js'); -const _watcher = require('./watcher.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Iterates all given tasks - */ -function _eachTask(cli, args, taskName, namespace) { - if ( !args ) { - return Promise.reject('Not enough arguments'); - } - - return new Promise((resolve, reject) => { - _config.getConfiguration().then((cfg) => { - _utils.eachp(args.replace(/\s/, '').split(',').map((iter) => { - return function() { - iter = (iter || '').replace('-', '_'); - if ( typeof namespace === 'function' ) { - return namespace(cli, cfg, iter); - } else { - if ( namespace[iter] ) { - let msg = _logger.color([taskName, iter].join(':'), 'green'); - if ( cli.option('debug') ) { - msg += ' (' + _logger.color('debug mode', 'blue') + ')'; - } - - _logger.log(_logger.color('Running task:', 'bold'), msg); - - return namespace[iter](cli, cfg); - } - } - - return Promise.reject('Invalid task: ' + iter); - }; - })).then(resolve).catch(reject); - }).catch(reject); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -const TASKS = { - build: { - config: function(cli, cfg) { - return _config.writeConfiguration(cli, cfg); - }, - - core: function(cli, cfg) { - return _core.buildFiles(cli, cfg); - }, - - dist: function(cli, cfg) { - return _dist.buildFiles(cli, cfg); - }, - - theme: function(cli, cfg) { - const targets = [ - [cli.option('style'), _themes.buildStyle], - [cli.option('icons'), _themes.buildIcon], - [cli.option('static'), _themes.buildStatic], - [cli.option('fonts'), _themes.buildFonts], - [cli.option('sounds'), _themes.buildSounds] - ]; - - const list = targets.filter((iter) => { - return iter && iter[0]; - }).map((iter) => { - return iter[1](cli, cfg, iter[0]); - }); - - return Promise.all(list); - }, - - themes: function(cli, cfg) { - return _themes.buildAll(cli, cfg); - }, - - manifest: function(cli, cfg) { - return _manifest.writeManifest(cli, cfg); - }, - - package: function(cli, cfg) { - const name = cli.option('name'); - if ( !name || name.indexOf('/') === -1 ) { - throw new Error('Invalid package name'); - } - - return _packages.buildPackage(cli, cfg, name); - }, - - packages: function(cli, cfg) { - return _packages.buildPackages(cli, cfg); - } - }, - - config: { - set: function(cli, cfg) { - return _config.set(cfg, cli.option('name'), cli.option('value'), cli.option('import'), cli.option('out')); - }, - get: function(cli, cfg) { - return _config.get(cfg, cli.option('name')); - }, - add_mount: function(cli, cfg) { - return _config.addMount(cfg, cli.option('name'), cli.option('description') || cli.option('desc'), cli.option('path'), cli.option('transport'), cli.option('ro')); - }, - add_preload: function(cli, cfg) { - return _config.addPreload(cfg, cli.option('name'), cli.option('path'), cli.option('type')); - }, - add_repository: function(cli, cfg) { - return _config.addRepository(cfg, cli.option('name')); - }, - add_script: function(cli, cfg) { - return _config.addOverlayFile(cfg, 'javascript', cli.option('path'), cli.option('overlay', 'custom')); - }, - add_style: function(cli, cfg) { - return _config.addOverlayFile(cfg, 'stylesheets', cli.option('path'), cli.option('overlay', 'custom')); - }, - add_locale: function(cli, cfg) { - return _config.addOverlayFile(cfg, 'locales', cli.option('path'), cli.option('overlay', 'custom')); - }, - remove_repository: function(cli, cfg) { - return _config.removeRepository(cfg, cli.option('name')); - }, - enable_package: function(cli, cfg) { - return _config.enablePackage(cfg, cli.option('name')); - }, - disable_package: function(cli, cfg) { - return _config.disablePackage(cfg, cli.option('name')); - }, - list_packages: function(cli, cfg) { - return _config.listPackages(cfg); - } - }, - - generate: function(cli, cfg, task) { - if ( _generate[task] ) { - return new Promise((resolve, reject) => { - _generate[task](cli, cfg).then((arg) => { - - const out = cli.option('out'); - if ( out ) { - _fs.writeFileSync(out, String(arg)); - resolve(); - return; - } else if ( arg ) { - _logger.log(arg); - } - - resolve(); - }).catch(reject); - }); - } else { - return Promise.reject('Invalid generator: ' + task); - } - } -}; - -const ORIGINAL_TASKS = (function() { - const tmp = {}; - Object.keys(TASKS).forEach(function(s) { - tmp[s] = Object.keys(TASKS[s]); - }); - return tmp; -})(); - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Init - */ -module.exports._init = function() { - _glob.sync(_path.join(__dirname, 'modules/*.js')).forEach((file) => { - require(file).register(TASKS); - }); -}; - -/* - * Task: `build` - */ -module.exports.build = function(cli, args) { - if ( !args ) { - args = ['config', 'dist', 'core', 'themes', 'manifest', 'packages']; - - args = args.concat(Object.keys(TASKS.build).filter(function(i) { - return ORIGINAL_TASKS.build.indexOf(i) === -1 && args.indexOf(i) === -1; - })).join(','); - } - - return _eachTask(cli, args, 'build', TASKS.build); -}; - -/* - * Task: `config` - */ -module.exports.config = function(cli, arg) { - return new Promise((resolve, reject) => { - arg = (arg || '').replace('-', '_'); - - if ( TASKS.config[arg] ) { - _config.getConfiguration().then((cfg) => { - TASKS.config[arg](cli, cfg).then((arg) => { - if ( typeof arg !== 'undefined' ) { - _logger.log(arg); - } - resolve(); - }).catch(reject); - }); - } else { - reject('Invalid action: ' + arg); - } - }); -}; - -/* - * Task: `watch` - */ -module.exports.watch = function(cli, args) { - return _watcher.watch(cli); -}; - -/* - * Task: `generate` - */ -module.exports.generate = function(cli, args) { - return _eachTask(cli, args, 'generate', TASKS.generate); -}; - -/* - * Task: `clean` - */ -module.exports.clean = function(cli, args) { - return new Promise((resolve, reject) => { - _logger.log(_logger.color('Running task:', 'bold'), _logger.color('clean', 'green')); - - _config.getConfiguration().then((cfg) => { - Promise.all([ - _config.clean(cli, cfg), - _dist.clean(cli, cfg), - _core.clean(cli, cfg), - _manifest.clean(cli, cfg), - _themes.clean(cli, cfg), - _packages.clean(cli, cfg) - ]).then(resolve).catch(reject); - }); - }); -}; - -/* - * Task: `run` - */ -module.exports.run = function(cli, args) { - const instance = require(_path.join(ROOT, 'src/server/node/core/instance.js')); - const settings = require(_path.join(ROOT, 'src/server/node/core/settings.js')); - - const opts = { - HOSTNAME: cli.option('hostname'), - DEBUG: cli.option('debug'), - PORT: cli.option('port'), - LOGLEVEL: cli.option('loglevel') - }; - - instance.init(opts).then((env) => { - const config = settings.get(); - if ( config.tz ) { - process.env.TZ = config.tz; - } - - process.on('exit', () => { - instance.destroy(); - }); - - instance.run(); - - process.on('uncaughtException', (error) => { - _logger.log('UNCAUGHT EXCEPTION', error, error.stack); - }); - - process.on('unhandledRejection', (error) => { - console.log('UNCAUGHT REJECTION', error); - }); - - ['SIGTERM', 'SIGINT'].forEach((sig) => { - process.on(sig, () => { - console.log('\n'); - instance.destroy((err) => { - process.exit(err ? 1 : 0); - }); - }); - }); - }).catch((error) => { - _logger.log(error); - process.exit(1); - }); - - return new Promise(() => { - // This is one promise we can't keep! :( - }); -}; diff --git a/src/build/manifest.js b/src/build/manifest.js deleted file mode 100644 index 55f0bc8e38..0000000000 --- a/src/build/manifest.js +++ /dev/null @@ -1,389 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _glob = require('glob-promise'); -const _fs = require('fs-extra'); - -const _config = require('./config.js'); -const _utils = require('./utils.js'); - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Parses the preload array(s) - */ -function parsePreloads(iter) { - if ( typeof iter === 'string' ) { - let niter = { - src: iter, - type: null - }; - - if ( iter.match(/\.js/) ) { - niter.type = 'javascript'; - } else if ( iter.match(/\.css/) ) { - niter.type = 'stylesheet'; - } else if ( iter.match(/\.html/) ) { - niter.type = 'html'; - } - - return niter; - } - - return iter; -} - -/* - * Gets package path(s) - */ -function getPackagePaths(cfg, repo) { - const paths = [ - _path.join(ROOT, 'src/packages', repo) - ]; - - _utils.enumOverlayPaths(cfg, 'packages', (p) => { - const rpath = _path.resolve(ROOT, p); - paths.push(_path.join(rpath, repo)); - }); - - return paths; -} - -/////////////////////////////////////////////////////////////////////////////// -// API -/////////////////////////////////////////////////////////////////////////////// - -/* - * Checks if package is enabled - */ -function checkEnabledState(enabled, disabled, meta) { - const name = meta.path; - const shortName = meta.path.split('/')[1]; - - if ( String(meta.enabled) === 'false' ) { - if ( enabled.indexOf(shortName) !== -1 || enabled.indexOf(name) !== -1 ) { - return true; - } - return false; - } - - if ( disabled.indexOf(shortName) !== -1 || disabled.indexOf(name) !== -1 ) { - return false; - } - return true; -} - -/* - * Get Package Metadata - */ -function getPackageMetadata(repo, file) { - - return new Promise((resolve, reject) => { - const name = [repo, _path.basename(_path.dirname(file))].join('/'); - try { - const meta = _fs.readJsonSync(file); - - meta._src = _path.dirname(file.replace(ROOT + '/', '')); - - meta.type = meta.type || 'application'; - meta.path = name; - meta.build = meta.build || {}; - meta.repo = repo; - meta.preload = (meta.preload ? meta.preload : []).map(parsePreloads); - - if ( typeof meta.sources !== 'undefined' ) { - meta.preload = meta.preload.concat(meta.sources.map(parsePreloads)); - } - - resolve(Object.freeze(meta)); - } catch (e) { - reject('Error with ' + file + e); - } - }); -} - -/* - * Get packages from repository - */ -function getRepositoryPackages(repo, all) { - - function enumPaths(cfg) { - const result = {}; - const paths = getPackagePaths(cfg, repo); - const forceEnabled = _config.getConfigPath(cfg, 'packages.ForceEnable', []); - const forceDisabled = _config.getConfigPath(cfg, 'packages.ForceDisable', []); - - function readDir(path) { - return new Promise((resolve, reject) => { - const glb = _path.join(path, '*', 'metadata.json'); - _glob(glb).then((files) => { - - Promise.all(files.map((file) => { - return new Promise((yes) => { - getPackageMetadata(repo, file).then((meta) => { - meta = Object.assign({}, meta); - if ( all || checkEnabledState(forceEnabled, forceDisabled, meta) ) { - result[meta.path] = meta; - } - - yes(); - }).catch(reject); - }); - })).then(resolve).catch(reject); - - }).catch(reject); - }); - } - - return new Promise((resolve, reject) => { - Promise.all(paths.map((p) => readDir(p))).then(() => { - resolve(result); - }).catch(reject); - }); - } - - return new Promise((resolve, reject) => { - _config.getConfiguration().then((cfg) => { - enumPaths(cfg).then(resolve).catch(reject); - }).catch(reject); - }); -} - -/* - * Get all packages (with filter) - */ -function getPackages(repos, filter, all) { - repos = repos || []; - filter = filter || function() { - return true; - }; - - let list = {}; - return new Promise((resolve, reject) => { - _utils.eachp(repos.map((repo) => { - return function() { - return getRepositoryPackages(repo, all); - }; - }), (packages) => { - list = Object.assign(list, packages); - }).then(() => { - const result = {}; - Object.keys(list).forEach((k) => { - if ( filter(list[k]) ) { - result[k] = list[k]; - } - }); - - resolve(result); - }).catch(reject); - }); -} - -/* - * Generates a client-side manifest file - */ -function generateClientManifest(manifest) { - return new Promise((resolve, reject) => { - const dest = _path.join(ROOT, 'dist', 'packages.js'); - - let tpl = _fs.readFileSync(_path.join(ROOT, 'src/templates/dist/packages.js')); - tpl = tpl.toString().replace('%PACKAGES%', JSON.stringify(manifest, null, 4)); - - _fs.writeFile(dest, tpl, (err) => { - /*eslint no-unused-expressions: "off"*/ - err ? reject(err) : resolve(); - }); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// API -/////////////////////////////////////////////////////////////////////////////// - -/* - * Gets a package manifest by name - */ -function getPackage(name) { - const repo = name.split('/')[0]; - - function _getPackage(cfg) { - const paths = getPackagePaths(cfg, repo); - - let found = null; - paths.some((p) => { - const file = _path.join(p, name.split('/')[1], 'metadata.json'); - if ( _fs.existsSync(file) ) { - found = file; - } - return !!found; - }); - - if ( found ) { - return getPackageMetadata(repo, found); - } - - return Promise.reject('No package found'); - } - - return new Promise((resolve, reject) => { - _config.getConfiguration().then((cfg) => { - _getPackage(cfg).then(resolve).catch(reject); - }).catch(reject); - }); -} - -/* - * Combines preload files - */ -function combinePreloads(manifest) { - let pcss = false; - let pjs = false; - let preload = []; - - manifest.preload.forEach((p) => { - if ( p.combine === false || p.src.match(/^(ftp|https?\:)?\/\//) ) { - preload.push(p); - return; - } - - if ( p.type === 'javascript' ) { - if ( !pjs ) { - preload.push({type: 'javascript', src: '_app.min.js'}); - } - pjs = true; - } else if ( p.type === 'stylesheet' ) { - if ( !pcss ) { - preload.push({type: 'stylesheet', src: '_app.min.css'}); - } - pcss = true; - } else { - preload.push(p); - } - }); - - return preload; -} - -/* - * Parses a client manifest - */ -function mutateManifest(packages) { - packages = JSON.parse(JSON.stringify(packages)); - - Object.keys(packages).forEach((p) => { - packages[p].preload = combinePreloads(packages[p]); - - if ( packages[p].build ) { - delete packages[p].build; - } - - if ( typeof packages[p].enabled !== 'undefined' ) { - delete packages[p].enabled; - } - - if ( packages[p].type === 'service' ) { - packages[p].singular = true; - } - }); - - return packages; -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -function createClientManifest(cli, cfg) { - if ( !cli.option('standalone') ) { - return Promise.resolve(); - } - - return new Promise((resolve, reject) => { - getPackages(cfg.repositories).then((packages) => { - packages = mutateManifest(packages); - - generateClientManifest(packages).then(resolve).catch(reject); - }); - }); -} - -function createServerManifest(cli, cfg) { - return new Promise((resolve, reject) => { - const dest = _path.join(ROOT, 'src', 'server', 'packages.json'); - - getPackages(cfg.repositories).then((packages) => { - const meta = mutateManifest(packages); - - _fs.writeFile(dest, JSON.stringify(meta, null, 4), (err) => { - err ? reject(err) : resolve(); - }); - }); - }); -} - -/* - * Writes the given manifest file(s) - */ -function writeManifest(cli, cfg) { - return new Promise((resolve, reject) => { - - createClientManifest(cli, cfg).then(() => { - createServerManifest(cli, cfg).then(resolve).catch(reject); - }).catch(reject); - }); -} - -/* - * Cleans up build files - */ -function cleanFiles() { - _utils.removeSilent(_path.join(ROOT, 'dist', 'packages.js')); - _utils.removeSilent(_path.join(ROOT, 'src', 'server', 'packages.json')); - return Promise.resolve(); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.getPackages = getPackages; -module.exports.getPackage = getPackage; -module.exports.writeManifest = writeManifest; -module.exports.combinePreloads = combinePreloads; -module.exports.checkEnabledState = checkEnabledState; -module.exports.clean = cleanFiles; diff --git a/src/build/packages.js b/src/build/packages.js deleted file mode 100644 index c3c2ed5685..0000000000 --- a/src/build/packages.js +++ /dev/null @@ -1,389 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _fs = require('fs-extra'); - -const _manifest = require('./manifest.js'); -const _utils = require('./utils.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Runs package build scripts - */ -function runBuildScripts(verbose, section, iter, src, dest, cb) { - const build = iter.build || {}; - const scripts = ((build.scripts ? build.scripts[section] : null) || []).filter((s) => { - return !!s; - }); - - return _utils.eachp(scripts.map((cmd) => { - return function() { - return new Promise((resolve, reject) => { - cmd = cmd.replace('%PACKAGE%', src); - _logger.log('$', cmd.replace(ROOT + '/', '')); - - let env = Object.create(process.env); - env.OSJS_TARGET = 'dist'; - env.OSJS_PACKAGE = src; - - require('child_process').exec(cmd, {cwd: dest, env: env}, (err, stdout, stderr) => { - if ( stderr ) { - _logger.error(stderr); - } - if ( verbose ) { - _logger.log(stdout); - } - resolve(); - }); - }); - }; - })); -} - -/* - * Copies package resources - */ -function copyResources(verbose, iter, src, dest, noclean) { - const copy = iter.build.copy || []; - if ( copy.length ) { - return new Promise((resolve, reject) => { - copy.forEach((file) => { - const d = _path.join(dest, file); - const p = _path.dirname(d); - - if ( verbose ) { - _utils.log('-', _path.join(src, file), '->', d); - } - - try { - if ( !_fs.existsSync(p) ) { - _fs.mkdirSync(p); - } - if ( _fs.existsSync(d) ) { - _fs.removeSync(d); - } - _fs.copySync(_path.join(src, file), d); - } catch ( e ) { - _logger.warn(e); - _logger.warn('Failed copying resource', _path.join(src, file)); - } - }); - - resolve(); - }); - } - - return new Promise((resolve, reject) => { - if ( verbose ) { - _utils.log('-', src, '->', dest); - } - - const removal = []; - - if ( !noclean ) { - if ( iter.main ) { - if ( typeof iter.main === 'string' ) { - removal.push(iter.main); - } else { - Object.keys(iter.main).forEach((k) => { - removal.push(iter.main[k]); - }); - } - } else { - if ( ['application', 'service', 'windowmanager'].indexOf(iter.type) !== -1 ) { - removal.push('server'); - } - } - } - - const rpath = _path.resolve(ROOT, src); - _fs.copy(_fs.realpathSync(rpath), dest, (err) => { - /*eslint no-unused-expressions: "off"*/ - const removed = removal.map((f) => { - let rem = _path.join(dest, f); - if ( _path.dirname(rem) !== _path.resolve(dest) ) { - rem = _path.dirname(rem); - } - - return rem; - }).filter((f) => { - return _utils.removeSilent(f); - }); - - if ( removed.length && verbose ) { - _utils.log(_logger.color('Removed:', 'yellow'), removed.join(', ') + '.', 'Use the --noclean option to keep files.'); - } - err ? reject(err) : resolve(); - }); - }); -} - -/* - * Builds LESS file(s) - */ -function buildLess(debug, verbose, iter, src, dest) { - const files = iter.build.less || {}; - - return Promise.all(Object.keys(files).map((f) => { - return new Promise((resolve, reject) => { - const from = _path.join(src, f); - const to = _path.join(dest, files[f]); - - if ( verbose ) { - console.log('$ less', from.replace(ROOT + '/', ''), to.replace(ROOT + '/', '')); - } - _utils.compileLess(debug, from, to, { - sourceMap: {}, - paths: [ - '.', - _path.join(ROOT, 'src', 'client', 'themes'), - _path.join(ROOT, 'src', 'client', 'stylesheets') - ] - }, (err) => { - /*eslint no-unused-expressions: "off"*/ - err ? reject(err) : resolve(); - }); - }); - })); -} - -/* - * Create standalone scheme files - */ -function createStandaloneScheme(iter, dest) { - let src = _path.join(dest, 'scheme.html'); - if ( _fs.existsSync(src) ) { - iter.preload.forEach((p) => { - if ( p.type === 'scheme' ) { - _utils.createStandaloneScheme(src, '/' + iter.path + '/' + p.src, _path.join(dest, '_scheme.js')); - _fs.removeSync(src); - } - }); - } -} - -/* - * Combines resources - */ -function combineResources(standalone, metadata, src, dest, debug, optimization) { - const remove = []; - const combined = { - javascript: [], - stylesheet: [] - }; - - let iter = JSON.parse(JSON.stringify(metadata)); - return new Promise((resolve, reject) => { - iter.preload.forEach((p) => { - if ( p.combine === false || p.src.match(/^(ftp|https?\:)?\/\//) ) { - return; - } - - try { - if ( Object.keys(combined).indexOf(p.type) !== -1 ) { - const path = _path.join(src, p.src); - const dpath = _path.join(dest, p.src); - try { - if ( _fs.existsSync(path) ) { - combined[p.type].push(path); - remove.push(dpath); - } - } catch ( e ) { - _utils.log(_logger.color('Failed reading:', 'yellow'), path); - } - } - } catch ( e ) { - _logger.error(e); - } - }); - - try { - _fs.mkdirsSync(dest); - } catch ( e ) {} - - _utils.writeScripts({ - sources: combined.javascript, - dest: _path.join(dest, '_app.min.js'), - debug: debug, - optimizations: optimization - }); - - _utils.writeStyles({ - dest: _path.join(dest, '_app.min.css'), - sources: combined.stylesheet, - debug: debug, - optimizations: optimization - }); - - const sfile = _path.join(dest, 'scheme.html'); - if ( _fs.existsSync(sfile) ) { - let scheme = String(_fs.readFileSync(sfile)); - - const found = scheme.match(//g); - if ( found ) { - found.forEach((f) => { - let src = f.split(//)[1]; - src = _path.join(dest, src); - - if ( src && _fs.existsSync(src) ) { - scheme = scheme.replace(f, String(_fs.readFileSync(src))); - remove.push(src); - } - }); - } - - _fs.writeFileSync(sfile, scheme); - } - - remove.forEach((f) => { - _fs.removeSync(f); - _fs.removeSync(f + '.map'); - }); - - if ( standalone ) { - createStandaloneScheme(iter, dest); - } - - iter.preload = _manifest.combinePreloads(iter); - if ( iter._src ) { - delete iter._src; - } - - _fs.writeFileSync(_path.join(dest, 'metadata.json'), JSON.stringify(iter, null, 4)); - - resolve(iter); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -function _buildPackage(cli, cfg, name, metadata) { - const verbose = cli.option('verbose'); - const standalone = cli.option('standalone'); - const debug = cli.option('debug'); - const optimization = cli.option('optimization', false); - const noclean = cli.option('noclean', false); - - return new Promise((resolve, reject) => { - const src = _path.resolve(ROOT, metadata._src); //_path.join(ROOT, 'src', 'packages', name); - const dest = _path.join(ROOT, 'dist', 'packages', name); - - _utils.eachp([ - function() { - _logger.log('Building', _logger.color(name, 'blue,bold')); - - _utils.removeSilent(dest); - _utils.mkdirSilent(dest); - - return Promise.resolve(); - }, - function() { - return runBuildScripts(verbose, 'before', metadata, src, dest); - }, () => { - return copyResources(verbose, metadata, src, dest, noclean); - }, () => { - return buildLess(debug, verbose, metadata, src, dest); - }, () => { - return new Promise((yes, no) => { - return combineResources(standalone, metadata, src, dest, debug, optimization).then((data) => { - metadata = data; // Make sure we set new metadata after changes - yes(); - }).catch(no); - }); - }, () => { - return runBuildScripts(verbose, 'after', metadata, src, dest); - } - ]).then(resolve).catch(reject); - }); -} - -/* - * Builds given package - */ -function buildPackage(cli, cfg, name, metadata) { - return new Promise((resolve, reject) => { - function _build(meta) { - _buildPackage(cli, cfg, name, meta).then(resolve).catch(reject); - } - - if ( metadata ) { - _build(metadata); - } else { - _manifest.getPackage(name).then((meta) => { - _build(meta); - }); - } - }); -} - -/* - * Builds all packages - */ -function buildPackages(cli, cfg) { - return new Promise((resolve, reject) => { - const cliRepos = cli.option('repositories', ''); - const repos = cliRepos.length ? cliRepos.split(',') : cfg.repositories; - _manifest.getPackages(repos).then((packages) => { - _utils.eachp(Object.keys(packages).map((iter) => { - return function() { - return buildPackage(cli, cfg, packages[iter].path, packages[iter]); - }; - })).catch(reject).then(resolve); - }).catch(reject); - }); -} - -/* - * Cleans up build files - */ -function cleanFiles() { - _utils.removeSilent(_path.join(ROOT, 'dist', 'packages')); - return Promise.resolve(); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.buildPackages = buildPackages; -module.exports.buildPackage = buildPackage; -module.exports.clean = cleanFiles; diff --git a/src/build/themes.js b/src/build/themes.js deleted file mode 100644 index a940bb3da2..0000000000 --- a/src/build/themes.js +++ /dev/null @@ -1,364 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _glob = require('glob-promise'); -const _fs = require('fs-extra'); - -const _utils = require('./utils.js'); -const _logger = _utils.logger; - -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Gets the correct template directory - */ -function getTemplatePath(cfg, category, name) { - const paths = [ - _path.join(ROOT, 'src', 'client', 'themes', category, name) - ]; - - _utils.enumOverlayPaths(cfg, 'themes', (p) => { - const rel = _path.resolve(ROOT, p); - paths.push(_path.join(rel, category, name)); - }); - - return paths.filter((p) => { - return _fs.existsSync(p); - })[0]; -} - -/////////////////////////////////////////////////////////////////////////////// -// API -/////////////////////////////////////////////////////////////////////////////// - -/* - * Reads all theme metadata - */ -function readMetadata(cfg) { - - const themes = _path.join(ROOT, 'src', 'client', 'themes'); - - const result = { - fonts: [], - icons: [], - sounds: [], - styles: [] - }; - - function _readMetadata(dir, whitelist) { - - return new Promise((resolve, reject) => { - whitelist = whitelist || []; - - _glob(_path.join(themes, dir, '*', 'metadata.json')).then((files) => { - const list = files.filter((check) => { - const d = _path.basename(_path.dirname(check)); - return whitelist.indexOf(d) >= 0; - }).map((check) => { - return _fs.readJsonSync(check); - }); - - resolve(list); - }); - }); - } - - function _readFonts(dir, whitelist) { - return new Promise((resolve, reject) => { - _glob(_path.join(themes, dir, '*', 'style.css')).then((files) => { - resolve(files.map((check) => { - return _path.basename(_path.dirname(check)); - })); - }); - }); - } - - return new Promise((resolve, reject) => { - return Promise.all([ - new Promise((yes, no) => { - _readFonts('fonts', cfg.themes.fonts).then((list) => { - result.fonts = list; - yes(); - }).catch(no); - }), - new Promise((yes, no) => { - _readMetadata('icons', cfg.themes.icons).then((list) => { - result.icons = list; - yes(); - }).catch(no); - }), - new Promise((yes, no) => { - _readMetadata('sounds', cfg.themes.sounds).then((list) => { - result.sounds = list; - yes(); - }).catch(no); - }), - new Promise((yes, no) => { - _readMetadata('styles', cfg.themes.styles).then((list) => { - result.styles = list; - yes(); - }).catch(no); - }) - ]).then(() => { - resolve(result); - }).catch(reject); - }); -} - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Builds fonts - */ -function buildFonts(cli, cfg) { - return new Promise((resolve, reject) => { - _utils.mkdirSilent(_path.join(ROOT, 'dist', 'themes', 'fonts')); - - let rep = cfg.client.Connection.FontURI; - if ( !rep.match(/^\//) ) { // Fix for relative paths (CSS) - rep = rep.replace(/^\w+\//, ''); - } - - const concated = cfg.themes.fonts.map((iter) => { - _logger.log('Building font pack', _logger.color(iter, 'blue,bold')); - - const src = getTemplatePath(cfg, 'fonts', iter); - const dst = _path.join(ROOT, 'dist', 'themes', 'fonts', iter); - - _fs.copySync(src, dst); - _utils.removeSilent(_path.join(dst, 'metadata.json')); - - const file = _path.join(dst, 'style.css'); - const css = _fs.readFileSync(file, 'utf8'); - return css.replace(/\%FONTURI\%/g, rep); - }); - - const src = _path.join(ROOT, 'dist', 'themes', 'fonts.css'); - const dest = _path.join(ROOT, 'dist', 'themes', 'fonts.min.css'); - _fs.writeFileSync(src, concated.join('\n')); - _utils.writeStyles({ - dest: dest, - sources: [src], - debug: cli.option('debug'), - optimizations: cli.option('optimization', false) - }); - _utils.removeSilent(src); - - resolve(); - }); -} - -/* - * Builds sound files - */ -function buildSounds(cli, cfg) { - return new Promise((resolve, reject) => { - - const sdst = _path.join(ROOT, 'dist', 'themes', 'sounds'); - _utils.mkdirSilent(sdst); - - cfg.themes.sounds.forEach((i) => { - _logger.log('Building sound pack', _logger.color(i, 'blue,bold')); - - const src = getTemplatePath(cfg, 'sounds', i); - const dst = _path.join(ROOT, 'dist', 'themes', 'sounds', i); - _fs.copySync(src, dst); - _utils.removeSilent(_path.join(dst, 'metadata.json')); - }); - - resolve(); - }); -} - -/* - * Builds static files - */ -function buildStatic(cli, cfg) { - return new Promise((resolve, reject) => { - _logger.log('Copying statics', _logger.color('wallpapers', 'blue,bold')); - - const dst = _path.join(ROOT, 'dist', 'themes', 'wallpapers'); - - const src = _path.join(ROOT, 'src', 'client', 'themes', 'wallpapers'); - _fs.copySync(src, dst); - - _utils.enumOverlayPaths(cfg, 'themes', (p) => { - const rel = _path.resolve(ROOT, p); - const dir = _path.join(rel, 'wallpapers'); - if ( _fs.existsSync(dir) ) { - _fs.copySync(dir, dst); - } - }); - - resolve(); - }); -} - -/* - * Builds icon packs - */ -function buildIcon(cli, cfg, name) { - - function _buildIcon(n) { - return new Promise((resolve) => { - _logger.log('Building icon pack', _logger.color(n, 'blue,bold')); - - const src = getTemplatePath(cfg, 'icons', n); - const dst = _path.join(ROOT, 'dist', 'themes', 'icons', n); - _utils.mkdirSilent(dst); - - function _next() { - _utils.removeSilent(_path.join(dst, 'metadata.json')); - _fs.copySync(src, dst); - - resolve(); - } - - const metafile = _path.join(src, 'metadata.json'); - const metadata = _fs.readJsonSync(metafile); - - if ( !metadata.parent ) { - _next(); - return; - } - - const psrc = _path.join(ROOT, 'src', 'client', 'themes', 'icons', metadata.parent); - _fs.copySync(psrc, dst); - - _next(); - }); - } - - const list = name ? [name] : cfg.themes.icons; - return Promise.all(list.map((n) => { - return _buildIcon(n); - })); -} - -/* - * Builds styles - */ -function buildStyle(cli, cfg, name) { - const debug = cli.option('debug'); - - function _buildStyle(n) { - return new Promise((resolve) => { - _logger.log('Building style', _logger.color(n, 'blue,bold')); - - const src = getTemplatePath(cfg, 'styles', n); - const dst = _path.join(ROOT, 'dist', 'themes', 'styles'); - - _utils.mkdirSilent(dst); - _fs.copySync(src, _path.join(dst, n)); - - const from = _path.join(src, 'style.less'); - const to = _path.join(dst, n + '.css'); - - let base = 'theme.less'; - try { - base = cfg.themes.styleBase; - } catch ( e ) {} - - if ( cli.option('verbose') ) { - console.log('$ less', from.replace(ROOT + '/', ''), to.replace(ROOT + '/', '')); - } - - _utils.compileLess(debug, from, to, { - sourceMap: {}, - paths: [ - '.', - _path.join(ROOT, 'src', 'client', 'themes'), - _path.join(ROOT, 'src', 'client', 'stylesheets') - ] - }, (err) => { - if ( !err ) { - _utils.removeSilent(_path.join(dst, n, 'metadata.json')); - _utils.removeSilent(_path.join(dst, n, 'style.less')); - } - - resolve(); - }, (css) => { - const header = '@import "' + base + '";\n\n'; - return header + css; - }); - }); - } - - const list = name ? [name] : cfg.themes.styles; - return Promise.all(list.map((n) => { - return _buildStyle(n); - })); -} - -/* - * Builds everything - */ -function buildAll(cli, cfg) { - const only = cli.option('only'); - - return Promise.all([ - !only || only === 'fonts' ? buildFonts(cli, cfg) : Promise.resolve(), - !only || only === 'sounds' ? buildSounds(cli, cfg) : Promise.resolve(), - !only || only === 'static' ? buildStatic(cli, cfg) : Promise.resolve(), - !only || only === 'icons' ? buildIcon(cli, cfg) : Promise.resolve(), - !only || only === 'styles' ? buildStyle(cli, cfg) : Promise.resolve() - ]); -} - -/* - * Cleans up build files - */ -function cleanFiles() { - _utils.removeSilent(_path.join(ROOT, 'dist', 'themes')); - return Promise.resolve(); -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -module.exports.readMetadata = readMetadata; -module.exports.buildAll = buildAll; -module.exports.buildStyle = buildStyle; -module.exports.buildIcon = buildIcon; -module.exports.buildStatic = buildStatic; -module.exports.buildFonts = buildFonts; -module.exports.buildSounds = buildSounds; -module.exports.clean = cleanFiles; diff --git a/src/build/utils.js b/src/build/utils.js deleted file mode 100644 index b742d33cd1..0000000000 --- a/src/build/utils.js +++ /dev/null @@ -1,373 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _path = require('path'); -const _less = require('less'); -const _fs = require('fs-extra'); -const _os = require('os'); - -const ISWIN = /^win/.test(process.platform); -const ROOT = _path.dirname(_path.dirname(_path.join(__dirname))); - -const _ugly = require('uglify-js'); -const Cleancss = require('clean-css'); - -require('colors'); - -/* - * Filter a file reference by string - */ -function _filter(i, debug) { - if ( i.match(/^dev:/) && !debug ) { - return false; - } - if ( i.match(/^prod:/) && debug ) { - return false; - } - return true; -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Fixes Windows paths - */ -module.exports.fixWinPath = function fixWinPath(str) { - if ( typeof str === 'string' && ISWIN ) { - return str.replace(/(["\s'$`\\])/g, '\\$1').replace(/\\+/g, '/'); - } - return str; -}; - -/* - * Logging proxy - */ -module.exports.log = function log() { - const str = Array.prototype.slice.call(arguments).join(' '); - console.log(module.exports.replaceAll(str, ROOT + '/', '')); -}; - -/* - * Reads a template - */ -module.exports.readTemplate = function readTemplate(name) { - const tpls = _path.join(ROOT, 'src', 'templates'); - return _fs.readFileSync(_path.join(tpls, name)).toString(); -}; - -/* - * Replace all occurences of something - */ -module.exports.replaceAll = function replaceAll(temp, stringToFind, stringToReplace) { - let index = temp.indexOf(stringToFind); - while (index !== -1) { - temp = temp.replace(stringToFind, stringToReplace); - index = temp.indexOf(stringToFind); - } - return temp; -}; - -/* - * Supresses errors while removing files - */ -module.exports.removeSilent = function removeSilent(file) { - try { - if ( _fs.existsSync(file) ) { - _fs.removeSync(file); - - return true; - } - } catch (e) {} - - return false; -}; - -/* - * Supresses errors while making directories - */ -module.exports.mkdirSilent = function mkdirSilent(file) { - try { - _fs.mkdirSync(file); - } catch (e) {} -}; - -/* - * Make a dictionary from list - */ -module.exports.makedict = function makedict(list, fn) { - let result = {}; - list.forEach((iter, idx) => { - let data = fn(iter, idx); - result[data[0]] = data[1]; - }); - return result; -}; - -/* - * Merges given objects together - */ -module.exports.mergeObject = function mergeObject(into, from) { - function mergeJSON(obj1, obj2) { - for ( let p in obj2 ) { - if ( obj2.hasOwnProperty(p) ) { - try { - if ( obj2[p].constructor === Object ) { - obj1[p] = mergeJSON(obj1[p], obj2[p]); - } else { - obj1[p] = obj2[p]; - } - } catch (e) { - obj1[p] = obj2[p]; - } - } - } - return obj1; - } - return mergeJSON(into, from); -}; - -/* - * Compiles given less file - */ -module.exports.compileLess = function compileLess(debug, src, dest, opts, cb, onRead) { - try { - let css = _fs.readFileSync(src).toString(); - if ( typeof onRead === 'function' ) { - css = onRead(css); - } - - _less.render(css, opts).then((result) => { - _fs.writeFileSync(dest, result.css); - _fs.writeFileSync(dest + '.map', result.map); - - const footer = '\n/*# sourceMappingURL=' + _path.basename(dest.replace(/\.css$/, '.min.css.map')) + ' */'; - - try { - const minified = new Cleancss({ - sourceMapInlineSources: debug, - sourceMap: true - }).minify(_fs.readFileSync(dest), _fs.readJsonSync(dest + '.map')); - - _fs.writeFileSync(dest.replace(/\.css$/, '.min.css'), minified.styles + footer); - _fs.writeFileSync(dest.replace(/\.css$/, '.min.css.map'), minified.sourceMap); - } catch ( e ) { - console.warn(e); - } - - module.exports.removeSilent(dest, result.css); - module.exports.removeSilent(dest + '.map', result.map); - - cb(false, true); - }, (error) => { - console.warn(error); - cb(error); - }); - } catch ( e ) { - console.warn(e, e.stack); - cb(e); - } -}; - -/* - * Creates standalone scheme files - */ -module.exports.createStandaloneScheme = function createStandaloneScheme(src, name, dest) { - let data = module.exports.addslashes(_fs.readFileSync(src).toString().replace(/\n/g, '')); - - let tpl = module.exports.readTemplate('dist/schemes.js'); - tpl = tpl.replace('%DATA%', data); - tpl = tpl.replace('%NAME%', name); - - _fs.writeFileSync(dest, tpl); -}; - -/* - * Escapes given string - */ -module.exports.addslashes = function addslashes(str) { - return (str + '').replace(/[\\"']/g, '\\$&').replace(/\u0000/g, '\\0'); -}; - -/* - * Helper for running promises in sequence - */ -module.exports.eachp = function(list, onentry) { - onentry = onentry || function() {}; - - return new Promise((resolve, reject) => { - (function next(i) { - if ( i >= list.length ) { - resolve(); - return; - } - - const iter = list[i](); - iter.then((arg) => { - onentry(arg); - next(i + 1); - }).catch(reject); - })(0); - }); -}; - -/* - * Logging helper - */ -module.exports.logger = { - log: function() { - console.log.apply(console, arguments); - }, - warn: function() { - console.warn.apply(console, arguments); - }, - info: function() { - console.info.apply(console, arguments); - }, - error: function() { - console.error.apply(console, arguments); - }, - color: (str, color) => { - str = String(str); - color.split(',').forEach((key) => { - str = str[key.trim()] || str; - }); - return str; - } -}; - -/* - * Helper for compiling scripts - */ -module.exports.writeScripts = function writeScripts(write) { - const outm = write.dest.replace(/\.min\.js$/, '.min.js.map'); - const header = module.exports.readTemplate('dist/header.js'); - const headerFile = _path.join(_os.tmpdir(), '__header.js'); - const finalList = [headerFile].concat(write.sources.filter((i) => { - return _filter(i, write.debug); - }).map((i) => { - if ( write.verbose ) { - console.log(i); - } - - if ( i.match(/^(dev|prod):/) ) { - return _path.join(ROOT, i.replace(/^(dev|prod):/, '')); - } - - return i; - })); - - _fs.writeFileSync(headerFile, header); - - const pureFuncs = write.debug ? [] : ['console.log', 'console.group', 'console.groupEnd', 'console.warn', 'console.info', 'console.dir', 'console.debug']; - let compression = { - pure_funcs: pureFuncs - }; - - if ( write.optimizations === 'none' ) { - compression = false; - } else if ( write.optimizations === 'all' ) { - compression.passes = 2; - } - - const minified = _ugly.minify(finalList, { - sourceMapIncludeSources: write.debug, - outSourceMap: _path.basename(outm), - compress: compression, - output: { - comments: /\*!/ - } - }); - - _fs.writeFileSync(write.dest, minified.code); - _fs.writeFileSync(outm, minified.map); - module.exports.removeSilent(headerFile); -}; - -/* - * Helper for compiling stylesheets - */ -module.exports.writeStyles = function writeStyles(write) { - const outm = write.dest.replace(/\.min\.css$/, '.min.css.map'); - const header = module.exports.readTemplate('dist/header.css'); - const headerFile = _path.join(_os.tmpdir(), '__header.css'); - const finalList = [headerFile].concat(write.sources.filter((i) => { - return _filter(i, write.debug); - }).map((i) => { - if ( write.verbose ) { - console.log(i); - } - return i.substr(0, 1) === '/' ? i : _path.join(ROOT, i.replace(/^(dev|prod):/, '')); - })); - - _fs.writeFileSync(headerFile, header); - - let compressionLevel = 1; - if ( write.optimizations === 'none' ) { - compressionLevel = 0; - } else if ( write.optimizations === 'all' ) { - compressionLevel = 2; - } - - const minified = new Cleancss({ - level: compressionLevel, - rebase: false, - sourceMapInlineSources: write.debug, - sourceMap: true - }).minify(finalList); - - const footer = '\n/*# sourceMappingURL=' + _path.basename(outm) + ' */'; - _fs.writeFileSync(write.dest, minified.styles + footer); - _fs.writeFileSync(outm, minified.sourceMap); - module.exports.removeSilent(headerFile); -}; - -/* - * Helper for enumerating overlay paths - */ -module.exports.enumOverlayPaths = function enumOverlayPaths(cfg, key, onentry) { - const overlays = cfg.build.overlays; - const paths = []; - - if ( overlays ) { - Object.keys(overlays).forEach((n) => { - const overlay = overlays[n]; - if ( overlay[key] instanceof Array ) { - overlay[key].forEach(onentry); - } - }); - } - - return paths; -}; diff --git a/src/build/watcher.js b/src/build/watcher.js deleted file mode 100644 index 3d36c9d340..0000000000 --- a/src/build/watcher.js +++ /dev/null @@ -1,228 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _index = require('./index.js'); -const _utils = require('./utils.js'); -const _config = require('./config.js'); - -const _chokidar = require('chokidar'); -const _path = require('path'); - -/////////////////////////////////////////////////////////////////////////////// -// HELPERS -/////////////////////////////////////////////////////////////////////////////// - -function log() { - var args = Array.prototype.slice.call(arguments); - args.unshift(new Date()); - console.log(args.join(' ')); -} - -function getBasedDirectory(path, watchdir) { - const basedir = _utils.fixWinPath(watchdir).replace(/\*+\/?/g, ''); - return _utils.fixWinPath(path).replace(basedir, ''); -} - -function getPackageFromPath(path, watchdir) { - const rdir = getBasedDirectory(path, watchdir); - const temp = rdir.split('/', 3); - const repository = temp[0]; - const packageName = temp[1]; - return repository + '/' + packageName; -} - -const runTask = (() => { - const timeouts = {}; - - function completed() { - console.log('\n'); - log('... done ...'); - } - - function failed(error) { - console.error('Something went wrong', error); - } - - return (t, ik, iv, debug) => { - const hash = [t, ik, iv].join(' '); - if ( timeouts[hash] ) { - clearTimeout(timeouts[hash]); - } - - timeouts[hash] = setTimeout(function() { - console.log('\n'); - _index.build({ - option: (k) => { - if ( k === 'debug' ) { - return debug; - } - return ik === null ? null : (k === ik ? iv : null); - } - }, t).then(completed).catch(failed); - }, 250); - }; -})(); - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -function watchDist(path, stats, watchdir, debug) { - log('Dist files changed'); - runTask('dist', null, null, debug); -} - -function watchCore(path, stats, watchdir, debug) { - const rdir = getBasedDirectory(path, watchdir); - - if ( rdir.match(/^\/locales\//) ) { - log('Base locales changed'); - runTask('core', 'only', 'locale', debug); - } else if ( path.match(/\.css$/) ) { - log('Base styles changed'); - runTask('core', 'only', 'css', debug); - } else if ( path.match(/\.js$/) ) { - log('Base scripts changed'); - runTask('core', 'only', 'javascript', debug); - } else if ( path.match(/\.less$/) ) { - log('Base theme changed'); - runTask('themes', 'only', 'styles', debug); - } else { - log('Core files changed'); - - runTask('core', null, null, debug); - } -} - -function watchThemes(path, stats, watchdir, debug) { - const rdir = getBasedDirectory(path, watchdir); - const name = rdir.split('/', 2)[1]; - - if ( path.match(/metadata\.json$/) ) { - log('Theme metadata changed'); - runTask('config', null, null, debug); - } else if ( rdir.match(/^icons/) ) { - log('Icon theme changed', name); - runTask('theme', 'icons', name, debug); - } else if ( rdir.match(/^wallpapers|sounds/) ) { - log('Theme files changed'); - runTask('theme', 'static', true, debug); - } else if ( rdir.match(/^font/) ) { - log('Fonts changed'); - runTask('theme', 'fonts', true, debug); - } else if ( rdir.match(/^styles/) ) { - log('Style theme changed', name, debug); - runTask('theme', 'style', name, debug); - } -} - -function watchConfig(path, stats, watchdir, debug) { - log('Configuration has changed'); - runTask('config', null, null, debug); -} - -function watchPackages(path, stats, watchdir, debug) { - const fullName = getPackageFromPath(path, watchdir); - if ( _path.basename(path) === 'metadata.json' ) { - log('Package manifest changed for', fullName); - runTask('manifest', null, null, debug); - } else { - log('Package sources changed for', fullName); - runTask('package', 'name', fullName, debug); - } -} - -/////////////////////////////////////////////////////////////////////////////// -// EXPORTS -/////////////////////////////////////////////////////////////////////////////// - -/* - * Watch for changes - */ -module.exports.watch = function watch(cli) { - const debug = cli.option('debug'); - const root = _path.dirname(_path.dirname(_path.join(__dirname))); - const paths = { - 'src/templates/dist/**/*': watchDist, - 'src/client/javascript/**/*': watchCore, - 'src/client/stylesheets/*': watchCore, - 'src/client/themes/**/*': watchThemes, - 'src/conf/*': watchConfig, - 'src/packages/*/**': watchPackages - }; - - return new Promise((resolve, reject) => { - - _config.getConfiguration().then((cfg) => { - if ( cfg.build.overlays ) { - Object.keys(cfg.build.overlays).forEach((name) => { - const overlay = cfg.build.overlays[name]; - (overlay.packages || []).forEach((p) => { - paths[p + '/*/**'] = watchPackages; - }); - (overlay.templates || []).forEach((p) => { - paths[p + '/dist/**/*'] = watchDist; - }); - - (overlay.javascript || []).forEach((p) => { - paths[p] = watchCore; - }); - (overlay.locales || []).forEach((p) => { - paths[p] = watchCore; - }); - (overlay.stylesheets || []).forEach((p) => { - paths[p] = watchCore; - }); - }); - } - - Object.keys(paths).forEach((p) => { - const path = _path.join(root, p); - const fn = (res, stats) => { - log('>>>', getBasedDirectory(res, path)); - - paths[p](res, stats, path, debug); - }; - - log('Watching', p); - - _chokidar.watch(path, { - ignored: /node_modules|\.git|\.swo|\.swp/, - ignoreInitial: true, - persistent: true - }).on('add', fn).on('change', fn); - - }); - }); - }); -}; - diff --git a/src/client/javascript/boot.js b/src/client/javascript/boot.js new file mode 100644 index 0000000000..ece5210b64 --- /dev/null +++ b/src/client/javascript/boot.js @@ -0,0 +1,71 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +// +// Makes sure a global namespace is available +// +window.OSjs = Object.assign({ + error: (title, message, error, exception, bugreport) => { + console.error(title, message, error, exception); + }, + runTests: () => { + // void + }, + getConfig: () => { + return {}; + }, + getManifest: () => { + return {}; + }, + Themes: {}, + Dialogs: {}, + Locales: {}, + Extensions: {}, + Applications: {} +}, window.OSjs || {}); + +// +// This allows packages to require modules almost like normal +// +window.OSjs.require = (n) => { + const mod = require('./' + n); + return mod && mod.default ? mod.default : mod; +}; + +// +// Then proceed to start up +// +import {start} from 'core/init'; + +if ( document.readyState !== 'loading' ) { + start(); +} else { + document.addEventListener('DOMContentLoaded', () => start()); +} diff --git a/src/client/javascript/broadway/broadway.js b/src/client/javascript/broadway/broadway.js deleted file mode 100644 index 03697328bf..0000000000 --- a/src/client/javascript/broadway/broadway.js +++ /dev/null @@ -1,1116 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -(function(Application, Window, Utils, VFS, GUI, API) { - 'use strict'; - - /** - * This script is based on https://github.com/GNOME/gtk/tree/master/gdk/broadway - * and was made to fit with OS.js - * - * @namespace Broadway - * @memberof OSjs - */ - - ///////////////////////////////////////////////////////////////////////////// - // CONSTANTS - ///////////////////////////////////////////////////////////////////////////// - - var GDK_CROSSING_NORMAL = 0; - //var GDK_CROSSING_GRAB = 1; - //var GDK_CROSSING_UNGRAB = 2; - - // GdkModifierType - var GDK_SHIFT_MASK = 1 << 0; - //var GDK_LOCK_MASK = 1 << 1; - var GDK_CONTROL_MASK = 1 << 2; - var GDK_MOD1_MASK = 1 << 3; - //var GDK_MOD2_MASK = 1 << 4; - //var GDK_MOD3_MASK = 1 << 5; - //var GDK_MOD4_MASK = 1 << 6; - //var GDK_MOD5_MASK = 1 << 7; - var GDK_BUTTON1_MASK = 1 << 8; - var GDK_BUTTON2_MASK = 1 << 9; - var GDK_BUTTON3_MASK = 1 << 10; - var GDK_BUTTON4_MASK = 1 << 11; - var GDK_BUTTON5_MASK = 1 << 12; - //var GDK_SUPER_MASK = 1 << 26; - //var GDK_HYPER_MASK = 1 << 27; - //var GDK_META_MASK = 1 << 28; - //var GDK_RELEASE_MASK = 1 << 30; - - var ON_KEYDOWN = 1 << 0; /* Report on keydown, otherwise wait until keypress */ - - var specialKeyTable = { - // These generate a keyDown and keyPress in Firefox and Opera - 8: [0xFF08, ON_KEYDOWN], // BACKSPACE - 13: [0xFF0D, ON_KEYDOWN], // ENTER - - // This generates a keyDown and keyPress in Opera - 9: [0xFF09, ON_KEYDOWN], // TAB - - 27: 0xFF1B, // ESCAPE - 46: 0xFFFF, // DELETE - 36: 0xFF50, // HOME - 35: 0xFF57, // END - 33: 0xFF55, // PAGE_UP - 34: 0xFF56, // PAGE_DOWN - 45: 0xFF63, // INSERT - 37: 0xFF51, // LEFT - 38: 0xFF52, // UP - 39: 0xFF53, // RIGHT - 40: 0xFF54, // DOWN - 16: 0xFFE1, // SHIFT - 17: 0xFFE3, // CONTROL - 18: 0xFFE9, // Left ALT (Mac Command) - 112: 0xFFBE, // F1 - 113: 0xFFBF, // F2 - 114: 0xFFC0, // F3 - 115: 0xFFC1, // F4 - 116: 0xFFC2, // F5 - 117: 0xFFC3, // F6 - 118: 0xFFC4, // F7 - 119: 0xFFC5, // F8 - 120: 0xFFC6, // F9 - 121: 0xFFC7, // F10 - 122: 0xFFC8, // F11 - 123: 0xFFC9 // F12 - }; - - ///////////////////////////////////////////////////////////////////////////// - // GLOBALS - ///////////////////////////////////////////////////////////////////////////// - - var ws = null; - var lastSerial = 0; - var lastState; - var lastTimeStamp = 0; - var surfaces = {}; - var keyDownList = []; - var outstandingCommands = []; - - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - function BinCommands(message) { - this.arraybuffer = message; - this.u8 = new Uint8Array(message); - this.length = this.u8.length; - this.pos = 0; - } - - BinCommands.prototype.get_char = function() { - return String.fromCharCode(this.u8[this.pos++]); - }; - - BinCommands.prototype.get_bool = function() { - return this.u8[this.pos++] !== 0; - }; - - BinCommands.prototype.get_flags = function() { - return this.u8[this.pos++]; - }; - - BinCommands.prototype.get_16 = function() { - var v = this.u8[this.pos] + (this.u8[this.pos + 1] << 8); - this.pos = this.pos + 2; - return v; - }; - - BinCommands.prototype.get_16s = function() { - var v = this.get_16(); - return (v > 32767) ? v - 65536 : v; - }; - - BinCommands.prototype.get_32 = function() { - var v = - this.u8[this.pos] + - (this.u8[this.pos + 1] << 8) + - (this.u8[this.pos + 2] << 16) + - (this.u8[this.pos + 3] << 24); - - this.pos = this.pos + 4; - return v; - }; - - BinCommands.prototype.get_data = function() { - var size = this.get_32(); - var data = new Uint8Array(this.arraybuffer, this.pos, size); - this.pos = this.pos + size; - return data; - }; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - function resizeCanvas(canvas, w, h) { - var tmpCanvas = canvas.ownerDocument.createElement('canvas'); - tmpCanvas.width = canvas.width; - tmpCanvas.height = canvas.height; - var tmpContext = tmpCanvas.getContext('2d'); - tmpContext.globalCompositeOperation = 'copy'; - tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height); - - canvas.width = w; - canvas.height = h; - - var context = canvas.getContext('2d'); - context.globalCompositeOperation = 'copy'; - context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height); - } - - function copyRect(src, srcX, srcY, dest, destX, destY, width, height) { - // Clip to src - if (srcX + width > src.width) { - width = src.width - srcX; - } - if (srcY + height > src.height) { - height = src.height - srcY; - } - - // Clip to dest - if (destX + width > dest.width) { - width = dest.width - destX; - } - if (destY + height > dest.height) { - height = dest.height - destY; - } - - var srcRect = src.width * 4 * srcY + srcX * 4; - var destRect = dest.width * 4 * destY + destX * 4; - - for (var i = 0; i < height; i++) { - var line = src.data.subarray(srcRect, srcRect + width * 4); - dest.data.set(line, destRect); - srcRect += src.width * 4; - destRect += dest.width * 4; - } - } - - function decodeBuffer(context, oldData, w, h, data, debug) { - var i; - var imageData = context.createImageData(w, h); - - if ( oldData !== null ) { - // Copy old frame into new buffer - copyRect(oldData, 0, 0, imageData, 0, 0, oldData.width, oldData.height); - } - - var src = 0; - var dest = 0; - - while (src < data.length) { - var b = data[src++]; - var g = data[src++]; - var r = data[src++]; - var alpha = data[src++]; - var len; - - if (alpha !== 0) { - imageData.data[dest++] = r; - imageData.data[dest++] = g; - imageData.data[dest++] = b; - imageData.data[dest++] = alpha; - } else { - var cmd = r & 0xf0; - switch (cmd) { - case 0x00: // Transparent pixel - //log("Got transparent"); - imageData.data[dest++] = 0; - imageData.data[dest++] = 0; - imageData.data[dest++] = 0; - imageData.data[dest++] = 0; - break; - - case 0x10: // Delta 0 run - len = (r & 0xf) << 16 | g << 8 | b; - //log("Got delta0, len: " + len); - dest += len * 4; - break; - - case 0x20: // Block reference - var blockid = (r & 0xf) << 16 | g << 8 | b; - - var block_stride = (oldData.width + 32 - 1) / 32 | 0; - var srcY = (blockid / block_stride | 0) * 32; - var srcX = (blockid % block_stride | 0) * 32; - - b = data[src++]; - g = data[src++]; - r = data[src++]; - alpha = data[src++]; - - var destX = alpha << 8 | r; - var destY = g << 8 | b; - - copyRect(oldData, srcX, srcY, imageData, destX, destY, 32, 32); - //log("Got block, id: " + blockid + "(" + srcX +"," + srcY + ") at " + destX + "," + destY); - - break; - - case 0x30: // Color run - len = (r & 0xf) << 16 | g << 8 | b; - //log("Got color run, len: " + len); - - b = data[src++]; - g = data[src++]; - r = data[src++]; - alpha = data[src++]; - - for (i = 0; i < len; i++) { - imageData.data[dest++] = r; - imageData.data[dest++] = g; - imageData.data[dest++] = b; - imageData.data[dest++] = alpha; - } - - break; - - case 0x40: // Delta run - len = (r & 0xf) << 16 | g << 8 | b; - //log("Got delta run, len: " + len); - - b = data[src++]; - g = data[src++]; - r = data[src++]; - alpha = data[src++]; - - for (i = 0; i < len; i++) { - imageData.data[dest] = (imageData.data[dest] + r) & 0xff; - dest++; - imageData.data[dest] = (imageData.data[dest] + g) & 0xff; - dest++; - imageData.data[dest] = (imageData.data[dest] + b) & 0xff; - dest++; - imageData.data[dest] = (imageData.data[dest] + alpha) & 0xff; - dest++; - } - break; - - default: - console.error('Unknown buffer commend ' + cmd); - } - } - } - - return imageData; - } - - function getLayer(ev, id) { - var cid = id; - if ( ev.target ) { - var tmp = ev.target.getAttribute('data-surface-id'); - if ( tmp ) { - cid = parseInt(tmp, 10); - } - } - return cid; - } - - ///////////////////////////////////////////////////////////////////////////// - // ACTIONS - ///////////////////////////////////////////////////////////////////////////// - - function sendInput(cmd, args) { - if ( ws === null ) { - return; - } - - var fullArgs = [cmd.charCodeAt(0), lastSerial, lastTimeStamp].concat(args); - var buffer = new window.ArrayBuffer(fullArgs.length * 4); - var view = new window.DataView(buffer); - fullArgs.forEach(function(arg, i) { - view.setInt32(i * 4, arg, false); - }); - - ws.send(buffer); - } - - ///////////////////////////////////////////////////////////////////////////// - // INPUT - ///////////////////////////////////////////////////////////////////////////// - - function updateForEvent(ev) { - lastState &= ~(GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK); - if (ev.shiftKey) { - lastState |= GDK_SHIFT_MASK; - } - if (ev.ctrlKey) { - lastState |= GDK_CONTROL_MASK; - } - if (ev.altKey) { - lastState |= GDK_MOD1_MASK; - } - - lastTimeStamp = ev.timeStamp; - } - - function getButtonMask(button) { - if (button === 1) { - return GDK_BUTTON1_MASK; - } - if (button === 2) { - return GDK_BUTTON2_MASK; - } - if (button === 3) { - return GDK_BUTTON3_MASK; - } - if (button === 4) { - return GDK_BUTTON4_MASK; - } - if (button === 5) { - return GDK_BUTTON5_MASK; - } - return 0; - } - - function cancelEvent(ev) { - ev = ev ? ev : window.event; - - if ( ev.stopPropagation ) { - ev.stopPropagation(); - } - if ( ev.preventDefault ) { - ev.preventDefault(); - } - ev.cancelBubble = true; - ev.cancel = true; - ev.returnValue = false; - - return false; - } - - function copyKeyEvent(ev) { - var members = ['type', 'keyCode', 'charCode', 'which', - 'altKey', 'ctrlKey', 'shiftKey', - 'keyLocation', 'keyIdentifier']; - - var i, obj = {}; - for ( i = 0; i < members.length; i++ ) { - if ( typeof ev[members[i]] !== 'undefined' ) { - obj[members[i]] = ev[members[i]]; - } - } - return obj; - } - - function getEventKeySym(ev) { - if (typeof ev.which !== 'undefined' && ev.which > 0) { - return ev.which; - } - return ev.keyCode; - } - - function getKeysym(ev) { - var keysym = getEventKeySym(ev); - var unicodeTable = OSjs.Broadway.unicodeTable; - if ((keysym > 255) && (keysym < 0xFF00)) { - // Map Unicode outside Latin 1 to gdk keysyms - keysym = unicodeTable[keysym]; - if (typeof keysym === 'undefined') { - keysym = 0; - } - } - - return keysym; - } - - function ignoreKeyEvent(ev) { - // Blarg. Some keys have a different keyCode on keyDown vs keyUp - if ( ev.keyCode === 229 ) { - // French AZERTY keyboard dead key. - // Lame thing is that the respective keyUp is 219 so we can't - // properly ignore the keyUp event - return true; - } - return false; - } - - // This is based on the approach from noVNC. We handle - // everything in keydown that we have all info for, and that - // are not safe to pass on to the browser (as it may do something - // with the key. The rest we pass on to keypress so we can get the - // translated keysym. - function getKeysymSpecial(ev) { - if (ev.keyCode in specialKeyTable) { - var r = specialKeyTable[ev.keyCode]; - var flags = 0; - if (typeof r !== 'number') { - flags = r[1]; - r = r[0]; - } - if (ev.type === 'keydown' || flags & ON_KEYDOWN) { - return r; - } - } - // If we don't hold alt or ctrl, then we should be safe to pass - // on to keypressed and look at the translated data - if (!ev.ctrlKey && !ev.altKey) { - return null; - } - - var keysym = getEventKeySym(ev); - - // Remap symbols - switch (keysym) { - case 186 : keysym = 59; break; // ; (IE) - case 187 : keysym = 61; break; // = (IE) - case 188 : keysym = 44; break; // , (Mozilla, IE) - case 109 : // - (Mozilla, Opera) - if (true) { - // TODO: check if browser is firefox or opera - keysym = 45; - } - break; - case 189 : keysym = 45; break; // - (IE) - case 190 : keysym = 46; break; // . (Mozilla, IE) - case 191 : keysym = 47; break; // / (Mozilla, IE) - case 192 : keysym = 96; break; // ` (Mozilla, IE) - case 219 : keysym = 91; break; // [ (Mozilla, IE) - case 220 : keysym = 92; break; // \ (Mozilla, IE) - case 221 : keysym = 93; break; // ] (Mozilla, IE) - case 222 : keysym = 39; break; // ' (Mozilla, IE) - } - - // Remap shifted and unshifted keys - if (!!ev.shiftKey) { - switch (keysym) { - case 48 : keysym = 41 ; break; // ) (shifted 0) - case 49 : keysym = 33 ; break; // ! (shifted 1) - case 50 : keysym = 64 ; break; // @ (shifted 2) - case 51 : keysym = 35 ; break; // # (shifted 3) - case 52 : keysym = 36 ; break; // $ (shifted 4) - case 53 : keysym = 37 ; break; // % (shifted 5) - case 54 : keysym = 94 ; break; // ^ (shifted 6) - case 55 : keysym = 38 ; break; // & (shifted 7) - case 56 : keysym = 42 ; break; // * (shifted 8) - case 57 : keysym = 40 ; break; // ( (shifted 9) - case 59 : keysym = 58 ; break; // : (shifted `) - case 61 : keysym = 43 ; break; // + (shifted ;) - case 44 : keysym = 60 ; break; // < (shifted ,) - case 45 : keysym = 95 ; break; // _ (shifted -) - case 46 : keysym = 62 ; break; // > (shifted .) - case 47 : keysym = 63 ; break; // ? (shifted /) - case 96 : keysym = 126; break; // ~ (shifted `) - case 91 : keysym = 123; break; // { (shifted [) - case 92 : keysym = 124; break; // | (shifted \) - case 93 : keysym = 125; break; // } (shifted ]) - case 39 : keysym = 34 ; break; // " (shifted ') - } - } else if ((keysym >= 65) && (keysym <= 90)) { - // Remap unshifted A-Z - keysym += 32; - } else if (ev.keyLocation === 3) { - // numpad keys - switch (keysym) { - case 96 : keysym = 48; break; // 0 - case 97 : keysym = 49; break; // 1 - case 98 : keysym = 50; break; // 2 - case 99 : keysym = 51; break; // 3 - case 100: keysym = 52; break; // 4 - case 101: keysym = 53; break; // 5 - case 102: keysym = 54; break; // 6 - case 103: keysym = 55; break; // 7 - case 104: keysym = 56; break; // 8 - case 105: keysym = 57; break; // 9 - case 109: keysym = 45; break; // - - case 110: keysym = 46; break; // . - case 111: keysym = 47; break; // / - } - } - - return keysym; - } - - function getKeyEvent(keyCode, pop) { - var i, fev = null; - for (i = keyDownList.length - 1; i >= 0; i--) { - if (keyDownList[i].keyCode === keyCode) { - if ((typeof pop !== 'undefined') && pop) { - fev = keyDownList.splice(i, 1)[0]; - } else { - fev = keyDownList[i]; - } - break; - } - } - return fev; - } - - ///////////////////////////////////////////////////////////////////////////// - // COMMANDS - ///////////////////////////////////////////////////////////////////////////// - - function cmdGrabPointer(id, ownerEvents) { - sendInput('g', []); - } - - function cmdUngrabPointer() { - sendInput('u', []); - } - - function cmdPutBuffer(id, w, h, compressed) { - var surface = surfaces[id]; - var context = surface.canvas.getContext('2d'); - - var inflate = new window.Zlib.RawInflate(compressed); - var data = inflate.decompress(); - - var imageData = decodeBuffer(context, surface.imageData, w, h, data, false); - context.putImageData(imageData, 0, 0); - surface.imageData = imageData; - } - - function sendConfigureNotify(surface) { - sendInput('w', [surface.id, surface.x, surface.y, surface.width, surface.height]); - } - - function cmdLowerSurface(id) { - /* TODO - var surface = surfaces[id]; - */ - } - - function cmdRaiseSurface(id) { - /* TODO - var surface = surfaces[id]; - */ - } - - function cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h) { - var surface = surfaces[id]; - - console.debug('Broadway', 'onMoveResizeSurface()', [id, has_pos, has_size], [x, y], [w, h], surface); - - if ( has_pos ) { - surface.positioned = true; - surface.x = x; - surface.y = y; - } - - if ( has_size ) { - surface.width = w; - surface.height = h; - } - - if ( has_size ) { - resizeCanvas(surface.canvas, w, h); - } - - if ( surface.isTemp ) { - if ( has_pos ) { - var parentSurface = surfaces[surface.transientParent]; - var xOffset = surface.x - parentSurface.x; - var yOffset = surface.y - parentSurface.y; - - surface.xOff = xOffset; - surface.yOff = yOffset; - - surface.canvas.style.left = xOffset + 'px'; - surface.canvas.style.top = yOffset + 'px'; - } - } else { - if ( surface.visible ) { - OSjs.Broadway.Events.onMoveSurface(id, has_pos, has_size, surface); - } - } - - sendConfigureNotify(surface); - } - - function cmdDeleteSurface(id) { - var surface = surfaces[id]; - - if ( surface ) { - console.debug('Broadway', 'onDeleteSurface()', id); - if ( surface.canvas.parentNode ) { - surface.canvas.parentNode.removeChild(surface.canvas); - } - - OSjs.Broadway.Events.onDeleteSurface(id); - - delete surfaces[id]; - } - } - - function cmdSetTransientFor(id, parentId) { - var surface = surfaces[id]; - - if ( surface ) { - if ( surface.transientParent === parentId ) { - return; - } - - surface.transientParent = parentId; - var parentSurface = surfaces[parentId]; - if ( surface.positioned ) { - console.debug('Broadway', 'onSetTransient()', id, parentId, surface); - parentSurface.canvas.parentNode.appendChild(surface.canvas); - } - } - } - - function cmdHideSurface(id) { - var surface = surfaces[id]; - if ( surface ) { - surface.visible = false; - if ( surface.canvas ) { - surface.canvas.style.display = 'none'; - } - - console.debug('Broadway', 'onHideSurface()', id); - OSjs.Broadway.Events.onHideSurface(id); - } - } - - function cmdShowSurface(id) { - var surface = surfaces[id]; - - if ( surface ) { - surface.visible = true; - if ( surface.canvas ) { - surface.canvas.style.display = 'inline'; - } - - console.debug('Broadway', 'onShowSurface()', id); - OSjs.Broadway.Events.onShowSurface(id); - } - } - - function cmdCreateSurface(id, x, y, width, height, isTemp) { - var surface = { - id: id, - xOff: 0, - yOff: 0, - x: x, - y: y, - width: width, - height: height, - isTemp: isTemp, - positioned: isTemp, - transientParent: 0, - visible: false, - imageData: null, - canvas: document.createElement('canvas') - }; - - console.debug('Broadway', 'onCreateSurface()', surface); - - surface.canvas.width = width; - surface.canvas.height = height; - surface.canvas.setAttribute('data-surface-id', String(id)); - - if ( isTemp ) { - surface.canvas.style.position = 'absolute'; - surface.canvas.style.left = x + 'px'; - surface.canvas.style.top = y + 'px'; - surface.canvas.style.zIndex = '9999999'; - surface.canvas.style.display = 'none'; - } - - OSjs.Broadway.Events.onCreateSurface(id, surface); - - surfaces[id] = surface; - sendConfigureNotify(surface); - } - - ///////////////////////////////////////////////////////////////////////////// - // COMMAND HANDLERS - ///////////////////////////////////////////////////////////////////////////// - - var Commands = { - D: function() { - OSjs.Broadway.GTK.disconnect(); - }, - - s: function(cmd) { // Create new surface - cmdCreateSurface( - cmd.get_16(), // id - cmd.get_16s(), // x - cmd.get_16s(), // y - cmd.get_16(), // w - cmd.get_16(), // h - cmd.get_bool() // tmp - ); - }, - - S: function(cmd) { // Shows a surface - cmdShowSurface(cmd.get_16()); - }, - - H: function(cmd) { // Hides a surface - cmdHideSurface(cmd.get_16()); - }, - - p: function(cmd) { // Set transient parent - cmdSetTransientFor(cmd.get_16(), cmd.get_16()); - }, - - d: function(cmd) { // Deletes a surface - cmdDeleteSurface(cmd.get_16()); - }, - - m: function(cmd) { // Moves a surface - var x, y, w, h; - - var id = cmd.get_16(); - var ops = cmd.get_flags(); - var has_pos = ops & 1; - - if ( has_pos ) { - x = cmd.get_16s(); - y = cmd.get_16s(); - } - - var has_size = ops & 2; - if ( has_size ) { - w = cmd.get_16(); - h = cmd.get_16(); - } - - cmdMoveResizeSurface(id, has_pos, x, y, has_size, w, h); - }, - - r: function(cmd) { // Raises a surface - cmdRaiseSurface(cmd.get_16()); - }, - - R: function(cmd) { // Lowers a surface - cmdLowerSurface(cmd.get_16()); - }, - - b: function(cmd) { // Put image buffer - cmdPutBuffer( - cmd.get_16(), // id - cmd.get_16(), // w - cmd.get_16(), // h - cmd.get_data() // data - ); - }, - - g: function(cmd) { // Grab - cmdGrabPointer(cmd.get_16(), cmd.get_bool()); - }, - - u: function() { // Ungrab - cmdUngrabPointer(); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // INPUT INJECTORS - ///////////////////////////////////////////////////////////////////////////// - - var Input = { - mousewheel: function(id, cid, ev, relx, rely, mx, my) { - var offset = ev.detail ? ev.detail : -ev.wheelDelta; - var dir = offset > 0 ? 1 : 0; - sendInput('s', [id, cid, relx, rely, mx, my, lastState, dir]); - }, - - mousedown: function(id, cid, ev, relx, rely, mx, my) { - updateForEvent(ev); - var button = ev.button + 1; - lastState = lastState | getButtonMask(button); - sendInput('b', [id, cid, relx, rely, mx, my, lastState, button]); - }, - - mouseup: function(id, cid, ev, relx, rely, mx, my) { - updateForEvent(ev); - var button = ev.button + 1; - lastState = lastState & ~getButtonMask(button); - sendInput('B', [id, cid, relx, rely, mx, my, lastState, button]); - }, - - mouseover: function(id, cid, ev, relx, rely, mx, my) { - updateForEvent(ev); - if ( id !== 0 ) { - sendInput('e', [id, cid, relx, rely, mx, my, lastState, GDK_CROSSING_NORMAL]); - } - }, - - mouseout: function(id, cid, ev, relx, rely, mx, my) { - updateForEvent(ev); - if ( id !== 0 ) { - sendInput('l', [id, cid, relx, rely, mx, my, lastState, GDK_CROSSING_NORMAL]); - } - }, - - mousemove: function(id, cid, ev, relx, rely, mx, my) { - updateForEvent(ev); - sendInput('m', [id, cid, relx, rely, mx, my, lastState]); - }, - - keydown: function(id, cid, ev) { - updateForEvent(ev); - - var fev = copyKeyEvent(ev || window.event); - var keysym = getKeysymSpecial(ev); - var suppress = false; - - fev.keysym = keysym; - if ( keysym ) { - if ( !ignoreKeyEvent(ev) ) { - sendInput('k', [keysym, lastState]); - } - suppress = true; - } - - if ( !ignoreKeyEvent(ev) ) { - keyDownList.push(fev); - } - - if ( suppress ) { - cancelEvent(ev); - } - }, - - keypress: function(id, cid, ev) { - var kdlen = keyDownList.length; - - if (((typeof ev.which !== 'undefined') && (ev.which === 0)) || getKeysymSpecial(ev)) { - // Firefox and Opera generate a keyPress event even if keyDown - // is suppressed. But the keys we want to suppress will have - // either: - // - the which attribute set to 0 - // - getKeysymSpecial() will identify it - cancelEvent(ev); - return; - } - - var keysym = getKeysym(ev); - - // Modify the which attribute in the depressed keys list so - // that the keyUp event will be able to have the character code - // translation available. - if (kdlen > 0) { - keyDownList[kdlen - 1].keysym = keysym; - } - - // Send the translated keysym - if (keysym > 0) { - sendInput('k', [keysym, lastState]); - } - - // Stop keypress events just in case - cancelEvent(ev); - }, - - keyup: function(id, cid, ev) { - var fev = getKeyEvent(ev.keyCode, true); - var keysym = fev ? fev.keysym : 0; - if ( keysym > 0 ) { - sendInput('K', [keysym, lastState]); - } - cancelEvent(ev); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// - - var Broadway = { - /** - * Connects to a Broadway server - * - * @param {String} url Connection URL - * @param {Option} opts Options - * - * @function connect - * @memberof OSjs.Broadway.GTK - */ - connect: function(url, opts) { - if ( ws ) { - OSjs.Broadway.Connection.disconnect(); - } - - ws = new WebSocket(url, 'broadway'); - ws.binaryType = 'arraybuffer'; - - ws.onopen = function() { - OSjs.Broadway.Events.onSocketOpen(); - }; - - ws.onclose = function() { - ws = null; - - OSjs.Broadway.Events.onSocketClose(); - }; - - function handleCommands(cmd) { - while ( cmd.pos < cmd.length ) { - var command = cmd.get_char(); - lastSerial = cmd.get_32(); - - if ( Commands[command] ) { - Commands[command](cmd); - } else { - console.warn('Unknown op ' + command); - } - } - - return true; - } - - ws.onmessage = function(ev) { - var message = ev.data; - var cmd = new BinCommands(message); - outstandingCommands.push(cmd); - - if ( outstandingCommands.length === 1 ) { - while ( outstandingCommands.length > 0 ) { - cmd = outstandingCommands.shift(); - if ( !handleCommands(cmd) ) { - outstandingCommands.unshift(cmd); - return; - } - } - } - }; - }, - - /** - * Disconnects the Broadway connection - * - * @function disconnect - * @memberof OSjs.Broadway.GTK - */ - disconnect: function() { - if ( ws ) { - ws.close(); - } - ws = null; - }, - - /** - * Sends a notification to move a window - * - * @param {Number} id Window ID - * @param {Number} x X Position - * @param {Number} y Y Position - * - * @function move - * @memberof OSjs.Broadway.GTK - */ - move: function(id, x, y) { - if ( surfaces[id] ) { - var surface = surfaces[id]; - surface.x = x; - surface.y = y; - sendConfigureNotify(surface); - } - }, - - /** - * Sends a notification to close a window - * - * @param {Number} id Window ID - * - * @function close - * @memberof OSjs.Broadway.GTK - */ - close: function(id) { - if ( surfaces[id] ) { - sendInput('W', [id]); - } - }, - - /** - * Sends a raw input - * - * @param {String} cmd Command name - * @param {Array} args Command arguments - * - * @function send - * @memberof OSjs.Broadway.GTK - */ - send: function(cmd, args) { - sendInput(cmd, args); - }, - - /** - * Injects an event into Broadway Window - * - * @param {Number} id Window ID - * @param {String} type Event Type - * @param {Event} ev Event - * @param {Object} [opts] Options - * - * @function inject - * @memberof OSjs.Broadway.GTK - */ - inject: function(id, type, ev, opts) { - if ( type === 'resize' ) { - sendInput('d', [opts.width, opts.height]); - return; - } else if ( type === 'blur' ) { - // TODO: Find some way to hide open menus etc - return; - } - - var surface = surfaces[id]; - if ( surface ) { - var cid = getLayer(ev, id); - var relx = -1; - var rely = -1; - var mx = -1; - var my = -1; - - if ( opts ) { - var tsurface = surfaces[cid] || surface; - - mx = opts.mx - tsurface.xOff; - my = opts.my - tsurface.yOff; - - relx = tsurface.x + mx; - rely = tsurface.y + my; - } - - if ( Input[type] ) { - Input[type](id, cid, ev, relx, rely, mx, my); - } - } - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * @namespace GTK - * @memberof OSjs.Broadway - */ - OSjs.Broadway.GTK = Broadway; - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI, OSjs.API); diff --git a/src/client/javascript/broadway/connection.js b/src/client/javascript/broadway/connection.js deleted file mode 100644 index 841d933b56..0000000000 --- a/src/client/javascript/broadway/connection.js +++ /dev/null @@ -1,361 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -(function(Application, Window, Utils, VFS, GUI, API) { - 'use strict'; - - /** - * @namespace Broadway - * @memberof OSjs - */ - - var _connected = false; - var _ws = null; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - /* - * Creates a new connection URL - */ - function createURL(cfg) { - var protocol = cfg.protocol || window.location.protocol.replace(/^http/, 'ws'); - var host = cfg.host || window.location.hostname; - if ( host === 'localhost' && host !== window.location.hostname ) { - host = window.location.hostname; - } - return protocol + '//' + host + ':' + cfg.port + '/' + cfg.uri; - } - - /* - * Get window - */ - function actionOnWindow(id, cb) { - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - var win = wm.getWindow('BroadwayWindow' + String(id)); - if ( win ) { - return cb(win); - } - } - return null; - } - - /* - * Removes the notification icon - */ - function removeNotification() { - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - wm.removeNotificationIcon('BroadwayService'); - } - } - - /* - * Updates notification icon based on state(s) - */ - function updateNotification() { - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - var n = wm.getNotificationIcon('BroadwayService'); - if ( n ) { - n.$image.style.opacity = _connected ? 1 : .4; - } - } - } - - /* - * Creates the notification icon - */ - function createNotification() { - var wm = OSjs.Core.getWindowManager(); - var conf = API.getConfig('Broadway'); - - function displayMenu(ev) { - var menuItems = []; - if ( _connected ) { - menuItems.push({ - title: 'Disconnect from Broadway server', - onClick: function() { - OSjs.Broadway.Connection.disconnect(); - } - }); - menuItems.push({ - title: 'Create new process', - onClick: function() { - API.createDialog('Input', {message: 'Launch process', value: '/usr/bin/gtk3-demo'}, function(ev, btn, value) { - if ( btn === 'ok' && value ) { - OSjs.Broadway.Connection.spawn(value); - } - }); - } - }); - } else { - menuItems.push({ - title: 'Connect to Broadway server', - onClick: function() { - OSjs.Broadway.Connection.connect(); - } - }); - } - - API.createMenu(menuItems, ev); - } - - removeNotification(); - - if ( wm && conf.enabled ) { - removeNotification(); - - wm.createNotificationIcon('BroadwayService', { - image: API.getIcon('gtk.png'), - onContextMenu: function(ev) { - displayMenu(ev); - return false; - }, - onClick: function(ev) { - displayMenu(ev); - return false; - } - }); - - updateNotification(); - } - } - - /* - * Creates a new Spawner connection - */ - function createSpawner(host, cb) { - _ws = new WebSocket(host, 'broadway-spawner'); - - _ws.onerror = function() { - cb('Failed to connect to spawner'); - }; - - _ws.onopen = function() { - cb(null, _ws); - }; - - _ws.onclose = function() { - OSjs.Broadway.Connection.disconnect(); - }; - } - - var onResize = (function() { - var wm; - return function() { - if ( !wm ) { - wm = OSjs.Core.getWindowManager(); - } - - if ( wm ) { - var space = wm.getWindowSpace(); - var theme = wm ? wm.getStyleTheme(true) : null; - var topMargin = theme ? (theme.style.window.margin) : 26; - - OSjs.Broadway.GTK.inject(null, 'resize', null, { - width: space.width, - height: space.height - topMargin - }); - } - - }; - })(); - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// - - /** - * Initializes Broadway - * - * @function init - * @memberof OSjs.Broadway.Connection - */ - function init() { - createNotification(); - } - - /** - * Disconnects the Broadway connections - * - * @function disconnect - * @memberof OSjs.Broadway.Connection - */ - function disconnect() { - _connected = false; - - if ( _ws ) { - _ws.close(); - } - _ws = null; - - try { - OSjs.Broadway.GTK.disconnect(); - } catch ( e ) { - console.warn(e); - } - - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - wm.getWindows().forEach(function(w) { - if ( w && w instanceof OSjs.Broadway.Window ) { - w.destroy(); - } - }); - } - - setTimeout(function() { - updateNotification(); - }, 100); - } - - /** - * Creates new Broadway connections - * - * @function connect - * @memberof OSjs.Broadway.Connection - */ - function connect() { - if ( _connected || _ws ) { - return; - } - - var conf = API.getConfig('Broadway'); - - createSpawner(createURL(conf.defaults.spawner), function(err) { - _connected = true; - - if ( err ) { - API.error('Broadway', 'Failed to connect', err); - } else { - try { - var host = createURL(conf.defaults.connection); - OSjs.Broadway.GTK.connect(host); - } catch ( e ) { - console.warn(e); - } - } - }); - } - - /** - * Spawns a new process on the Broadway server - * - * @param {String} cmd Command - * - * @function spawn - * @memberof OSjs.Broadway.Connection - */ - function spawn(cmd) { - if ( !_connected || !_ws ) { - return; - } - - _ws.send(JSON.stringify({ - method: 'launch', - argument: cmd - })); - } - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Broadway.Events = { - onSocketOpen: function() { - window.addEventListener('resize', onResize); - - updateNotification(); - onResize(); - }, - - onSocketClose: function() { - window.removeEventListener('resize', onResize); - - disconnect(); - }, - - onDeleteSurface: function(id) { - return actionOnWindow(id, function(win) { - return win._close(); - }); - }, - - onShowSurface: function(id) { - return actionOnWindow(id, function(win) { - return win._restore(); - }); - }, - - onHideSurface: function(id) { - return actionOnWindow(id, function(win) { - return win._minimize(); - }); - }, - - onMoveSurface: function(id, has_pos, has_size, surface) { - return actionOnWindow(id, function(win) { - var wm = OSjs.Core.getWindowManager(); - var space = wm.getWindowSpace(); - - if ( has_pos ) { - win._move(space.left + surface.x, space.top + surface.y); - } - - if ( has_size ) { - win._resize(surface.width, surface.height); - } - }); - }, - - onCreateSurface: function(id, surface) { - var wm = OSjs.Core.getWindowManager(); - if ( !surface.isTemp ) { - var win = new OSjs.Broadway.Window(id, surface.x, surface.y, surface.width, surface.height, surface.canvas); - wm.addWindow(win, true); - } - } - }; - - /** - * @namespace Connection - * @memberof OSjs.Broadway - */ - OSjs.Broadway.Connection = { - init: init, - connect: connect, - disconnect: disconnect, - spawn: spawn - }; - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI, OSjs.API); diff --git a/src/client/javascript/broadway/unicode.js b/src/client/javascript/broadway/unicode.js deleted file mode 100644 index 9207f3dea6..0000000000 --- a/src/client/javascript/broadway/unicode.js +++ /dev/null @@ -1,1306 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -(function(Application, Window, Utils, VFS, GUI, API) { - 'use strict'; - - /* Some of the keyboard handling code is from noVNC and - * (c) Joel Martin (github@martintribe.org), used with permission - * Original code at: - * https://github.com/kanaka/noVNC/blob/master/include/input.js - */ - var unicodeTable = { - 0x0104: 0x01a1, - 0x02D8: 0x01a2, - 0x0141: 0x01a3, - 0x013D: 0x01a5, - 0x015A: 0x01a6, - 0x0160: 0x01a9, - 0x015E: 0x01aa, - 0x0164: 0x01ab, - 0x0179: 0x01ac, - 0x017D: 0x01ae, - 0x017B: 0x01af, - 0x0105: 0x01b1, - 0x02DB: 0x01b2, - 0x0142: 0x01b3, - 0x013E: 0x01b5, - 0x015B: 0x01b6, - 0x02C7: 0x01b7, - 0x0161: 0x01b9, - 0x015F: 0x01ba, - 0x0165: 0x01bb, - 0x017A: 0x01bc, - 0x02DD: 0x01bd, - 0x017E: 0x01be, - 0x017C: 0x01bf, - 0x0154: 0x01c0, - 0x0102: 0x01c3, - 0x0139: 0x01c5, - 0x0106: 0x01c6, - 0x010C: 0x01c8, - 0x0118: 0x01ca, - 0x011A: 0x01cc, - 0x010E: 0x01cf, - 0x0110: 0x01d0, - 0x0143: 0x01d1, - 0x0147: 0x01d2, - 0x0150: 0x01d5, - 0x0158: 0x01d8, - 0x016E: 0x01d9, - 0x0170: 0x01db, - 0x0162: 0x01de, - 0x0155: 0x01e0, - 0x0103: 0x01e3, - 0x013A: 0x01e5, - 0x0107: 0x01e6, - 0x010D: 0x01e8, - 0x0119: 0x01ea, - 0x011B: 0x01ec, - 0x010F: 0x01ef, - 0x0111: 0x01f0, - 0x0144: 0x01f1, - 0x0148: 0x01f2, - 0x0151: 0x01f5, - 0x0171: 0x01fb, - 0x0159: 0x01f8, - 0x016F: 0x01f9, - 0x0163: 0x01fe, - 0x02D9: 0x01ff, - 0x0126: 0x02a1, - 0x0124: 0x02a6, - 0x0130: 0x02a9, - 0x011E: 0x02ab, - 0x0134: 0x02ac, - 0x0127: 0x02b1, - 0x0125: 0x02b6, - 0x0131: 0x02b9, - 0x011F: 0x02bb, - 0x0135: 0x02bc, - 0x010A: 0x02c5, - 0x0108: 0x02c6, - 0x0120: 0x02d5, - 0x011C: 0x02d8, - 0x016C: 0x02dd, - 0x015C: 0x02de, - 0x010B: 0x02e5, - 0x0109: 0x02e6, - 0x0121: 0x02f5, - 0x011D: 0x02f8, - 0x016D: 0x02fd, - 0x015D: 0x02fe, - 0x0138: 0x03a2, - 0x0156: 0x03a3, - 0x0128: 0x03a5, - 0x013B: 0x03a6, - 0x0112: 0x03aa, - 0x0122: 0x03ab, - 0x0166: 0x03ac, - 0x0157: 0x03b3, - 0x0129: 0x03b5, - 0x013C: 0x03b6, - 0x0113: 0x03ba, - 0x0123: 0x03bb, - 0x0167: 0x03bc, - 0x014A: 0x03bd, - 0x014B: 0x03bf, - 0x0100: 0x03c0, - 0x012E: 0x03c7, - 0x0116: 0x03cc, - 0x012A: 0x03cf, - 0x0145: 0x03d1, - 0x014C: 0x03d2, - 0x0136: 0x03d3, - 0x0172: 0x03d9, - 0x0168: 0x03dd, - 0x016A: 0x03de, - 0x0101: 0x03e0, - 0x012F: 0x03e7, - 0x0117: 0x03ec, - 0x012B: 0x03ef, - 0x0146: 0x03f1, - 0x014D: 0x03f2, - 0x0137: 0x03f3, - 0x0173: 0x03f9, - 0x0169: 0x03fd, - 0x016B: 0x03fe, - 0x1E02: 0x1001e02, - 0x1E03: 0x1001e03, - 0x1E0A: 0x1001e0a, - 0x1E80: 0x1001e80, - 0x1E82: 0x1001e82, - 0x1E0B: 0x1001e0b, - 0x1EF2: 0x1001ef2, - 0x1E1E: 0x1001e1e, - 0x1E1F: 0x1001e1f, - 0x1E40: 0x1001e40, - 0x1E41: 0x1001e41, - 0x1E56: 0x1001e56, - 0x1E81: 0x1001e81, - 0x1E57: 0x1001e57, - 0x1E83: 0x1001e83, - 0x1E60: 0x1001e60, - 0x1EF3: 0x1001ef3, - 0x1E84: 0x1001e84, - 0x1E85: 0x1001e85, - 0x1E61: 0x1001e61, - 0x0174: 0x1000174, - 0x1E6A: 0x1001e6a, - 0x0176: 0x1000176, - 0x0175: 0x1000175, - 0x1E6B: 0x1001e6b, - 0x0177: 0x1000177, - 0x0152: 0x13bc, - 0x0153: 0x13bd, - 0x0178: 0x13be, - 0x203E: 0x047e, - 0x3002: 0x04a1, - 0x300C: 0x04a2, - 0x300D: 0x04a3, - 0x3001: 0x04a4, - 0x30FB: 0x04a5, - 0x30F2: 0x04a6, - 0x30A1: 0x04a7, - 0x30A3: 0x04a8, - 0x30A5: 0x04a9, - 0x30A7: 0x04aa, - 0x30A9: 0x04ab, - 0x30E3: 0x04ac, - 0x30E5: 0x04ad, - 0x30E7: 0x04ae, - 0x30C3: 0x04af, - 0x30FC: 0x04b0, - 0x30A2: 0x04b1, - 0x30A4: 0x04b2, - 0x30A6: 0x04b3, - 0x30A8: 0x04b4, - 0x30AA: 0x04b5, - 0x30AB: 0x04b6, - 0x30AD: 0x04b7, - 0x30AF: 0x04b8, - 0x30B1: 0x04b9, - 0x30B3: 0x04ba, - 0x30B5: 0x04bb, - 0x30B7: 0x04bc, - 0x30B9: 0x04bd, - 0x30BB: 0x04be, - 0x30BD: 0x04bf, - 0x30BF: 0x04c0, - 0x30C1: 0x04c1, - 0x30C4: 0x04c2, - 0x30C6: 0x04c3, - 0x30C8: 0x04c4, - 0x30CA: 0x04c5, - 0x30CB: 0x04c6, - 0x30CC: 0x04c7, - 0x30CD: 0x04c8, - 0x30CE: 0x04c9, - 0x30CF: 0x04ca, - 0x30D2: 0x04cb, - 0x30D5: 0x04cc, - 0x30D8: 0x04cd, - 0x30DB: 0x04ce, - 0x30DE: 0x04cf, - 0x30DF: 0x04d0, - 0x30E0: 0x04d1, - 0x30E1: 0x04d2, - 0x30E2: 0x04d3, - 0x30E4: 0x04d4, - 0x30E6: 0x04d5, - 0x30E8: 0x04d6, - 0x30E9: 0x04d7, - 0x30EA: 0x04d8, - 0x30EB: 0x04d9, - 0x30EC: 0x04da, - 0x30ED: 0x04db, - 0x30EF: 0x04dc, - 0x30F3: 0x04dd, - 0x309B: 0x04de, - 0x309C: 0x04df, - 0x06F0: 0x10006f0, - 0x06F1: 0x10006f1, - 0x06F2: 0x10006f2, - 0x06F3: 0x10006f3, - 0x06F4: 0x10006f4, - 0x06F5: 0x10006f5, - 0x06F6: 0x10006f6, - 0x06F7: 0x10006f7, - 0x06F8: 0x10006f8, - 0x06F9: 0x10006f9, - 0x066A: 0x100066a, - 0x0670: 0x1000670, - 0x0679: 0x1000679, - 0x067E: 0x100067e, - 0x0686: 0x1000686, - 0x0688: 0x1000688, - 0x0691: 0x1000691, - 0x060C: 0x05ac, - 0x06D4: 0x10006d4, - 0x0660: 0x1000660, - 0x0661: 0x1000661, - 0x0662: 0x1000662, - 0x0663: 0x1000663, - 0x0664: 0x1000664, - 0x0665: 0x1000665, - 0x0666: 0x1000666, - 0x0667: 0x1000667, - 0x0668: 0x1000668, - 0x0669: 0x1000669, - 0x061B: 0x05bb, - 0x061F: 0x05bf, - 0x0621: 0x05c1, - 0x0622: 0x05c2, - 0x0623: 0x05c3, - 0x0624: 0x05c4, - 0x0625: 0x05c5, - 0x0626: 0x05c6, - 0x0627: 0x05c7, - 0x0628: 0x05c8, - 0x0629: 0x05c9, - 0x062A: 0x05ca, - 0x062B: 0x05cb, - 0x062C: 0x05cc, - 0x062D: 0x05cd, - 0x062E: 0x05ce, - 0x062F: 0x05cf, - 0x0630: 0x05d0, - 0x0631: 0x05d1, - 0x0632: 0x05d2, - 0x0633: 0x05d3, - 0x0634: 0x05d4, - 0x0635: 0x05d5, - 0x0636: 0x05d6, - 0x0637: 0x05d7, - 0x0638: 0x05d8, - 0x0639: 0x05d9, - 0x063A: 0x05da, - 0x0640: 0x05e0, - 0x0641: 0x05e1, - 0x0642: 0x05e2, - 0x0643: 0x05e3, - 0x0644: 0x05e4, - 0x0645: 0x05e5, - 0x0646: 0x05e6, - 0x0647: 0x05e7, - 0x0648: 0x05e8, - 0x0649: 0x05e9, - 0x064A: 0x05ea, - 0x064B: 0x05eb, - 0x064C: 0x05ec, - 0x064D: 0x05ed, - 0x064E: 0x05ee, - 0x064F: 0x05ef, - 0x0650: 0x05f0, - 0x0651: 0x05f1, - 0x0652: 0x05f2, - 0x0653: 0x1000653, - 0x0654: 0x1000654, - 0x0655: 0x1000655, - 0x0698: 0x1000698, - 0x06A4: 0x10006a4, - 0x06A9: 0x10006a9, - 0x06AF: 0x10006af, - 0x06BA: 0x10006ba, - 0x06BE: 0x10006be, - 0x06CC: 0x10006cc, - 0x06D2: 0x10006d2, - 0x06C1: 0x10006c1, - 0x0492: 0x1000492, - 0x0493: 0x1000493, - 0x0496: 0x1000496, - 0x0497: 0x1000497, - 0x049A: 0x100049a, - 0x049B: 0x100049b, - 0x049C: 0x100049c, - 0x049D: 0x100049d, - 0x04A2: 0x10004a2, - 0x04A3: 0x10004a3, - 0x04AE: 0x10004ae, - 0x04AF: 0x10004af, - 0x04B0: 0x10004b0, - 0x04B1: 0x10004b1, - 0x04B2: 0x10004b2, - 0x04B3: 0x10004b3, - 0x04B6: 0x10004b6, - 0x04B7: 0x10004b7, - 0x04B8: 0x10004b8, - 0x04B9: 0x10004b9, - 0x04BA: 0x10004ba, - 0x04BB: 0x10004bb, - 0x04D8: 0x10004d8, - 0x04D9: 0x10004d9, - 0x04E2: 0x10004e2, - 0x04E3: 0x10004e3, - 0x04E8: 0x10004e8, - 0x04E9: 0x10004e9, - 0x04EE: 0x10004ee, - 0x04EF: 0x10004ef, - 0x0452: 0x06a1, - 0x0453: 0x06a2, - 0x0451: 0x06a3, - 0x0454: 0x06a4, - 0x0455: 0x06a5, - 0x0456: 0x06a6, - 0x0457: 0x06a7, - 0x0458: 0x06a8, - 0x0459: 0x06a9, - 0x045A: 0x06aa, - 0x045B: 0x06ab, - 0x045C: 0x06ac, - 0x0491: 0x06ad, - 0x045E: 0x06ae, - 0x045F: 0x06af, - 0x2116: 0x06b0, - 0x0402: 0x06b1, - 0x0403: 0x06b2, - 0x0401: 0x06b3, - 0x0404: 0x06b4, - 0x0405: 0x06b5, - 0x0406: 0x06b6, - 0x0407: 0x06b7, - 0x0408: 0x06b8, - 0x0409: 0x06b9, - 0x040A: 0x06ba, - 0x040B: 0x06bb, - 0x040C: 0x06bc, - 0x0490: 0x06bd, - 0x040E: 0x06be, - 0x040F: 0x06bf, - 0x044E: 0x06c0, - 0x0430: 0x06c1, - 0x0431: 0x06c2, - 0x0446: 0x06c3, - 0x0434: 0x06c4, - 0x0435: 0x06c5, - 0x0444: 0x06c6, - 0x0433: 0x06c7, - 0x0445: 0x06c8, - 0x0438: 0x06c9, - 0x0439: 0x06ca, - 0x043A: 0x06cb, - 0x043B: 0x06cc, - 0x043C: 0x06cd, - 0x043D: 0x06ce, - 0x043E: 0x06cf, - 0x043F: 0x06d0, - 0x044F: 0x06d1, - 0x0440: 0x06d2, - 0x0441: 0x06d3, - 0x0442: 0x06d4, - 0x0443: 0x06d5, - 0x0436: 0x06d6, - 0x0432: 0x06d7, - 0x044C: 0x06d8, - 0x044B: 0x06d9, - 0x0437: 0x06da, - 0x0448: 0x06db, - 0x044D: 0x06dc, - 0x0449: 0x06dd, - 0x0447: 0x06de, - 0x044A: 0x06df, - 0x042E: 0x06e0, - 0x0410: 0x06e1, - 0x0411: 0x06e2, - 0x0426: 0x06e3, - 0x0414: 0x06e4, - 0x0415: 0x06e5, - 0x0424: 0x06e6, - 0x0413: 0x06e7, - 0x0425: 0x06e8, - 0x0418: 0x06e9, - 0x0419: 0x06ea, - 0x041A: 0x06eb, - 0x041B: 0x06ec, - 0x041C: 0x06ed, - 0x041D: 0x06ee, - 0x041E: 0x06ef, - 0x041F: 0x06f0, - 0x042F: 0x06f1, - 0x0420: 0x06f2, - 0x0421: 0x06f3, - 0x0422: 0x06f4, - 0x0423: 0x06f5, - 0x0416: 0x06f6, - 0x0412: 0x06f7, - 0x042C: 0x06f8, - 0x042B: 0x06f9, - 0x0417: 0x06fa, - 0x0428: 0x06fb, - 0x042D: 0x06fc, - 0x0429: 0x06fd, - 0x0427: 0x06fe, - 0x042A: 0x06ff, - 0x0386: 0x07a1, - 0x0388: 0x07a2, - 0x0389: 0x07a3, - 0x038A: 0x07a4, - 0x03AA: 0x07a5, - 0x038C: 0x07a7, - 0x038E: 0x07a8, - 0x03AB: 0x07a9, - 0x038F: 0x07ab, - 0x0385: 0x07ae, - 0x2015: 0x07af, - 0x03AC: 0x07b1, - 0x03AD: 0x07b2, - 0x03AE: 0x07b3, - 0x03AF: 0x07b4, - 0x03CA: 0x07b5, - 0x0390: 0x07b6, - 0x03CC: 0x07b7, - 0x03CD: 0x07b8, - 0x03CB: 0x07b9, - 0x03B0: 0x07ba, - 0x03CE: 0x07bb, - 0x0391: 0x07c1, - 0x0392: 0x07c2, - 0x0393: 0x07c3, - 0x0394: 0x07c4, - 0x0395: 0x07c5, - 0x0396: 0x07c6, - 0x0397: 0x07c7, - 0x0398: 0x07c8, - 0x0399: 0x07c9, - 0x039A: 0x07ca, - 0x039B: 0x07cb, - 0x039C: 0x07cc, - 0x039D: 0x07cd, - 0x039E: 0x07ce, - 0x039F: 0x07cf, - 0x03A0: 0x07d0, - 0x03A1: 0x07d1, - 0x03A3: 0x07d2, - 0x03A4: 0x07d4, - 0x03A5: 0x07d5, - 0x03A6: 0x07d6, - 0x03A7: 0x07d7, - 0x03A8: 0x07d8, - 0x03A9: 0x07d9, - 0x03B1: 0x07e1, - 0x03B2: 0x07e2, - 0x03B3: 0x07e3, - 0x03B4: 0x07e4, - 0x03B5: 0x07e5, - 0x03B6: 0x07e6, - 0x03B7: 0x07e7, - 0x03B8: 0x07e8, - 0x03B9: 0x07e9, - 0x03BA: 0x07ea, - 0x03BB: 0x07eb, - 0x03BC: 0x07ec, - 0x03BD: 0x07ed, - 0x03BE: 0x07ee, - 0x03BF: 0x07ef, - 0x03C0: 0x07f0, - 0x03C1: 0x07f1, - 0x03C3: 0x07f2, - 0x03C2: 0x07f3, - 0x03C4: 0x07f4, - 0x03C5: 0x07f5, - 0x03C6: 0x07f6, - 0x03C7: 0x07f7, - 0x03C8: 0x07f8, - 0x03C9: 0x07f9, - 0x23B7: 0x08a1, - 0x2320: 0x08a4, - 0x2321: 0x08a5, - 0x23A1: 0x08a7, - 0x23A3: 0x08a8, - 0x23A4: 0x08a9, - 0x23A6: 0x08aa, - 0x239B: 0x08ab, - 0x239D: 0x08ac, - 0x239E: 0x08ad, - 0x23A0: 0x08ae, - 0x23A8: 0x08af, - 0x23AC: 0x08b0, - 0x2264: 0x08bc, - 0x2260: 0x08bd, - 0x2265: 0x08be, - 0x222B: 0x08bf, - 0x2234: 0x08c0, - 0x221D: 0x08c1, - 0x221E: 0x08c2, - 0x2207: 0x08c5, - 0x223C: 0x08c8, - 0x2243: 0x08c9, - 0x21D4: 0x08cd, - 0x21D2: 0x08ce, - 0x2261: 0x08cf, - 0x2282: 0x08da, - 0x2283: 0x08db, - 0x2229: 0x08dc, - 0x222A: 0x08dd, - 0x2227: 0x08de, - 0x2228: 0x08df, - 0x0192: 0x08f6, - 0x2190: 0x08fb, - 0x2191: 0x08fc, - 0x2192: 0x08fd, - 0x2193: 0x08fe, - 0x25C6: 0x09e0, - 0x2592: 0x09e1, - 0x2409: 0x09e2, - 0x240C: 0x09e3, - 0x240D: 0x09e4, - 0x240A: 0x09e5, - 0x2424: 0x09e8, - 0x240B: 0x09e9, - 0x2518: 0x09ea, - 0x2510: 0x09eb, - 0x250C: 0x09ec, - 0x2514: 0x09ed, - 0x253C: 0x09ee, - 0x23BA: 0x09ef, - 0x23BB: 0x09f0, - 0x2500: 0x09f1, - 0x23BC: 0x09f2, - 0x23BD: 0x09f3, - 0x251C: 0x09f4, - 0x2524: 0x09f5, - 0x2534: 0x09f6, - 0x252C: 0x09f7, - 0x2502: 0x09f8, - 0x2003: 0x0aa1, - 0x2002: 0x0aa2, - 0x2004: 0x0aa3, - 0x2005: 0x0aa4, - 0x2007: 0x0aa5, - 0x2008: 0x0aa6, - 0x2009: 0x0aa7, - 0x200A: 0x0aa8, - 0x2014: 0x0aa9, - 0x2013: 0x0aaa, - 0x2026: 0x0aae, - 0x2025: 0x0aaf, - 0x2153: 0x0ab0, - 0x2154: 0x0ab1, - 0x2155: 0x0ab2, - 0x2156: 0x0ab3, - 0x2157: 0x0ab4, - 0x2158: 0x0ab5, - 0x2159: 0x0ab6, - 0x215A: 0x0ab7, - 0x2105: 0x0ab8, - 0x2012: 0x0abb, - 0x215B: 0x0ac3, - 0x215C: 0x0ac4, - 0x215D: 0x0ac5, - 0x215E: 0x0ac6, - 0x2122: 0x0ac9, - 0x2018: 0x0ad0, - 0x2019: 0x0ad1, - 0x201C: 0x0ad2, - 0x201D: 0x0ad3, - 0x211E: 0x0ad4, - 0x2032: 0x0ad6, - 0x2033: 0x0ad7, - 0x271D: 0x0ad9, - 0x2663: 0x0aec, - 0x2666: 0x0aed, - 0x2665: 0x0aee, - 0x2720: 0x0af0, - 0x2020: 0x0af1, - 0x2021: 0x0af2, - 0x2713: 0x0af3, - 0x2717: 0x0af4, - 0x266F: 0x0af5, - 0x266D: 0x0af6, - 0x2642: 0x0af7, - 0x2640: 0x0af8, - 0x260E: 0x0af9, - 0x2315: 0x0afa, - 0x2117: 0x0afb, - 0x2038: 0x0afc, - 0x201A: 0x0afd, - 0x201E: 0x0afe, - 0x22A4: 0x0bc2, - 0x230A: 0x0bc4, - 0x2218: 0x0bca, - 0x2395: 0x0bcc, - 0x22A5: 0x0bce, - 0x25CB: 0x0bcf, - 0x2308: 0x0bd3, - 0x22A3: 0x0bdc, - 0x22A2: 0x0bfc, - 0x2017: 0x0cdf, - 0x05D0: 0x0ce0, - 0x05D1: 0x0ce1, - 0x05D2: 0x0ce2, - 0x05D3: 0x0ce3, - 0x05D4: 0x0ce4, - 0x05D5: 0x0ce5, - 0x05D6: 0x0ce6, - 0x05D7: 0x0ce7, - 0x05D8: 0x0ce8, - 0x05D9: 0x0ce9, - 0x05DA: 0x0cea, - 0x05DB: 0x0ceb, - 0x05DC: 0x0cec, - 0x05DD: 0x0ced, - 0x05DE: 0x0cee, - 0x05DF: 0x0cef, - 0x05E0: 0x0cf0, - 0x05E1: 0x0cf1, - 0x05E2: 0x0cf2, - 0x05E3: 0x0cf3, - 0x05E4: 0x0cf4, - 0x05E5: 0x0cf5, - 0x05E6: 0x0cf6, - 0x05E7: 0x0cf7, - 0x05E8: 0x0cf8, - 0x05E9: 0x0cf9, - 0x05EA: 0x0cfa, - 0x0E01: 0x0da1, - 0x0E02: 0x0da2, - 0x0E03: 0x0da3, - 0x0E04: 0x0da4, - 0x0E05: 0x0da5, - 0x0E06: 0x0da6, - 0x0E07: 0x0da7, - 0x0E08: 0x0da8, - 0x0E09: 0x0da9, - 0x0E0A: 0x0daa, - 0x0E0B: 0x0dab, - 0x0E0C: 0x0dac, - 0x0E0D: 0x0dad, - 0x0E0E: 0x0dae, - 0x0E0F: 0x0daf, - 0x0E10: 0x0db0, - 0x0E11: 0x0db1, - 0x0E12: 0x0db2, - 0x0E13: 0x0db3, - 0x0E14: 0x0db4, - 0x0E15: 0x0db5, - 0x0E16: 0x0db6, - 0x0E17: 0x0db7, - 0x0E18: 0x0db8, - 0x0E19: 0x0db9, - 0x0E1A: 0x0dba, - 0x0E1B: 0x0dbb, - 0x0E1C: 0x0dbc, - 0x0E1D: 0x0dbd, - 0x0E1E: 0x0dbe, - 0x0E1F: 0x0dbf, - 0x0E20: 0x0dc0, - 0x0E21: 0x0dc1, - 0x0E22: 0x0dc2, - 0x0E23: 0x0dc3, - 0x0E24: 0x0dc4, - 0x0E25: 0x0dc5, - 0x0E26: 0x0dc6, - 0x0E27: 0x0dc7, - 0x0E28: 0x0dc8, - 0x0E29: 0x0dc9, - 0x0E2A: 0x0dca, - 0x0E2B: 0x0dcb, - 0x0E2C: 0x0dcc, - 0x0E2D: 0x0dcd, - 0x0E2E: 0x0dce, - 0x0E2F: 0x0dcf, - 0x0E30: 0x0dd0, - 0x0E31: 0x0dd1, - 0x0E32: 0x0dd2, - 0x0E33: 0x0dd3, - 0x0E34: 0x0dd4, - 0x0E35: 0x0dd5, - 0x0E36: 0x0dd6, - 0x0E37: 0x0dd7, - 0x0E38: 0x0dd8, - 0x0E39: 0x0dd9, - 0x0E3A: 0x0dda, - 0x0E3F: 0x0ddf, - 0x0E40: 0x0de0, - 0x0E41: 0x0de1, - 0x0E42: 0x0de2, - 0x0E43: 0x0de3, - 0x0E44: 0x0de4, - 0x0E45: 0x0de5, - 0x0E46: 0x0de6, - 0x0E47: 0x0de7, - 0x0E48: 0x0de8, - 0x0E49: 0x0de9, - 0x0E4A: 0x0dea, - 0x0E4B: 0x0deb, - 0x0E4C: 0x0dec, - 0x0E4D: 0x0ded, - 0x0E50: 0x0df0, - 0x0E51: 0x0df1, - 0x0E52: 0x0df2, - 0x0E53: 0x0df3, - 0x0E54: 0x0df4, - 0x0E55: 0x0df5, - 0x0E56: 0x0df6, - 0x0E57: 0x0df7, - 0x0E58: 0x0df8, - 0x0E59: 0x0df9, - 0x0587: 0x1000587, - 0x0589: 0x1000589, - 0x055D: 0x100055d, - 0x058A: 0x100058a, - 0x055C: 0x100055c, - 0x055B: 0x100055b, - 0x055E: 0x100055e, - 0x0531: 0x1000531, - 0x0561: 0x1000561, - 0x0532: 0x1000532, - 0x0562: 0x1000562, - 0x0533: 0x1000533, - 0x0563: 0x1000563, - 0x0534: 0x1000534, - 0x0564: 0x1000564, - 0x0535: 0x1000535, - 0x0565: 0x1000565, - 0x0536: 0x1000536, - 0x0566: 0x1000566, - 0x0537: 0x1000537, - 0x0567: 0x1000567, - 0x0538: 0x1000538, - 0x0568: 0x1000568, - 0x0539: 0x1000539, - 0x0569: 0x1000569, - 0x053A: 0x100053a, - 0x056A: 0x100056a, - 0x053B: 0x100053b, - 0x056B: 0x100056b, - 0x053C: 0x100053c, - 0x056C: 0x100056c, - 0x053D: 0x100053d, - 0x056D: 0x100056d, - 0x053E: 0x100053e, - 0x056E: 0x100056e, - 0x053F: 0x100053f, - 0x056F: 0x100056f, - 0x0540: 0x1000540, - 0x0570: 0x1000570, - 0x0541: 0x1000541, - 0x0571: 0x1000571, - 0x0542: 0x1000542, - 0x0572: 0x1000572, - 0x0543: 0x1000543, - 0x0573: 0x1000573, - 0x0544: 0x1000544, - 0x0574: 0x1000574, - 0x0545: 0x1000545, - 0x0575: 0x1000575, - 0x0546: 0x1000546, - 0x0576: 0x1000576, - 0x0547: 0x1000547, - 0x0577: 0x1000577, - 0x0548: 0x1000548, - 0x0578: 0x1000578, - 0x0549: 0x1000549, - 0x0579: 0x1000579, - 0x054A: 0x100054a, - 0x057A: 0x100057a, - 0x054B: 0x100054b, - 0x057B: 0x100057b, - 0x054C: 0x100054c, - 0x057C: 0x100057c, - 0x054D: 0x100054d, - 0x057D: 0x100057d, - 0x054E: 0x100054e, - 0x057E: 0x100057e, - 0x054F: 0x100054f, - 0x057F: 0x100057f, - 0x0550: 0x1000550, - 0x0580: 0x1000580, - 0x0551: 0x1000551, - 0x0581: 0x1000581, - 0x0552: 0x1000552, - 0x0582: 0x1000582, - 0x0553: 0x1000553, - 0x0583: 0x1000583, - 0x0554: 0x1000554, - 0x0584: 0x1000584, - 0x0555: 0x1000555, - 0x0585: 0x1000585, - 0x0556: 0x1000556, - 0x0586: 0x1000586, - 0x055A: 0x100055a, - 0x10D0: 0x10010d0, - 0x10D1: 0x10010d1, - 0x10D2: 0x10010d2, - 0x10D3: 0x10010d3, - 0x10D4: 0x10010d4, - 0x10D5: 0x10010d5, - 0x10D6: 0x10010d6, - 0x10D7: 0x10010d7, - 0x10D8: 0x10010d8, - 0x10D9: 0x10010d9, - 0x10DA: 0x10010da, - 0x10DB: 0x10010db, - 0x10DC: 0x10010dc, - 0x10DD: 0x10010dd, - 0x10DE: 0x10010de, - 0x10DF: 0x10010df, - 0x10E0: 0x10010e0, - 0x10E1: 0x10010e1, - 0x10E2: 0x10010e2, - 0x10E3: 0x10010e3, - 0x10E4: 0x10010e4, - 0x10E5: 0x10010e5, - 0x10E6: 0x10010e6, - 0x10E7: 0x10010e7, - 0x10E8: 0x10010e8, - 0x10E9: 0x10010e9, - 0x10EA: 0x10010ea, - 0x10EB: 0x10010eb, - 0x10EC: 0x10010ec, - 0x10ED: 0x10010ed, - 0x10EE: 0x10010ee, - 0x10EF: 0x10010ef, - 0x10F0: 0x10010f0, - 0x10F1: 0x10010f1, - 0x10F2: 0x10010f2, - 0x10F3: 0x10010f3, - 0x10F4: 0x10010f4, - 0x10F5: 0x10010f5, - 0x10F6: 0x10010f6, - 0x1E8A: 0x1001e8a, - 0x012C: 0x100012c, - 0x01B5: 0x10001b5, - 0x01E6: 0x10001e6, - 0x019F: 0x100019f, - 0x1E8B: 0x1001e8b, - 0x012D: 0x100012d, - 0x01B6: 0x10001b6, - 0x01E7: 0x10001e7, - //0x01D2: 0x10001d1, - 0x01D2: 0x10001d2, - 0x0275: 0x1000275, - 0x018F: 0x100018f, - 0x0259: 0x1000259, - 0x1E36: 0x1001e36, - 0x1E37: 0x1001e37, - 0x1EA0: 0x1001ea0, - 0x1EA1: 0x1001ea1, - 0x1EA2: 0x1001ea2, - 0x1EA3: 0x1001ea3, - 0x1EA4: 0x1001ea4, - 0x1EA5: 0x1001ea5, - 0x1EA6: 0x1001ea6, - 0x1EA7: 0x1001ea7, - 0x1EA8: 0x1001ea8, - 0x1EA9: 0x1001ea9, - 0x1EAA: 0x1001eaa, - 0x1EAB: 0x1001eab, - 0x1EAC: 0x1001eac, - 0x1EAD: 0x1001ead, - 0x1EAE: 0x1001eae, - 0x1EAF: 0x1001eaf, - 0x1EB0: 0x1001eb0, - 0x1EB1: 0x1001eb1, - 0x1EB2: 0x1001eb2, - 0x1EB3: 0x1001eb3, - 0x1EB4: 0x1001eb4, - 0x1EB5: 0x1001eb5, - 0x1EB6: 0x1001eb6, - 0x1EB7: 0x1001eb7, - 0x1EB8: 0x1001eb8, - 0x1EB9: 0x1001eb9, - 0x1EBA: 0x1001eba, - 0x1EBB: 0x1001ebb, - 0x1EBC: 0x1001ebc, - 0x1EBD: 0x1001ebd, - 0x1EBE: 0x1001ebe, - 0x1EBF: 0x1001ebf, - 0x1EC0: 0x1001ec0, - 0x1EC1: 0x1001ec1, - 0x1EC2: 0x1001ec2, - 0x1EC3: 0x1001ec3, - 0x1EC4: 0x1001ec4, - 0x1EC5: 0x1001ec5, - 0x1EC6: 0x1001ec6, - 0x1EC7: 0x1001ec7, - 0x1EC8: 0x1001ec8, - 0x1EC9: 0x1001ec9, - 0x1ECA: 0x1001eca, - 0x1ECB: 0x1001ecb, - 0x1ECC: 0x1001ecc, - 0x1ECD: 0x1001ecd, - 0x1ECE: 0x1001ece, - 0x1ECF: 0x1001ecf, - 0x1ED0: 0x1001ed0, - 0x1ED1: 0x1001ed1, - 0x1ED2: 0x1001ed2, - 0x1ED3: 0x1001ed3, - 0x1ED4: 0x1001ed4, - 0x1ED5: 0x1001ed5, - 0x1ED6: 0x1001ed6, - 0x1ED7: 0x1001ed7, - 0x1ED8: 0x1001ed8, - 0x1ED9: 0x1001ed9, - 0x1EDA: 0x1001eda, - 0x1EDB: 0x1001edb, - 0x1EDC: 0x1001edc, - 0x1EDD: 0x1001edd, - 0x1EDE: 0x1001ede, - 0x1EDF: 0x1001edf, - 0x1EE0: 0x1001ee0, - 0x1EE1: 0x1001ee1, - 0x1EE2: 0x1001ee2, - 0x1EE3: 0x1001ee3, - 0x1EE4: 0x1001ee4, - 0x1EE5: 0x1001ee5, - 0x1EE6: 0x1001ee6, - 0x1EE7: 0x1001ee7, - 0x1EE8: 0x1001ee8, - 0x1EE9: 0x1001ee9, - 0x1EEA: 0x1001eea, - 0x1EEB: 0x1001eeb, - 0x1EEC: 0x1001eec, - 0x1EED: 0x1001eed, - 0x1EEE: 0x1001eee, - 0x1EEF: 0x1001eef, - 0x1EF0: 0x1001ef0, - 0x1EF1: 0x1001ef1, - 0x1EF4: 0x1001ef4, - 0x1EF5: 0x1001ef5, - 0x1EF6: 0x1001ef6, - 0x1EF7: 0x1001ef7, - 0x1EF8: 0x1001ef8, - 0x1EF9: 0x1001ef9, - 0x01A0: 0x10001a0, - 0x01A1: 0x10001a1, - 0x01AF: 0x10001af, - 0x01B0: 0x10001b0, - 0x20A0: 0x10020a0, - 0x20A1: 0x10020a1, - 0x20A2: 0x10020a2, - 0x20A3: 0x10020a3, - 0x20A4: 0x10020a4, - 0x20A5: 0x10020a5, - 0x20A6: 0x10020a6, - 0x20A7: 0x10020a7, - 0x20A8: 0x10020a8, - 0x20A9: 0x10020a9, - 0x20AA: 0x10020aa, - 0x20AB: 0x10020ab, - 0x20AC: 0x20ac, - 0x2070: 0x1002070, - 0x2074: 0x1002074, - 0x2075: 0x1002075, - 0x2076: 0x1002076, - 0x2077: 0x1002077, - 0x2078: 0x1002078, - 0x2079: 0x1002079, - 0x2080: 0x1002080, - 0x2081: 0x1002081, - 0x2082: 0x1002082, - 0x2083: 0x1002083, - 0x2084: 0x1002084, - 0x2085: 0x1002085, - 0x2086: 0x1002086, - 0x2087: 0x1002087, - 0x2088: 0x1002088, - 0x2089: 0x1002089, - //0x2202: 0x08ef, - 0x2202: 0x1002202, - 0x2205: 0x1002205, - 0x2208: 0x1002208, - 0x2209: 0x1002209, - 0x220B: 0x100220B, - //0x221A: 0x08d6, - 0x221A: 0x100221A, - 0x221B: 0x100221B, - 0x221C: 0x100221C, - 0x222C: 0x100222C, - 0x222D: 0x100222D, - 0x2235: 0x1002235, - 0x2245: 0x1002248, - 0x2247: 0x1002247, - 0x2262: 0x1002262, - 0x2263: 0x1002263, - 0x2800: 0x1002800, - 0x2801: 0x1002801, - 0x2802: 0x1002802, - 0x2803: 0x1002803, - 0x2804: 0x1002804, - 0x2805: 0x1002805, - 0x2806: 0x1002806, - 0x2807: 0x1002807, - 0x2808: 0x1002808, - 0x2809: 0x1002809, - 0x280a: 0x100280a, - 0x280b: 0x100280b, - 0x280c: 0x100280c, - 0x280d: 0x100280d, - 0x280e: 0x100280e, - 0x280f: 0x100280f, - 0x2810: 0x1002810, - 0x2811: 0x1002811, - 0x2812: 0x1002812, - 0x2813: 0x1002813, - 0x2814: 0x1002814, - 0x2815: 0x1002815, - 0x2816: 0x1002816, - 0x2817: 0x1002817, - 0x2818: 0x1002818, - 0x2819: 0x1002819, - 0x281a: 0x100281a, - 0x281b: 0x100281b, - 0x281c: 0x100281c, - 0x281d: 0x100281d, - 0x281e: 0x100281e, - 0x281f: 0x100281f, - 0x2820: 0x1002820, - 0x2821: 0x1002821, - 0x2822: 0x1002822, - 0x2823: 0x1002823, - 0x2824: 0x1002824, - 0x2825: 0x1002825, - 0x2826: 0x1002826, - 0x2827: 0x1002827, - 0x2828: 0x1002828, - 0x2829: 0x1002829, - 0x282a: 0x100282a, - 0x282b: 0x100282b, - 0x282c: 0x100282c, - 0x282d: 0x100282d, - 0x282e: 0x100282e, - 0x282f: 0x100282f, - 0x2830: 0x1002830, - 0x2831: 0x1002831, - 0x2832: 0x1002832, - 0x2833: 0x1002833, - 0x2834: 0x1002834, - 0x2835: 0x1002835, - 0x2836: 0x1002836, - 0x2837: 0x1002837, - 0x2838: 0x1002838, - 0x2839: 0x1002839, - 0x283a: 0x100283a, - 0x283b: 0x100283b, - 0x283c: 0x100283c, - 0x283d: 0x100283d, - 0x283e: 0x100283e, - 0x283f: 0x100283f, - 0x2840: 0x1002840, - 0x2841: 0x1002841, - 0x2842: 0x1002842, - 0x2843: 0x1002843, - 0x2844: 0x1002844, - 0x2845: 0x1002845, - 0x2846: 0x1002846, - 0x2847: 0x1002847, - 0x2848: 0x1002848, - 0x2849: 0x1002849, - 0x284a: 0x100284a, - 0x284b: 0x100284b, - 0x284c: 0x100284c, - 0x284d: 0x100284d, - 0x284e: 0x100284e, - 0x284f: 0x100284f, - 0x2850: 0x1002850, - 0x2851: 0x1002851, - 0x2852: 0x1002852, - 0x2853: 0x1002853, - 0x2854: 0x1002854, - 0x2855: 0x1002855, - 0x2856: 0x1002856, - 0x2857: 0x1002857, - 0x2858: 0x1002858, - 0x2859: 0x1002859, - 0x285a: 0x100285a, - 0x285b: 0x100285b, - 0x285c: 0x100285c, - 0x285d: 0x100285d, - 0x285e: 0x100285e, - 0x285f: 0x100285f, - 0x2860: 0x1002860, - 0x2861: 0x1002861, - 0x2862: 0x1002862, - 0x2863: 0x1002863, - 0x2864: 0x1002864, - 0x2865: 0x1002865, - 0x2866: 0x1002866, - 0x2867: 0x1002867, - 0x2868: 0x1002868, - 0x2869: 0x1002869, - 0x286a: 0x100286a, - 0x286b: 0x100286b, - 0x286c: 0x100286c, - 0x286d: 0x100286d, - 0x286e: 0x100286e, - 0x286f: 0x100286f, - 0x2870: 0x1002870, - 0x2871: 0x1002871, - 0x2872: 0x1002872, - 0x2873: 0x1002873, - 0x2874: 0x1002874, - 0x2875: 0x1002875, - 0x2876: 0x1002876, - 0x2877: 0x1002877, - 0x2878: 0x1002878, - 0x2879: 0x1002879, - 0x287a: 0x100287a, - 0x287b: 0x100287b, - 0x287c: 0x100287c, - 0x287d: 0x100287d, - 0x287e: 0x100287e, - 0x287f: 0x100287f, - 0x2880: 0x1002880, - 0x2881: 0x1002881, - 0x2882: 0x1002882, - 0x2883: 0x1002883, - 0x2884: 0x1002884, - 0x2885: 0x1002885, - 0x2886: 0x1002886, - 0x2887: 0x1002887, - 0x2888: 0x1002888, - 0x2889: 0x1002889, - 0x288a: 0x100288a, - 0x288b: 0x100288b, - 0x288c: 0x100288c, - 0x288d: 0x100288d, - 0x288e: 0x100288e, - 0x288f: 0x100288f, - 0x2890: 0x1002890, - 0x2891: 0x1002891, - 0x2892: 0x1002892, - 0x2893: 0x1002893, - 0x2894: 0x1002894, - 0x2895: 0x1002895, - 0x2896: 0x1002896, - 0x2897: 0x1002897, - 0x2898: 0x1002898, - 0x2899: 0x1002899, - 0x289a: 0x100289a, - 0x289b: 0x100289b, - 0x289c: 0x100289c, - 0x289d: 0x100289d, - 0x289e: 0x100289e, - 0x289f: 0x100289f, - 0x28a0: 0x10028a0, - 0x28a1: 0x10028a1, - 0x28a2: 0x10028a2, - 0x28a3: 0x10028a3, - 0x28a4: 0x10028a4, - 0x28a5: 0x10028a5, - 0x28a6: 0x10028a6, - 0x28a7: 0x10028a7, - 0x28a8: 0x10028a8, - 0x28a9: 0x10028a9, - 0x28aa: 0x10028aa, - 0x28ab: 0x10028ab, - 0x28ac: 0x10028ac, - 0x28ad: 0x10028ad, - 0x28ae: 0x10028ae, - 0x28af: 0x10028af, - 0x28b0: 0x10028b0, - 0x28b1: 0x10028b1, - 0x28b2: 0x10028b2, - 0x28b3: 0x10028b3, - 0x28b4: 0x10028b4, - 0x28b5: 0x10028b5, - 0x28b6: 0x10028b6, - 0x28b7: 0x10028b7, - 0x28b8: 0x10028b8, - 0x28b9: 0x10028b9, - 0x28ba: 0x10028ba, - 0x28bb: 0x10028bb, - 0x28bc: 0x10028bc, - 0x28bd: 0x10028bd, - 0x28be: 0x10028be, - 0x28bf: 0x10028bf, - 0x28c0: 0x10028c0, - 0x28c1: 0x10028c1, - 0x28c2: 0x10028c2, - 0x28c3: 0x10028c3, - 0x28c4: 0x10028c4, - 0x28c5: 0x10028c5, - 0x28c6: 0x10028c6, - 0x28c7: 0x10028c7, - 0x28c8: 0x10028c8, - 0x28c9: 0x10028c9, - 0x28ca: 0x10028ca, - 0x28cb: 0x10028cb, - 0x28cc: 0x10028cc, - 0x28cd: 0x10028cd, - 0x28ce: 0x10028ce, - 0x28cf: 0x10028cf, - 0x28d0: 0x10028d0, - 0x28d1: 0x10028d1, - 0x28d2: 0x10028d2, - 0x28d3: 0x10028d3, - 0x28d4: 0x10028d4, - 0x28d5: 0x10028d5, - 0x28d6: 0x10028d6, - 0x28d7: 0x10028d7, - 0x28d8: 0x10028d8, - 0x28d9: 0x10028d9, - 0x28da: 0x10028da, - 0x28db: 0x10028db, - 0x28dc: 0x10028dc, - 0x28dd: 0x10028dd, - 0x28de: 0x10028de, - 0x28df: 0x10028df, - 0x28e0: 0x10028e0, - 0x28e1: 0x10028e1, - 0x28e2: 0x10028e2, - 0x28e3: 0x10028e3, - 0x28e4: 0x10028e4, - 0x28e5: 0x10028e5, - 0x28e6: 0x10028e6, - 0x28e7: 0x10028e7, - 0x28e8: 0x10028e8, - 0x28e9: 0x10028e9, - 0x28ea: 0x10028ea, - 0x28eb: 0x10028eb, - 0x28ec: 0x10028ec, - 0x28ed: 0x10028ed, - 0x28ee: 0x10028ee, - 0x28ef: 0x10028ef, - 0x28f0: 0x10028f0, - 0x28f1: 0x10028f1, - 0x28f2: 0x10028f2, - 0x28f3: 0x10028f3, - 0x28f4: 0x10028f4, - 0x28f5: 0x10028f5, - 0x28f6: 0x10028f6, - 0x28f7: 0x10028f7, - 0x28f8: 0x10028f8, - 0x28f9: 0x10028f9, - 0x28fa: 0x10028fa, - 0x28fb: 0x10028fb, - 0x28fc: 0x10028fc, - 0x28fd: 0x10028fd, - 0x28fe: 0x10028fe, - 0x28ff: 0x10028ff - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Broadway.unicodeTable = unicodeTable; - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI, OSjs.API); diff --git a/src/client/javascript/broadway/window.js b/src/client/javascript/broadway/window.js deleted file mode 100644 index e9e5d58e1d..0000000000 --- a/src/client/javascript/broadway/window.js +++ /dev/null @@ -1,205 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -(function(Application, Window, Utils, VFS, GUI, API) { - 'use strict'; - - /** - * @namespace Broadway - * @memberof OSjs - */ - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// - - /** - * Broadway Window - * - * @param {Number} id Window ID - * @param {Number} x X Position - * @param {Number} y Y Position - * @param {Number} w Width - * @param {Number} h Height - * @param {Node} canvas Canvas DOM Node - * - * @abstract - * @constructor - * @memberof OSjs.Broadway - * @extends OSjs.Core.Window - */ - function BroadwayWindow(id, x, y, w, h, canvas) { - Window.apply(this, ['BroadwayWindow' + String(id), { - width: w, - height: h, - title: 'Broadway Window ' + String(id), - min_width: 100, - min_height: 100, - allow_resize: false, - allow_minimize: false, - allow_maximize: false, - allow_session: false, - //allow_close: false, - key_capture: true // IMPORTANT - }]); - - this._broadwayId = id; - this._canvas = canvas; - } - - BroadwayWindow.prototype = Object.create(Window.prototype); - - BroadwayWindow.prototype.init = function() { - var self = this; - var root = Window.prototype.init.apply(this, arguments); - - this._canvas.width = this._dimension.w; - this._canvas.height = this._dimension.h; - - function getMousePos(ev) { - var wm = OSjs.Core.getWindowManager(); - var theme = wm ? wm.getStyleTheme(true) : null; - var topMargin = theme ? (theme.style.window.margin) : 26; - - return { - x: ev.pageX - self._position.x, - y: ev.pageY - self._position.y - topMargin - }; - } - - function inject(type, ev) { - var pos = getMousePos(ev); - return OSjs.Broadway.GTK.inject(self._broadwayId, type, ev, { - wx: self._position.x, - wy: self._position.y, - mx: parseInt(pos.x, 0), - my: parseInt(pos.y, 0) - }); - } - - Utils.$bind(root, 'mouseover', function(ev) { - return inject('mouseover', ev); - }); - Utils.$bind(root, 'mouseout', function(ev) { - return inject('mouseout', ev); - }); - Utils.$bind(root, 'mousemove', function(ev) { - return inject('mousemove', ev); - }); - Utils.$bind(root, 'mousedown', function(ev) { - return inject('mousedown', ev); - }); - Utils.$bind(root, 'mouseup', function(ev) { - return inject('mouseup', ev); - }); - Utils.$bind(root, 'DOMMouseScroll', function(ev) { - return inject('mousewheel', ev); - }); - Utils.$bind(root, 'mousewheel', function(ev) { - return inject('mousewheel', ev); - }); - - root.appendChild(this._canvas); - return root; - }; - - BroadwayWindow.prototype.destroy = function() { - Window.prototype.destroy.apply(this, arguments); - this._canvas = null; - }; - - BroadwayWindow.prototype._inited = function() { - Window.prototype._inited.apply(this, arguments); - - this._onChange('move', true); - }; - - BroadwayWindow.prototype._close = function() { - if ( !Window.prototype._close.apply(this, arguments) ) { - return false; - } - - OSjs.Broadway.GTK.close(this._broadwayId); - - return true; - }; - - BroadwayWindow.prototype._resize = function(w, h) { - if ( !Window.prototype._resize.apply(this, [w, h, true]) ) { - return false; - } - - function resizeCanvas(canvas, w, h) { - var tmpCanvas = canvas.ownerDocument.createElement('canvas'); - tmpCanvas.width = canvas.width; - tmpCanvas.height = canvas.height; - var tmpContext = tmpCanvas.getContext('2d'); - tmpContext.globalCompositeOperation = 'copy'; - tmpContext.drawImage(canvas, 0, 0, tmpCanvas.width, tmpCanvas.height); - - canvas.width = w; - canvas.height = h; - - var context = canvas.getContext('2d'); - - context.globalCompositeOperation = 'copy'; - context.drawImage(tmpCanvas, 0, 0, tmpCanvas.width, tmpCanvas.height); - } - - if ( this._canvas ) { - resizeCanvas(this._canvas, w, h); - } - - return true; - }; - - BroadwayWindow.prototype._onKeyEvent = function(ev, type) { - OSjs.Broadway.GTK.inject(this._broadwayId, type, ev); - }; - - BroadwayWindow.prototype._onChange = function(ev, byUser) { - if ( !byUser ) { - return; - } - - if ( ev === 'move' ) { - OSjs.Broadway.GTK.move(this._broadwayId, this._position.x, this._position.y); - } else if ( ev === 'resize' ) { - OSjs.Broadway.GTK.resize(this._broadwayId, this._dimension.w, this._dimension.h); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Broadway.Window = BroadwayWindow; - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI, OSjs.API); diff --git a/src/client/javascript/core/api.js b/src/client/javascript/core/api.js deleted file mode 100644 index af94bda4f8..0000000000 --- a/src/client/javascript/core/api.js +++ /dev/null @@ -1,1926 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -(function(Utils, API) { - 'use strict'; - - /** - * @namespace API - * @memberof OSjs - */ - - /** - * @namespace Core - * @memberof OSjs - */ - - /** - * @namespace Utils - * @memberof OSjs - */ - - /** - * @namespace Helpers - * @memberof OSjs - */ - - /*@ - * Please note that there are some more methods defined in `process.js` - */ - - var DefaultLocale = 'en_EN'; - var CurrentLocale = 'en_EN'; - - var _CLIPBOARD; // Current 'clipboard' data - var _LAUNCHING = []; - - var _hooks = { - 'onInitialize': [], - 'onInited': [], - 'onWMInited': [], - 'onSessionLoaded': [], - 'onShutdown': [], - 'onApplicationPreload': [], - 'onApplicationLaunch': [], - 'onApplicationLaunched': [], - 'onBlurMenu': [] - }; - - ///////////////////////////////////////////////////////////////////////////// - // SERVICERING - ///////////////////////////////////////////////////////////////////////////// - - /* - * Service Notification Icon Class - * - * This is a private class and can only be retrieved through - * OSjs.API.getServiceNotificationIcon() - */ - 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/dialog-password.png'), - onContextMenu: show, - onClick: show, - onInited: function(el, img) { - self._updateIcon(); - } - }); - - this._updateIcon(); - } - }; - - /* - * Destroys the notification icon - */ - 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())); - } - }; - - /* - * Show the menu - */ - 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); - }; - - /* - * Adds an entry - */ - ServiceNotificationIcon.prototype.add = function(name, menu) { - if ( !this.entries[name] ) { - this.entries[name] = menu; - - this.size++; - this._updateIcon(); - } - }; - - /* - * Removes an entry - */ - ServiceNotificationIcon.prototype.remove = function(name) { - if ( this.entries[name] ) { - delete this.entries[name]; - this.size--; - this._updateIcon(); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // LOCALE API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Translate given string - * - * @function _ - * @memberof OSjs.API - * - * @param {String} s Translation key/string - * @param {...String} sargs Format values - * - * @return {String} - */ - API._ = function API_() { - var s = arguments[0]; - var a = arguments; - - try { - var cl = OSjs.Locales[CurrentLocale]; - if ( cl && cl[s] ) { - a[0] = cl[s]; - } else { - a[0] = OSjs.Locales[DefaultLocale][s] || s; - } - - return a.length > 1 ? Utils.format.apply(null, a) : a[0]; - } catch ( e ) { - console.warn(e.stack, e); - } - - return s; - }; - - /** - * Same as _ only you can supply the list as first argument - * - * @function __ - * @memberof OSjs.API - * @see OSjs.API._ - * - * @return {String} - */ - API.__ = function API__() { - 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]; - }; - - /** - * Get current locale - * - * @function getLocale - * @memberof OSjs.API - * - * @return {String} - */ - API.getLocale = function API_getLocale() { - return CurrentLocale; - }; - - /** - * Set locale - * - * @function setLocale - * @memberof OSjs.API - * - * @param {String} l Locale name - */ - API.setLocale = function API_setLocale(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'); - } - - console.info('API::setLocale()', CurrentLocale); - }; - - ///////////////////////////////////////////////////////////////////////////// - // REQUEST API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Perform cURL call - * - * The response is in form of: {httpCode, body} - * - * @function curl - * @memberof OSjs.API - * - * @param {Object} args cURL Arguments (see docs) - * @param {Function} callback Callback function => fn(error, response) - * - * @link https://os-js.org/manual/api/usage/curl/ - */ - API.curl = function API_curl(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); - }; - - /** - * Global function for calling API (backend) - * - * You can call VFS functions by prefixing your method name with "FS:" - * - * @function call - * @memberof OSjs.API - * @see OSjs.Core.Connection#request - * @see OSjs.Utils.ajax - * @throws {Error} On invalid arguments - * - * @param {String} m Method name - * @param {Object} a Method arguments - * @param {Function} cb Callback on success => fn(err, res) - * @param {Object} [options] Options (all options except the ones listed below are sent to Connection) - * @param {Boolean} [options.indicator=true] Show loading indicator - */ - var _CALL_INDEX = 1; - API.call = function API_call(m, a, cb, options) { - a = a || {}; - options = options || {}; - - var lname = 'APICall_' + _CALL_INDEX; - - 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'); - } - - if ( options.indicator !== false ) { - API.createLoading(lname, {className: 'BusyNotification', tooltip: 'API Call'}); - } - - if ( typeof options.indicator !== 'undefined' ) { - delete options.indicator; - } - - _CALL_INDEX++; - - var conn = OSjs.Core.getConnection(); - return conn.request(m, a, function API_call_success(response) { - API.destroyLoading(lname); - response = response || {}; - cb(response.error || false, response.result); - }, function API_call_error(err) { - API.destroyLoading(lname); - cb(err); - }, options); - }; - - ///////////////////////////////////////////////////////////////////////////// - // PROCESS API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Open a file - * - * @function open - * @memberof OSjs.API - * @see OSjs.API.launch - * @throws {Error} On invalid arguments - * - * @param {OSjs.VFS.File} file The File reference (can also be a tuple with 'path' and 'mime') - * @param {Object} launchArgs Arguments to send to process launch function - */ - API.open = function API_open(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); - - console.debug('getApplicationNameByFile()', 'default application', val); - if ( !forceList && val ) { - if ( pacman.getPackage(val) ) { - callback([val]); - return; - } - } - callback(pacman.getPackagesByMime(file.mime)); - } - - function setDefaultApplication(mime, app, callback) { - callback = callback || function() {}; - console.debug('setDefaultApplication()', mime, app); - 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) { - console.groupEnd(); - API.launch(name, ar); - } - - function _onDone(app) { - console.debug('Found', app.length, 'applications supporting this mime'); - console.groupEnd(); - 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) - ); - } - } - - console.group('API::open()', file); - - 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); - } - }; - - /** - * Restarts all processes with the given name - * - * This also reloads any metadata preload items defined in the application. - * - * @function relaunch - * @memberof OSjs.API - * - * @param {String} n Application Name - */ - API.relaunch = function API_relaunch(n) { - function relaunch(p) { - var data = null; - var args = {}; - if ( p instanceof OSjs.Core.Application ) { - data = p._getSessionData(); - } - - try { - n = p.__pname; - 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 with 500 ms is used to allow applications that might need - // some time to destroy resources before it can be relaunched. - setTimeout(function() { - API.launch(n, args); - }, 500); - } - - var res = API.getProcess(n); - if ( !(res instanceof Array) ) { - res = [res]; - } - res.forEach(relaunch); - }; - - /** - * Launch a Process - * - * @function launch - * @memberof OSjs.API - * - * @param {String} name Application Name - * @param {Object} [args] Launch arguments - * @param {Function} [ondone] Callback on success - * @param {Function} [onerror] Callback on error - * @param {Function} [onconstruct] Callback on application init - */ - API.launch = function API_launch(name, args, ondone, onerror, onconstruct) { - args = args || {}; - - if ( _LAUNCHING.indexOf(name) !== -1 ) { - console.warn('Application', name, 'is already launching...'); - return; - } - - 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 launchIndex = -1; - - 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 this package depends on another package, make sure - // to load the resources for the related one as well - if ( metadata.depends instanceof Array ) { - metadata.depends.forEach(function(k) { - if ( !OSjs.Applications[k] ) { - console.info('Using dependency', k); - _add(packman.getPackage(k)); - } - }); - } - - // ... same goes for packages that uses this package - // as a dependency. - var pkgs = packman.getPackages(false); - Object.keys(pkgs).forEach(function(pn) { - var p = pkgs[pn]; - if ( p.type === 'extension' && p.uses === name ) { - console.info('Using extension', pn); - _add(p); - } - }); - - list = additions.concat(list); - additions = []; - - // For user packages, make sure to load the correct URL - 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() { - if ( launchIndex >= 0 ) { - _LAUNCHING.splice(launchIndex, 1); - } - - 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 - ); - - console.groupEnd(); - - (onerror || function() {})(err, name, args, exception); - } - - function _onFinished(skip) { - _destroySplash(); - - console.groupEnd(); - - (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 ) { - launchIndex = _LAUNCHING.push(name) - 1; - - if ( running ) { - if ( running instanceof OSjs.Core.Application ) { - // In this case we do not trigger an error. Applications simply get a signal for attention - 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 asyncIter(qi, i, n) { - qi(name, args, preloads, function(p) { - if ( p && (p instanceof Array) ) { - preloads = p; - } - n(); - }); - }, function asyncDone() { - _createSplash(); - cb(); - }); - - API.triggerHook('onApplicationLaunch', [name, args]); - } - - function _preload(cb) { - Utils.preload(preloads, function preloadIter(total, failed, succeeded, data) { - if ( failed.length ) { - cb(API._('ERR_APP_PRELOAD_FAILED_FMT', name, failed.join(','))); - } else { - cb(false, data); - } - }, function preloadDone(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); - - // Main blob - try { - _preLaunch(function onPreLaunch() { - _preload(function onPreload(err, res) { - if ( err ) { - _onError(err, res); - } else { - try { - _createProcess(res, function onCreateProcess(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()); - } - }; - - /** - * Launch Processes from a List - * - * @function launchList - * @memberof OSjs.API - * @see OSjs.API.launch - * - * @param {Array} list List of launch application arguments - * @param {Function} onSuccess Callback on success => fn(app, metadata, appName, appArgs) - * @param {Function} onError Callback on error => fn(error, appName, appArgs) - * @param {Function} onFinished Callback on finished running => fn() - */ - API.launchList = function API_launchList(list, onSuccess, onError, onFinished) { - list = list || []; /* idx => {name: 'string', args: 'object', data: 'mixed, optional'} */ - onSuccess = onSuccess || function() {}; - onError = onError || function() {}; - onFinished = onFinished || function() {}; - - Utils.asyncs(list, function asyncIter(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 launchSuccess(app, metadata) { - onSuccess(app, metadata, aname, aargs); - next(); - }, function launchError(err, name, args) { - console.warn('API::launchList() _onError()', err); - onError(err, name, args); - next(); - }); - }, onFinished); - }; - - ///////////////////////////////////////////////////////////////////////////// - // RESOURCE API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Get a resource from application - * - * @function getApplicationResource - * @memberof OSjs.API - * - * @param {OSjs.Core.Process} app Application instance reference. You can also specify a name by String - * @param {String} name Resource Name - * @param {Boolean} vfspath Return a valid VFS path - * - * @return {String} The absolute URL of resource - */ - API.getApplicationResource = function API_getAppResource(app, name, vfspath) { - if ( name.match(/^(https?:)?\//) ) { - 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) { - 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 = '/user-package/' + OSjs.Utils.filename(pkg.path) + '/' + name.replace(/^\//, ''); - } else { - path = 'packages/' + pkg.path + '/' + name; - } - } - - return getResultPath(path, pkg.scope === 'user'); - })(); - }; - - /** - * Get path to css theme - * - * @function getThemeCSS - * @memberof OSjs.API - * - * @param {String} name CSS Stylesheet name (without extension) - * - * @return {String} The absolute URL of css file - */ - API.getThemeCSS = function API_getThemeCSS(name) { - var root = API.getConfig('Connection.RootURI', '/'); - if ( name === null ) { - return root + 'blank.css'; - } - - root = API.getConfig('Connection.ThemeURI'); - return root + '/' + name + '.min.css'; - }; - - /** - * Get a icon based in file and mime - * - * @function getFileIcon - * @memberof OSjs.API - * - * @param {File} file File Data (see supported types) - * @param {String} [size=16x16] Icon size - * @param {String} [icon] Default icon - * - * @return {String} The absolute URL to the icon - */ - API.getFileIcon = function API_getFileIcon(file, size, icon) { - icon = icon || 'mimetypes/text-x-preview.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/x-office-document.png'}, - {match: 'application/zip', icon: 'mimetypes/package-x-generic.png'}, - {match: 'application/x-python', icon: 'mimetypes/text-x-script.png'}, - {match: 'application/x-lua', icon: 'mimetypes/text-x-script.png'}, - {match: 'application/javascript', icon: 'mimetypes/text-x-script.png'}, - {match: 'text/html', icon: 'mimetypes/text-html.png'}, - {match: 'text/xml', icon: 'mimetypes/text-html.png'}, - {match: 'text/css', icon: 'mimetypes/text-x-script.png'}, - - {match: 'osjs/document', icon: 'mimetypes/x-office-document.png'}, - {match: 'osjs/draw', icon: 'mimetypes/image-x-generic.png'}, - - {match: /^text\//, icon: 'mimetypes/text-x-generic.png'}, - {match: /^audio\//, icon: 'mimetypes/audio-x-generic.png'}, - {match: /^video\//, icon: 'mimetypes/video-x-generic.png'}, - {match: /^image\//, icon: 'mimetypes/image-x-generic.png'}, - {match: /^application\//, icon: 'mimetypes/application-x-executable.png'} - ]; - - if ( file.type === 'dir' ) { - icon = 'places/folder.png'; - } else if ( file.type === 'trash' ) { - icon = 'places/user-trash.png'; - } else if ( file.type === 'application' ) { - var pm = OSjs.Core.getPackageManager(); - var appname = Utils.filename(file.path); - var meta = pm.getPackage(appname); - - if ( meta ) { - return API.getIcon(meta.icon, size, appname); - } - } 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); - }; - - /** - * Default method for getting a resource from current theme - * - * @function getThemeResource - * @memberof OSjs.API - * - * @param {String} name Resource filename - * @param {String} type Type ('base' or a sub-folder) - * - * @return {String} The absolute URL to the resource - */ - API.getThemeResource = function API_getThemeResource(name, type) { - name = name || null; - type = type || null; - - var root = API.getConfig('Connection.ThemeURI'); - - 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 name; - }; - - /** - * Default method for getting a sound from theme - * - * @function getSound - * @memberof OSjs.API - * - * @param {String} name Resource filename - * - * @return {String} The absolute URL to the resource - */ - API.getSound = function API_getSound(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 name; - }; - - /** - * Default method for getting a icon from theme - * - * @function getIcon - * @memberof OSjs.API - * - * @param {String} name Resource filename - * @param {String} [size=16x16] Icon size - * @param {OSjs.Core.Process} [app] Application instance reference. Can also be String. For `name` starting with './' - * - * @return {String} The absolute URL to the resource - */ - API.getIcon = function API_getIcon(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 name; - }; - - /** - * Method for getting a config parameter by path (Ex: "VFS.Mountpoints.shared.enabled") - * - * @function getConfig - * @memberof OSjs.API - * @see OSjs.Core.getConfig - * - * @param {String} [path] Path - * @param {Mixed} [defaultValue=undefined] Use default value - * - * @return {Mixed} Parameter value or entire tree on no path - */ - API.getConfig = function API_getConfig(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; - }; - - /** - * Get default configured path - * - * @function getDefaultPath - * @memberof OSjs.API - * - * @param {String} fallback Fallback path on error (default= "osjs:///") - * @return {String} - */ - API.getDefaultPath = function API_getDefaultPath(fallback) { - if ( fallback && fallback.match(/^\//) ) { - fallback = null; - } - return API.getConfig('VFS.Home') || fallback || 'osjs:///'; - }; - - ///////////////////////////////////////////////////////////////////////////// - // GUI API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Create a new Desktop Notification - * - * @param {Object} opts Notification options - * - * @function createNotification - * @memberof OSjs.API - * @see OSjs.Core.WindowManager#notification - * - * @return {Object} The created notification instance - */ - API.createNotification = function API_createNotification(opts) { - var wm = OSjs.Core.getWindowManager(); - return wm.notification(opts); - }; - - /** - * Create a new dialog - * - * You can also pass a function as `className` to return an instance of your own class - * - * @function createDialog - * @memberof OSjs.API - * - * @param {String} className Dialog Namespace Class Name - * @param {Object} args Arguments you want to send to dialog - * @param {CallbackDialog} callback Callback on dialog action (close/ok etc) => fn(ev, button, result) - * @param {Mixed} [options] A window or app (to make it a child window) or a set of options: - * @param {OSjs.Core.Window|OSjs.Core.Application} [options.parent] Same as above argument (without options context) - * @param {Boolean} [options.modal=false] If you provide a parent you can toggle "modal" mode. - * - * @return {OSjs.Core.Window} - */ - API.createDialog = function API_createDialog(className, args, callback, options) { - callback = callback || function() {}; - options = options || {}; - - var parentObj = options; - var parentIsWindow = (parentObj instanceof OSjs.Core.Window); - var parentIsProcess = (parentObj instanceof OSjs.Core.Process); - if ( parentObj && !(parentIsWindow && parentIsProcess) ) { - parentObj = options.parent; - parentIsWindow = (parentObj instanceof OSjs.Core.Window); - parentIsProcess = (parentObj instanceof OSjs.Core.Process); - } - - function cb() { - if ( parentObj ) { - if ( parentIsWindow && parentObj._destroyed ) { - console.warn('API::createDialog()', 'INGORED EVENT: Window was destroyed'); - return; - } - if ( parentIsProcess && parentObj.__destroyed ) { - console.warn('API::createDialog()', 'INGORED EVENT: Process was destroyed'); - return; - } - } - - if ( options.modal && parentIsWindow ) { - parentObj._toggleDisabled(false); - } - - 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); - } - - if ( options.modal && parentIsWindow ) { - parentObj._toggleDisabled(true); - } - - setTimeout(function() { - win._focus(); - }, 10); - - return win; - }; - - /** - * Create (or show) loading indicator - * - * @function createLoading - * @memberof OSjs.API - * - * @param {String} name Name of notification (unique) - * @param {Object} opts Options - * @param {Number} [panelId] Panel ID - * - * @return {String} Or false on error - */ - API.createLoading = function API_createLoading(name, opts, panelId) { - try { - var wm = OSjs.Core.getWindowManager(); - if ( wm && wm.createNotificationIcon(name, opts, panelId) ) { - return name; - } - } catch ( e ) { - console.warn(e, e.stack); - } - - return false; - }; - - /** - * Destroy (or hide) loading indicator - * - * @function destroyLoading - * @memberof OSjs.API - * - * @param {String} name Name of notification (unique) - * @param {Number} [panelId] Panel ID - * - * @return {Boolean} - */ - API.destroyLoading = function API_destroyLoading(name, panelId) { - try { - var wm = OSjs.Core.getWindowManager(); - if ( wm && wm.removeNotificationIcon(name, panelId) ) { - return true; - } - } catch ( e ) { - console.warn(e, e.stack); - } - - return false; - }; - - /** - * Checks the given permission (groups) against logged in user - * - * @function checkPermission - * @memberof OSjs.API - * - * @param {Mixed} group Either a string or array of groups - * - * @return {Boolean} - */ - API.checkPermission = function API_checkPermission(group) { - var user = OSjs.Core.getAuthenticator().getUser(); - 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; - }; - - /** - * Creates a new splash screen - * - * @function createSplash - * @memberof OSjs.API - * - * @param {String} name The name to display - * @param {String} icon The icon to display - * @param {String} [label=Starting] The label - * @param {Node} [parentEl] The parent element - * - * @return {Object} - */ - API.createSplash = function API_createSplash(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 progressBar; - - if ( img ) { - splash.appendChild(img); - } - splash.appendChild(title); - - try { - progressBar = OSjs.GUI.Element.create('gui-progress-bar'); - splash.appendChild(progressBar.$element); - } catch ( e ) { - console.warn(e, e.stack); - } - - parentEl.appendChild(splash); - - return { - destroy: function() { - splash = Utils.$remove(splash); - - img = null; - title = null; - titleText = null; - progressBar = null; - }, - - update: function(p, c) { - if ( !splash || !progressBar ) { - return; - } - - var per = c ? 0 : 100; - if ( c ) { - per = (p / c) * 100; - } - progressBar.set('value', per); - } - }; - }; - - ///////////////////////////////////////////////////////////////////////////// - // MISC API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Global function for showing an error dialog - * - * @function error - * @memberof OSjs.API - * - * @param {String} title Dialog title - * @param {String} message Dialog message - * @param {String} error Error message - * @param {Object} [exception] Exception reference - * @param {Boolean} [bugreport=false] Enable bugreporting for this error - */ - API.error = function API_error(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); - console.warn(title, message, error, exception); - } - }; - - /** - * Global function for playing a sound - * - * @function playSound - * @memberof OSjs.API - * - * @param {String} name Sound name - * @param {Number} volume Sound volume (0.0 - 1.0) - * - * @return {Audio} - */ - API.playSound = function API_playSound(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 ) { - console.debug('API::playSound()', 'Cannot play sound!'); - return false; - } - - if ( typeof volume === 'undefined' ) { - volume = 1.0; - } - - var f = API.getSound(filename); - console.debug('API::playSound()', name, filename, f, volume); - - var a = new Audio(f); - a.volume = volume; - a.play(); - return a; - }; - - /** - * Set the "clipboard" data - * - * NOTE: This does not set the operating system clipboard (yet...) - * - * @function setClipboard - * @memberof OSjs.API - * - * @param {Mixed} data What data to set - */ - API.setClipboard = function API_setClipboard(data) { - console.debug('OSjs.API.setClipboard()', data); - _CLIPBOARD = data; - }; - - /** - * Get the "clipboard" data - * - * NOTE: This does not the operating system clipboard (yet...) - * - * @function getClipboard - * @memberof OSjs.API - * - * @return {Mixed} - */ - API.getClipboard = function API_getClipboard() { - return _CLIPBOARD; - }; - - /** - * Returns an instance of ServiceNotificationIcon - * - * This is the icon in the panel where external connections - * etc gets a menu entry. - * - * @function getServiceNotificationIcon - * @memberof OSjs.API - * - * @return {ServiceNotificationIcon} - */ - API.getServiceNotificationIcon = (function() { - var _instance; - - return function _apiGetServiceNotificationIcon() { - if ( !_instance ) { - _instance = new ServiceNotificationIcon(); - } - return _instance; - }; - })(); - - /** - * Toggles fullscreen of an element - * - * @function toggleFullscreen - * @memberof OSjs.API - * - * @param {Node} el The DOM Node - * @param {Boolean} [t] Toggle value (auto-detected) - */ - 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; - }; - - })(); - - ///////////////////////////////////////////////////////////////////////////// - // MISC - ///////////////////////////////////////////////////////////////////////////// - - /** - * Checks if running OS.js instance is in standalone mode - * - * @function isStandalone - * @memberof OSjs.API - * @return {Boolean} - */ - API.isStandalone = function API_isStandlone() { - return API.getConfig('Connection.Type') === 'standalone' || window.location.protocol === 'file:'; - }; - - /** - * Gets the browser window path - * - * @param {String} [app] Append this path - * - * @function getBrowserPath - * @memberof OSjs.API - * @return {String} - */ - API.getBrowserPath = function API_getBrowserPath(app) { - var str = API.getConfig('Connection.RootURI'); - if ( typeof app === 'string' ) { - str = str.replace(/\/?$/, app.replace(/^\/?/, '/')); - } - return str; - }; - - /** - * Signs the user out and shuts down OS.js - * - * @function signOut - * @memberof OSjs.API - */ - API.signOut = function API_signOut() { - var auth = OSjs.Core.getAuthenticator(); - var storage = OSjs.Core.getStorage(); - var wm = OSjs.Core.getWindowManager(); - - function signOut(save) { - API.playSound('LOGOUT'); - - if ( save ) { - storage.saveSession(function() { - auth.logout(function() { - API.shutdown(); - }); - }); - } else { - auth.logout(function() { - API.shutdown(); - }); - } - } - - if ( wm ) { - var user = auth.getUser() || {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); - } - }; - - /** - * Method for triggering a hook - * - * @function triggerHook - * @memberof OSjs.API - * - * @param {String} name Hook name - * @param {Array} args List of arguments - * @param {Object} thisarg 'this' ref - */ - API.triggerHook = function API_triggerHook(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); - } - }); - } - }; - - /** - * Method for adding a hook - * - * @function addHook - * @memberof OSjs.API - * - * @param {String} name Hook name - * @param {Function} fn Callback => fn() - * - * @return {Number} The index of hook - */ - API.addHook = function API_addHook(name, fn) { - if ( typeof _hooks[name] !== 'undefined' ) { - return _hooks[name].push(fn) - 1; - } - return -1; - }; - - /** - * Method for removing a hook - * - * @function removeHook - * @memberof OSjs.API - * - * @param {String} name Hook name - * @param {Number} index Hook index - * - * @return {Boolean} - */ - API.removeHook = function API_removeHook(name, index) { - if ( typeof _hooks[name] !== 'undefined' ) { - if ( _hooks[name][index] ) { - _hooks[name][index] = null; - return true; - } - } - return false; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXTERNALS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Shuts down OS.js - * - * @function shutdown - * @memberof OSjs.API - * @return {Boolean} - */ - API.shutdown = function API_shutdown() { - return OSjs.Bootstrap.stop(); - }; - - /** - * Check if OS.js is shutting down - * - * @function isShuttingDown - * @memberof OSjs.API - * @return {Boolean} - */ - API.isShuttingDown = function API_isShuttingDown() { - return OSjs.Bootstrap.isShuttingDown.apply(null, arguments); - }; - - /** - * @function createMenu - * @memberof OSjs.API - * @see OSjs.GUI.Helpers.createMenu - * - * @return {Boolean} - */ - API.createMenu = function API_createMenu() { - return OSjs.GUI.Helpers.createMenu.apply(null, arguments); - }; - - /** - * @function blurMenu - * @memberof OSjs.API - * @see OSjs.GUI.Helpers.blurMenu - * - * @return {Boolean} - */ - API.blurMenu = function API_blurMenu() { - return OSjs.GUI.Helpers.blurMenu.apply(null, arguments); - }; - - /** - * Get default configured settings - * - * THIS IS JUST A PLACEHOLDER. 'settings.js' SHOULD HAVE THIS! - * - * You should use 'OSjs.API.getConfig()' to get a setting - * - * @function getConfig - * @memberof OSjs.Core - * @see OSjs.API.getConfig - * - * @return {Object} - */ - OSjs.Core.getConfig = OSjs.Core.getConfig || function() { - return {}; - }; - - /** - * Get default configured packages - * - * THIS IS JUST A PLACEHOLDER. 'packages.js' SHOULD HAVE THIS! - * - * @function getMetadata - * @memberof OSjs.Core - * - * @return {Metadata[]} - */ - OSjs.Core.getMetadata = OSjs.Core.getMetadata || function() { - return {}; - }; - -})(OSjs.Utils, OSjs.API); diff --git a/src/client/javascript/core/application.js b/src/client/javascript/core/application.js index 4018a5c336..50f3664f7f 100644 --- a/src/client/javascript/core/application.js +++ b/src/client/javascript/core/application.js @@ -27,134 +27,117 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API, Process) { - 'use strict'; - /** - * Look at the 'ProcessEvent' for more. - * The predefined events are as follows: - * - *

-   *  init        When application was inited              => (settings, metadata, scheme)
-   * 
- * @typedef ApplicationEvent - */ +import Process from 'core/process'; +import SettingsManager from 'core/settings-manager'; +import WindowManager from 'core/window-manager'; +import Window from 'core/window'; - ///////////////////////////////////////////////////////////////////////////// - // APPLICATION - ///////////////////////////////////////////////////////////////////////////// +/** + * Look at the 'ProcessEvent' for more. + * The predefined events are as follows: + * + *

+ *  init        When application was inited              => (settings, metadata)
+ * 
+ * @typedef ApplicationEvent + */ - /** - * Application Class - * - * The 'Process arguments' is a JSON object with the arguments the - * Applications was launched with. Just like 'argv' - * - *

-   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
-   * 
- * - * @summary Class used for basis as an Application. - * - * @param {String} name Process name - * @param {Object} args Process arguments - * @param {Metadata} metadata Application metadata - * @param {Object} [settings] Application settings - * - * @link https://os-js.org/manual/package/application/ - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @extends OSjs.Core.Process - */ - function Application(name, args, metadata, settings) { +///////////////////////////////////////////////////////////////////////////// +// APPLICATION +///////////////////////////////////////////////////////////////////////////// + +/** + * Application Base Class + * + * @desc The class used for creating Applications. + * + * @param {String} name Process name + * @param {Object} args Process arguments + * @param {Metadata} metadata Application metadata + * @param {Object} [settings] Application settings + * @param {Object} [options] Options + * @param {Boolean} [options.closeWithMain=true] Close application when main window closes + * @param {Boolean} [options.closeOnEmpty=false] Close applications when all windows have been removed + * + * @link https://manual.os-js.org/packages/ + * + * @abstract + */ +export default class Application extends Process { + + constructor(name, args, metadata, settings, options) { console.group('Application::constructor()', arguments); + options = Object.assign({ + closeWithMain: true, + closeOnEmpty: true + }, options || {}); + + super(...arguments); + /** * If Application was inited - * @name __inited - * @memberof OSjs.Core.Application# * @type {Boolean} */ this.__inited = false; /** * Registered main window - * @name __mainwindow - * @memberof OSjs.Core.Application# - * @type {OSjs.Core.Window} + * @type {Window} */ this.__mainwindow = null; - /** - * Scheme reference - * @name __scheme - * @memberof OSjs.Core.Application# - * @type {OSjs.GUI.Scheme} - */ - this.__scheme = null; - /** * Registered Windows - * @name __windows - * @memberof OSjs.Core.Application# - * @type {OSjs.Core.Window[]} + * @type {Window[]} */ this.__windows = []; /** * Registered Settings - * @name __settings - * @memberof OSjs.Core.Application# * @type {Object} */ - this.__settings = {}; + this.__settings = null; /** * If is in the process of destroying - * @name __destroying - * @memberof OSjs.Core.Application# * @type {Boolean} */ this.__destroying = false; + /** + * Custom options + * @type {Object} + */ + this.__options = options; + try { - this.__settings = OSjs.Core.getSettingsManager().instance(name, settings || {}); + this.__settings = SettingsManager.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, {}); + this.__settings = SettingsManager.instance(name, {}); } - Process.apply(this, arguments); - console.groupEnd(); } - Application.prototype = Object.create(Process.prototype); - Application.constructor = Process; - /** * Initialize the Application * - * @function init - * @memberof OSjs.Core.Application# - * - * @param {Object} settings Settings JSON - * @param {Metadata} metadata Metadata JSON - * @param {OSjs.GUI.Scheme} [scheme] GUI Scheme instance + * @param {Object} settings Settings JSON + * @param {Object} metadata Metadata JSON */ - Application.prototype.init = function(settings, metadata, scheme) { + init(settings, metadata) { - var wm = OSjs.Core.getWindowManager(); - var self = this; + const wm = WindowManager.instance; - function focusLastWindow() { - var last; + const focusLastWindow = () => { + let last; if ( wm ) { - self.__windows.forEach(function(win, i) { + this.__windows.forEach((win, i) => { if ( win ) { wm.addWindow(win); last = win; @@ -165,82 +148,79 @@ if ( last ) { last._focus(); } - } + }; if ( !this.__inited ) { console.debug('Application::init()', this.__pname); - if ( scheme ) { - this._setScheme(scheme); + if ( this.__settings ) { + this.__settings.set(null, settings); } - this.__settings.set(null, settings); - this.__inited = true; - this.__evHandler.emit('init', [settings, metadata, scheme]); + this.__evHandler.emit('init', [settings, metadata]); focusLastWindow(); } - }; + } /** * Destroy the application * * @override - * @function destroy - * @memberof OSjs.Core.Application# - * @see OSjs.Core.Process#destroy */ - Application.prototype.destroy = function(sourceWid) { + destroy() { if ( this.__destroying || this.__destroyed ) { // From 'process.js' return true; } + this.__destroying = true; console.group('Application::destroy()', this.__pname); - 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 = []; + this.__windows.forEach((w) => (w && w.destroy())); if ( this.__scheme && typeof this.__scheme.destroy === 'function' ) { this.__scheme.destroy(); } + + this.__mainwindow = null; + this.__settings = {}; + this.__windows = []; this.__scheme = null; - var result = Process.prototype.destroy.apply(this, arguments); + const result = super.destroy(...arguments); console.groupEnd(); return result; - }; + } /** * Application has received a message * + * @param {String} msg Message + * @param {Object} obj Message object + * @param {Object} args Arguments * @override - * @function _onMessage - * @memberof OSjs.Core.Application# */ - Application.prototype._onMessage = function(msg, obj, args) { + _onMessage(msg, obj, args) { if ( this.__destroying || this.__destroyed ) { return false; } if ( msg === 'destroyWindow' ) { - if ( obj._name === this.__mainwindow ) { - this.destroy(obj._wid); - } else { + if ( !this.__destroying ) { this._removeWindow(obj); + + if ( this.__options.closeOnEmpty && !this.__windows.length ) { + console.info('All windows removed, destroying application'); + this.destroy(); + } else if ( obj._name === this.__mainwindow ) { + if ( this.__options.closeWithMain ) { + console.info('Main window was closed, destroying application'); + this.destroy(); + } + } } } else if ( msg === 'attention' ) { if ( this.__windows.length && this.__windows[0] ) { @@ -248,47 +228,22 @@ } } - return Process.prototype._onMessage.apply(this, arguments); - }; - - /** - * Default method for loading a Scheme file - * - * @TODO DEPRECATED This is kept for backward compability - * - * @function _loadScheme - * @memberof OSjs.Core.Application# - * - * @param {String} s Scheme filename - * @param {Function} cb Callback => fn(scheme) - */ - 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); - }; + return super._onMessage(...arguments); + } /** * Add a window to the application * * This will automatically add it to the WindowManager and show it to you * - * @function _addWindow - * @memberof OSjs.Core.Application# - * - * @param {OSjs.Core.Window} w The Window - * @param {Function} [cb] Callback for when window was successfully inited - * @param {Boolean} [setmain] Set if this is the main window (First window always will be) + * @param {Window} w The Window + * @param {Function} [cb] Callback for when window was successfully inited + * @param {Boolean} [setmain] Set if this is the main window (First window always will be) * - * @return {OSjs.Core.Window} + * @return {Window} */ - Application.prototype._addWindow = function(w, cb, setmain) { - if ( !(w instanceof OSjs.Core.Window) ) { + _addWindow(w, cb, setmain) { + if ( !(w instanceof Window) ) { throw new TypeError('Application::_addWindow() expects Core.Window'); } @@ -299,14 +254,14 @@ this.__mainwindow = w._name; } - var wm = OSjs.Core.getWindowManager(); + const wm = WindowManager.instance; if ( this.__inited ) { if ( wm ) { wm.addWindow(w); } if ( w._properties.start_focused ) { - setTimeout(function() { + setTimeout(() => { w._focus(); }, 5); } @@ -315,39 +270,36 @@ (cb || function() {})(w, wm); return w; - }; + } /** * Removes given Window * - * @function _removeWindow - * @memberof OSjs.Core.Application# - * - * @param {OSjs.Core.Window} w The Windo + * @param {Window} w The Windo * * @return {Boolean} */ - Application.prototype._removeWindow = function(w) { - if ( !(w instanceof OSjs.Core.Window) ) { + _removeWindow(w) { + if ( !(w instanceof Window) ) { throw new TypeError('Application::_removeWindow() expects Core.Window'); } - var self = this; - return this.__windows.some(function(win, i) { - if ( win ) { - if ( win._wid === w._wid ) { - console.debug('Application::_removeWindow()', w._wid); - win.destroy(); - - self.__windows.splice(i, 1); + const found = this.__windows.findIndex((win) => win && win._wid === w._wid); + if ( found !== -1 ) { + const win = this.__windows[found]; - return true; - } + console.debug('Application::_removeWindow()', win._wid); + try { + win.destroy(); + } catch ( e ) { + console.warn(e); } - return true; - }); - }; + this.__windows.splice(found, 1); + } + + return found !== -1; + } /** * Gets a Window by X @@ -357,22 +309,19 @@ * * If you specify 'null' it will try to return the 'main' window. * - * @function _getWindow - * @memberof OSjs.Core.Application# - * * @param {String} value The value - * @param {Mixed} key The key to check for + * @param {String} key The key to check for * - * @return {OSjs.Core.Window} Or null on error or nothing + * @return {Window} Or null on error or nothing */ - Application.prototype._getWindow = function(value, key) { + _getWindow(value, key) { key = key || 'name'; if ( value === null ) { value = this.__mainwindow; } - var result = key === 'tag' ? [] : null; - this.__windows.every(function(win, i) { + let result = key === 'tag' ? [] : null; + this.__windows.every((win, i) => { if ( win ) { if ( win['_' + key] === value ) { if ( key === 'tag' ) { @@ -387,90 +336,74 @@ }); return result; - }; + } /** * Get a Window by Name * - * @function _getWindowByName - * @memberof OSjs.Core.Application# - * @see OSjs.Core.Application#_getWindow + * @see Application#_getWindow * * @param {String} name Window Name * - * @return {OSjs.Core.Window} + * @return {Window} */ - Application.prototype._getWindowByName = function(name) { + _getWindowByName(name) { return this._getWindow(name); - }; + } /** * Get Windows(!) by Tag * - * @function _getWindowByTag - * @memberof OSjs.Core.Application# - * @see OSjs.Core.Application#_getWindow + * @see Application#_getWindow * * @param {String} tag Tag name * - * @return {OSjs.Core.Window[]} + * @return {Window[]} */ - Application.prototype._getWindowsByTag = function(tag) { + _getWindowsByTag(tag) { return this._getWindow(tag, 'tag'); - }; + } /** * Get a list of all windows * - * @function _getWindows - * @memberof OSjs.Core.Application# - * - * @return {OSjs.Core.Window[]} + * @return {Window[]} */ - Application.prototype._getWindows = function() { + _getWindows() { return this.__windows; - }; + } /** * Get the "main" window * - * @function _getMainWindow - * @memberof OSjs.Core.Application# - * - * @return {OSjs.Core.Window} + * @return {Window} */ - Application.prototype._getMainWindow = function() { + _getMainWindow() { return this._getWindow(this.__mainwindow, 'name'); - }; + } /** * Get the sessions JSON * - * @function _getSettings - * @memberof OSjs.Core.Application# - * * @param {String} k The settings key * * @return {Object} the current settings */ - Application.prototype._getSetting = function(k) { - return this.__settings.get(k); - }; + _getSetting(k) { + return this.__settings ? this.__settings.get(k) : null; + } /** * Get the current application session data * - * @function _getSessionData - * @memberof OSjs.Core.Application# - * * @return {Object} the current session data */ - Application.prototype._getSessionData = function() { - var args = this.__args; - var wins = this.__windows; - var data = {name: this.__pname, args: args, windows: []}; + _getSessionData() { + const args = this.__args; + const wins = this.__windows; + const data = {name: this.__pname, args: args, windows: []}; - wins.forEach(function(win, i) { + wins.forEach((win, i) => { if ( win && win._properties.allow_session ) { data.windows.push({ name: win._name, @@ -482,56 +415,26 @@ }); return data; - }; - - /** - * Gets the scheme instance - * - * @function _getScheme - * @memberof OSjs.Core.Application# - * @return OSjs.GUI.Scheme - */ - Application.prototype._getScheme = function() { - return this.__scheme; - }; + } /** * Set a setting * - * @function _setSetting - * @memberof OSjs.Core.Application# - * * @param {String} k Key * @param {String} v Value * @param {Boolean|Function} [save=true] Save given setting(s) (can be a callback function) */ - Application.prototype._setSetting = function(k, v, save) { + _setSetting(k, v, save) { if ( typeof save === 'undefined' ) { save = true; } if ( arguments.length === 4 && typeof arguments[3] === 'function' ) { save = arguments[3]; } - this.__settings.set(k, v, save); - }; - - /** - * Sets the scheme instance - * - * @function _setScheme - * @memberof OSjs.Core.Application# - * @see OSjs.GUI.Scheme - * - * @param {OSjs.GUI.Scheme} s Scheme Ref - */ - Application.prototype._setScheme = function(s) { - this.__scheme = s; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + if ( this.__settings ) { + this.__settings.set(k, v, save); + } + } - OSjs.Core.Application = Object.seal(Application); +} -})(OSjs.Utils, OSjs.API, OSjs.Core.Process); diff --git a/src/client/javascript/core/auth/database.js b/src/client/javascript/core/auth/database.js index 69df6df5b1..40af116d19 100644 --- a/src/client/javascript/core/auth/database.js +++ b/src/client/javascript/core/auth/database.js @@ -27,16 +27,12 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Authenticator) { - 'use strict'; +import Authenticator from 'core/authenticator'; - function DatabaseAuthenticator() { - Authenticator.apply(this, arguments); - } - - DatabaseAuthenticator.prototype = Object.create(Authenticator.prototype); - DatabaseAuthenticator.constructor = Authenticator; - - OSjs.Auth.database = DatabaseAuthenticator; +/** + * Database Authentication Handler + * @extends Authenticator + */ +export default class DatabaseAuthenticator extends Authenticator { +} -})(OSjs.API, OSjs.Utils, OSjs.Core.Authenticator); diff --git a/src/client/javascript/core/auth/demo.js b/src/client/javascript/core/auth/demo.js index a699970a8b..fe02380cb5 100644 --- a/src/client/javascript/core/auth/demo.js +++ b/src/client/javascript/core/auth/demo.js @@ -27,21 +27,20 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Authenticator) { - 'use strict'; - function DemoAuthenticator() { - Authenticator.apply(this, arguments); - } - - DemoAuthenticator.prototype = Object.create(Authenticator.prototype); - DemoAuthenticator.constructor = Authenticator; +import Promise from 'bluebird'; +import Authenticator from 'core/authenticator'; - DemoAuthenticator.prototype.login = function(login, callback) { - var settings = {}; - var key; +/** + * Demo Authentication Handler + * @extends Authenticator + */ +export default class DemoAuthenticator extends Authenticator { - for ( var i = 0; i < localStorage.length; i++ ) { + _getSettings() { + let settings = {}; + let key; + for ( let i = 0; i < localStorage.length; i++ ) { key = localStorage.key(i); if ( key.match(/^OSjs\//) ) { try { @@ -52,41 +51,24 @@ } } - if ( API.isStandalone() ) { - return callback(false, { - userData: { - id: 0, - username: 'demo', - name: 'Demo User', - groups: ['admin'] - }, - userSettings: settings, - blacklistedPackages: [] - }); - } + return settings; + } - return Authenticator.prototype.login.call(this, login, function(error, result) { - if ( error ) { - callback(error); - } else { - result.userSettings = settings; - callback(null, result); - } + login(login) { + return new Promise((resolve, reject) => { + super.login(login).then((result) => { + result.userSettings = this._getSettings(); + return resolve(result); + }).catch(reject); }); - }; + } - DemoAuthenticator.prototype.onCreateUI = function(callback) { - this.onLoginRequest({ + onCreateUI() { + return this.onLoginRequest({ username: 'demo', password: 'demo' - }, callback); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + }); + } - OSjs.Auth = OSjs.Auth || {}; - OSjs.Auth.demo = DemoAuthenticator; +} -})(OSjs.API, OSjs.Utils, OSjs.Core.Authenticator); diff --git a/src/client/javascript/core/auth/pam.js b/src/client/javascript/core/auth/pam.js index bcea8ae5fa..1aae418efe 100644 --- a/src/client/javascript/core/auth/pam.js +++ b/src/client/javascript/core/auth/pam.js @@ -27,16 +27,11 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Authenticator) { - 'use strict'; +import Authenticator from 'core/authenticator'; - function PAMAuthenticator() { - Authenticator.apply(this, arguments); - } - - PAMAuthenticator.prototype = Object.create(Authenticator.prototype); - PAMAuthenticator.constructor = Authenticator; - - OSjs.Auth.pam = PAMAuthenticator; - -})(OSjs.API, OSjs.Utils, OSjs.Core.Authenticator); +/** + * PAM Authentication Handler + * @extends Authenticator + */ +export default class PAMAuthenticator extends Authenticator { +} diff --git a/src/templates/package/dummy/main.js b/src/client/javascript/core/auth/standalone.js similarity index 76% rename from src/templates/package/dummy/main.js rename to src/client/javascript/core/auth/standalone.js index d89454c0f3..85c1160055 100644 --- a/src/templates/package/dummy/main.js +++ b/src/client/javascript/core/auth/standalone.js @@ -28,18 +28,27 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function(Utils, API, VFS, GUI) { - 'use strict'; +import Promise from 'bluebird'; +import DemoAuthenticator from './demo'; - ///////////////////////////////////////////////////////////////////////////// - // APP - ///////////////////////////////////////////////////////////////////////////// +/** + * Default Standalone Authenticator + * @extends DemoAuthenticator + */ +export default class StandaloneAuthenticator extends DemoAuthenticator { - function ApplicationEXAMPLE() { + login(login) { + return Promise.resolve({ + userData: { + id: 1, + username: 'root', + name: 'Administrator User', + groups: ['admin'] + }, + userSettings: this._getSettings(), + blacklistedPackages: [] + }); } - OSjs.Applications = OSjs.Applications || {}; - OSjs.Applications.ApplicationEXAMPLE = ApplicationEXAMPLE; +} -})(OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/core/authenticator.js b/src/client/javascript/core/authenticator.js index d125ff33d2..b3048b9e52 100644 --- a/src/client/javascript/core/authenticator.js +++ b/src/client/javascript/core/authenticator.js @@ -28,24 +28,32 @@ * @licence Simplified BSD License */ -(function(API, Utils) { - 'use strict'; +import Promise from 'bluebird'; +import {_, setLocale} from 'core/locales'; +import {getConfig, getUserLocale} from 'core/config'; +import Connection from 'core/connection'; +import SettingsManager from 'core/settings-manager'; +import PackageManager from 'core/package-manager'; - var _authInstance; +let _instance; - /** - * Authenticator Base Class - * - * @abstract - * @constructor Authenticator - * @memberof OSjs.Core - */ - function Authenticator() { +/** + * Authenticator Base Class + * + * @abstract + */ +export default class Authenticator { + + static get instance() { + return _instance; + } + + constructor() { + /* eslint consistent-this: "off" */ + _instance = this; /** * User data - * @name userData - * @memberof OSjs.Core.Authenticator# * @type {Object} * @example * { @@ -63,133 +71,118 @@ /** * If user is logged in - * @name loggedIn - * @memberof OSjs.Core.Authenticator# * @type {Boolean} */ this.loggedIn = false; - - /*eslint consistent-this: "off"*/ - _authInstance = this; } /** * Initializes the Authenticator - * - * @function init - * @memberof OSjs.Core.Authenticator# - * - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Authenticator.prototype.init = function(callback) { - this.onCreateUI(callback); - }; + init() { + return this.onCreateUI(); + } /** * Destroys the Authenticator - * - * @function destroy - * @memberof OSjs.Core.Authenticator# */ - Authenticator.prototype.destroy = function() { - }; + destroy() { + _instance = null; + } /** * Get data for logged in user * - * @function getUser - * @memberof OSjs.Core.Authenticator# - * * @return {Object} JSON With user data */ - Authenticator.prototype.getUser = function() { - return Utils.cloneObject(this.userData || {}, true); - }; + getUser() { + return Object.assign({}, this.userData); + } /** * Gets if there is a user logged in * - * @function isLoggedIn - * @memberof OSjs.Core.Authenticator# - * * @return {Boolean} */ - Authenticator.prototype.isLoggedIn = function() { + isLoggedIn() { return this.isLoggedIn; - }; + } /** * Log in user * - * @function login - * @memberof OSjs.Core.Authenticator# - * - * @param {Object} data Login form data - * @param {CallbackHandler} callback Callback function + * @param {Object} data Login form data + * @return {Promise} */ - Authenticator.prototype.login = function(data, callback) { - API.call('login', data, function onLoginResponse(error, result) { - if ( result ) { - callback(false, result); - } else { - error = error || API._('ERR_LOGIN_INVALID'); - callback(API._('ERR_LOGIN_FMT', error), false); - } + login(data) { + return new Promise((resolve, reject) => { + Connection.request('login', data).then((result) => { + return resolve(result ? result : _('ERR_LOGIN_INVALID')); + }).catch((error) => { + reject(new Error(_('ERR_LOGIN_FMT', error))); + }); }); - }; + } /** * Log out user + * @return {Promise} + */ + logout() { + return new Promise((resolve, reject) => { + Connection.request('logout', {}).then((result) => { + return resolve(!!result); + }).catch((err) => { + reject(new Error('An error occured: ' + err)); + }); + }); + } + + /** + * Checks the given permission (groups) against logged in user * - * @function logout - * @memberof OSjs.Core.Authenticator# + * @param {String|String[]} group Either a string or array of groups * - * @param {CallbackHandler} callback Callback function + * @return {Boolean} */ - Authenticator.prototype.logout = function(callback) { - var opts = {}; - - API.call('logout', opts, function onLogoutResponse(error, result) { - if ( result ) { - callback(false, true); - } else { - callback('An error occured: ' + (error || 'Unknown error')); - } - }); - }; + checkPermission(group) { + const user = this.getUser(); + const userGroups = user.groups || []; + + if ( !(group instanceof Array) ) { + group = [group]; + } + + if ( userGroups.indexOf('admin') === -1 ) { + return !!group.every((g) => userGroups.indexOf(g) >= 0); + } + + return true; + } /** * When login is requested * - * @function onLoginRequest - * @memberof OSjs.Core.Authenticator# - * - * @param {Object} data Login data - * @param {CallbackHandler} callback Callback function + * @param {Object} data Login data + * @return {Promise} */ - Authenticator.prototype.onLoginRequest = function(data, callback) { - var self = this; - - this.login(data, function onLoginRequest(err, result) { - if ( err ) { - callback(err); - } else { - self.onLogin(result, callback); - } + onLoginRequest(data) { + return new Promise((resolve, reject) => { + this.login(data).then((res) => { + return this.onLogin(res).then(resolve).catch(reject); + }).catch(reject); }); - }; + } /** * When login has occured * - * @function onLogin - * @memberof OSjs.Core.Authenticator# - * * @param {Object} data User data - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Authenticator.prototype.onLogin = function(data, callback) { - var userSettings = data.userSettings; + onLogin(data) { + let userSettings = data.userSettings; if ( !userSettings || userSettings instanceof Array ) { userSettings = {}; } @@ -197,16 +190,16 @@ this.userData = data.userData; // Ensure we get the user-selected locale configured from WM - function getUserLocale() { - var curLocale = API.getConfig('Locale'); - var detectedLocale = Utils.getUserLocale(); + function getLocale() { + let curLocale = getConfig('Locale'); + let detectedLocale = getUserLocale(); - if ( API.getConfig('LocaleOptions.AutoDetect', true) && detectedLocale ) { + if ( getConfig('LocaleOptions.AutoDetect', true) && detectedLocale ) { console.info('Auto-detected user locale via browser', detectedLocale); curLocale = detectedLocale; } - var result = OSjs.Core.getSettingsManager().get('CoreWM'); + let result = SettingsManager.get('CoreWM'); if ( !result ) { try { result = userSettings.CoreWM; @@ -217,37 +210,28 @@ document.getElementById('LoadingScreen').style.display = 'block'; - API.setLocale(getUserLocale()); - OSjs.Core.getSettingsManager().init(userSettings); + setLocale(getLocale()); + SettingsManager.init(userSettings); if ( data.blacklistedPackages ) { - OSjs.Core.getPackageManager().setBlacklist(data.blacklistedPackages); + PackageManager.setBlacklist(data.blacklistedPackages); } this.loggedIn = true; - callback(null, true); - }; + return Promise.resolve(true); + } /** * When login UI is requested - * - * @function onCreateUI - * @memberof OSjs.Core.Authenticator# - * - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Authenticator.prototype.onCreateUI = 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'); - } + onCreateUI() { + const container = document.getElementById('Login'); + const login = document.getElementById('LoginForm'); + const u = document.getElementById('LoginUsername'); + const p = document.getElementById('LoginPassword'); + const s = document.getElementById('LoginSubmit'); function _restore() { s.removeAttribute('disabled'); @@ -261,48 +245,29 @@ p.setAttribute('disabled', 'disabled'); } - login.onsubmit = function(ev) { - _lock(); - if ( ev ) { - ev.preventDefault(); - } - - self.onLoginRequest({ - username: u.value, - password: p.value - }, function(err) { - if ( err ) { - alert(err); - _restore(); - } else { - container.parentNode.removeChild(container); - callback(); - } - }); - }; - container.style.display = 'block'; - _restore(); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - OSjs.Core.Authenticator = Authenticator; + return new Promise((resolve, reject) => { + login.onsubmit = (ev) => { + _lock(); + if ( ev ) { + ev.preventDefault(); + } - /** - * Get running 'Authenticator' instance - * - * @function getAuthenticator - * @memberof OSjs.Core - * - * @return {OSjs.Core.Authenticator} - */ - OSjs.Core.getAuthenticator = function Core_getAuthenticator() { - return _authInstance; - }; + this.onLoginRequest({ + username: u.value, + password: p.value + }).then(() => { + container.parentNode.removeChild(container); + return resolve(); + }).catch((err) => { + alert(err); + _restore(); + }); + }; + }); + } -})(OSjs.API, OSjs.Utils); +} diff --git a/src/client/javascript/core/boot.js b/src/client/javascript/core/boot.js deleted file mode 100644 index 2e2e980c56..0000000000 --- a/src/client/javascript/core/boot.js +++ /dev/null @@ -1,874 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -(function() { - 'use strict'; - - /** - * @namespace Bootstrap - * @memberof OSjs - */ - - // Make sure these namespaces exist - (['Bootstrap', 'Utils', 'API', 'GUI', 'Core', 'Dialogs', 'Helpers', 'Applications', 'Locales', 'VFS', 'Extensions', 'Auth', 'Storage', 'Connections', 'Broadway']).forEach(function(ns) { - OSjs[ns] = OSjs[ns] || {}; - }); - - (['Helpers']).forEach(function(ns) { - OSjs.GUI[ns] = OSjs.GUI[ns] || {}; - }); - - (['Helpers', 'Transports']).forEach(function(ns) { - OSjs.VFS[ns] = OSjs.VFS[ns] || {}; - }); - - // Globals - - var inited = false; - var loaded = false; - var signingOut = false; - var instanceOptions = {}; - - ///////////////////////////////////////////////////////////////////////////// - // GLOBAL EVENTS - ///////////////////////////////////////////////////////////////////////////// - - function checkForbiddenKeyCombo(ev) { - return false; - /* FIXME: This is not supported in browsers :( (in app mode it should be) - var forbiddenCtrl = ['n', 't', 'w']; - if ( ev.ctrlKey ) { - return forbiddenCtrl.some(function(i) { - return String.fromCharCode(ev.keyCode).toLowerCase() === i; - }); - } - return false; - */ - } - - var events = { - body_contextmenu: function(ev) { - ev.stopPropagation(); - - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - wm.onContextMenu(ev); - } - - if ( !OSjs.Utils.$isFormElement(ev) ) { - ev.preventDefault(); - return false; - } - - return true; - }, - - body_click: function(ev) { - var t = ev.target; - var allowed = ['GUI-MENU-BAR-ENTRY', 'GUI-MENU-ENTRY']; - if ( !t || allowed.indexOf(t.tagName) === -1 ) { - OSjs.API.blurMenu(); - } - - var wm = OSjs.Core.getWindowManager(); - if ( t === document.body ) { - var win = wm ? wm.getCurrentWindow() : null; - if ( win ) { - win._blur(); - } - } - - if ( wm ) { - wm.onGlobalClick(ev); - } - }, - - message: function(ev) { - if ( ev && ev.data && typeof ev.data.message !== 'undefined' && typeof ev.data.pid === 'number' ) { - console.debug('window::message()', ev.data); - 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) { - try { - 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/view-fullscreen.png', '16x16')); - } else { - notif.opts._isFullscreen = true; - notif.setImage(OSjs.API.getIcon('actions/view-restore.png', '16x16')); - } - } - } catch ( e ) { - console.warn(e.stack, e); - } - }, - - 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; - - // What browser default keys we prevent in certain situations - 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; - } - } - - // Only prevent default event if current window is not set up to capture them by force - 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 ) { - try { - if ( OSjs.API.getConfig('ShowQuitWarning') ) { - return OSjs.API._('MSG_SESSION_WARNING'); - } - } catch ( e ) {} - } - - return null; - }, - - 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) { - _timeout = clearTimeout(_timeout); - _timeout = setTimeout(function() { - _resize(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); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // INITIALIZERS - ///////////////////////////////////////////////////////////////////////////// - - /* - * Initialized some layout stuff - */ - function initLayout() { - console.debug('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('
').replace(/%VERSION%/, ver); - - document.body.appendChild(el); - } - - document.getElementById('LoadingScreen').style.display = 'none'; - } - - /* - * Initializes handlers - */ - function initHandler(config, callback) { - console.debug('initHandler()'); - - var conf = OSjs.API.getConfig('Connection'); - var ctype = conf.Type === 'standalone' ? 'http' : conf.Type; - - var connection = new OSjs.Connections[ctype](); - var authenticator = new OSjs.Auth[conf.Authenticator](); - var storage = new OSjs.Storage[conf.Storage](); - - OSjs.API.setLocale(OSjs.API.getConfig('Locale')); - - connection.init(function(err) { - console.groupEnd(); - - if ( err ) { - callback(err); - } else { - storage.init(function() { - authenticator.init(function(err) { - if ( !err ) { - inited = true; - } - callback(err); - }); - }); - } - }); - } - - /* - * Initializes events - */ - function initEvents() { - console.debug('initEvents()'); - - 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 __onerror(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; - }; - } - - /* - * Preloads configured files - */ - function initPreload(config, callback) { - console.debug('initPreload()'); - var list = []; - - (function flatten(a) { - a.forEach(function(i) { - if ( i instanceof Array ) { - flatten(i); - } else { - list.push(i); - } - }); - })(config.Preloads); - - OSjs.Utils.preload(list, function preloadIter(total, failed) { - if ( failed.length ) { - console.warn('doInitialize()', 'some preloads failed to load:', failed); - } - - setTimeout(function() { - callback(); - }, 0); - }); - } - - /* - * Loads all extensions - */ - function initExtensions(config, callback) { - if ( instanceOptions.mocha ) { - callback(); - return; - } - - if ( OSjs.API.getConfig('Broadway.enabled') ) { - OSjs.API.addHook('onSessionLoaded', function() { - OSjs.Broadway.Connection.init(); - }); - - OSjs.API.addHook('onLogout', function() { - OSjs.Broadway.Connection.disconnect(); - }); - - OSjs.API.addHook('onBlurMenu', function() { - OSjs.Broadway.GTK.inject(null, 'blur'); - }); - } - - var exts = Object.keys(OSjs.Extensions); - var manifest = OSjs.Core.getMetadata(); - - console.group('initExtensions()', exts); - 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() { - console.groupEnd(); - callback(); - }); - } - - /* - * Initializes the SettingsManager pools - * from configuration file(s) - */ - function initSettingsManager(cfg, callback) { - console.debug('initSettingsManager()'); - var pools = cfg.SettingsManager || {}; - var manager = OSjs.Core.getSettingsManager(); - - Object.keys(pools).forEach(function(poolName) { - console.debug('initSettingsManager()', 'initializes pool', poolName, pools[poolName]); - manager.instance(poolName, pools[poolName] || {}); - }); - - callback(); - } - - /* - * Initializes the PackageManager - */ - 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); - }); - - }); - } - - /* - * Initalizes the VFS - */ - function initVFS(config, callback) { - console.debug('initVFS()'); - - OSjs.Core.getMountManager().init(callback); - } - - /* - * Initializes the Search Engine - */ - function initSearch(config, callback) { - console.debug('initSearch()'); - - OSjs.Core.getSearchEngine().init(callback); - } - - /* - * Initializes the Window Manager - */ - function initWindowManager(config, callback) { - console.debug('initWindowManager()'); - if ( !config.WM || !config.WM.exec ) { - callback(OSjs.API._('ERR_CORE_INIT_NO_WM')); - return; - } - - OSjs.API.launch(config.WM.exec, (config.WM.args || {}), function onWMLaunchSuccess(app) { - app.setup(callback); - }, function onWMLaunchError(error, name, args, exception) { - callback(OSjs.API._('ERR_CORE_INIT_WM_FAILED_FMT', error), exception); - }); - } - - /* - * Initializes the Session - */ - function initSession(config, callback) { - console.debug('initSession()'); - OSjs.API.playSound('LOGIN'); - - var list = []; - - // In this case we merge the Autostart and the previous session together. - // This ensures that items with autostart are loaded with correct - // session data on restore. This is much better than relying on the internal - // event/message system which does not trigger until after everything is loaded... - // this does everything beforehand! :) - // - 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); - } - } - }); - - var stor = OSjs.Core.getStorage(); - stor.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); - } - } - }); - } - - console.info('initSession()->autostart()', list); - - OSjs.API.launchList(list, null, null, callback); - }); - } - - /* - * Wrapper for initializing OS.js - */ - function init(opts) { - console.group('init()'); - - try { - opts = opts || {}; - - instanceOptions = OSjs.Utils.argumentDefaults(opts, { - mocha: false, - onInit: function() {}, - onInited: function() {} - }); - } catch ( e ) { - console.warn('Invalid options', opts); - } - - var config = OSjs.Core.getConfig(); - var splash = document.getElementById('LoadingScreen'); - var loading = OSjs.API.createSplash('OS.js', null, null, splash); - var freeze = ['Bootstrap', 'API', 'Core', 'Dialogs', 'Extensions', 'GUI', 'Helpers', 'Locales', 'Utils', 'VFS']; - var queue = [ - initPreload, - initHandler, - initVFS, - initSettingsManager, - initPackageManager, - initExtensions, - initSearch, - function initStoredMounts(cfg, cb) { - OSjs.Core.getMountManager().restore(cb); - }, - function initDialogs(cfg, cb) { - return OSjs.GUI.DialogScheme.init(cb); - } - ]; - - function _inited() { - loading = loading.destroy(); - splash = splash.style.display = 'none'; - - var wm = OSjs.Core.getWindowManager(); - wm._fullyLoaded = true; - - OSjs.API.triggerHook('onWMInited'); - - try { - instanceOptions.onInited(); - } catch ( e ) { - console.warn(e); - } - - console.groupEnd(); - } - - function _error(err) { - OSjs.API.error(OSjs.API._('ERR_CORE_INIT_FAILED'), - OSjs.API._('ERR_CORE_INIT_FAILED_DESC'), err, null, true); - } - - function _done() { - OSjs.API.triggerHook('onInited'); - try { - instanceOptions.onInit(); - } catch ( e ) { - console.warn(e); - } - - loading.update(queue.length, queue.length); - - freeze.forEach(function(f) { - if ( typeof OSjs[f] === 'object' ) { - Object.freeze(OSjs[f]); - } - }); - - if ( instanceOptions.mocha ) { - _inited(); - } else { - initWindowManager(config, function wmInited(err) { - if ( err ) { - _error(err); - return; - } - - initEvents(); - - _inited(); - - initSession(config, function onSessionLoaded() { - OSjs.API.triggerHook('onSessionLoaded'); - }); - }); - } - } - - splash.style.display = 'block'; - - initLayout(); - - OSjs.Utils.asyncs(queue, function asyncIter(entry, index, next) { - if ( index < 1 ) { - OSjs.API.triggerHook('onInitialize'); - } - - loading.update(index, queue.length); - - entry(config, function asyncDone(err) { - if ( err ) { - _error(err); - return; - } - - next(); - }); - }, _done); - } - - OSjs.Bootstrap = { - - /** - * Restart OS.js - * @param {Boolean} [save] Save current session when logging out - * @function run - * @memberof OSjs.Bootstrap - */ - restart: function(save) { - if ( !loaded ) { - return; - } - - var auth = OSjs.Core.getAuthenticator(); - var storage = OSjs.Core.getStorage(); - - var saveFunction = save && storage ? function(cb) { - storage.saveSession(function() { - auth.logout(cb); - }); - } : function(cb) { - auth.logout(cb); - }; - - saveFunction(function() { - console.clear(); - OSjs.Bootstrap.stop(true); - OSjs.Bootstrap.run(); - }); - }, - - /** - * Start OS.js - * @param {Object} opts Options - * @function run - * @memberof OSjs.Bootstrap - */ - run: function(opts) { - if ( loaded ) { - return; - } - loaded = true; - - init(opts); - }, - - /** - * Stop OS.js - * @param {Boolean} [restart] Restart does not fully shut down - * @function stop - * @memberof OSjs.Bootstrap - */ - stop: function(restart) { - if ( !inited || !loaded || signingOut ) { - return; - } - - signingOut = true; - - 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('fullscreenchange', events.fullscreen, false); - window.removeEventListener('mozfullscreenchange', events.fullscreen, false); - window.removeEventListener('webkitfullscreenchange', events.fullscreen, false); - window.removeEventListener('msfullscreenchange', events.fullscreen, 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(); - } - - OSjs.Core.getSearchEngine().destroy(); - OSjs.Core.getPackageManager().destroy(); - OSjs.Core.getAuthenticator().destroy(); - OSjs.Core.getStorage().destroy(); - OSjs.Core.getConnection().destroy(); - - OSjs.Utils._clearPreloadCache(); - - if ( restart ) { - Object.keys(OSjs.Applications).forEach(function(k) { - try { - delete OSjs.Applications[k]; - } catch (e) {} - }); - Object.keys(OSjs.Extensions).forEach(function(k) { - try { - delete OSjs.Extensions[k]; - } catch (e) {} - }); - } else { - OSjs.API.triggerHook('onShutdown'); - - console.warn('OS.js was shut down!'); - - if ( OSjs.API.getConfig('ReloadOnShutdown') === true ) { - window.location.reload(); - } - - Object.keys(OSjs).forEach(function(k) { - try { - delete OSjs[k]; - } catch ( e ) {} - }); - } - - loaded = false; - inited = false; - signingOut = false; - }, - - isShuttingDown: function() { - return signingOut; - } - }; - -})(); diff --git a/src/client/javascript/core/config.js b/src/client/javascript/core/config.js new file mode 100644 index 0000000000..e684f0616c --- /dev/null +++ b/src/client/javascript/core/config.js @@ -0,0 +1,104 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import * as SimpleJSON from 'simplejsonconf'; + +/** + * Method for getting a config parameter by path (Ex: "VFS.Mountpoints.shared.enabled") + * + * @param {String} [path] Path + * @param {*} [defaultValue=undefined] Use default value + * + * @return {*} Parameter value or entire tree on no path + */ +export function getConfig(path, defaultValue) { + const config = OSjs.getConfig(); + if ( !path ) { + return config; + } + + const result = SimpleJSON.getJSON(config, path, defaultValue); + return (typeof result === 'object' && !(result instanceof Array)) ? Object.assign({}, result) : result; +} + +/** + * Get default configured path + * + * @param {String} fallback Fallback path on error (default= "osjs:///") + * @return {String} + */ +export function getDefaultPath(fallback) { + if ( fallback && fallback.match(/^\//) ) { + fallback = null; + } + return getConfig('VFS.Home') || fallback || 'osjs:///'; +} + +/** + * Gets the browser window path + * + * @param {String} [app] Append this path + * + * @return {String} + */ +export function getBrowserPath(app) { + let str = getConfig('Connection.RootURI'); + if ( typeof app === 'string' ) { + str = str.replace(/\/?$/, app.replace(/^\/?/, '/')); + } + return str; +} + +/** + * Gets the browser Locale + * + * For example 'en_EN' + * + * @return {String} Locale string + */ +export function getUserLocale() { + const loc = ((window.navigator.userLanguage || window.navigator.language) || 'en-EN').replace('-', '_'); + + // Restricts to a certain type of language. + // Example: There are lots of variants of the English language, but currently we only + // provide locales for one of them, so we force to use the one available. + const map = { + 'nb': 'no_NO', + 'es': 'es_ES', + 'ru': 'ru_RU', + 'en': 'en_EN' + }; + + const major = loc.split('_')[0] || 'en'; + const minor = loc.split('_')[1] || major.toUpperCase(); + if ( map[major] ) { + return map[major]; + } + return major + '_' + minor; +} diff --git a/src/client/javascript/core/connection.js b/src/client/javascript/core/connection.js index 592160cf87..742c601834 100644 --- a/src/client/javascript/core/connection.js +++ b/src/client/javascript/core/connection.js @@ -28,123 +28,125 @@ * @licence Simplified BSD License */ -(function(API, Utils) { - 'use strict'; +import axios from 'axios'; +import Promise from 'bluebird'; +import EventHandler from 'helpers/event-handler'; +import Loader from 'helpers/loader'; +import {getConfig} from 'core/config'; + +//let _CALL_INDEX = 1; +function progressHandler(ev, onprogress) { + if ( ev.lengthComputable ) { + onprogress(ev, ev.loaded / ev.total); + } else { + onprogress(ev, -1); + } +} - var _connectionInstance; +/* + * Attaches options to a XHR call + */ +function appendRequestOptions(data, options) { + options = options || {}; - /* - * Attaches options to a XHR call - */ - function appendRequestOptions(data, options) { - options = options || {}; + const onprogress = options.onprogress || function() {}; + const ignore = ['onsuccess', 'onerror', 'onprogress', 'oncanceled']; - var onprogress = options.onprogress || function() {}; - var ignore = ['onsuccess', 'onerror', 'onprogress', 'oncanceled']; + Object.keys(options).forEach((key) => { + if ( ignore.indexOf(key) === -1 ) { + data[key] = options[key]; + } + }); - Object.keys(options).forEach(function(key) { - if ( ignore.indexOf(key) === -1 ) { - data[key] = options[key]; - } - }); + data.onUploadProgress = (ev) => progressHandler(ev, onprogress); + data.onDownloadProgress = (ev) => progressHandler(ev, onprogress); - data.onprogress = function XHR_onprogress(ev) { - if ( ev.lengthComputable ) { - onprogress(ev, ev.loaded / ev.total); - } else { - onprogress(ev, -1); - } - }; + return data; +} + +let _instance; + +/** + * Default Connection Implementation + * + * @desc Wrappers for communicating over HTTP, WS and NW + * + * @mixes utils/event-handler~EventHandler + */ +export default class Connection { - return data; + static get instance() { + return _instance; } /** - * Default Connection Implementation - * - * @summary Wrappers for communicating over HTTP, WS and NW - * - * @constructor Connection - * @memberof OSjs.Core - * @mixes OSjs.Helpers.EventHandler + * Create a new Connection */ - function Connection() { - this.index = 0; + constructor() { + /* eslint consistent-this: "off" */ + if ( !_instance ) { + _instance = this; + } /** * If browser is offline - * @name offline - * @memberof OSjs.Core.Connection# * @type {Boolean} */ this.offline = false; - this._evHandler = new OSjs.Helpers.EventHandler(name, []); + this.index = 0; + this._evHandler = new EventHandler(name, []); - /*eslint consistent-this: "off"*/ - _connectionInstance = this; + this.onlineFn = () => this.onOnline(); + this.offlineFn = () => this.onOffline(); } /** * Initializes the instance - * - * @param {Function} callback Callback function - * - * @function init - * @memberof OSjs.Core.Connection# + * @return {Promise} */ - Connection.prototype.init = function(callback) { - var self = this; - + init() { if ( typeof navigator.onLine !== 'undefined' ) { - Utils.$bind(window, 'offline', function(ev) { - self.onOffline(); - }); - Utils.$bind(window, 'online', function(ev) { - self.onOnline(); - }); + window.addEventListener('offline', this.offlineFn); + window.addEventListener('online', this.onlineFn); } - callback(); - }; + return Promise.resolve(); + } /** * Destroys the instance - * - * @function destroy - * @memberof OSjs.Core.Connection# */ - Connection.prototype.destroy = function() { - Utils.$unbind(window, 'offline'); - Utils.$unbind(window, 'online'); + destroy() { + window.removeEventListener('offline', this.offlineFn); + window.removeEventListener('online', this.onlineFn); if ( this._evHandler ) { this._evHandler = this._evHandler.destroy(); } - }; + + _instance = null; + } /** * Default method to perform a resolve on a VFS File object. * * This should return the URL for given resource. * - * @function getVFSPath - * @memberof OSjs.Core.Connection# - * - * @param {OSjs.VFS.File} item The File Object - * @param {Object} [options] Options. These are added to the URL + * @param {FileMetadata} item The File Object + * @param {Object} [options] Options. These are added to the URL * * @return {String} */ - Connection.prototype.getVFSPath = function(item, options) { + getVFSPath(item, options) { options = options || {}; - var base = API.getConfig('Connection.RootURI', '/'); + const base = getConfig('Connection.RootURI', '/'); if ( window.location.protocol === 'file:' ) { return base + item.path.replace(/^osjs:\/\/\//, ''); } - var url = API.getConfig('Connection.FSURI', '/'); + let url = getConfig('Connection.FSURI', '/'); if ( item ) { url += '/read'; options.path = item.path; @@ -153,7 +155,7 @@ } if ( options ) { - var q = Object.keys(options).map(function(k) { + const q = Object.keys(options).map((k) => { return k + '=' + encodeURIComponent(options[k]); }); @@ -163,360 +165,199 @@ } return url; - }; + } /** * Get if connection is Online * - * @function isOnline - * @memberof OSjs.Core.Connection# * @return {Boolean} */ - Connection.prototype.isOnline = function() { + isOnline() { return !this.offline; - }; + } /** * Get if connection is Offline * - * @function isOffline - * @memberof OSjs.Core.Connection# * @return {Boolean} */ - Connection.prototype.isOffline = function() { + isOffline() { return this.offline; - }; - - /** - * Called upon a VFS request - * - * You can use this to interrupt/hijack operations. - * - * It is what gets called 'before' a VFS request takes place - * - * @function onVFSRequest - * @memberof OSjs.Core.Connection# - * - * @param {String} vfsModule VFS Module Name - * @param {String} vfsMethod VFS Method Name - * @param {Object} vfsArguments VFS Method Arguments - * @param {Function} callback Callback function - */ - Connection.prototype.onVFSRequest = function(vfsModule, vfsMethod, vfsArguments, callback) { - // If you want to interrupt/hijack or modify somehow, just send the two arguments to the - // callback: (error, result) - callback(/* continue normal behaviour */); - }; + } /** * Called upon a VFS request completion * * It is what gets called 'after' a VFS request has taken place * - * @function onVFSRequestCompleted - * @memberof OSjs.Core.Connection# - * - * @param {String} vfsModule VFS Module Name - * @param {String} vfsMethod VFS Method Name - * @param {Object} vfsArguments VFS Method Arguments - * @param {String} vfsError VFS Response Error - * @param {Mixed} vfsResult VFS Response Result - * @param {Function} callback Callback function + * @param {Mountpoint} mount VFS Module Name + * @param {String} method VFS Method Name + * @param {Object} args VFS Method Arguments + * @param {*} response VFS Response Result + * @param {Process} [appRef] Application reference + * @return {Promise} */ - Connection.prototype.onVFSRequestCompleted = function(vfsModule, vfsMethod, vfsArguments, vfsError, vfsResult, callback) { - // If you want to interrupt/hijack or modify somehow, just send the two arguments to the - // callback: (error, result) - callback(/* continue normal behaviour */); - }; + onVFSRequestCompleted(mount, method, args, response, appRef) { + return Promise.resolve(true); + } /** * When browser goes online - * - * @function onOnline - * @memberof OSjs.Core.Connection# */ - Connection.prototype.onOnline = function() { + onOnline() { console.warn('Connection::onOnline()', 'Going online...'); this.offline = false; - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - wm.notification({title: API._('LBL_INFO'), message: API._('CONNECTION_RESTORED')}); - } - if ( this._evHandler ) { this._evHandler.emit('online'); } - }; + } /** * When browser goes offline * * @param {Number} reconnecting Amount retries for connection - * - * @function onOffline - * @memberof OSjs.Core.Connection# */ - Connection.prototype.onOffline = function(reconnecting) { + onOffline(reconnecting) { console.warn('Connection::onOffline()', 'Going offline...'); if ( !this.offline && this._evHandler ) { - this._evHandler.emit('offline'); + this._evHandler.emit('offline', [reconnecting]); } this.offline = true; - - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - wm.notification({title: API._('LBL_WARNING'), message: API._(reconnecting ? 'CONNECTION_RESTORE_FAILED' : 'CONNECTION_LOST')}); - } - }; + } /** * Default method to perform a call to the backend (API) * - * Please note that this function is internal, and if you want to make - * a actual API call, use "API.call()" instead. + * Please use the static request() method externally. * * @param {String} method API method name * @param {Object} args API method arguments - * @param {Function} cbSuccess On success - * @param {Function} cbError On error - * @param {Object} [options] Options passed on to the connection request method (ex: Utils.ajax) - * - * @return {Boolean} + * @param {Object} [options] Options passed on to the connection request method (ex: XHR.ajax) * - * @function request - * @memberof OSjs.Core.Connection# - * @see OSjs.Core.API.call + * @return {Promise} */ - Connection.prototype.request = function(method, args, cbSuccess, cbError, options) { + createRequest(method, args, options) { args = args || {}; - cbSuccess = cbSuccess || function() {}; - cbError = cbError || function() {}; + options = options || {}; if ( this.offline ) { - cbError('You are currently off-line and cannot perform this operation!'); - return false; - } else if ( (API.getConfig('Connection.Type') === 'standalone') ) { - cbError('You are currently running locally and cannot perform this operation!'); - return false; - } - - if ( method.match(/^FS:/) ) { - return this.requestVFS(method.replace(/^FS:/, ''), args, options, cbSuccess, cbError); + return Promise.reject(new Error('You are currently off-line and cannot perform this operation!')); } - return this.requestAPI(method, args, options, cbSuccess, cbError); - }; - - /** - * Wrapper for server API XHR calls - * - * @param {String} method API Method name - * @param {Object} args API Method arguments - * @param {Object} options Call options - * @param {Function} cbSuccess Callback on success - * @param {Function} cbError Callback on error - * - * @function requestAPI - * @memberof OSjs.Core.Connection# - * @see OSjs.Core.Connection.request - * - * @return {Boolean} - */ - Connection.prototype.requestAPI = function(method, args, options, cbSuccess, cbError) { - return false; - }; + const {raw, requestOptions} = this.createRequestOptions(method, args); - /** - * Wrapper for server VFS XHR calls - * - * @param {String} method API Method name - * @param {Object} args API Method arguments - * @param {Object} options Call options - * @param {Function} cbSuccess Callback on success - * @param {Function} cbError Callback on error - * - * @function requestVFS - * @memberof OSjs.Core.Connection# - * @see OSjs.Core.Connection.request - * - * @return {Boolean} - */ - Connection.prototype.requestVFS = function(method, args, options, cbSuccess, cbError) { - if ( method === 'get' ) { - return this._requestGET(args, options, cbSuccess, cbError); - } else if ( method === 'upload' ) { - return this._requestPOST(args, options, cbSuccess, cbError); - } - - return false; - }; + return new Promise((resolve, reject) => { + axios(appendRequestOptions(requestOptions, options)).then((result) => { + return resolve(raw ? result.data : {error: false, result: result.data}); + }).catch((error) => { + reject(new Error(error.message || error)); + }); + }); + } /** - * Makes a HTTP POST call - * - * @param {Object} form Call data - * @param {Object} options Call options - * @param {Function} onsuccess Callback on success - * @param {Function} onerror Callback on error + * Creates default request options * - * @function _requestPOST - * @memberof OSjs.Core.Connection# + * @param {String} method API method name + * @param {Object} args API method arguments * - * @return {Boolean} + * @return {Object} */ - Connection.prototype._requestPOST = function(form, options, onsuccess, onerror) { - onerror = onerror || function() { - console.warn('Connection::_requestPOST()', 'error', arguments); - }; + createRequestOptions(method, args) { + const realMethod = method.replace(/^FS:/, ''); - Utils.ajax(appendRequestOptions({ - url: OSjs.VFS.Transports.OSjs.path(), + let raw = true; + let requestOptions = { + responseType: 'json', + url: getConfig('Connection.APIURI') + '/' + realMethod, method: 'POST', - body: form, - onsuccess: function Connection_POST_success(result) { - onsuccess(false, result); - }, - onerror: function Connection_POST_error(result) { - onerror('error', null, result); - }, - oncanceled: function Connection_POST_cancel(evt) { - onerror('canceled', null, evt); - } - }, options)); - - return true; - }; - - /** - * Makes a HTTP GET call - * - * @param {Object} args Call data - * @param {Object} options Call options - * @param {Function} onsuccess Callback on success - * @param {Function} onerror Callback on error - * - * @function _requestGET - * @memberof OSjs.Core.Connection# - * - * @return {Boolean} - */ - Connection.prototype._requestGET = function(args, options, onsuccess, onerror) { - onerror = onerror || function() { - console.warn('Connection::_requestGET()', 'error', arguments); + data: args }; - var self = this; - - Utils.ajax(appendRequestOptions({ - url: args.url || OSjs.VFS.Transports.OSjs.path(args.path), - method: args.method || 'GET', - responseType: 'arraybuffer', - onsuccess: function Connection_GET_success(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 Connection_GET_error() { - onerror.apply(self, arguments); - } - }, options)); - - return true; - }; - - /** - * Makes a HTTP XHR call - * - * @param {String} url Call URL - * @param {Object} args Call data - * @param {Object} options Call options - * @param {Function} onsuccess Callback on success - * @param {Function} onerror Callback on error - * - * @function _requestXHR - * @memberof OSjs.Core.Connection# - * - * @return {Boolean} - */ - Connection.prototype._requestXHR = function(url, args, options, onsuccess, onerror) { - onerror = onerror || function() { - console.warn('Connection::_requestXHR()', 'error', arguments); - }; - - var self = this; - - Utils.ajax(appendRequestOptions({ - url: url, - method: 'POST', - json: true, - body: args, - onsuccess: function Connection_XHR_onsuccess(/*response, request, url*/) { - onsuccess.apply(self, arguments); - }, - onerror: function Connection_XHR_onerror(/*error, response, request, url*/) { - onerror.apply(self, arguments); + if ( method.match(/^FS:/) ) { + if ( realMethod === 'get' ) { + requestOptions.responseType = 'arraybuffer'; + requestOptions.url = args.url || this.getVFSPath({path: args.path}); + requestOptions.method = args.method || 'GET'; + raw = false; + } else if ( realMethod === 'upload' ) { + requestOptions.url = this.getVFSPath(); + } else { + requestOptions.url = getConfig('Connection.FSURI') + '/' + realMethod; } - }, options)); + } - return true; - }; + return {raw, requestOptions}; + } /** * Subscribe to a event * * NOTE: This is only available on WebSocket connections * - * @function subscribe - * @memberof OSjs.Core.Connection# - * @see OSjs.Helpers.EventHandler#on - * * @param {String} k Event name * @param {Function} func Callback function * * @return {Number} + * + * @see EventHandler#on */ - Connection.prototype.subscribe = function(k, func) { + subscribe(k, func) { return this._evHandler.on(k, func, this); - }; + } /** * Removes an event subscription * - * @function unsubscribe - * @memberof OSjs.Core.Connection# - * @see OSjs.Helpers.EventHandler#off - * * @param {String} k Event name * @param {Number} [idx] The hook index returned from subscribe() * * @return {Boolean} + * + * @see EventHandler#off */ - Connection.prototype.unsubscribe = function(k, idx) { + unsubscribe(k, idx) { return this._evHandler.off(k, idx); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Core.Connection = Connection; + } - /** - * Get running 'Connection' instance + /* + * This is a wrapper for making a request * - * @function getConnection - * @memberof OSjs.Core + * @desc This method performs a request to the server * - * @return {OSjs.Core.Connection} + * @param {String} m Method name + * @param {Object} a Method arguments + * @param {Object} options Request options + * @return {Promise} */ - OSjs.Core.getConnection = function Core_getConnection() { - return _connectionInstance; - }; + static request(m, a, options) { + a = a || {}; + options = options || {}; -})(OSjs.API, OSjs.Utils); + if ( options && typeof options !== 'object' ) { + return Promise.reject(new TypeError('request() expects an object as options')); + } + Loader.create('Connection.request'); + + if ( typeof options.indicator !== 'undefined' ) { + delete options.indicator; + } + + return new Promise((resolve, reject) => { + this.instance.createRequest(m, a, options).then((response) => { + if ( response.error ) { + return reject(new Error(response.error)); + } + return resolve(response.result); + }).catch(((err) => { + reject(new Error(err)); + })).finally(() => { + Loader.destroy('Connection.request'); + }); + }); + } +} diff --git a/src/client/javascript/core/connections/http.js b/src/client/javascript/core/connections/http.js index 16b5e1450b..b84377d243 100644 --- a/src/client/javascript/core/connections/http.js +++ b/src/client/javascript/core/connections/http.js @@ -27,54 +27,29 @@ * @author Anders Evenrud * @licence Simplified BSD License */ +import * as VFS from 'vfs/fs'; +import FileMetadata from 'vfs/file'; +import Connection from 'core/connection'; -(function(VFS, API, Utils, Connection) { - 'use strict'; - - function HttpConnection() { - Connection.apply(this, arguments); - } - - HttpConnection.prototype = Object.create(Connection.prototype); - HttpConnection.constructor = Connection; - - HttpConnection.prototype.request = function(method, args, onsuccess, onerror, options) { - var res = Connection.prototype.request.apply(this, arguments); - - if ( res === false ) { - var url = (function() { - if ( method.match(/^FS:/) ) { - return API.getConfig('Connection.FSURI') + '/' + method.replace(/^FS\:/, ''); - } - return API.getConfig('Connection.APIURI') + '/' + method; - })(); - - return this._requestXHR(url, args, options, onsuccess, onerror); - } - - return res; - }; +/** + * HTTP Connection Handler + * @extends Connection + */ +export default class HttpConnection extends Connection { - HttpConnection.prototype.onVFSRequestCompleted = function(module, method, args, error, result, callback, appRef) { - if ( !error ) { - // Emit a VFS event when a change occures - if ( ['write', 'mkdir', 'copy', 'move', 'unlink'].indexOf(method) !== -1 ) { - var arg = method === 'move' ? { - source: args[0] instanceof VFS.File ? args[0] : null, - destination: args[1] instanceof VFS.File ? args[1] : null - } : args[method === 'copy' ? 1 : 0]; + onVFSRequestCompleted(module, method, args, result, appRef) { + // Emit a VFS event when a change occures + if ( ['upload', 'write', 'mkdir', 'copy', 'move', 'unlink'].indexOf(method) !== -1 ) { + const arg = method === 'move' ? { + source: args[0] instanceof FileMetadata ? args[0] : null, + destination: args[1] instanceof FileMetadata ? args[1] : null + } : args[method === 'copy' ? 1 : 0]; - VFS.Helpers.triggerWatch(method, arg, appRef); - } + VFS.triggerWatch(method, arg, appRef); } - callback(); - }; - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + return super.onVFSRequestCompleted(...arguments); + } - OSjs.Connections = OSjs.Connections || {}; - OSjs.Connections.http = HttpConnection; +} -})(OSjs.VFS, OSjs.API, OSjs.Utils, OSjs.Core.Connection); diff --git a/src/templates/package/simple-application/server/main.js b/src/client/javascript/core/connections/standalone.js similarity index 77% rename from src/templates/package/simple-application/server/main.js rename to src/client/javascript/core/connections/standalone.js index 947e4f7377..96be650521 100644 --- a/src/templates/package/simple-application/server/main.js +++ b/src/client/javascript/core/connections/standalone.js @@ -28,24 +28,21 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function() { - 'use strict'; +import Promise from 'bluebird'; +import HttpConnection from './http'; - /** - * Registers your package when OS.js server starts. - */ - module.exports.register = function(env, metadata, servers) { - }; +/** + * Standalone Connection Handler + * @extends HttpConnection + */ +export default class StandaloneConnection extends HttpConnection { - /** - * Registers your Application API methods - */ - module.exports.api = { - test: function(env, http, resolve, reject, args) { - resolve('This is a response from your application'); + createRequest(method, args, options) { + if ( method === 'packages' ) { + return Promise.resolve({result: OSjs.getManifest()}); } - }; + return Promise.reject(new Error('You are currently running locally and cannot perform this operation!')); + } -})(); +} diff --git a/src/client/javascript/core/connections/ws.js b/src/client/javascript/core/connections/ws.js index 37339e70af..0bed24e9ac 100644 --- a/src/client/javascript/core/connections/ws.js +++ b/src/client/javascript/core/connections/ws.js @@ -27,17 +27,25 @@ * @author Anders Evenrud * @licence Simplified BSD License */ +import {getConfig} from 'core/config'; +import {_} from 'core/locales'; +import * as VFS from 'vfs/fs'; +import FileMetadata from 'vfs/file'; +import Connection from 'core/connection'; +import Promise from 'bluebird'; + +/** + * WebSocket Connection Handler + * @xtends Connection + */ +export default class WSConnection extends Connection { + constructor() { + super(...arguments); -(function(API, VFS, Utils, Connection) { - 'use strict'; - - function WSConnection() { - Connection.apply(this, arguments); - - var port = API.getConfig('Connection.WSPort'); - var path = API.getConfig('Connection.WSPath') || ''; - var url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host; + const port = getConfig('Connection.WSPort'); + const path = getConfig('Connection.WSPath') || ''; + let url = window.location.protocol.replace('http', 'ws') + '//' + window.location.host; if ( port !== 'upgrade' ) { if ( url.match(/:\d+$/) ) { url = url.replace(/:\d+$/, ''); @@ -52,78 +60,88 @@ this.destroying = false; } - WSConnection.prototype = Object.create(Connection.prototype); - WSConnection.constructor = Connection; - - WSConnection.prototype.destroy = function() { - this.destroying = true; + destroy() { + if ( !this.destroying ) { + if ( this.ws ) { + this.ws.close(); + } - if ( this.ws ) { - this.ws.close(); + this.ws = null; + this.wsqueue = {}; } - this.ws = null; - this.wsqueue = {}; - return Connection.prototype.destroy.apply(this, arguments); - }; + this.destroying = true; + + return super.destroy.apply(this, arguments); + } - WSConnection.prototype.init = function(callback) { + init() { this.destroying = false; - this._connect(false, callback); - }; + return new Promise((resolve, reject) => { + this._connect(false, (err, res) => { + if ( err ) { + reject(err instanceof Error ? err : new Error(err)); + } else { + resolve(res); + } + }); + }); + } - WSConnection.prototype._connect = function(reconnect, callback) { + _connect(reconnect, callback) { if ( this.destroying || this.ws && !reconnect ) { return; } console.info('Trying WebSocket Connection', this.wsurl); - var self = this; - var connected = false; + let connected = false; this.ws = new WebSocket(this.wsurl); - this.ws.onopen = function() { + this.ws.onopen = function(ev) { connected = true; // NOTE: For some reason it needs to be fired on next tick - setTimeout(function() { - callback(); - }, 0); + setTimeout(() => callback(false), 0); }; - this.ws.onmessage = function(ev) { - var data = JSON.parse(ev.data); - var idx = data._index; - self._onmessage(idx, data); + this.ws.onmessage = (ev) => { + console.debug('websocket open', ev); + const data = JSON.parse(ev.data); + const idx = data._index; + this._onmessage(idx, data); }; - this.ws.onclose = function(ev) { + this.ws.onerror = (ev) => { + console.error('websocket error', ev); + }; + + this.ws.onclose = (ev) => { + console.debug('websocket close', ev); if ( !connected && ev.code !== 3001 ) { - callback(API._('CONNECTION_ERROR')); + callback(_('CONNECTION_ERROR')); return; } - self._onclose(); + this._onclose(); }; - }; + } - WSConnection.prototype._onmessage = function(idx, data) { + _onmessage(idx, data) { if ( typeof idx === 'undefined' ) { this.message(data); } else { if ( this.wsqueue[idx] ) { delete data._index; - this.wsqueue[idx](data); + this.wsqueue[idx](false, data); delete this.wsqueue[idx]; } } - }; + } - WSConnection.prototype._onclose = function(reconnecting) { - var self = this; + _onclose(reconnecting) { if ( this.destroying ) { return; } @@ -132,44 +150,40 @@ this.ws = null; - setTimeout(function() { - self._connect(true, function(err) { + setTimeout(() => { + this._connect(true, (err) => { if ( err ) { - self._onclose((reconnecting || 0) + 1); + this._onclose((reconnecting || 0) + 1); } else { - self.onOnline(); + this.onOnline(); } }); }, reconnecting ? 10000 : 1000); - }; + } - WSConnection.prototype.message = function(data) { + message(data) { // Emit a VFS event when a change occures if ( data.action === 'vfs:watch' ) { - VFS.Helpers.triggerWatch(data.args.event, VFS.file(data.args.file)); + VFS.triggerWatch(data.args.event, new FileMetadata(data.args.file)); } // Emit a subscription event if ( this._evHandler ) { this._evHandler.emit(data.action, data.args); } - }; - - WSConnection.prototype.request = function(method, args, onsuccess, onerror, options) { - onerror = onerror || function() { - console.warn('Connection::callWS()', 'error', arguments); - }; + } - var res = Connection.prototype.request.apply(this, arguments); - if ( res !== false ) { - return res; - } + createRequest(method, args, options) { if ( !this.ws ) { - return false; + return Promise.reject(new Error('No websocket connection')); + } + + if ( ['FS:upload', 'FS:get', 'logout'].indexOf(method) !== -1 ) { + return super.createRequest(...arguments); } - var idx = this.index++; - var base = method.match(/^FS:/) ? '/FS/' : '/API/'; + const idx = this.index++; + const base = method.match(/^FS:/) ? '/FS/' : '/API/'; try { this.ws.send(JSON.stringify({ @@ -177,23 +191,15 @@ path: base + method.replace(/^FS:/, ''), args: args })); - - this.wsqueue[idx] = onsuccess || function() {}; - - return true; } catch ( e ) { - console.warn('callWS() Warning', e.stack, e); - onerror(e); + return Promise.reject(e); } - return false; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Connections = OSjs.Connections || {}; - OSjs.Connections.ws = WSConnection; + return new Promise((resolve, reject) => { + this.wsqueue[idx] = function(err, res) { + return err ? reject(err) : resolve(res); + }; + }); + } +} -})(OSjs.API, OSjs.VFS, OSjs.Utils, OSjs.Core.Connection); diff --git a/src/client/javascript/core/dialog.js b/src/client/javascript/core/dialog.js index 61e2031091..9a5d8ad6bd 100644 --- a/src/client/javascript/core/dialog.js +++ b/src/client/javascript/core/dialog.js @@ -27,69 +27,68 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API, Window) { - 'use strict'; +import {$empty, $addClass, $escape} from 'utils/dom'; +import Keycodes from 'utils/keycodes'; +import Window from 'core/window'; +import Application from 'core/application'; +import WindowManager from 'core/window-manager'; +import GUIScheme from 'gui/scheme'; +import {_} from 'core/locales'; + +/** + * A callback for Dialogs. + * + *
+ * The list of included buttons are: ok, cancel, yes, no
+ * depending on which dialog was called.
+ *
+ * The result also depends on which dialog was called.
+ *
+ * The default button is 'cancel' if window was closed.
+ *
+ * You only get an event back if an actual button was pressed.
+ * 
+ * + * @callback CallbackDialog + * @param {Event} ev Browser event that occured from action + * @param {String} button Which button that was clicked + * @param {*} result Result from dialog input + */ - /** - * A callback for Dialogs. - * - *
-   * The list of included buttons are: ok, cancel, yes, no
-   * depending on which dialog was called.
-   *
-   * The result also depends on which dialog was called.
-   *
-   * The default button is 'cancel' if window was closed.
-   *
-   * You only get an event back if an actual button was pressed.
-   * 
- * - * @callback CallbackDialog - * @param {Event} ev Browser event that occured from action - * @param {String} button Which button that was clicked - * @param {Mixed} result Result from dialog input - */ +let _dialogScheme; + +///////////////////////////////////////////////////////////////////////////// +// DIALOG +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // DIALOG - ///////////////////////////////////////////////////////////////////////////// +/** + * Base Dialog Window Class + * + * @desc Class used for basis as a Dialog. + * + * @extends {Window} + * @abstract + */ +export default class DialogWindow extends Window { /** - * Dialog Window - * - * A simple wrapper with some pre-defined options - * - *

-   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
-   * 
- * - * @summary Class used for basis as a Dialog. - * * @param {String} className Dialog Class Name * @param {Object} opts Dialog Class Options * @param {Object} args Dialog Class Arguments * @param {CallbackDialog} callback Callback function - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @extends OSjs.Core.Window - * @see OSjs.API.createDialog */ - function DialogWindow(className, opts, args, callback) { - var self = this; - + constructor(className, opts, args, callback) { opts = opts || {}; args = args || {}; - callback = callback || function() {}; + if ( typeof callback !== 'function' ) { throw new TypeError('DialogWindow expects a callback Function, gave: ' + typeof callback); } console.info('DialogWindow::construct()', className, opts, args); - Window.apply(this, [className, opts]); + super(className, opts); this._properties.gravity = 'center'; this._properties.allow_resize = false; @@ -100,117 +99,114 @@ this._state.ontop = true; this._tag = 'DialogWindow'; - if ( args.scheme && args.scheme instanceof OSjs.GUI.Scheme ) { + if ( args.scheme && args.scheme instanceof GUIScheme ) { this.scheme = args.scheme; delete args.scheme; } else { - this.scheme = OSjs.GUI.DialogScheme.get(); + try { + if ( !_dialogScheme ) { + const cachedHtml = require('osjs-scheme-loader!dialogs.html'); + if ( cachedHtml ) { + _dialogScheme = GUIScheme.fromString(cachedHtml); + } + } + } catch ( e ) { + console.warn(e); + } + + this.scheme = _dialogScheme; } this.args = args; this.className = className; this.buttonClicked = false; - this.closeCallback = function Dialog_closeCallback(ev, button, result) { - if ( self._destroyed ) { + this.closeCallback = (ev, button, result) => { + if ( this._destroyed ) { return; } - self.buttonClicked = true; - callback.apply(self, arguments); - self._close(); + this.buttonClicked = true; + callback.call(this, ev, button, result); + this._close(); }; } - DialogWindow.prototype = Object.create(Window.prototype); - DialogWindow.constructor = Window; - /** * @override - * @function init - * @memberof OSjs.Core.DialogWindow# */ - DialogWindow.prototype.init = function() { - var self = this; + init() { + const root = super.init(...arguments); - var root = Window.prototype.init.apply(this, arguments); root.setAttribute('role', 'dialog'); if ( this.scheme ) { - this.scheme.render(this, this.className.replace(/Dialog$/, ''), root, 'application-dialog', function(node) { - node.querySelectorAll('gui-label').forEach(function(el) { + this.scheme.render(this, this.className.replace(/Dialog$/, ''), root, 'application-dialog', (node) => { + node.querySelectorAll('gui-label').forEach((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))); + const label = el.childNodes[0].nodeValue; + $empty(el); + el.appendChild(document.createTextNode(_(label))); } }); }); - var buttonMap = { + const buttonMap = { ButtonOK: 'ok', ButtonCancel: 'cancel', ButtonYes: 'yes', ButtonNo: 'no' }; - var focusButtons = ['ButtonCancel', 'ButtonNo']; + const focusButtons = ['ButtonCancel', 'ButtonNo']; - Object.keys(buttonMap).forEach(function(id) { - if ( self._findDOM(id) ) { - var btn = self._find(id); - btn.on('click', function(ev) { - self.onClose(ev, buttonMap[id]); - }); - if ( focusButtons.indexOf(id) >= 0 ) { - btn.focus(); - } + Object.keys(buttonMap).filter((id) => this._findDOM(id)).forEach((id) => { + const btn = this._find(id); + btn.on('click', (ev) => { + this.onClose(ev, buttonMap[id]); + }); + + if ( focusButtons.indexOf(id) >= 0 ) { + btn.focus(); } }); } - Utils.$addClass(root, 'DialogWindow'); + $addClass(root, 'DialogWindow'); return root; - }; + } /** * When dialog closes * * @param {Event} ev DOM Event * @param {String} button Button used - * - * @function onClose - * @memberof OSjs.Core.DialogWindow# */ - DialogWindow.prototype.onClose = function(ev, button) { + onClose(ev, button) { this.closeCallback(ev, button, null); - }; + } /** * @override - * @function _close - * @memberof OSjs.Core.DialogWindow# */ - DialogWindow.prototype._close = function() { + _close() { if ( !this.buttonClicked ) { this.onClose(null, 'cancel', null); } - return Window.prototype._close.apply(this, arguments); - }; + return super._close(...arguments); + } /** * @override - * @function _onKeyEvent - * @memberof OSjs.Core.DialogWindow# */ - DialogWindow.prototype._onKeyEvent = function(ev) { - Window.prototype._onKeyEvent.apply(this, arguments); + _onKeyEvent(ev) { + super._onKeyEvent(...arguments); - if ( ev.keyCode === Utils.Keys.ESC ) { + if ( ev.keyCode === Keycodes.ESC ) { this.onClose(ev, 'cancel'); } - }; + } /** * Parses given message to be inserted into Dialog @@ -218,29 +214,93 @@ * @param {String} msg Message * * @return {DocumentFragment} - * - * @function parseMessage - * @memberof OSjs.Core.DialogWindow */ - DialogWindow.parseMessage = function(msg) { - msg = Utils.$escape(msg || '').replace(/\*\*(.*)\*\*/g, '$1'); + static parseMessage(msg) { + msg = $escape(msg || '').replace(/\*\*(.*)\*\*/g, '$1'); - var tmp = document.createElement('div'); + let tmp = document.createElement('div'); tmp.innerHTML = msg; - var frag = document.createDocumentFragment(); - for ( var i = 0; i < tmp.childNodes.length; i++ ) { + const frag = document.createDocumentFragment(); + for ( let i = 0; i < tmp.childNodes.length; i++ ) { frag.appendChild(tmp.childNodes[i].cloneNode(true)); } tmp = null; return frag; - }; + } + + /** + * Create a new dialog + * + * You can also pass a function as `className` to return an instance of your own class + * + * @param {String} className Dialog Namespace Class Name + * @param {Object} args Arguments you want to send to dialog + * @param {CallbackDialog} callback Callback on dialog action (close/ok etc) => fn(ev, button, result) + * @param {Object|Window|Application} [options] A window or app (to make it a child window) or a set of options: + * @param {Window|Application} [options.parent] Same as above argument (without options context) + * @param {Boolean} [options.modal=false] If you provide a parent you can toggle "modal" mode. + * + * @return {Window} + */ + static create(className, args, callback, options) { + + callback = callback || function() {}; + options = options || {}; + + let parentObj = options; + let parentIsWindow = (parentObj instanceof Window); + let parentIsProcess = (parentObj instanceof Application); + if ( parentObj && !(parentIsWindow && parentIsProcess) ) { + parentObj = options.parent; + parentIsWindow = (parentObj instanceof Window); + parentIsProcess = (parentObj instanceof Application); + } + + function cb() { + if ( parentObj ) { + if ( parentIsWindow && parentObj._destroyed ) { + console.warn('DialogWindow::create()', 'INGORED EVENT: Window was destroyed'); + return; + } + if ( parentIsProcess && parentObj.__destroyed ) { + console.warn('DialogWindow::create()', 'INGORED EVENT: Process was destroyed'); + return; + } + } + + if ( options.modal && parentIsWindow ) { + parentObj._toggleDisabled(false); + } + + callback.apply(null, arguments); + } + + const win = typeof className === 'string' ? new OSjs.Dialogs[className](args, cb) : className(args, cb); + + if ( !parentObj ) { + const wm = WindowManager.instance; + wm.addWindow(win, true); + } else if ( parentObj instanceof Window ) { + win._on('destroy', () => { + if ( parentObj ) { + parentObj._focus(); + } + }); + parentObj._addChild(win, true); + } else if ( parentObj instanceof Application ) { + parentObj._addWindow(win); + } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + if ( options.modal && parentIsWindow ) { + parentObj._toggleDisabled(true); + } - OSjs.Core.DialogWindow = Object.seal(DialogWindow); + setTimeout(() => { + win._focus(); + }, 10); -})(OSjs.Utils, OSjs.API, OSjs.Core.Window); + return win; + } +} diff --git a/src/client/javascript/core/init.js b/src/client/javascript/core/init.js new file mode 100644 index 0000000000..cf3fdb1157 --- /dev/null +++ b/src/client/javascript/core/init.js @@ -0,0 +1,630 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import Promise from 'bluebird'; +import * as Locales from 'core/locales'; +import MountManager from 'core/mount-manager'; +import SettingsManager from 'core/settings-manager'; +import PackageManager from 'core/package-manager'; +import SearchEngine from 'core/search-engine'; +import Authenticator from 'core/authenticator'; +import WindowManager from 'core/window-manager'; +import DialogWindow from 'core/dialog'; +import Storage from 'core/storage'; +import Process from 'core/process'; +import Theme from 'core/theme'; +import Connection from 'core/connection'; +import {triggerHook} from 'helpers/hooks'; +import {getConfig} from 'core/config'; +import SplashScreen from 'gui/splash'; +import * as Utils from 'utils/misc'; +import * as Menu from 'gui/menu'; +import Preloader from 'utils/preloader'; + +import AlertDialog from 'dialogs/alert'; +import ApplicationChooserDialog from 'dialogs/applicationchooser'; +import ColorDialog from 'dialogs/color'; +import ConfirmDialog from 'dialogs/confirm'; +import ErrorDialog from 'dialogs/error'; +import FileInfoDialog from 'dialogs/fileinfo'; +import FileDialog from 'dialogs/file'; +import FileProgressDialog from 'dialogs/fileprogress'; +import FileUploadDialog from 'dialogs/fileupload'; +import FontDialog from 'dialogs/font'; +import InputDialog from 'dialogs/input'; + +let hasBooted = false; +let hasShutDown = false; + +/////////////////////////////////////////////////////////////////////////////// +// HELPERS +/////////////////////////////////////////////////////////////////////////////// + +function onError(title, message, error, exception, bugreport) { + bugreport = (() => { + if ( getConfig('BugReporting.enabled') ) { + return typeof bugreport === 'undefined' ? false : (bugreport ? true : false); + } + return false; + })(); + + function _dialog() { + const wm = WindowManager.instance; + if ( wm && wm._fullyLoaded ) { + try { + DialogWindow.create('Error', { + title: title, + message: message, + error: error, + exception: exception, + bugreport: bugreport + }); + + return true; + } catch ( e ) { + console.warn('An error occured while creating Error Dialog', e); + console.warn('stack', e.stack); + } + } + + return false; + } + + Menu.blur(); + + if ( (exception instanceof Error) && (exception.message.match(/^Script Error/i) && String(exception.lineNumber).match(/^0/)) ) { + console.error('VENDOR ERROR', { + title: title, + message: message, + error: error, + exception: exception + }); + return; + } else { + console.error(title, message, error, exception); + } + + const testMode = OSJS_DEBUG && window.location.hash.match(/mocha=true/); + if ( !testMode ) { + if ( !_dialog() ) { + window.alert(title + '\n\n' + message + '\n\n' + error); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// INITIALIZERS +/////////////////////////////////////////////////////////////////////////////// + +/** + * Initialize: Preloading + * @param {Object} config Configuration + * @return {Promise} + */ +const initPreloading = (config) => new Promise((resolve, reject) => { + const flatten = (list) => list.reduce((a, b) => + a.concat(Array.isArray(b) ? flatten(b) : b), []); + + Preloader.preload(flatten(config.Preloads)).then((result) => { + return resolve(); + }).catch(reject); +}); + +/** + * Initialize: Handlers + * @param {Object} config Configuration + * @return {Promise} + */ +const initHandlers = (config) => new Promise((resolve, reject) => { + const options = config.Connection; + console.log({ + authenticator: options.Authenticator, + connection: options.Connection, + storage: options.Storage + }); + + let Authenticator, Connection, Storage; + try { + Authenticator = require('core/auth/' + options.Authenticator + '.js').default; + Connection = require('core/connections/' + options.Connection + '.js').default; + Storage = require('core/storage/' + options.Storage + '.js').default; + } catch ( e ) { + reject(e); + return; + } + + const connection = new Connection(); + const authenticator = new Authenticator(); + const storage = new Storage(); + + Promise.each([connection, storage, authenticator], (iter) => { + return iter.init(); + }).then(resolve).catch(reject); +}); + +/** + * Initialize: VFS + * @param {Object} config Configuration + * @return {Promise} + */ +const initVFS = (config) => new Promise((resolve, reject) => { + const mountPoints = SettingsManager.instance('VFS').get('mounts', []); + + MountManager.init().then((res) => { + return MountManager.addList(mountPoints).then((res) => { + return resolve(res); + }).catch((e) => { + console.warn('A module failed to load!', e); + resolve(); + }); + }).catch(reject); +}); + +/** + * Initialize: Settings Manager + * @param {Object} config Configuration + * @return {Promise} + */ +const initSettingsManager = (config) => new Promise((resolve, reject) => { + const pools = config.SettingsManager || {}; + + Object.keys(pools).forEach(function(poolName) { + console.debug('initSettingsManager()', 'initializes pool', poolName, pools[poolName]); + SettingsManager.instance(poolName, pools[poolName] || {}); + }); + + resolve(); +}); + +/** + * Initialize: Package Manager + * @param {Object} config Configuration + * @return {Promise} + */ +const initPackageManager = (config) => new Promise((resolve, reject) => { + const list = config.PreloadOnBoot || []; + + let metadata = {}; + try { + // In case of standalone + metadata = OSjs.getManifest(); + } catch ( e ) {} + + PackageManager.init(metadata).then(() => { + return Promise.each(list, (iter) => { + return new Promise((next) => { + var pkg = PackageManager.getPackage(iter); + if ( pkg && pkg.preload ) { + Preloader.preload(pkg.preload).then(next).catch(() => next()); + } else { + next(); + } + }); + }).then(resolve).catch(reject); + }).catch(reject); +}); + +/** + * Initialize: Extensions + * @param {Object} config Configuration + * @return {Promise} + */ +const initExtensions = (config) => new Promise((resolve, reject) => { + const packages = PackageManager.getPackages(); + + const preloadExtensions = () => new Promise((resolve, reject) => { + let preloads = []; + Object.keys(packages).forEach((k) => { + const iter = packages[k]; + if ( iter.type === 'extension' && iter.preload ) { + preloads = preloads.concat(iter.preload); + } + }); + + if ( preloads.length ) { + Preloader.preload(preloads).then(resolve).catch(() => resolve()); + } else { + resolve(); + } + }); + + const launchExtensions = () => new Promise((resolve, reject) => { + const exts = Object.keys(OSjs.Extensions); + + Promise.each(exts, (entry) => { + return new Promise((next) => { + try { + // FIXME + const m = packages[entry]; + OSjs.Extensions[entry].init(m, () => next()); + } catch ( e ) { + console.warn('Extension init failed', e.stack, e); + next(); + } + }); + }).then(resolve).catch((err) => { + console.warn(err); + reject(new Error(err)); + }); + }); + + preloadExtensions().then(() => { + return launchExtensions().then(resolve).catch(reject); + }).catch(() => resolve()); +}); + +/** + * Initialize: Search Engine + * @param {Object} config Configuration + * @return {Promise} + */ +const initSearchEngine = (config) => new Promise((resolve, reject) => { + SearchEngine.init().then(resolve).catch(reject); +}); + +/** + * Initialize: GUI + * @param {Object} config Configuration + * @return {Promise} + */ +const initGUI = (config) => new Promise((resolve, reject) => { + + const guiElements = ['containers', 'visual', 'tabs', 'richtext', 'misc', 'inputs', 'treeview', 'listview', 'iconview', 'fileview', 'menus']; + guiElements.forEach((f) => { + const gel = require('gui/elements/' + f + '.js').default; + Object.keys(gel).forEach((name) => { + gel[name].register(); + }); + }); + + OSjs.error = onError; + OSjs.Dialogs.Alert = AlertDialog; + OSjs.Dialogs.ApplicationChooser = ApplicationChooserDialog; + OSjs.Dialogs.Color = ColorDialog; + OSjs.Dialogs.Confirm = ConfirmDialog; + OSjs.Dialogs.Error = ErrorDialog; + OSjs.Dialogs.File = FileDialog; + OSjs.Dialogs.FileInfo = FileInfoDialog; + OSjs.Dialogs.FileProgress = FileProgressDialog; + OSjs.Dialogs.FileUpload = FileUploadDialog; + OSjs.Dialogs.Font = FontDialog; + OSjs.Dialogs.Input = InputDialog; + + Theme.init(); + + resolve(); +}); + +/** + * Initialize: Window Manager + * @param {Object} config Configuration + * @return {Promise} + */ +const initWindowManager = (config) => new Promise((resolve, reject) => { + const wmConfig = config.WindowManager; + + if ( !wmConfig || !wmConfig.exec ) { + reject(new Error(Locales._('ERR_CORE_INIT_NO_WM'))); + } else { + Process.create(wmConfig.exec, (wmConfig.args || {})).then((app) => { + return app.setup().then(resolve).catch(reject); + }).catch((error) => { + reject(new Error(Locales._('ERR_CORE_INIT_WM_FAILED_FMT', error))); + }); + } +}); + +/** + * Initialize: Mocha + * @param {Object} config Configuration + * @return {Promise} + */ +const initMocha = (config) => new Promise((resolve, reject) => { + + const div = document.createElement('div'); + div.id = 'mocha'; + document.body.appendChild(div); + document.body.style.overflow = 'auto'; + document.body.style.backgroundColor = '#ffffff'; + + Preloader.preload([ + '/test.css', + '/test.js' + ]).then(() => { + OSjs.runTests(); + }); + + resolve(true); +}); + +/////////////////////////////////////////////////////////////////////////////// +// MISC +/////////////////////////////////////////////////////////////////////////////// + +/* + * Initializes the user session + */ +function initSession(config) { + console.debug('initSession()'); + + var list = []; + + // In this case we merge the Autostart and the previous session together. + // This ensures that items with autostart are loaded with correct + // session data on restore. This is much better than relying on the internal + // event/message system which does not trigger until after everything is loaded... + // this does everything beforehand! :) + // + 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); + } + } + }); + + return new Promise((resolve) => { + Storage.instance.getLastSession().then((adds) => { + 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 = Utils.mergeObject(ref.args, iter.args); + } + } + }); + + console.info('initSession()->autostart()', list); + return Process.createFromArray(list).then(resolve).catch(resolve); + }).catch((err) => { + console.warn(err); + resolve(); + }); + }); +} + +/* + * When window gets an external message + */ +function onMessage(ev) { + if ( ev && ev.data && typeof ev.data.message !== 'undefined' && typeof ev.data.pid === 'number' ) { + console.debug('window::message()', ev.data); + var proc = Process.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); + } + } + } + } +} + +/////////////////////////////////////////////////////////////////////////////// +// API +/////////////////////////////////////////////////////////////////////////////// + +/** + * Starts OS.js + */ +export function start() { + if ( hasBooted || hasShutDown ) { + return; + } + hasBooted = true; + + console.info('Starting OS.js'); + + const config = OSjs.getConfig(); + const testMode = OSJS_DEBUG && window.location.hash.match(/mocha=true/); + const total = 9; + + Locales.init(config.Locale, config.LocaleOptions, config.Languages); + + SplashScreen.watermark(config); + SplashScreen.show(); + + triggerHook('onInitialize'); + + Promise.each([ + initPreloading, + initHandlers, + initVFS, + initSettingsManager, + initPackageManager, + initExtensions, + initSearchEngine, + initGUI, + testMode ? initMocha : initWindowManager + ], (fn, index) => { + return new Promise((resolve, reject) => { + console.group('Initializing', index + 1, 'of', total); + SplashScreen.update(index, total); + + return fn(config).then((res) => { + console.groupEnd(); + return resolve(res); + }).catch((err) => { + console.groupEnd(); + return reject(new Error(err)); + }); + }); + }).then(() => { + console.info('Done!'); + + window.addEventListener('message', onMessage, false); + + triggerHook('onInited'); + SplashScreen.hide(); + + if ( !testMode ) { + Theme.playSound('LOGIN'); + + var wm = WindowManager.instance; + if ( wm ) { + wm._fullyLoaded = true; + } + + initSession(config).then(() => { + return triggerHook('onSessionLoaded'); + }); + } + + return true; + }).catch((err) => { + const title = Locales._('ERR_CORE_INIT_FAILED'); + const message = Locales._('ERR_CORE_INIT_FAILED_DESC'); + alert(title + '\n\n' + message); + console.error(title, message, err); + }); +} + +/** + * Stops OS.js + * @param {Boolean} [restart=false] Restart instead of full stop + */ +export function stop(restart = false) { + if ( hasShutDown || !hasBooted ) { + return; + } + + hasShutDown = true; + hasBooted = false; + + window.removeEventListener('message', onMessage, false); + + const wm = WindowManager.instance; + if ( wm ) { + wm.toggleFullscreen(); + } + + Preloader.clear(); + Menu.blur(); + Process.killAll(); + SearchEngine.destroy(); + PackageManager.destroy(); + Authenticator.instance.destroy(); + Storage.instance.destroy(); + Connection.instance.destroy(); + + triggerHook('onShutdown'); + + console.warn('OS.js was shut down!'); + + if ( !restart && getConfig('ReloadOnShutdown') === true ) { + window.location.reload(); + } +} + +/** + * Restarts OS.js + * @param {Boolean} [save=false] Save session + */ +export function restart(save = false) { + const lout = (cb) => Authenticator.instance.logout().then(cb).catch(cb); + + const saveFunction = save && Storage.instance ? function(cb) { + Storage.instance.saveSession() + .then(() => lout(cb)) + .catch(() => lout(cb)); + } : lout; + + saveFunction(function() { + console.clear(); + stop(true); + start(); + }); +} + +/** + * Perfors a log out of OS.js + */ +export function logout() { + const storage = Storage.instance; + const wm = WindowManager.instance; + + function signOut(save) { + Theme.playSound('LOGOUT'); + + const lout = (cb) => Authenticator.instance.logout().then(cb).catch(cb); + + if ( save ) { + storage.saveSession() + .then(() => lout(stop)) + .catch(() => lout(stop)); + } else { + lout(stop); + } + } + + if ( wm ) { + const user = Authenticator.instance.getUser() || {name: Locales._('LBL_UNKNOWN')}; + DialogWindow.create('Confirm', { + title: Locales._('DIALOG_LOGOUT_TITLE'), + message: Locales._('DIALOG_LOGOUT_MSG_FMT', user.name) + }, function(ev, btn) { + if ( ['no', 'yes'].indexOf(btn) !== -1 ) { + signOut(btn === 'yes'); + } + }); + } else { + signOut(true); + } +} + +/** + * Checks if OS.js is running + * @return {Boolean} + */ +export function running() { + return !hasShutDown; +} diff --git a/src/client/javascript/core/locales.js b/src/client/javascript/core/locales.js new file mode 100644 index 0000000000..1aa406e8f2 --- /dev/null +++ b/src/client/javascript/core/locales.js @@ -0,0 +1,172 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import {format} from 'utils/misc'; + +let DefaultLocale = 'en_EN'; +let CurrentLocale = 'en_EN'; +let CurrentRTL = []; + +///////////////////////////////////////////////////////////////////////////// +// LOCALE API METHODS +///////////////////////////////////////////////////////////////////////////// + +/** + * Translate given string + * + * @param {String} s Translation key/string + * @param {...String} sargs Format values + * + * @return {String} + */ +export function _() { + let userLocale = {}; + let systemLocale = {}; + try { + userLocale = require('locales/' + CurrentLocale + '.js'); + systemLocale = require('locales/' + DefaultLocale + '.js'); + } catch ( e ) { + console.warn('Locale error', e); + } + + const s = arguments[0]; + let a = arguments; + try { + if ( userLocale && userLocale[s] ) { + a[0] = userLocale[s]; + } else { + a[0] = systemLocale[s] || s; + } + + return a.length > 1 ? format.apply(null, a) : a[0]; + } catch ( e ) { + console.warn(e.stack, e); + } + + return s; +} + +/** + * Same as _ only you can supply the list as first argument + * @see _ + * + * @return {String} + */ +export function __() { + const l = arguments[0]; + const s = arguments[1]; + + let 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] = _.apply(null, a); + } + } + + return a.length > 1 ? format.apply(null, a) : a[0]; +} + +/** + * Get current locale + * + * @return {String} + */ +export function getLocale() { + return CurrentLocale; +} + +/** + * Set locale + * + * @param {String} l Locale name + */ +export function setLocale(l) { + let locale; + + try { + locale = require('locales/' + l + '.js'); + } catch ( e ) { + console.warn('Failed to set locale', e); + return; + } + + if ( locale ) { + CurrentLocale = l; + } else { + console.warn('Locales::setLocale()', 'Invalid locale', l, '(Using default)'); + CurrentLocale = DefaultLocale; + } + + const major = CurrentLocale.split('_')[0]; + const html = document.querySelector('html'); + if ( html ) { + html.setAttribute('lang', l); + html.setAttribute('dir', CurrentRTL.indexOf(major) !== -1 ? 'rtl' : 'ltr'); + } + + console.info('Locales::setLocale()', CurrentLocale); +} + +/** + * Creates a new translation function based on a map + * @param {Object} locales A localization map + * @return {Function} + */ +export function createLocalizer(locales) { + return function() { + var args = Array.prototype.slice.call(arguments, 0); + args.unshift(locales); + return __(...args); + }; +} + +/** + * Initializes locales + * @param {String} locale Locale name + * @param {Object} options Locale options + * @param {Array} [options.RTL] RTL Languages + * @param {Array} languages Available languages + */ +export function init(locale, options, languages) { + options = options || {}; + + const names = languages ? Object.keys(languages) : {}; + if ( names.indexOf(locale) !== -1 ) { + CurrentLocale = locale; + } + + CurrentRTL = options.RTL || []; + + names.forEach((k) => { + OSjs.Locales[k] = require('locales/' + k + '.js'); + }); +} diff --git a/src/client/javascript/core/mount-manager.js b/src/client/javascript/core/mount-manager.js index 69cec1239b..3d5b67ab9f 100644 --- a/src/client/javascript/core/mount-manager.js +++ b/src/client/javascript/core/mount-manager.js @@ -27,492 +27,233 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, VFS, API) { - 'use strict'; - /** - * A mountpoint object for use in MountManager - * @property {String} name Mountpoint Name (unique) - * @property {String} description General description - * @property {String} icon Icon - * @property {String} root The root path (ex: home:///) - * @property {RegExp} match Matches a path given in VFS methods to this - * @property {String} transport Transporter name (OSjs/WebDAV) - * @property {Boolean} [readOnly=false] If this is a readonly point - * @property {Boolean} [visible=true] If this is visible in the UIs - * @property {Boolean} [searchable=true] If you can search for files in this module - * @property {Boolean} [internal=false] If this is a internal module - * @property {Function} [mount] Method for mounting (INTERNAL) - * @property {Function} [unmount] Method for unmounting (INTERNAL) - * @property {Function} [enabled] Method for getting enabled state (INTERNAL) - * @property {Function} [request] Method for making a request (INTERNAL) - * @property {Object} options Connection options (for external services like webdav) - * @property {String} [options.host] Host (full URL) - * @property {String} [options.username] Username - * @property {String} [options.password] Password - * @property {Boolean} [options.cors=false] If CORS is enabled - * @typedef Mountpoint - */ +import Promise from 'bluebird'; + +import Mountpoint from 'vfs/mountpoint'; +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; - var DefaultModule = 'home'; +function loadTransports() { + const list = ['web', 'osjs', 'dist', 'applications', 'webdav', 'google-drive', 'onedrive']; + const result = {}; + list.forEach((name) => { + result[name] = require(`vfs/transports/${name}`).default; + }); + return result; +} - ///////////////////////////////////////////////////////////////////////////// - // MOUNT MANAGER - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// MOUNT MANAGER +///////////////////////////////////////////////////////////////////////////// + +/** + * Mount Manager Class + * + * @desc Class for maintaining mountpoints and handling + * requests over to VFS. + */ +class MountManager { /** - * Mount Manager Class - * - * @summary Class for maintaining mountpoints - * - *

-   * YOU CAN ONLY GET AN INSTANCE WITH `Core.getMountManager()`
-   * 
- * - * @example - * OSjs.Core.getMountManager() - * - * @constructor - * @memberof OSjs.Core - * @see OSjs.Core.getMountManager + * Constructs a new MountManager */ - var MountManager = (function() { - var _queue = []; - var _inited = false; - var _modules = {}; - - /* - * Checks if given transport mount is read-only - */ - function isReadOnly(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; - } + constructor() { + this.inited = false; + this.mountpoints = []; + this.transports = loadTransports(); + } - if ( restricted.indexOf(name) !== -1 ) { - return true; - } - } - return false; + /** + * Initializes MountManager + * + * @return {Promise} + */ + init() { + if ( this.inited ) { + return Promise.resolve(); } - /* - * Creates a new mount object - */ - function createMountPoint(name, args, dynamic) { - if ( name === null ) { - name = args.name; - } + this.inited = true; - var sname = name.replace(/\s/g, '-').toLowerCase(); - if ( _modules[name] ) { - throw new Error(API._('ERR_VFSMODULE_ALREADY_MOUNTED_FMT', name)); - } - - var match = new RegExp('^' + (sname + '://').replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&')); - - var mount = Utils.argumentDefaults(Utils.cloneObject(args, true), { - searchable: true, - readOnly: false, - visible: true, - dynamic: dynamic === true, - options: {}, - - transport: 'OSjs', - root: sname + ':///', - name: name, - description: name, - icon: 'devices/drive-harddisk.png', - - request: function _request(n, a, callback, options) { - MountManager._request(mount, n, a, callback, options); - }, - unmount: function(cb) { - (cb || function() {})(API._('ERR_VFS_UNAVAILABLE'), false); - }, - mounted: function() { - return true; - }, - enabled: function() { - return true; - } - }, true); + const config = getConfig('VFS.Mountpoints', {}); + const enabled = Object.keys(config).filter((name) => { + return config[name].enabled !== false; + }); - mount.match = args.match || match; + return Promise.each(enabled, (name) => { + return new Promise((resolve) => { + const iter = Object.assign({ + name: name, + dynamic: false + }, config[name]); + + this.add(iter, true, { + notify: false + }).then(resolve).catch((e) => { + console.warn('Failed to init VFS Mountpoint', name, iter, String(e)); + return resolve(false); // We skip errors on init + }); + }); + }); + } - // TODO: Make sure aliases inherit correct transport - var internals = ['OSjs']; - if ( typeof mount.internal === 'undefined' ) { - mount.internal = internals.indexOf(mount.transport) !== -1; - } + /** + * Adds a list of mountpoints + * + * @param {Mountpoint[]|Object[]} mountPoints Mountpoints + * @return {Promise} + */ + addList(mountPoints) { + return Promise.each(mountPoints, (iter) => this.add(iter)); + } - if ( mount.transport.toLowerCase() === 'owndrive' ) { - mount.transport = 'WebDAV'; - } + /** + * Adds a mountpoint + * + * @param {Mountpoint|Object} point The mountpoint + * @param {Boolean} mount Mounts the mountpoint + * @param {Object} options Mount options + * @return {Promise} + */ + add(point, mount, options) { - var target = VFS.Transports[mount.transport]; - if ( target && typeof target.defaults === 'function' ) { - target.defaults(mount); - } + try { + if ( !(point instanceof Mountpoint) ) { - if ( dynamic ) { - var validModule = (function() { - if ( Object.keys(VFS.Transports).indexOf(mount.transport) < 0 ) { - return 'No such transport \'' + mount.transport + '\''; + if ( typeof point.transport === 'string' ) { + const T = this.transports[point.transport]; + if ( !T ) { + return Promise.reject(new Error('No such transport: ' + point.transport)); } - if ( mount.transport === 'WebDAV' && !mount.options.username ) { - return 'Connection requires username (authorization)'; - } - return true; - })(); - - if ( validModule !== true ) { - throw new Error(API._('ERR_VFSMODULE_INVALID_CONFIG_FMT', validModule)); + point.transport = new T(); } - } - return Object.freeze(mount); - } - - return Object.seal({ - - /** - * Method for adding pre-defined modules like Dropbox and GoogleDrive - * - * @function _add - * @memberof OSjs.Core.MountManager# - * - * @param {Mountpoint} opts Mounpoint options - * @param {Boolean} [emitEvent=false] Emit the internal mount event - */ - _add: function(opts, emitEvent) { - if ( _inited ) { - _modules[opts.name] = Object.seal(opts); - if ( emitEvent ) { - API.message('vfs:mount', opts.name, {source: null}); - } + point = new Mountpoint(point); + } - console.debug('MountManager::_add()', 'Created mountpoint...', opts); - } else { - _queue.push(arguments); + const found = this.mountpoints.filter((m) => { + if ( m.option('name') === point.option('name') ) { + return true; } - }, - - /** - * Initializes all pre-configured mountpoints - * - * @function init - * @memberof OSjs.Core.MountManager# - * - * @param {Function} callback Callback when done - */ - init: function(callback) { - if ( _inited ) { - callback(); - return; + if ( m.option('root') === point.option('root') ) { + return true; } + return false; + }); - _inited = true; + if ( found.length ) { + return Promise.reject(new Error(_('ERR_VFSMODULE_ALREADY_MOUNTED_FMT', point.option('name')))); + } - var config = API.getConfig('VFS.Mountpoints', {}); + this.mountpoints.push(point); + } catch ( e ) { + return Promise.reject(e); + } - _queue.forEach(function(args) { - var mount = createMountPoint(null, args[0]); - MountManager._add(mount, args[1]); - }); + console.info('Mounting', point); - Object.keys(config).forEach(function(key) { - var m = config[key]; - if ( m.enabled !== false ) { - m.name = key; - delete m.enabled; + return new Promise((resolve, reject) => { + if ( mount ) { + point.mount().then(() => { + return resolve(point); + }).catch(reject); + } else { + resolve(point); + } + }); + } - var mount = createMountPoint(null, m); - MountManager._add(mount, false); + /** + * Removes a mountpoint + * + * @param {String} moduleName Name of the mountpoint + * @param {Object} options Unmount options + * @return {Promise} + */ + remove(moduleName, options) { + const module = this.getModule(moduleName); + const index = this.getModule(moduleName, true); + if ( module ) { + return new Promise((resolve, reject) => { + module.unmount(options).then((res) => { + if ( index !== -1 ) { + this.mountpoints.splice(index, 1); } - }); - - _queue = []; - - callback(); - }, - - /** - * Makes a VFS request via a Transport module from mountpoint - * - * @function _request - * @memberof OSjs.Core.MountManager# - * - * @param {Object} mount Mountpoint - * @param {String} method VFS method - * @param {Object} args VFS arguments - * @param {Function} callback Callback when done - * @param {Object} [options] VFS options - */ - _request: function(mount, method, args, callback, options) { - callback = callback || function() { - console.warn('NO CALLBACK FUNCTION WAS ASSIGNED IN VFS REQUEST'); - }; - - var target = VFS.Transports[mount.transport]; - if ( !target ) { - callback(API._('ERR_VFSMODULE_INVALID_TYPE_FMT', mount.transport)); - return; - } + return resolve(res); + }).catch(reject); + }); + } - if ( isReadOnly(method, mount, args) ) { - callback(API._('ERR_VFSMODULE_READONLY')); - return; - } + return Promise.reject(new Error(_('ERR_VFSMODULE_NOT_MOUNTED_FMT', moduleName))); + } - var mparams = (function() { - var o = {}; - Object.keys(mount).forEach(function(k) { - if ( typeof mount[k] !== 'function' ) { - o[k] = mount[k]; - } - }); - return Object.freeze(o); - })(); - - var module = target.module || {}; - if ( !module[method] ) { - callback(API._('ERR_VFS_UNAVAILABLE')); - } else { - var fargs = args || []; - fargs.push(callback); - fargs.push(options); - fargs.push(mparams); - module[method].apply(module, fargs); - } - }, - - /** - * Restores all stored connections - * - * @function restore - * @memberof OSjs.Core.MountManager# - * - * @param {Function} callback Callback when done - */ - 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(); - }); - }, - - /** - * Mounts given mountpoint - * - * Currently supports: Custom internal methods, webdav/owncloud - * - * If you want to configure default mountpoints, look at the manual linked below. - * - * @function add - * @memberof OSjs.Core.MountManager# - * @throws {Error} If the mountpoint is already mounted or the module is invalid - * - * @param {Mountpoint} opts Mountpoint options - * @param {Function} cb Callback function => fn(err, result) - * - * @link https://os-js.org/manual/vfs/#mountpoints - */ - add: function(opts, cb) { - var mount = (function() { - var isMounted = true; - - return Utils.argumentDefaults(Utils.cloneObject(opts, true), { - icon: 'places/network-server.png', - searchable: false, - unmount: function(done) { - isMounted = false; - API.message('vfs:unmount', opts.name, {source: null}); - (done || function() {})(false, true); - }, - mounted: function() { - return isMounted; - } - }); - })(); - - var module = createMountPoint(null, mount, true); - MountManager._add(module, true); - - (cb || function() {})(false, true); - }, - - /** - * Unmounts given mountpoint - * - * @function remove - * @memberof OSjs.Core.MountManager# - * @throws {Error} If the mountpoint does not exist - * - * @param {String} moduleName Name of registered module - * @param {Function} cb Callback function => fn(err, result) - */ - remove: function(moduleName, cb) { - if ( !_modules[moduleName] ) { - throw new Error(API._('ERR_VFSMODULE_NOT_MOUNTED_FMT', moduleName)); - } + /** + * Gets all modules (with filtering) + * + * @param {Object} filter The filter + * @return {Mountpoint[]} + */ + getModules(filter) { + filter = Object.assign({}, { + visible: true, + special: false + }, filter); - _modules[moduleName].unmount(function() { - delete _modules[moduleName]; - cb.apply(MountManager, arguments); - }); - }, - - /** - * Check if given path is an internal module - * - * @function isInternal - * @memberof OSjs.Core.MountManager# - * - * @param {String} test Module Name - * - * @return {Boolean} - */ - 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 this.mountpoints.filter((mount) => { + if ( mount.enabled() && mount.option('visible') ) { - return d; - }, - - /** - * Returns a list of all enabled VFS modules - * - * @function getModules - * @memberof OSjs.Core.MountManager# - * - * @param {Object} opts Options - * @param {Boolean} [opts.visible=true] All visible modules only - * - * @return {Object[]} List of all Modules found - */ - getModules: function(opts) { - opts = Utils.argumentDefaults(opts, { - visible: true, - special: false + const hits = Object.keys(filter).filter((filterName) => { + return mount.option(filterName) === filter[filterName]; }); - var m = _modules; - var a = []; - Object.keys(m).forEach(function(name) { - var iter = m[name]; - if ( !iter.enabled() || (!opts.special && iter.special) ) { - return; - } + return hits.length > 0; + } - if ( opts.visible && iter.visible === opts.visible ) { - a.push({ - name: name, - module: iter - }); - } - }); - return a; - }, - - getModule: function(name) { - return _modules[name]; - }, - - /** - * Get module name from path - * - * @function getModuleFromPath - * @memberof OSjs.Core.MountManager# - * - * @param {String} test Path name - * @param {Boolean} [retdef=true] Return default upon failure - * @param {Boolean} [retobj=false] Return module object instead of name - * - * @return {Mixed} Module name or object based on arguments - */ - 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 instanceof RegExp && test.match(i.match) ) { - d = name; - } - } - }); - } + return false; + }); + } - var moduleName = d || (retdef ? DefaultModule : null); - return retobj ? _modules[moduleName] : moduleName; - }, - - /** - * Get root from path (ex: foo:///) - * - * @function getRootFromPath - * @memberof OSjs.Core.MountManager# - * - * @param {String} path Path name - * @return {String} - * @api OSjs.VFS.getRootFromPath() - */ - getRootFromPath: function getRootFromPath(path) { - return MountManager.getModuleFromPath(path, false, true).root; - }, - - getModuleProperty: function(module, property) { - if ( typeof module === 'string' ) { - module = _modules[module]; + /** + * Gets a mountpoint from a matching path + * @param {String} test Path to test + * @return {Mountpoint} + */ + getModuleFromPath(test) { + return this.mountpoints.find((mount) => { + if ( typeof test === 'string' && mount.enabled() ) { + if ( mount.option('match') && test.match(mount.option('match')) ) { + return true; } - - return module[property]; } + return false; }); + } - })(); - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + /** + * Gets a mountpoint by name + * @param {String} name Mountpoint name + * @param {Boolean} [idx=false] Get index and not the actual mountpoint + * @return {Mountpoint|Number} + */ + getModule(name, idx) { + const m = idx ? 'findIndex' : 'find'; + return this.mountpoints[m]((i) => i.option('name') === name); + } /** - * Get the current MountManager instance - * - * @function getMountManager - * @memberof OSjs.Core - * @return {OSjs.Core.MountManager} + * Gets a transport by name + * @param {String} name Transport name + * @return {Mountpoint} */ - OSjs.Core.getMountManager = function Core_getMountManager() { - return MountManager; - }; + getTransport(name) { + return this.transports[name]; + } + +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.Utils, OSjs.VFS, OSjs.API); +export default (new MountManager()); diff --git a/src/client/javascript/core/package-manager.js b/src/client/javascript/core/package-manager.js index 6ccc5b2083..b4bbc2e489 100644 --- a/src/client/javascript/core/package-manager.js +++ b/src/client/javascript/core/package-manager.js @@ -28,481 +28,453 @@ * @licence Simplified BSD License */ -(function(Utils, VFS, API) { - 'use strict'; +// TODO: Could use a cleanup after 2.1 + +import Promise from 'bluebird'; +import Authenticator from 'core/authenticator'; +import SettingsManager from 'core/settings-manager'; +import {cloneObject} from 'utils/misc'; +import {_, getLocale} from 'core/locales'; +import {getConfig} from 'core/config'; +import * as VFS from 'vfs/fs'; +import * as FS from 'utils/fs'; + +import Connection from 'core/connection'; + +const resolvePreloads = (metadata, pm) => { + const packageURI = getConfig('Connection.PackageURI'); + + const mapIter = (s) => (typeof s === 'string' ? {src: s} : s); + + let additions = []; + let list = (metadata.preload || []).slice(0).map(mapIter); + + // If this package depends on another package, make sure + // to load the resources for the related one as well + if ( metadata.depends instanceof Array ) { + metadata.depends.forEach((k) => { + if ( !OSjs.Applications[k] ) { + const pkg = pm.getPackage(k); + if ( pkg ) { + console.info('Using dependency', k); + additions = additions.concat(pkg.preload.map(mapIter)); + } + } + }); + } + + // ... same goes for packages that uses this package + // as a dependency. + const pkgs = pm.getPackages(false); + Object.keys(pkgs).forEach((pn) => { + const p = pkgs[pn]; + if ( p.type === 'extension' && p.uses === name ) { + if ( p ) { + console.info('Using extension', pn); + additions = additions.concat(p.preload.map(mapIter)); + } + } + }); + + return additions.concat(list).map((p) => { + if ( !p.src.match(/^(\/|https?|ftp)/) ) { + if ( metadata.scope === 'user' ) { + // For user packages, make sure to load the correct URL + VFS.url(FS.pathJoin(metadata.path, p.src)).then((url) => { + p.src = url; + return true; + }); + } else { + p.src = FS.pathJoin(packageURI, metadata.path, p.src); + } + } + + return p; + }); +}; + +///////////////////////////////////////////////////////////////////////////// +// PACKAGE MANAGER +///////////////////////////////////////////////////////////////////////////// + +class PackageManager { + + constructor() { + this.packages = {}; + this.blacklist = []; + } + + destroy() { + this.packages = {}; + this.blacklist = []; + } /** - * This is the contents of a 'metadata.json' file for a package. - * @typedef Metadata + * Initializes Package Manager + * @param {Object} [metadata] An initial set of packages + * @return {Promise} */ + init(metadata) { + console.debug('PackageManager::load()', metadata); - ///////////////////////////////////////////////////////////////////////////// - // PACKAGE MANAGER - ///////////////////////////////////////////////////////////////////////////// + return new Promise((resolve, reject) => { + const setPackages = metadata ? this.setPackages(metadata) : Promise.resolve(); + + setPackages.then(() => { + return this._loadMetadata().then(() => { + const len = Object.keys(this.packages).length; + if ( len ) { + return resolve(true); + } + return reject(new Error(_('ERR_PACKAGE_ENUM_FAILED'))); + }).catch(reject); + }).catch(reject); + }); + } /** - * Package Manager Class - * - * For maintaining packages + * Internal method for loading all package metadata + * @return {Promise} + */ + _loadMetadata() { + const paths = SettingsManager.instance('PackageManager').get('PackagePaths', []); + return new Promise((resolve, reject) => { + Connection.request('packages', {command: 'list', args: {paths: paths}}).then((res) => { + return this.setPackages(res).then(resolve).catch(reject); + }).catch(reject); + }); + } + + /** + * Generates user-installed package metadata (on runtime) + * @return {Promise} + */ + generateUserMetadata() { + const paths = SettingsManager.instance('PackageManager').get('PackagePaths', []); + return new Promise((resolve, reject) => { + const cb = () => this._loadMetadata().then(resolve).catch(reject); + + Connection.request('packages', {command: 'cache', args: {action: 'generate', scope: 'user', paths: paths}}) + .then(cb) + .catch(cb); + }); + } + + /** + * Add a list of packages * - *

-   * YOU CAN ONLY GET AN INSTANCE WITH `Core.getPackageManager()`
-   * 
+ * @param {Object} result Package dict (manifest data) + * @param {String} scope Package scope (system/user) + */ + _addPackages(result, scope) { + console.debug('PackageManager::_addPackages()', result); + + const keys = Object.keys(result); + if ( !keys.length ) { + return; + } + + const currLocale = getLocale(); + + keys.forEach((i) => { + const newIter = 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'; + + this.packages[i] = newIter; + }); + } + + /** + * Installs a package by ZIP * - * @example - * OSjs.Core.getPackageManager() + * @param {FileMetadata} file The ZIP file + * @param {String} root Packge install root (defaults to first path) + * @return {Promise} + */ + install(file, root) { + const paths = SettingsManager.instance('PackageManager').get('PackagePaths', []); + if ( typeof root !== 'string' ) { + root = paths[0]; + } + + const dest = FS.pathJoin(root, file.filename.replace(/\.zip$/i, '')); + return new Promise((resolve, reject) => { + Connection.request('packages', {command: 'install', args: {zip: file.path, dest: dest, paths: paths}}).then(() => { + return this.generateUserMetadata().then(resolve).catch(reject); + }).catch(reject); + }); + } + + /** + * Uninstalls given package * - * @summary Used for managing packages + * @param {FileMetadata} file The path + * @return {Promise} + */ + uninstall(file) { + return new Promise((resolve, reject) => { + Connection.request('packages', {command: 'uninstall', args: {path: file.path}}).then(() => { + return this.generateUserMetadata().then(resolve).catch(reject); + }).catch(reject); + }); + } + + /** + * Sets the package blacklist * - * @constructor - * @memberof OSjs.Core - * @see OSjs.Core.getPackageManager + * @param {String[]} list List of package names */ - var PackageManager = (function() { - var blacklist = []; - var packages = {}; - - return Object.seal({ - destroy: function() { - blacklist = []; - packages = {}; - }, - - /** - * Load Metadata from server and set packages - * - * @function load - * @memberof OSjs.Core.PackageManager# - * - * @param {Function} callback callback - */ - load: function(callback) { - var self = this; - callback = callback || {}; - - console.debug('PackageManager::load()'); - - function loadMetadata(cb) { - self._loadMetadata(function(err) { - if ( err ) { - callback(err, false, PackageManager); - return; - } + setBlacklist(list) { + this.blacklist = list || []; + } - var len = Object.keys(packages).length; - if ( len ) { - cb(); - } else { - callback(false, API._('ERR_PACKAGE_ENUM_FAILED'), PackageManager); - } - }); - } + /** + * Get a list of packges from online repositories + * + * @param {Object} opts Options + * @return {Promise} + */ + getStorePackages(opts) { + const repos = SettingsManager.instance('PackageManager').get('Repositories', []); - loadMetadata(function() { - self._loadExtensions(function() { - callback(true, false, PackageManager); - }); - }); - }, - - /** - * Internal method for loading all extensions - * - * @function _loadExtensions - * @memberof OSjs.Core.PackageManager# - * - * @param {Function} callback callback - */ - _loadExtensions: function(callback) { - var preloads = []; - - Object.keys(packages).forEach(function(k) { - var iter = packages[k]; - if ( iter.type === 'extension' && iter.preload ) { - preloads = preloads.concat(iter.preload); - } - }); + let entries = []; - if ( preloads.length ) { - Utils.preload(preloads, function(total, failed) { - callback(); - }); - } else { - callback(); - } - }, - - /** - * Internal method for loading all package metadata - * - * @function _loadMetadata - * @memberof OSjs.Core.PackageManager# - * - * @param {Function} callback callback - */ - _loadMetadata: function(callback) { - var packageURI = API.getConfig('Connection.PackageURI').replace(/\/?$/, '/'); - var rootURI = API.getBrowserPath().replace(/\/$/, packageURI); - - function checkEntry(key, iter, scope) { - iter = Utils.cloneObject(iter); - - iter.type = iter.type || 'application'; - - if ( scope ) { - iter.scope = scope; - } + return new Promise((resolve, reject) => { + Promise.all(repos.map((url) => { + return new Promise((yes, no) => { + Connection.request('curl', { + url: url, + method: 'GET' + }).then((result) => { + let list = []; + if ( typeof result.body === 'string' ) { + try { + list = JSON.parse(result.body); + } catch ( e ) {} + } - 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); - } - } - }); - } + entries = entries.concat(list.map((iter) => { + iter._repository = url; + return iter; + })); - return iter; - } + return yes(); + }).catch(no); + }); + })).then(() => resolve(entries)).catch(reject); + }); + } - if ( API.isStandalone() ) { - var uri = API.getConfig('Connection.MetadataURI'); - Utils.preload([uri], function(total, failed) { - if ( failed.length ) { - callback(API._('ERR_PACKAGE_MANIFEST'), failed); - return; - } + /** + * Get package by name + * + * @param {String} name Package name + * + * @return {Object} + */ + getPackage(name) { + if ( typeof this.packages[name] !== 'undefined' ) { + return Object.freeze(cloneObject(this.packages)[name]); + } + return false; + } - packages = {}; + /** + * Get all packages + * + * @param {Boolean} [filtered=true] Returns filtered list + * + * @return {Object[]} + */ + getPackages(filtered) { + const hidden = SettingsManager.instance('PackageManager').get('Hidden', []); + const p = cloneObject(this.packages); - var list = OSjs.Core.getMetadata(); - Object.keys(list).forEach(function(name) { - var iter = list[name]; - packages[iter.className] = checkEntry(name, iter); - }); + const allowed = (iter) => { + if ( this.blacklist.indexOf(iter.path) >= 0 ) { + return false; + } - callback(); - }); - return; + if ( iter && (iter.groups instanceof Array) ) { + if ( !Authenticator.instance().checkPermission(iter.groups) ) { + return false; } + } - 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); - } - }); - } + return true; + }; - callback(err); - }); - }, - - /** - * Generates user-installed package metadata (on runtime) - * - * @function generateUserMetadata - * @memberof OSjs.Core.PackageManager# - * - * @param {Function} callback 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); - }); - }, - - /** - * Add a list of packages - * - * @param {Object} result Package dict (manifest data) - * @param {String} scope Package scope (system/user) - * - * - * @function _addPackages - * @memberof OSjs.Core.PackageManager# - */ - _addPackages: function(result, scope) { - console.debug('PackageManager::_addPackages()', result); - - var keys = Object.keys(result); - if ( !keys.length ) { + if ( typeof filtered === 'undefined' || filtered === true ) { + const result = {}; + Object.keys(p).forEach((name) => { + const iter = p[name]; + if ( !allowed(iter) ) { return; } + if ( iter && hidden.indexOf(name) < 0 ) { + result[name] = iter; + } + }); - var currLocale = API.getLocale(); + return Object.freeze(result); + } - keys.forEach(function(i) { - var newIter = Utils.cloneObject(result[i]); - if ( typeof newIter !== 'object' ) { - return; - } + return Object.freeze(p); + } - 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; + /** + * Get packages by Mime support type + * + * @param {String} mime MIME string + * + * @return {Object[]} + */ + getPackagesByMime(mime) { + const list = []; + const p = cloneObject(this.packages); + + Object.keys(p).forEach((i) => { + if ( this.blacklist.indexOf(i) < 0 ) { + const a = p[i]; + if ( a && a.mime ) { + if ( FS.checkAcceptMime(mime, a.mime) ) { + list.push(i); } + } + } + }); + return list; + } - newIter.scope = scope || 'system'; - newIter.type = newIter.type || 'application'; + /** + * Get package resource + * + * @param {Process|String} app The application (or package name) + * @param {String} name Resource name + * @param {String} vfspath Return a VFS path + * @return {String} + */ + getPackageResource(app, name, vfspath) { + if ( name.match(/^((https?:)|\.)?\//) ) { + return name; + } + name = name.replace(/^\.\//, ''); + + const appname = typeof app === 'string' ? app : app.__pname; + const fsuri = getConfig('Connection.FSURI'); + const pkg = this.getPackage(appname); + + let path = name; + if ( pkg ) { + path = pkg.scope === 'user' + ? '/user-package/' + FS.filename(pkg.path) + '/' + name.replace(/^\//, '') + : 'packages/' + pkg.path + '/' + name; + + if ( vfspath ) { + return pkg.scope === 'user' + ? path.substr(fsuri.length) + : 'osjs:///' + path; + } + } - packages[i] = newIter; - }); - }, - - /** - * Installs a package by ZIP - * - * @function install - * @memberof OSjs.Core.PackageManager# - * - * @param {OSjs.VFS.File} file The ZIP file - * @param {String} root Packge install root (defaults to first path) - * @param {Function} cb Callback function - */ - install: function(file, root, cb) { - var self = this; - var paths = OSjs.Core.getSettingsManager().instance('PackageManager').get('PackagePaths', []); - if ( typeof root !== 'string' ) { - root = paths[0]; - } + return path; + } - 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); - } - }); - }, - - /** - * Uninstalls given package - * - * @function uninstall - * @memberof OSjs.Core.PackageManager# - * - * @param {OSjs.VFS.File} file The path - * @param {Function} cb Callback function - */ - 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); - } - }); - }, - - /** - * Sets the package blacklist - * - * @function setBlacklist - * @memberof OSjs.Core.PackageManager# - * - * @param {String[]} list List of package names - */ - setBlacklist: function(list) { - blacklist = list || []; - }, - - /** - * Get a list of packges from online repositories - * - * @function getStorePackages - * @memberof OSjs.Core.PackageManager# - * - * @param {Object} opts Options - * @param {Function} callback Callback => fn(error, result) - */ - 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); - }); - }, - - /** - * Get package by name - * - * @function getPackage - * @memberof OSjs.Core.PackageManager# - * - * @param {String} name Package name - * - * @return {Metadata} - */ - getPackage: function(name) { - if ( typeof packages[name] !== 'undefined' ) { - return Object.freeze(Utils.cloneObject(packages)[name]); - } - return false; - }, - - /** - * Get all packages - * - * @function getPackages - * @memberof OSjs.Core.PackageManager# - * - * @param {Boolean} [filtered=true] Returns filtered list - * - * @return {Metadata[]} - */ - 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; - } + /** + * Sets the current list of packages + * @param {Object} res Package map + * @return {Promise} + */ + setPackages(res) { + const packages = {}; + const locale = getLocale(); - if ( iter && (iter.groups instanceof Array) ) { - if ( !API.checkPermission(iter.groups) ) { - return false; - } - } + const checkEntry = (key, iter, scope) => { + iter = Object.assign({}, iter); + iter.type = iter.type || 'application'; - return true; - } + if ( scope ) { + iter.scope = scope; + } - 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; - } - }); + if ( iter.names && iter.names[locale] ) { + iter.name = iter.names[locale]; + } - return Object.freeze(result); - } + if ( iter.descriptions && iter.descriptions[locale] ) { + iter.description = iter.descriptions[locale]; + } + + let resolveIcon = () => { + if ( iter.icon && iter.path ) { + let packagePath = iter.path.replace(/^\//, ''); - return Object.freeze(p); - }, - - /** - * Get packages by Mime support type - * - * @function getPackagesByMime - * @memberof OSjs.Core.PackageManager# - * - * @param {String} mime MIME string - * - * @return {Metadata[]} - */ - 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); - } + if ( iter.scope === 'user' ) { + return VFS.url(FS.pathJoin(packagePath, iter.icon)); + } else { + if ( iter.icon.match(/^\.\//) ) { + const packageURI = getConfig('Connection.PackageURI').replace(/\/?$/, '/'); + return Promise.resolve(packageURI + packagePath + iter.icon.replace(/^\./, '')); } } - }); - return list; - }, - - /** - * Add a dummy package (useful for having shortcuts in the launcher menu) - * - * @function addDummyPackage - * @memberof OSjs.Core.PackageManager# - * @throws {Error} On invalid package name or callback - * - * @param {String} n Name of your package - * @param {String} title The display title - * @param {String} icon The display icon - * @param {Function} fn The function to run when the package tries to launch - */ - 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({ - _dummy: true, - type: 'application', - className: n, - description: title, - name: title, - icon: icon, - cateogry: 'other', - scope: 'system' - }); + return Promise.resolve(iter.icon); + }; - OSjs.Applications[n] = fn; - } + iter.preload = resolvePreloads(iter, this); + return new Promise((resolve, reject) => { + resolveIcon().then((icon) => { + if ( icon ) { + iter.icon = icon; + } + + return resolve(iter); + }).catch(reject); + }); + }; + + return new Promise((resolve, reject) => { + const entries = Object.keys(res || {}); + Promise.each(entries, (key) => { + return new Promise((yes, no) => { + const iter = res[key]; + if ( iter && !packages[iter.className] ) { + checkEntry(key, iter).then((pkg) => { + packages[iter.className] = pkg; + return yes(); + }).catch(no); + } else { + console.warn('No such package', key); + yes(); + } + }); + }).catch(reject).then(() => { + this.packages = packages; + return resolve(); + }); }); - })(); + } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// +} - /** - * Get the current PackageManager instance - * - * @function getPackageManager - * @memberof OSjs.Core - * - * @return {OSjs.Core.PackageManager} - */ - OSjs.Core.getPackageManager = function Core_getPackageManager() { - return PackageManager; - }; +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.Utils, OSjs.VFS, OSjs.API); +export default (new PackageManager()); diff --git a/src/client/javascript/core/process.js b/src/client/javascript/core/process.js index bc84162fd0..a00d8a7e2c 100644 --- a/src/client/javascript/core/process.js +++ b/src/client/javascript/core/process.js @@ -27,270 +27,148 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API) { - 'use strict'; - /** - * The predefined events are as follows: - *

-   *  message       All events                               => (msg, object, options)
-   *  attention     When application gets attention signal   => (args)
-   *  hashchange    When URL hash has changed                => (args)
-   *  api           API event                                => (method)
-   *  destroy       Destruction event                        => (killed)
-   *  destroyWindow Attached window destruction event        => (win)
-   *  initedWindow  Attached window event                    => (win)
-   *  vfs           For all VFS events                       => (msg, object, options)
-   *  vfs:mount     VFS mount event                          => (module, options, msg)
-   *  vfs:unmount   VFS unmount event                        => (module, options, msg)
-   *  vfs:write     VFS write event                          => (dest, options, msg)
-   *  vfs:mkdir     VFS mkdir event                          => (dest, options, msg)
-   *  vfs:move      VFS move event                           => ({src,dest}, options, msg)
-   *  vfs:delete    VFS delete event                         => (dest, options, msg)
-   *  vfs:upload    VFS upload event                         => (file, options, msg)
-   *  vfs:update    VFS update event                         => (dir, options, msg)
-   * 
- * @typedef ProcessEvent - */ +import Promise from 'bluebird'; +import Connection from 'core/connection'; +import EventHandler from 'helpers/event-handler'; +import Theme from 'core/theme'; +import * as FS from 'utils/fs'; +import * as Config from 'core/config'; +import * as Compability from 'utils/compability'; +import {_} from 'core/locales'; +import {triggerHook} from 'helpers/hooks'; +import Loader from 'helpers/loader'; +import FileMetadata from 'vfs/file'; +import Preloader from 'utils/preloader'; +import SettingsManager from 'core/settings-manager'; +import PackageManager from 'core/package-manager'; + +/** + * The predefined events are as follows: + *

+ *  message       All events                               => (msg, object, options)
+ *  attention     When application gets attention signal   => (args)
+ *  hashchange    When URL hash has changed                => (args)
+ *  api           API event                                => (method)
+ *  destroy       Destruction event                        => (killed)
+ *  destroyWindow Attached window destruction event        => (win)
+ *  initedWindow  Attached window event                    => (win)
+ *  vfs           For all VFS events                       => (msg, object, options)
+ *  vfs:mount     VFS mount event                          => (module, options, msg)
+ *  vfs:unmount   VFS unmount event                        => (module, options, msg)
+ *  vfs:write     VFS write event                          => (dest, options, msg)
+ *  vfs:mkdir     VFS mkdir event                          => (dest, options, msg)
+ *  vfs:move      VFS move event                           => ({src,dest}, options, msg)
+ *  vfs:delete    VFS delete event                         => (dest, options, msg)
+ *  vfs:upload    VFS upload event                         => (file, options, msg)
+ *  vfs:update    VFS update event                         => (dir, options, msg)
+ * 
+ * @typedef ProcessEvent + */ - ///////////////////////////////////////////////////////////////////////////// - // GLOBALS - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// GLOBALS +///////////////////////////////////////////////////////////////////////////// - var _PROCS = []; // Running processes +let alreadyLaunching = []; +let runningProcesses = []; - function _kill(pid) { - if ( pid >= 0 && _PROCS[pid] ) { - var res = _PROCS[pid].destroy(); +function _kill(pid, force) { + if ( pid >= 0 && runningProcesses[pid] ) { + try { + const res = runningProcesses[pid].destroy(force); console.warn('Killing application', pid, res); if ( res !== false ) { - _PROCS[pid] = null; + runningProcesses[pid] = null; return true; } + } catch ( e ) { + console.warn(e); } - return false; } - - ///////////////////////////////////////////////////////////////////////////// - // API METHODS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Kills all processes - * - * @param {(String|RegExp)} match Kill all matching this - * - * @function killAll - * @memberof OSjs.API - */ - 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; + return false; +} + +function getLaunchObject(s) { + if ( typeof s === 'string' ) { + const spl = s.split('@'); + const name = spl[0]; + + let args = {}; + if ( typeof spl[1] !== 'undefined' ) { + try { + args = JSON.parse(spl[1]); + } catch ( e ) {} } - _PROCS.forEach(function(proc, i) { - if ( proc ) { - proc.destroy(true); - } - _PROCS[i] = null; - }); - _PROCS = []; - } - - /** - * Kills a process - * - * @param {Number} pid Process ID - * - * @return {Boolean} Success or not - * - * @function kill - * @memberof OSjs.API - */ - function doKillProcess(pid) { - return _kill(pid); - } - - /** - * Sends a message to all processes - * - * Example: VFS uses this to signal file changes etc. - * - * @param {String} msg Message name - * @param {Object} obj Message object - * @param {Object} opts Options - * @param {Process|Window|Number} [opts.source] Source Process, Window or ID - * @param {String|Function} [opts.filter] Filter by string or fn(process) - * - * @see OSjs.Core.Process#_onMessage - * - * @function message - * @memberof OSjs.API - */ - function doProcessMessage(msg, obj, opts) { - opts = opts || {}; - - console.debug('doProcessMessage', msg, opts); - - var filter = opts.filter || function() { - return true; + s = { + name: name, + args: args }; - - 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); - } - } - }); } - /** - * Get a process by name - * - * @param {String} name Process Name (or by number) - * @param {Boolean} first Return the first found - * - * @return {(OSjs.Core.Process[]|OSjs.Core.Process)} Array of Processes or a Process depending on arguments - * - * @function getProcess - * @memberof OSjs.API - */ - 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; - } + return s; +} - /** - * Get all processes - * - * @function getProcesses - * @memberof OSjs.API - * - * @return {OSjs.Core.Process[]} - */ - function doGetProcesses() { - return _PROCS; - } +///////////////////////////////////////////////////////////////////////////// +// PROCESS +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // PROCESS - ///////////////////////////////////////////////////////////////////////////// +/** + * Process Base Class + * + * @desc The basis for an Application or Service + * + * @abstract + * @mixes EventHandler + */ +export default class Process { /** - * Process Template Class - * - *

-   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
-   * 
- * - * @summary Class used for basis as a Process. - * - * @param {string} name Process Name - * @param {Object} args Process Arguments - * @param {Metadata} metadata Package Metadata - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @mixes OSjs.Helpers.EventHandler + * @param {string} name Process Name + * @param {Object} args Process Arguments + * @param {Object} metadata Package Metadata */ - function Process(name, args, metadata) { - console.group('Process::constructor()', _PROCS.length, arguments); + constructor(name, args, metadata) { + console.group('Process::constructor()', runningProcesses.length, arguments); /** * Process ID - * @name __pid - * @memberof OSjs.Core.Process# * @type {Number} */ - this.__pid = _PROCS.push(this) - 1; + this.__pid = runningProcesses.push(this) - 1; /** * Process Name - * @name __pname - * @memberof OSjs.Core.Process# * @type {String} */ this.__pname = name; /** * Process Arguments - * @name __args - * @memberof OSjs.Core.Process# * @type {Object} */ this.__args = args || {}; /** * Package Metadata - * @name __metadata - * @memberof OSjs.Core.Process# * @type {Metadata} */ this.__metadata = metadata || {}; /** * Started timestamp - * @name __started - * @memberof OSjs.Core.Process# * @type {Date} */ this.__started = new Date(); /** * If process was destroyed - * @name __destroyed - * @memberof OSjs.Core.Process# * @type {Boolean} */ this.__destroyed = false; - this.__evHandler = new OSjs.Helpers.EventHandler(name, [ + this.__evHandler = new 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' @@ -307,12 +185,9 @@ /** * Destroys the process * - * @function destroy - * @memberof OSjs.Core.Process# - * * @return {Boolean} */ - Process.prototype.destroy = function() { + destroy() { if ( !this.__destroyed ) { this.__destroyed = true; @@ -325,7 +200,7 @@ } if ( this.__pid >= 0 ) { - _PROCS[this.__pid] = null; + runningProcesses[this.__pid] = null; } console.groupEnd(); @@ -334,26 +209,25 @@ } return false; - }; + } /** * Method for handling internal messaging system * - * @function _onMessage - * @memberof OSjs.Core.Process# - * * @param {string} msg Message type * @param {Object} obj Message object * @param {Object} [opts] Message options */ - Process.prototype._onMessage = function(msg, obj, opts) { + _onMessage(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; + let sourceId = opts.source; + if ( sourceId && (typeof sourceId === 'object') ) { + if ( sourceId instanceof Process ) { + sourceId = sourceId.__pid; + } else if ( sourceId._app ) { + sourceId = sourceId._app ? sourceId._app.__pid : -1; + } } if ( this.__evHandler && sourceId !== this.__pid ) { @@ -371,57 +245,51 @@ // for custom events bound with _on(evname) this.__evHandler.emit(msg, [obj, opts, msg]); } - }; + } /** * Fire a hook to internal event * - * @function _emit - * @memberof OSjs.Core.Process# - * @see OSjs.Core.Process#on - * @see OSjs.Helpers.EventHandler#emit + * @see Process#on + * @see EventHandler#emit * * @param {ProcessEvent} k Event name * @param {Array} args Send these arguments (fn.apply) * - * @return {Mixed} Result (last) from bound function(s) + * @return {*} Result (last) from bound function(s) */ - Process.prototype._emit = function(k, args) { + _emit(k, args) { return this.__evHandler ? this.__evHandler.emit(k, args) : null; - }; + } /** * Adds a hook to internal event * - * @function _on - * @memberof OSjs.Core.Process# - * @see OSjs.Helpers.EventHandler#on + * @see EventHandler#on * * @param {ProcessEvent} k Event name * @param {Function} func Callback function * * @return {Number} */ - Process.prototype._on = function(k, func) { + _on(k, func) { return this.__evHandler ? this.__evHandler.on(k, func, this) : null; - }; + } /** * Removes a hook to an internal even * - * @function _off - * @memberof OSjs.Core.Process# - * @see OSjs.Core.Process#_on - * @see OSjs.Helpers.EventHandler#off + * @see Process#_on + * @see EventHandler#off * * @param {ProcessEvent} k Event name * @param {Number} idx The hook index returned from _on() */ - Process.prototype._off = function(k, idx) { + _off(k, idx) { if ( this.__evHandler ) { this.__evHandler.off(k, idx); } - }; + } /** * Call the ApplicationAPI @@ -430,17 +298,12 @@ * * On Lua or Arduino it is called 'server.lua' * - * @function _api - * @memberof OSjs.Core.Process# - * * @param {String} method Name of method * @param {Object} args Arguments in JSON - * @param {Function} callback Callback method => fn(error, result) * @param {Object} [options] Options (See API::call) - * @return {Boolean} + * @return {Promise} */ - Process.prototype._api = function(method, args, callback, options) { - var self = this; + _api(method, args, options) { // NOTE: Backward compability if ( typeof options === 'boolean' ) { @@ -451,91 +314,467 @@ options = {}; } - 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, - args: args - }, cb, options); - }; + return new Promise((resolve, reject) => { + Connection.request('application', { + application: this.__iter, + path: this.__path, + method: method, + args: args + }, options).then((res) => { + if ( !this.__destroyed ) { + resolve(res); + return true; + } + console.warn('Process::_api()', 'INGORED RESPONSE: Process was closed'); + return false; + }).catch((err) => { + if ( !this.__destroyed ) { + reject(err instanceof Error ? err : new Error(err)); + } + }); + }); + } /** * Get a launch/session argument * - * @function _getArgument - * @memberof OSjs.Core.Process# - * * @param {String} [k] Argument * - * @return {Mixed} Argument value or null + * @return {*} Argument value or null */ - Process.prototype._getArgument = function(k) { + _getArgument(k) { return typeof this.__args[k] === 'undefined' ? null : this.__args[k]; - }; + } /** * Get all launch/session argument * - * @function _getArguments - * @memberof OSjs.Core.Process# - * * @return {Object} */ - Process.prototype._getArguments = function() { + _getArguments() { return this.__args; - }; + } /** * Get full path to a resorce belonging to this process (package) * - * This is a shortcut for API.getApplicationResource() - * - * @function _getResource - * @memberof OSjs.Core.Process# - * @see API.getApplicationResource() - * * @param {String} src Resource name (path) * @param {Boolean} [vfspath] Return a valid VFS path * * @return {String} */ - Process.prototype._getResource = function(src, vfspath) { - return API.getApplicationResource(this, src, vfspath); - }; + _getResource(src, vfspath) { + return PackageManager.getPackageResource(this, src, vfspath); + } /** * Set a launch/session argument * - * @function _setArgument - * @memberof OSjs.Core.Process# - * * @param {String} k Key * @param {String} v Value */ - Process.prototype._setArgument = function(k, v) { + _setArgument(k, v) { this.__args[k] = v; - }; + } + + /** + * Kills a process + * + * @param {Number} pid Process ID + * + * @return {Boolean} Success or not + */ + static kill(pid) { + return _kill(pid); + } + + /** + * Kills all processes + * + * @param {(String|RegExp)} match Kill all matching this + */ + static killAll(match) { + let matcher = () => true; - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + if ( match ) { + matcher = match instanceof RegExp + ? (p) => p.__pname.match(match) + : (p) => p.__pname === match; + } + + this.getProcesses() + .filter((p) => matcher(p)) + .forEach((p) => _kill(p.__pid, true)); + + runningProcesses = []; + } + + /** + * Sends a message to all processes + * + * Example: VFS uses this to signal file changes etc. + * + * @param {String} msg Message name + * @param {Object} obj Message object + * @param {Object} opts Options + * @param {Process|Window|Number} [opts.source] Source Process, Window or ID + * @param {String|Function} [opts.filter] Filter by string or fn(process) + * + * @see Process#_onMessage + */ + static message(msg, obj, opts) { + opts = opts || {}; + + console.debug('Process::message()', msg, obj, opts); + + let filter = opts.filter || (() => true); + if ( typeof filter === 'string' ) { + const s = filter; + filter = (p) => { + return p.__pname === s; + }; + } + + this.getProcesses() + .filter(filter) + .forEach((p) => p._onMessage(msg, obj, opts)); + } + + /** + * Get a process by name + * + * @param {String} name Process Name (or by number) + * @param {Boolean} first Return the first found + * + * @return {(Process[]|Process)} Array of Processes or a Process depending on arguments + */ + static getProcess(name, first) { + if ( typeof name === 'number' ) { + return runningProcesses[name]; + } + + const found = this.getProcesses().filter((p) => { + return p.__pname === name; + }); + + return first ? found[0] : found; + } + + /** + * Get all processes + * + * @return {Process[]} + */ + static getProcesses() { + return runningProcesses.filter((p) => !!p); + } + + /** + * Reloads a process + * @param {String|String[]} n Process name(s) + */ + static reload(n) { + if ( !(n instanceof Array) ) { + n = [n]; + } + + n.map((name) => this.getProcess(name)).filter((p) => !!p).forEach((p) => { + let promise = null; + let data = p instanceof Process ? p._getSessionData() : null; + let args = {}; + + try { + n = p.__pname; + promise = p.destroy(); // kill + } catch ( e ) { + console.warn('Process::reload()', e.stack, e); + } + + if ( data !== null ) { + args = data.args; + args.__resume__ = true; + args.__windows__ = data.windows || []; + } + args.__preload__ = {force: true}; + + if ( !(promise instanceof Promise) ) { + promise = Promise.resolve(true); + } + + promise.then(() => { + return setTimeout(() => { + this.create(n, args); + }, 500); + }); + }); + } + + /** + * Launch a Process + * + * @param {String} name Application Name + * @param {Object} [args] Launch arguments + * @param {Function} [onconstruct] Callback on application init + * @return {Promise} + */ + static create(name, args, onconstruct) { + args = args || {}; + onconstruct = onconstruct || function() {}; + + const hash = name + JSON.stringify(args); + if ( alreadyLaunching.indexOf(hash) !== -1 ) { + return Promise.resolve(null); + } + alreadyLaunching.push(hash); + + const init = () => { + if ( !name ) { + throw new Error('Cannot Process::create() witout a application name'); + } + + const compability = Compability.getCompability(); + const metadata = PackageManager.getPackage(name); + const alreadyRunning = Process.getProcess(name, true); - OSjs.Core.Process = Object.seal(Process); + // + // Pre-checks + // + + if ( !metadata ) { + throw new Error(_('ERR_APP_LAUNCH_MANIFEST_FAILED_FMT', name)); + } + + const compabilityFailures = (metadata.compability || []).filter((c) => { + if ( typeof compability[c] !== 'undefined' ) { + return !compability[c]; + } + return false; + }); + + if ( compabilityFailures.length ) { + throw new Error(_('ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT', name, compabilityFailures.join(', '))); + } + + if ( metadata.singular === true && alreadyRunning ) { + console.warn('Process::create()', 'detected that this application is a singular and already running...'); + alreadyRunning._onMessage('attention', args); + + //throw new Error(_('ERR_APP_LAUNCH_ALREADY_RUNNING_FMT', name)); + return Promise.resolve(alreadyRunning); + } + + triggerHook('onApplicationLaunch', [name, args]); + + // Create loading ui + Loader.create('Main.launch.' + name, { + title: _('LBL_STARTING') + ' ' + metadata.name, + icon: Theme.getIcon(metadata.icon, '16x16') + }); + + // Preload + let pargs = { + max: metadata.preloadParallel === true + ? Config.getConfig('Connection.PreloadParallel') + : metadata.preloadParallel/*, + + progress: (index, total) => { + }*/ + }; + + if ( args.__preload__ ) { // This is for Process.reload() + pargs = Object.assign(pargs, args.__preload__); + delete args.__preload__; + } + + return new Promise((resolve, reject) => { + const onerror = (e) => { + console.warn(e); + return reject(new Error(e)); + }; + + Preloader.preload(metadata.preload, pargs).then((result) => { + if ( result.failed.length ) { + return onerror(_('ERR_APP_PRELOAD_FAILED_FMT', name, result.failed.join(','))); + } + + if ( typeof OSjs.Applications[name] === 'undefined' ) { + return onerror(new Error(_('ERR_APP_RESOURCES_MISSING_FMT', name))); + } + + // Run + let instance; + + try { + const ResolvedPackage = OSjs.Applications[name]; + if ( ResolvedPackage.Class ) { + // FIXME: Backward compability + instance = new ResolvedPackage.Class(args, metadata); + } else { + instance = new ResolvedPackage(args, metadata); + } + + onconstruct(instance, metadata); + } catch ( e ) { + return onerror(e); + } + + try { + const settings = SettingsManager.get(instance.__pname) || {}; + instance.init(settings, metadata); + + triggerHook('onApplicationLaunched', [{ + application: instance, + name: name, + args: args, + settings: settings, + metadata: metadata + }]); + } catch ( e ) { + return onerror(e); + } + + return resolve(instance); + }).catch(onerror); + }); + }; + + const onerror = (err) => { + OSjs.error(_('ERR_APP_LAUNCH_FAILED'), + _('ERR_APP_LAUNCH_FAILED_FMT', name), + err, err, true); + }; + + return new Promise((resolve, reject) => { + console.group('Process::create()', name, args); + + const remove = () => { + console.groupEnd(); + const i = alreadyLaunching.indexOf(hash); + if ( i >= 0 ) { + alreadyLaunching.splice(i, 1); + } + Loader.destroy('Main.launch.' + name); + }; + + const fail = (e) => { + Loader.destroy('Main.launch.' + name); + remove(); + onerror(e); + return reject(e); + }; + + try { + init().then(resolve).catch(fail).finally(remove); + } catch ( e ) { + fail(e); + } + }); + } + + /** + * Launch Processes from a List + * + * @param {Array} list List of launch application arguments + * @param {Function} onconstruct Callback on success => fn(app, metadata, appName, appArgs) + * @return {Promise} + */ + static createFromArray(list, onconstruct) { + list = list || []; + onconstruct = onconstruct || function() {}; + + console.info('Process::createFromArray()', list); + + return Promise.each(list, (s) => { + return new Promise((resolve, reject) => { + s = getLaunchObject(s); + if ( s.name ) { + try { + this.create(s.name, s.args, (instance, metadata) => { + onconstruct(instance, metadata, s.name, s.args); + }).then(resolve).catch(reject); + } catch ( e ) { + reject(e); + } + } else { + resolve(); + } + }); + }); + } + + /** + * Open a file + * + * @param {FileMetadata} file The File reference (can also be a tuple with 'path' and 'mime') + * @param {Object} args Arguments to send to process launch function + * @return {Promise} + */ + static createFromFile(file, args) { + file = new FileMetadata(file); + + args = Object.assign({ + file: file + }, args || {}); + + if ( args.args ) { + Object.keys(args.args).forEach((i) => { + args[i] = args.args[i]; + }); + } + + if ( !file.path ) { + throw new Error('Cannot open file without a path'); + } + + console.info('Process::createFromFile()', file, args); + + if ( file.mime === 'osjs/application' ) { + return this.create(FS.filename(file.path)); + } else if ( file.type === 'dir' ) { + const fm = SettingsManager.instance('DefaultApplication').get('dir', 'ApplicationFileManager'); + return this.create(fm, {path: file.path}); + } + + return new Promise((resolve, reject) => { + const val = SettingsManager.get('DefaultApplication', file.mime); + let pack = PackageManager.getPackagesByMime(file.mime); + if ( !args.forceList && val ) { + if ( PackageManager.getPackage(val) ) { + console.debug('Process::createFromFile()', 'default application', val); + pack = [val]; + } + } + + if ( pack.length === 0 ) { + OSjs.error(_('ERR_FILE_OPEN'), + _('ERR_FILE_OPEN_FMT', file.path), + _('ERR_APP_MIME_NOT_FOUND_FMT', file.mime) ); + + reject(new Error(_('ERR_APP_MIME_NOT_FOUND_FMT', file.mime))); + } else if ( pack.length === 1 ) { + this.create(pack[0], args).then(resolve).catch(reject); + } else { + const DialogWindow = require('core/dialog'); + DialogWindow.default.create('ApplicationChooser', { + file: file, + list: pack + }, (ev, btn, result) => { + if ( btn === 'ok' ) { + this.create(result.name, args); + + SettingsManager.set('DefaultApplication', file.mime, result.useDefault ? result.name : null, true) + .then(resolve) + .catch((err) => { + reject(typeof err === 'string' ? new Error(err) : err); + }); + } + }); + } + }); + + } - OSjs.API.killAll = doKillAllProcesses; - OSjs.API.kill = doKillProcess; - OSjs.API.message = doProcessMessage; - OSjs.API.getProcess = doGetProcess; - OSjs.API.getProcesses = doGetProcesses; +} -})(OSjs.Utils, OSjs.API); diff --git a/src/client/javascript/core/search-engine.js b/src/client/javascript/core/search-engine.js index cc84f53f8d..2438a214df 100644 --- a/src/client/javascript/core/search-engine.js +++ b/src/client/javascript/core/search-engine.js @@ -28,324 +28,288 @@ * @licence Simplified BSD License */ -(function(Utils, VFS, API) { - 'use strict'; +import Promise from 'bluebird'; +import PackageManager from 'core/package-manager'; +import SettingsManager from 'core/settings-manager'; +import FileMetadata from 'vfs/file'; +import Theme from 'core/theme'; +import * as VFS from 'vfs/fs'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +/* + * Searches an object field for matches + */ +function search(list, query) { + const result = []; - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// + list.forEach((obj) => { + let found = false; - /* - * Searches an object field for matches - */ - function search(list, query) { - var result = []; + obj.fields.forEach((s) => { + if ( found ) { + return; + } - list.forEach(function(obj) { - var found = false; + const qry = String(query).toLowerCase(); + const str = String(s).toLowerCase(); + if ( str.indexOf(qry) !== -1 ) { + result.push(obj.value); - obj.fields.forEach(function(s) { - if ( found ) { - return; - } + found = true; + } + }); + }); - var qry = String(query).toLowerCase(); - var str = String(s).toLowerCase(); - if ( str.indexOf(qry) !== -1 ) { - result.push(obj.value); + return result; +} - found = true; - } +/* + * A search Object + */ +function SearchObject(obj) { + Object.keys(obj).forEach((k) => { + this[k] = obj[k]; + }); +} + +///////////////////////////////////////////////////////////////////////////// +// MODULES +///////////////////////////////////////////////////////////////////////////// + +/* + * Search Applications + */ +const ApplicationModule = (function() { + function query() { + const packages = PackageManager.getPackages(); + + return Object.keys(packages).map((pn) => { + const p = packages[pn]; + + return new SearchObject({ + value: { + title: p.name, + description: p.description, + icon: Theme.getFileIcon(new FileMetadata('applications:///' + p.className, 'application'), '16x16'), + launch: {application: pn, args: {}} + }, + fields: [ + p.className, + p.name, + p.description + ] }); }); - - return result; } - /* - * A search Object - */ - function SearchObject(obj) { - var self = this; - Object.keys(obj).forEach(function(k) { - self[k] = obj[k]; - }); - } + return { + search: function(q, args, settings) { + if ( settings.applications ) { + let results = search(query(), q); - ///////////////////////////////////////////////////////////////////////////// - // MODULES - ///////////////////////////////////////////////////////////////////////////// + if ( args.limit && results.length > args.dlimit ) { + results = results.splice(0, args.dlimit); + } - /** - * Search Applications - */ - 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.getFileIcon(new VFS.File('applications:///' + p.className, 'application'), '16x16'), - launch: {application: pn, args: {}} - }, - fields: [ - p.className, - p.name, - p.description - ] - }); - }); + return Promise.resolve(results); + } + return Promise.resolve([]); + }, + reindex: function(args) { + return Promise.resolve(true); + }, + destroy: function() { } + }; +})(); - 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); - } +/* + * Search VFS for files + */ +const FilesystemModule = { + search: function(q, args, settings, cb) { + if ( !settings.files || !settings.paths ) { + return Promise.resolve([]); + } - cb(false, results); - } else { - cb(false, []); - } - }, - reindex: function(args, cb) { - cb(false, true); - }, - destroy: function() { + let found = []; + const append = (result) => { + if ( result ) { + found = found.concat(result.map((iter) => { + return { + title: iter.filename, + description: iter.path, + icon: Theme.getFileIcon(new FileMetadata(iter)), + launch: {application: '', args: '', file: iter} + }; + })); } }; - })(); - /** - * Search VFS for files - */ - 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 ) { + return new Promise((resolve, reject) => { + Promise.each(settings.paths, (e) => { + return new Promise((n) => { + VFS.find(e, {query: q, limit: (args.limit ? args.dlimit : 0), recursive: args.recursive}).then((result) => { + return n(append(result)); + }).catch((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(); + n(); + }); }); - }, function() { - cb(false, found); - }); - }, - reindex: function(args, cb) { - cb(false, true); - }, - destroy: function() { - } - }; + }).then(() => { + return resolve(found); + }).catch(reject); + }); + }, + reindex: function(args) { + return Promise.resolve(); + }, + destroy: function() { + } +}; - ///////////////////////////////////////////////////////////////////////////// - // ENGINE - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// ENGINE +///////////////////////////////////////////////////////////////////////////// - /** - * Settings Manager Class - * - * For maintaining settings - * - *

-   * You can only get an instance with `Core.getSearchEngine()`
-   * 
- * - * @example - * OSjs.Core.getSearchEngine() - * - * @summary The Search Engine for location files and application. - * - * @constructor - * @memberof OSjs.Core - * @see OSjs.Core.getSearchEngine - */ - var SearchEngine = (function() { +/** + * Settings Manager Class + * + * @desc The Search Engine for location files and application. + */ +class SearchEngine { - var modules = [ + constructor() { + this.settings = {}; + this.inited = false; + this.modules = [ ApplicationModule, FilesystemModule ]; + } - var settings = {}; - var inited = false; - - return Object.seal({ - - /** - * Initialize instance - * - * @function init - * @memberof OSjs.Core.SearchEngine# - * - * @param {Function} cb Callback => fn(error, result) - */ - init: function(cb) { - console.debug('SearchEngine::init()'); - - if ( inited ) { - return; - } + /** + * Initialize instance + * + * @return {Promise} + */ + init() { + console.debug('SearchEngine::init()'); - var manager = OSjs.Core.getSettingsManager(); - settings = manager.get('SearchEngine') || {}; + if ( !this.inited ) { + this.settings = SettingsManager.get('SearchEngine') || {}; + this.inited = true; + } - inited = true; + return Promise.resolve(); + } - cb(); - }, + /** + * Destroy instance + */ + destroy() { + console.debug('SearchEngine::destroy()'); - /** - * Destroy instance - * - * @function destroy - * @memberof OSjs.Core.SearchEngine# - */ - destroy: function() { - console.debug('SearchEngine::destroy()'); + this.modules.forEach((m) => { + m.destroy(); + }); - modules.forEach(function(m) { - m.destroy(); - }); + this.modules = []; + this.settings = {}; + this.inited = false; + } - modules = []; - settings = {}; - inited = false; - }, - - /** - * Perform a search - * - * @function search - * @memberof OSjs.Core.SearchEngine# - * - * @param {String} q Search query - * @param {Object} args Arguments - * @param {Function} cb Callback => fn(error, result) - */ - search: function(q, args, cb) { - var result = []; - var errors = []; - - args = Utils.argumentDefaults(args, { - recursive: false, - limit: 0, - dlimit: 0 - }); + /** + * Perform a search + * + * @param {String} q Search query + * @param {Object} args Arguments + * @return {Promise} + */ + search(q, args) { + let result = []; + let errors = []; + + args = Object.assign({}, { + recursive: false, + limit: 0, + dlimit: 0 + }, args); + + if ( args.limit ) { + args.dlimit = args.limit; + } - if ( args.limit ) { - args.dlimit = args.limit; - } + return new Promise((resolve, reject) => { + Promise.each(this.modules, (module) => { + return new Promise((next, reject) => { - Utils.asyncs(modules, function(module, index, next) { console.debug('SearchEngine::search()', '=>', module); 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); - } + module.search(q, args, this.settings).then((res) => { + args.dlimit -= res.length; + result = result.concat(res); + next(); + }).catch((err) => { + console.warn(err); + errors.push(err instanceof Error ? err.toString() : err); next(); }); } else { - cb(errors, result); - } - }, function() { - cb(errors, result); - }); - }, - - /** - * Reindex databases - * - * @TODO implement - * @function reindex - * @memberof OSjs.Core.SearchEngine# - * - * @param {Object} args Arguments - * @param {Function} cb Callback => fn(error, result) - */ - reindex: function(args, cb) { - var errors = []; - - Utils.asyncs(modules, function(module, index, next) { - console.debug('SearchEngine::reindex()', '=>', module); - - module.reindex(args, function(err, res) { - if ( err ) { - errors.push(err); - } next(); - }); - }, function() { - cb(errors, true); + //reject(new Error(errors.join(', '))); + } }); - }, - - /** - * Configure the Search Engine - * - * @TODO implement - * @function configure - * @memberof OSjs.Core.SearchEngine# - * - * @param {Object} opts Settings Object - * @param {Boolean} [save=true] Save settings - */ - configure: function(opts, save) { - } + }).then(() => resolve(result)).catch(reject); }); + } - })(); + /** + * Reindex databases + * + * @TODO implement + * + * @param {Object} args Arguments + * @param {Function} cb Callback => fn(error, result) + * @return {Promise} + */ + reindex(args) { + const errors = []; + + return Promise.each(this.modules, (module) => { + return new Promise((next) => { + console.debug('SearchEngine::reindex()', '=>', module); - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + module.reindex(args).then(next).catch((err) => { + if ( err ) { + errors.push(err); + } + next(); + }); + }); + }); + } /** - * Get the current SearchEngine instance + * Configure the Search Engine * - * @function getSearchEngine - * @memberof OSjs.Core + * @TODO implement * - * @return {OSjs.Core.SearchEngine} + * @param {Object} opts Settings Object + * @param {Boolean} [save=true] Save settings */ - OSjs.Core.getSearchEngine = function Core_getSearchEngine() { - return SearchEngine; - }; + configure(opts, save) { + } + +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.Utils, OSjs.VFS, OSjs.API); +export default (new SearchEngine()); diff --git a/src/client/javascript/core/service.js b/src/client/javascript/core/service.js index db9759d74c..67361b1c3a 100644 --- a/src/client/javascript/core/service.js +++ b/src/client/javascript/core/service.js @@ -27,53 +27,32 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API, Process) { - 'use strict'; - ///////////////////////////////////////////////////////////////////////////// - // SERVICE - ///////////////////////////////////////////////////////////////////////////// +import Process from 'core/process'; - /** - * Service Class - * - *

-   * YOU CANNOT CANNOT USE THIS VIA 'new' KEYWORD.
-   * 
- * - * @summary Class used for basis as a Service. - * - * @param {String} name Process name - * @param {Object} args Process arguments - * @param {Object} metadata Package metadata - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @extends OSjs.Core.Process - */ - function Service(name, args, metadata) { +///////////////////////////////////////////////////////////////////////////// +// SERVICE +///////////////////////////////////////////////////////////////////////////// + +/** + * Service Base Class + * + * @desc Class used for making Services + * + * @param {String} name Process name + * @param {Object} args Process arguments + * @param {Object} metadata Package metadata + * + * @extends Process + * @abstract + */ +export default class Service extends Process { + + constructor(name, args, metadata) { console.group('Service::constructor()', name); - Process.apply(this, arguments); + super(...arguments); console.groupEnd(); } - Service.prototype = Object.create(Process.prototype); - Service.constructor = Process; - - /** - * Intiaialize the Service - * - * @function init - * @memberof OSjs.Core.Service# - */ - Service.prototype.init = function() { - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Core.Service = Object.seal(Service); +} -})(OSjs.Utils, OSjs.API, OSjs.Core.Process); diff --git a/src/client/javascript/core/settings-manager.js b/src/client/javascript/core/settings-manager.js index 215bbea956..c778001061 100644 --- a/src/client/javascript/core/settings-manager.js +++ b/src/client/javascript/core/settings-manager.js @@ -28,87 +28,72 @@ * @licence Simplified BSD License */ -(function(Utils, VFS, API) { - 'use strict'; +import Promise from 'bluebird'; +import Storage from 'core/storage'; +import SettingsFragment from 'helpers/settings-fragment'; - /** - * Settings Manager Class - * - * @summary Class for maintaining settings - * - *

-   * YOU CAN ONLY GET AN INSTANCE WITH `Core.getSettingsManager()`
-   * 
- * - * @example - * OSjs.Core.getSettingsManager() - * - * @summary Used for managing Settings across all applications and modules. - * - * @constructor - * @memberof OSjs.Core - * @see OSjs.Helpers.EventHandler - * @see OSjs.Core.getSettingsManager - */ - var SettingsManager = { - storage: {}, - defaults: {}, - watches: [] - }; +/** + * Settings Manager Class + * + * @desc Used for managing Settings across all applications and modules. + */ +class SettingsManager { + + constructor() { + this.storage = {}; + this.defaultSettings = {}; + this.watches = []; + } /** - * Initialize SettingsManager. + * Initialize Settings. * This is run when a user logs in. It will give saved data here * - * @function init - * @memberof OSjs.Core.SettingsManager# - * * @param {Object} settings Entire settings tree + * @return {Promise} */ - SettingsManager.init = function SettingsManager_init(settings) { + init(settings) { this.storage = settings || {}; - }; + + return Promise.resolve(); + } /** * Gets either the full tree or tree entry by key * - * @function get - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool * @param {String} [key] Key entry of tree * - * @return {Mixed} + * @return {*} */ - SettingsManager.get = function SettingsManager_get(pool, key) { + get(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]; + return key ? this.defaultSettings[pool][key] : this.defaultSettings[pool]; } catch ( e ) { console.warn('SettingsManager::get()', 'exception', e, e.stack); } return false; - }; + } /** * Sets either full tree or a tree entry by key * - * @function set - * @memberof OSjs.Core.SettingsManager# - * - * @param {String} pool Name of settings pool - * @param {String} [key] Key entry of tree - * @param {Mixed} value The value (or entire tree if no key given) - * @param {Mixed} [save] boolean or callback function for saving + * @param {String} pool Name of settings pool + * @param {String} [key] Key entry of tree + * @param {*} value The value (or entire tree if no key given) + * @param {Boolean|Function} [save] boolean or callback function for saving * @param {Boolean} [triggerWatch=true] trigger change event for watchers * - * @return {Boolean} + * @return {Promise} */ - SettingsManager.set = function SettingsManager_set(pool, key, value, save, triggerWatch) { + set(pool, key, value, save, triggerWatch) { + let promise = Promise.resolve(true); + try { if ( key ) { if ( typeof this.storage[pool] === 'undefined' ) { @@ -127,164 +112,138 @@ } if ( save ) { - this.save(pool, save); + promise = this.save(pool); + if ( typeof save === 'function' ) { + console.warn('Using a callback is deprecated, you should use the returned promise'); + promise.then((res) => save(false, res)).catch((err) => save(err, false)); + } } if ( typeof triggerWatch === 'undefined' || triggerWatch === true ) { this.changed(pool); } - return true; - }; + return promise; + } /** * Saves the storage to a location * - * @function save - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool - * @param {Function} callback Callback + * @return {Promise} */ - SettingsManager.save = function SettingsManager_save(pool, callback) { + save(pool) { console.debug('SettingsManager::save()', pool, this.storage); - if ( typeof callback !== 'function' ) { - callback = function() {}; - } - var storage = OSjs.Core.getStorage(); - storage.saveSettings(pool, this.storage, callback); - }; + const saveableStorage = {}; + Object.keys(this.storage).filter((n) => { + return !n.match(/^__/); + }).forEach((n) => { + saveableStorage[n] = this.storage[n]; + }); + + return Storage.instance.saveSettings(pool, saveableStorage); + } /** * Sets the defaults for a specific pool * - * @function defaults - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool * @param {Object} [defaults] Default settings tree */ - SettingsManager.defaults = function SettingsManager_defaults(pool, defaults) { - this.defaults[pool] = defaults; - }; + defaults(pool, defaults) { + this.defaultSettings[pool] = defaults; + } /** * Creates a new proxy instance * - * @function instance - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool * @param {Object} [defaults] Default settings tree * * @return {Object} */ - SettingsManager.instance = function SettingsManager_instance(pool, defaults) { + instance(pool, defaults) { if ( !this.storage[pool] || (this.storage[pool] instanceof Array) ) { this.storage[pool] = {}; } - var instance = new OSjs.Helpers.SettingsFragment(this.storage[pool], pool); + const instance = new SettingsFragment(this.storage[pool], pool, this); if ( arguments.length > 1 ) { - SettingsManager.defaults(pool, defaults); + this.defaults(pool, defaults); instance.mergeDefaults(defaults); } return instance; - }; + } /** * Destroy a watcher * - * @function unwatch - * @memberof OSjs.Core.SettingsManager# - * * @param {Number} index The index from watch() */ - SettingsManager.unwatch = function SettingsManager_unwatch(index) { + unwatch(index) { if ( typeof this.watches[index] !== 'undefined' ) { delete this.watches[index]; } - }; + } /** * Receive events when a pool changes. * - * @function watch - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool * @param {Function} callback Callback * - * @return {Mixed} false on error, index for unwatch() otherwise + * @return {Boolean|Number} false on error, index for unwatch() otherwise */ - SettingsManager.watch = function SettingsMananger_watch(pool, callback) { + watch(pool, callback) { if ( !this.storage[pool] ) { return false; } - var index = this.watches.push({ + const index = this.watches.push({ pool: pool, callback: callback }); return index - 1; - }; + } /** * Notify the SettingsManager that somewhere in a pool's tree it has changed. * - * @function changed - * @memberof OSjs.Core.SettingsManager# - * * @param {String} pool Name of settings pool that changed * - * @return {OSjs.Core.SettingsManager} this + * @return {SettingsManager} this */ - SettingsManager.changed = function SettingsManager_changed(pool) { - var self = this; - this.watches.forEach(function(watch) { + changed(pool) { + this.watches.forEach((watch) => { if ( watch && watch.pool === pool ) { - watch.callback(self.storage[pool]); + watch.callback(this.storage[pool]); } }); return this; - }; + } /** * Clears a pool * - * @function clear - * @memberof OSjs.Core.SettingsManager# + * @param {String} pool Name of settings pool + * @param {Boolean|Function} [save=true] Boolean or callback function for saving * - * @param {String} pool Name of settings pool - * @param {Mixed} [save=true] Boolean or callback function for saving - * - * @return {OSjs.Core.SettingsManager} this + * @return {SettingsManager} this */ - SettingsManager.clear = function SettingsManager_clear(pool, save) { + clear(pool, save) { save = (typeof save === 'undefined') || (save === true); this.set(pool, null, {}, save); return this; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - Object.seal(SettingsManager); +} - /** - * Get the current SettingsManager instance - * - * @function getSettingsManager - * @memberof OSjs.Core - * @return {OSjs.Core.SettingsManager} - */ - OSjs.Core.getSettingsManager = function Core_getSettingsManager() { - return SettingsManager; - }; +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.Utils, OSjs.VFS, OSjs.API); +export default (new SettingsManager()); diff --git a/src/client/javascript/core/storage.js b/src/client/javascript/core/storage.js index 203db63575..050cdaa981 100644 --- a/src/client/javascript/core/storage.js +++ b/src/client/javascript/core/storage.js @@ -28,160 +28,95 @@ * @licence Simplified BSD License */ -(function(API, Utils) { - 'use strict'; +import Promise from 'bluebird'; +import Connection from 'core/connection'; +import Process from 'core/process'; +import SettingsManager from 'core/settings-manager'; - var _storageInstance; +let _instance; - /** - * Storage Base Class - * - * @abstract - * @constructor Storage - * @memberof OSjs.Core - */ - function Storage() { - this.saveTimeout = null; +/** + * Storage Base Class + * + * @abstract + */ +export default class Storage { - /*eslint consistent-this: "off"*/ - _storageInstance = this; + static get instance() { + return _instance; + } + + constructor() { + /* eslint consistent-this: "off" */ + _instance = this; + + this.saveTimeout = null; } /** * Initializes the Storage - * - * @function init - * @memberof OSjs.Core.Storage# - * - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Storage.prototype.init = function(callback) { - callback(null, true); - }; + init() { + return Promise.resolve(); + } /** * Destroys the Storage - * - * @function destroy - * @memberof OSjs.Core.Storage# - */ - Storage.prototype.destroy = function() { - }; - - /** - * Internal for saving settings - * - * @function _settings - * @memberof OSjs.Core.Storage# - * - * @param {String} [pool] Settings pool - * @param {Object} storage Settings storage data - * @param {CallbackHandler} callback Callback function */ - Storage.prototype._settings = function(pool, storage, callback) { - API.call('settings', {pool: pool, settings: Utils.cloneObject(storage)}, callback); - }; + destroy() { + _instance = null; + } /** * Default method to save given settings pool * - * @function saveSettings - * @memberof OSjs.Core.Storage# - * - * @param {String} [pool] Pool Name - * @param {Mixed} storage Storage data - * @param {CallbackHandler} callback Callback function + * @param {String} [pool] Pool Name + * @param {*} storage Storage data + * @return {Promise} */ - Storage.prototype.saveSettings = function(pool, storage, callback) { - var self = this; + saveSettings(pool, storage) { clearTimeout(this.saveTimeout); - this.saveTimeout = setTimeout(function() { - self._settings(pool, storage, callback); - clearTimeout(self.saveTimeout); - }, 250); - }; + + return new Promise((resolve, reject) => { + this.saveTimeout = setTimeout(() => { + Connection.request('settings', {pool: pool, settings: Object.assign({}, storage)}) + .then(resolve).catch(reject); + clearTimeout(this.saveTimeout); + }, 250); + }); + } /** * Default method for saving current sessions - * - * @function saveSession - * @memberof OSjs.Core.Storage# - * - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Storage.prototype.saveSession = function(callback) { - var data = []; - API.getProcesses().forEach(function(proc, i) { - if ( proc && (proc instanceof OSjs.Core.Application) ) { - data.push(proc._getSessionData()); - } + saveSession() { + return new Promise((resolve, reject) => { + const data = Process.getProcesses() + .filter((proc) => typeof proc._getSessionData === 'function') + .map((proc) => proc._getSessionData()); + + SettingsManager.set('UserSession', null, data, (err, res) => { + return err ? reject(err) : resolve(res); + }); }); - OSjs.Core.getSettingsManager().set('UserSession', null, data, callback); - }; + } /** * Get last saved sessions - * - * @function getLastSession - * @memberof OSjs.Core.Storage# - * - * @param {CallbackHandler} callback Callback function + * @return {Promise} */ - Storage.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; + getLastSession() { + const res = SettingsManager.get('UserSession'); + const list = (res || []).map((iter) => { + const args = iter.args; args.__resume__ = true; args.__windows__ = iter.windows || []; - - list.push({name: iter.name, args: args}); - }); - - callback(false, list); - }; - - /** - * Default method to restore last running session - * - * @function loadSession - * @memberof OSjs.Core.Storage# - * - * @param {Function} callback Callback function => fn() - */ - Storage.prototype.loadSession = function(callback) { - callback = callback || function() {}; - - console.info('Storage::loadSession()'); - - this.getLastSession(function onGetLastSession(err, list) { - if ( err ) { - callback(); - } else { - API.launchList(list, null, null, callback); - } + return {name: iter.name, args}; }); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Core.Storage = Storage; - /** - * Get running 'Storage' instance - * - * @function getStorage - * @memberof OSjs.Core - * - * @return {OSjs.Core.Storage} - */ - OSjs.Core.getStorage = function Core_getStorage() { - return _storageInstance; - }; - -})(OSjs.API, OSjs.Utils); + return Promise.resolve(list); + } +} diff --git a/src/client/javascript/core/storage/database.js b/src/client/javascript/core/storage/database.js index 39d2c362ef..91504d34c9 100644 --- a/src/client/javascript/core/storage/database.js +++ b/src/client/javascript/core/storage/database.js @@ -27,21 +27,12 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Storage) { - 'use strict'; +import Storage from 'core/storage'; - function DatabaseStorage() { - Storage.apply(this, arguments); - } - - DatabaseStorage.prototype = Object.create(Storage.prototype); - DatabaseStorage.constructor = Storage; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Storage = OSjs.Storage || {}; - OSjs.Storage.database = DatabaseStorage; +/** + * Database Storage Handler + * @xtends Storage + */ +export default class DatabaseStorage extends Storage { +} -})(OSjs.API, OSjs.Utils, OSjs.Core.Storage); diff --git a/src/client/javascript/core/storage/demo.js b/src/client/javascript/core/storage/demo.js index 6e89a80a49..8311bcffb5 100644 --- a/src/client/javascript/core/storage/demo.js +++ b/src/client/javascript/core/storage/demo.js @@ -27,29 +27,30 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Storage) { - 'use strict'; +import Promise from 'bluebird'; +import {getConfig} from 'core/config'; +import Storage from 'core/storage'; - function DemoStorage() { - Storage.apply(this, arguments); - } +/** + * Demo Storage Handler + * @xtends Storage + */ +export default class DemoStorage extends Storage { - DemoStorage.prototype = Object.create(Storage.prototype); - DemoStorage.constructor = Storage; + init() { + const curr = getConfig('Version'); + const version = localStorage.getItem('__version__'); - DemoStorage.prototype.init = function(callback) { - var curr = API.getConfig('Version'); - var version = localStorage.getItem('__version__'); if ( curr !== version ) { localStorage.clear(); } localStorage.setItem('__version__', String(curr)); - callback(null, true); - }; + return Promise.resolve(); + } - DemoStorage.prototype.saveSettings = function(pool, storage, callback) { - Object.keys(storage).forEach(function(key) { + saveSettings(pool, storage) { + Object.keys(storage).forEach((key) => { if ( pool && key !== pool ) { return; } @@ -61,14 +62,8 @@ } }); - callback(); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + return Promise.resolve(); + } - OSjs.Storage = OSjs.Storage || {}; - OSjs.Storage.demo = DemoStorage; +} -})(OSjs.API, OSjs.Utils, OSjs.Core.Storage); diff --git a/src/server/node/modules/generic/example.js b/src/client/javascript/core/storage/standalone.js similarity index 87% rename from src/server/node/modules/generic/example.js rename to src/client/javascript/core/storage/standalone.js index a4593f4df8..f0443d6a12 100644 --- a/src/server/node/modules/generic/example.js +++ b/src/client/javascript/core/storage/standalone.js @@ -13,7 +13,7 @@ * 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 + * 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 @@ -27,13 +27,9 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -/*eslint strict:["error", "global"]*/ -'use strict'; -/* - * Just loads a generic module. You can put whatever you want here. - */ -module.exports.register = function(env, config) { - return Promise.resolve(); -}; +import DemoStorage from './demo'; + +export default class StandaloneStorage extends DemoStorage { +} diff --git a/src/client/javascript/core/storage/system.js b/src/client/javascript/core/storage/system.js index 19a002c340..04fe76bc1b 100644 --- a/src/client/javascript/core/storage/system.js +++ b/src/client/javascript/core/storage/system.js @@ -27,21 +27,11 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, Storage) { - 'use strict'; +import Storage from 'core/storage'; - function SystemStorage() { - Storage.apply(this, arguments); - } - - SystemStorage.prototype = Object.create(Storage.prototype); - SystemStorage.constructor = Storage; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Storage = OSjs.Storage || {}; - OSjs.Storage.system = SystemStorage; - -})(OSjs.API, OSjs.Utils, OSjs.Core.Storage); +/** + * System Storage Handler + * @xtends Storage + */ +export default class SystemStorage extends Storage { +} diff --git a/src/client/javascript/core/theme.js b/src/client/javascript/core/theme.js new file mode 100644 index 0000000000..9d6828654b --- /dev/null +++ b/src/client/javascript/core/theme.js @@ -0,0 +1,485 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import SettingsManager from 'core/settings-manager'; +import {getConfig} from 'core/config'; +import FileMetadata from 'vfs/file'; +import PackageManager from 'core/package-manager'; +import * as FS from 'utils/fs'; +import * as Compability from 'utils/compability'; +import * as DOM from 'utils/dom'; +import * as VFS from 'vfs/fs'; + +/** + * Theme resource handling + */ +class Theme { + + constructor() { + this.settings = null; + this.$themeScript = null; + } + + init() { + this.settings = SettingsManager.instance('__theme__', { + enableSounds: true, + styleTheme: 'default', + soundTheme: 'default', + iconTheme: 'default', + sounds: {} + }); + } + + update(settings, settheme) { + this.settings.set(null, settings); + if ( settheme ) { + this.setTheme(settings); + } + } + + destroy() { + this.$themeScript = DOM.$remove(this.$themeScript); + } + + /** + * Perform an action on current theme + * @param {String} action Method name + * @param {Array} args Method arumentgs + * @return {*} + */ + themeAction(action, args) { + const theme = this.getStyleTheme(); + args = args || []; + + try { + if ( OSjs.Themes[theme] ) { + return OSjs.Themes[theme][action].apply(null, args); + } + } catch ( e ) { + console.warn(e); + } + + return null; + } + + /** + * Set the background + * @param {Object} settings Settings + */ + _setBackground(settings) { + const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; + const typeMap = { + 'image': 'normal', + 'image-center': 'center', + 'image-fill': 'fill', + 'image-strech': 'strech' + }; + + let className = 'color'; + let back = 'none'; + if ( settings.wallpaper && settings.background.match(/^image/) ) { + back = settings.wallpaper; + className = typeMap[settings.background] || 'default'; + } + + if ( back !== 'none' ) { + try { + VFS.url(back).then((result) => { + back = 'url(\'' + result + '\')'; + document.body.style.backgroundImage = back; + return true; + }); + } catch ( e ) { + console.warn(e); + } + } else { + document.body.style.backgroundImage = back; + } + + if ( settings.backgroundColor ) { + document.body.style.backgroundColor = settings.backgroundColor; + } + + if ( settings.fontFamily ) { + document.body.style.fontFamily = settings.fontFamily; + } + + if ( isFirefox ) { + document.body.style.backgroundAttachment = 'fixed'; + } else { + document.body.style.backgroundAttachment = 'scroll'; + } + + document.body.setAttribute('data-background-style', className); + } + + getThemeCSS(name) { + let root = getConfig('Connection.RootURI', '/'); + if ( name === null ) { + return root + 'blank.css'; + } + + root = getConfig('Connection.ThemeURI'); + return root + '/' + name + '.css'; + } + + /** + * Set theme + * @param {Object} settings Settings + */ + setTheme(settings) { + this.themeAction('destroy'); + + this.setThemeScript(this.getThemeResource('theme.js')); + + document.body.setAttribute('data-style-theme', settings.styleTheme); + document.body.setAttribute('data-icon-theme', settings.iconTheme); + document.body.setAttribute('data-sound-theme', settings.soundTheme); + document.body.setAttribute('data-animations', String(settings.animations)); + + this._setBackground(settings); + + this.settings.set(null, settings); + } + + /** + * Set theme script + * @param {String} src Source file + */ + setThemeScript(src) { + if ( this.$themeScript ) { + this.$themeScript = DOM.$remove(this.$themeScript); + } + + if ( src ) { + this.$themeScript = DOM.$createJS(src, null, () => { + this.themeAction('init'); + }); + } + } + + /** + * Gets current Style theme + * + * @param {Boolean} returnMetadata Return theme metadata instead of name + * @param {Boolean} [convert=false] Converts the measures into px + * + * @return {String} Or JSON + */ + getStyleTheme(returnMetadata, convert) { + const name = this.settings.get('styleTheme') || null; + if ( returnMetadata ) { + let found = null; + if ( name ) { + this.getStyleThemes().forEach(function(t) { + if ( t && t.name === name ) { + found = t; + } + }); + } + + // FIXME: Optimize + if ( found && convert === true ) { + const tmpEl = document.createElement('div'); + tmpEl.style.visibility = 'hidden'; + tmpEl.style.position = 'fixed'; + tmpEl.style.top = '-10000px'; + tmpEl.style.left = '-10000px'; + tmpEl.style.width = '1em'; + tmpEl.style.height = '1em'; + + document.body.appendChild(tmpEl); + const wd = tmpEl.offsetWidth; + tmpEl.parentNode.removeChild(tmpEl); + + if ( typeof found.style.window.margin === 'string' && found.style.window.margin.match(/em$/) ) { + const marginf = parseFloat(found.style.window.margin); + found.style.window.margin = marginf * wd; + } + + if ( typeof found.style.window.border === 'string' && found.style.window.border.match(/em$/) ) { + const borderf = parseFloat(found.style.window.border); + found.style.window.border = borderf * wd; + } + } + + return found; + } + + return name; + } + + /** + * Default method for getting a resource from current theme + * + * @param {String} name Resource filename + * @param {String} type Type ('base' or a sub-folder) + * + * @return {String} The absolute URL to the resource + */ + getThemeResource(name, type) { + name = name || null; + type = type || null; + + const root = getConfig('Connection.ThemeURI'); + + 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 ) { + const theme = this.getStyleTheme(); + name = getName(name, theme); + } + + return name; + } + + /** + * Default method for getting a sound from theme + * + * @param {String} name Resource filename + * + * @return {String} The absolute URL to the resource + */ + getSound(name) { + name = name || null; + if ( name ) { + const theme = this.getSoundTheme(); + const root = getConfig('Connection.SoundURI'); + const compability = Compability.getCompability(); + + if ( !name.match(/^\//) ) { + let ext = 'oga'; + if ( !compability.audioTypes.ogg ) { + ext = 'mp3'; + } + name = root + '/' + theme + '/' + name + '.' + ext; + } + } + return name; + } + + /** + * Global function for playing a sound + * + * @param {String} name Sound name + * @param {Number} volume Sound volume (0.0 - 1.0) + * + * @return {Audio} + */ + playSound(name, volume) { + const filename = this.getSoundFilename(name); + if ( !filename ) { + console.debug('playSound()', 'Cannot play sound, no compability or not enabled!'); + return null; + } + + if ( typeof volume === 'undefined' ) { + volume = 1.0; + } + + const f = this.getSound(filename); + console.debug('playSound()', name, filename, f, volume); + + const a = new Audio(f); + a.volume = volume; + a.play(); + return a; + } + + /** + * Default method for getting a icon from theme + * + * @param {String} name Resource filename + * @param {String} [size=16x16] Icon size + * + * @return {String} The absolute URL to the resource + */ + getIcon(name, size) { + name = name || ''; + size = size || '16x16'; + + if ( !name.match(/^(https?)?:?\//) ) { + const root = getConfig('Connection.IconURI'); + const theme = this.getIconTheme(); + + return root + '/' + theme + '/' + size + '/' + name; + } + + return name; + } + + /** + * Get a icon based in file and mime + * + * @param {File} file File Data (see supported types) + * @param {String} [size=16x16] Icon size + * @param {String} [icon] Default icon + * + * @return {String} The absolute URL to the icon + */ + getFileIcon(file, size, icon) { + icon = icon || 'mimetypes/text-x-preview.png'; + + if ( typeof file === 'object' && !(file instanceof FileMetadata) ) { + file = new FileMetadata(file); + } + + if ( !file.filename ) { + throw new Error('Filename is required for getFileIcon()'); + } + + const map = [ + {match: 'application/pdf', icon: 'mimetypes/x-office-document.png'}, + {match: 'application/zip', icon: 'mimetypes/package-x-generic.png'}, + {match: 'application/x-python', icon: 'mimetypes/text-x-script.png'}, + {match: 'application/x-lua', icon: 'mimetypes/text-x-script.png'}, + {match: 'application/javascript', icon: 'mimetypes/text-x-script.png'}, + {match: 'text/html', icon: 'mimetypes/text-html.png'}, + {match: 'text/xml', icon: 'mimetypes/text-html.png'}, + {match: 'text/css', icon: 'mimetypes/text-x-script.png'}, + + {match: 'osjs/document', icon: 'mimetypes/x-office-document.png'}, + {match: 'osjs/draw', icon: 'mimetypes/image-x-generic.png'}, + + {match: /^text\//, icon: 'mimetypes/text-x-generic.png'}, + {match: /^audio\//, icon: 'mimetypes/audio-x-generic.png'}, + {match: /^video\//, icon: 'mimetypes/video-x-generic.png'}, + {match: /^image\//, icon: 'mimetypes/image-x-generic.png'}, + {match: /^application\//, icon: 'mimetypes/application-x-executable.png'} + ]; + + if ( file.type === 'dir' ) { + icon = 'places/folder.png'; + } else if ( file.type === 'trash' ) { + icon = 'places/user-trash.png'; + } else if ( file.type === 'application' ) { + const appname = FS.filename(file.path); + const meta = PackageManager.getPackage(appname); + + if ( meta ) { + if ( !meta.icon.match(/^((https?:)|\.)?\//) ) { + return this.getIcon(meta.icon, size); + } + return PackageManager.getPackageResource(appname, meta.icon); + } + } else { + const mime = file.mime || 'application/octet-stream'; + + map.every((iter) => { + let 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 this.getIcon(icon, size); + } + + /** + * Gets current icon theme + * @return {String} + */ + getIconTheme() { + return this.settings.get('iconTheme', 'default'); + } + + /** + * Gets current sound theme + * @return {String} + */ + getSoundTheme() { + return this.settings.get('soundTheme', 'default'); + } + + /** + * Gets sound filename from key + * + * @param {String} k Sound name key + * + * @return {String} + */ + getSoundFilename(k) { + const compability = Compability.getCompability(); + if ( !compability.audio || !this.settings.get('enableSounds') || !k ) { + return false; + } + + const sounds = this.settings.get('sounds', {}); + return sounds[k] || null; + } + + /** + * Gets a list of Style themes + * + * @return {String[]} The list of themes + */ + getStyleThemes() { + return getConfig('Styles', []); + } + + /** + * Gets a list of Sound themes + * + * @return {String[]} The list of themes + */ + getSoundThemes() { + return getConfig('Sounds', []); + } + + /** + * Gets a list of Icon themes + * + * @return {String[]} The list of themes + */ + getIconThemes() { + return getConfig('Icons', []); + } + +} + +export default (new Theme()); diff --git a/src/client/javascript/core/window-manager.js b/src/client/javascript/core/window-manager.js new file mode 100644 index 0000000000..9cd1fb7cb4 --- /dev/null +++ b/src/client/javascript/core/window-manager.js @@ -0,0 +1,893 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +import * as DOM from 'utils/dom'; +import * as Menu from 'gui/menu'; +import * as Events from 'utils/events'; +import * as Utils from 'utils/misc'; +import Keycodes from 'utils/keycodes'; + +import Theme from 'core/theme'; +import Process from 'core/process'; +import Window from 'core/window'; +import DialogWindow from 'core/dialog'; +import Connection from 'core/connection'; +import SettingsManager from 'core/settings-manager'; +import Notification from 'gui/notification'; + +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; +import {createWindowBehaviour} from 'helpers/window-behaviour'; + +///////////////////////////////////////////////////////////////////////////// +// MISC HELPERS +///////////////////////////////////////////////////////////////////////////// + +function checkForbiddenKeyCombo(ev) { + return false; + /* FIXME: This is not supported in browsers :( (in app mode it should be) + var forbiddenCtrl = ['n', 't', 'w']; + if ( ev.ctrlKey ) { + return forbiddenCtrl.some(function(i) { + return String.fromCharCode(ev.keyCode).toLowerCase() === i; + }); + } + return false; + */ +} + +function checkPrevent(ev, win) { + const d = ev.srcElement || ev.target; + const accept = [122, 123]; + let doPrevent = d.tagName === 'BODY' ? true : false; + + // What browser default keys we prevent in certain situations + if ( (ev.keyCode === Keycodes.BACKSPACE) && !DOM.$isFormElement(ev) ) { // Backspace + doPrevent = true; + } else if ( (ev.keyCode === Keycodes.TAB) && DOM.$isFormElement(ev) ) { // Tab + doPrevent = true; + } else { + if ( accept.indexOf(ev.keyCode) !== -1 ) { + doPrevent = false; + } else if ( checkForbiddenKeyCombo(ev) ) { + doPrevent = true; + } + } + + // Only prevent default event if current window is not set up to capture them by force + if ( doPrevent && (!win || !win._properties.key_capture) ) { + return true; + } + + return false; +} + +function triggerFullscreen(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(); + } + } +} + +///////////////////////////////////////////////////////////////////////////// +// WINDOW MANAGER +///////////////////////////////////////////////////////////////////////////// + +let _instance; + +/** + * WindowManager Process Class + * + * @desc Class used for basis as a Window Manager. + * + * @abstract + */ +export default class WindowManager extends Process { + + static get instance() { + return _instance; + } + + /** + * @param {String} name Window Manager name + * @param {Object} args Constructed arguments + * @param {Object} metadata Package Metadata + * @param {Object} settings Restored settings + */ + constructor(name, args, metadata, settings) { + console.group('WindowManager::constructor()'); + console.debug('Name', name); + console.debug('Arguments', args); + + super(name, args, metadata); + + /* eslint consistent-this: "off" */ + _instance = this; + + this._windows = []; + this._settings = SettingsManager.instance(name, settings); + this._currentWin = null; + this._lastWin = null; + this._mouselock = true; + this._stylesheet = null; + this._sessionLoaded = false; + this._fullyLoaded = false; + this._isResponsive = false; + this._responsiveRes = 800; + this._dcTimeout = null; + this._resizeTimeout = null; + this._$fullscreen = null; + + // Important for usage as "Application" + this.__name = (name || 'WindowManager'); + this.__path = metadata.path; + this.__iter = metadata.iter; + + Connection.instance.subscribe('online', () => { + Notification.create({title: _('LBL_INFO'), message: _('CONNECTION_RESTORED')}); + }); + + Connection.instance.subscribe('offline', (reconnecting) => { + Notification.create({title: _('LBL_WARNING'), message: _(reconnecting ? 'CONNECTION_RESTORE_FAILED' : 'CONNECTION_LOST')}); + }); + + console.groupEnd(); + } + + /** + * Destroy the WindowManager + * + * @return {Boolean} + */ + destroy() { + console.debug('WindowManager::destroy()'); + + this.destroyStylesheet(); + + Events.$unbind(document, 'mouseout:windowmanager'); + Events.$unbind(document, 'mouseenter:windowmanager'); + Events.$unbind(window, 'orientationchange:windowmanager'); + Events.$unbind(window, 'hashchange:windowmanager'); + Events.$unbind(window, 'resize:windowmanager'); + Events.$unbind(window, 'scroll:windowmanager'); + Events.$unbind(window, 'fullscreenchange:windowmanager'); + Events.$unbind(window, 'mozfullscreenchange:windowmanager'); + Events.$unbind(window, 'webkitfullscreenchange:windowmanager'); + Events.$unbind(window, 'msfullscreenchange:windowmanager'); + Events.$unbind(document.body, 'contextmenu:windowmanager'); + Events.$unbind(document.body, 'click:windowmanager'); + Events.$unbind(document, 'keyup:windowmanager'); + Events.$unbind(document, 'keydown:windowmanager'); + Events.$unbind(document, 'keypress:windowmanager'); + + window.onerror = null; + window.onbeforeunload = null; + + // Destroy all windows + this._windows.forEach((win, i) => { + if ( win ) { + win.destroy(true); + this._windows[i] = null; + } + }); + + this._windows = []; + this._currentWin = null; + this._lastWin = null; + this._$fullscreen = null; + + _instance = null; + + return super.destroy(); + } + + /** + * Initialize the WindowManager + * + * @param {Object} metadata Package metadata + * @param {Object} settings Package settings + */ + init(metadata, settings) { + console.debug('WindowManager::init()'); + + Events.$bind(document, 'mouseout:windowmanager', (ev) => this._onMouseLeave(ev)); + Events.$bind(document, 'mouseenter:windowmanager', (ev) => this._onMouseLeave(ev)); + Events.$bind(window, 'orientationchange:windowmanager', (ev) => this._onOrientationChange(ev)); + Events.$bind(window, 'hashchange:windowmanager', (ev) => this._onHashChange(ev)); + Events.$bind(window, 'resize:windowmanager', (ev) => this._onResize(ev)); + Events.$bind(window, 'scroll:windowmanager', (ev) => this._onScroll(ev)); + Events.$bind(window, 'fullscreenchange:windowmanager', (ev) => this._onFullscreen(ev)); + Events.$bind(window, 'mozfullscreenchange:windowmanager', (ev) => this._onFullscreen(ev)); + Events.$bind(window, 'webkitfullscreenchange:windowmanager', (ev) => this._onFullscreen(ev)); + Events.$bind(window, 'msfullscreenchange:windowmanager', (ev) => this._onFullscreen(ev)); + Events.$bind(document.body, 'contextmenu:windowmanager', (ev) => this._onContextMenu(ev)); + Events.$bind(document.body, 'click:windowmanager', (ev) => this._onClick(ev)); + Events.$bind(document, 'keyup:windowmanager', (ev) => this._onKeyUp(ev)); + Events.$bind(document, 'keydown:windowmanager', (ev) => this._onKeyDown(ev)); + Events.$bind(document, 'keypress:windowmanager', (ev) => this._onKeyPress(ev)); + + window.onerror = this._onError.bind(this); + window.onbeforeunload = this._onBeforeUnload(this); + + const queries = this.getDefaultSetting('mediaQueries') || {}; + + let maxWidth = 0; + Object.keys(queries).forEach((q) => { + maxWidth = Math.max(maxWidth, queries[q]); + }); + this._responsiveRes = maxWidth || 800; + + this._onOrientationChange(); + this.resize(); + } + + /** + * Setup features + * + * THIS IS IMPLEMENTED IN COREWM + * + * @param {Function} cb Callback + */ + setup(cb) { + // Implement in your WM + cb(); + } + + /** + * Get a Window by name + * + * @param {String} name Window name + * + * @return {Window} + */ + getWindow(name) { + return this.getWindows().find((w) => { + return w.__name === name; + }); + } + + /** + * Add a Window + * + * @throws {Error} If invalid window is given + * + * @param {Window} w Window reference + * @param {Boolean} focus Focus the window + * + * @return {Window} The added window + */ + addWindow(w, focus) { + if ( !(w instanceof Window) ) { + console.warn('WindowManager::addWindow()', 'Got', w); + throw new TypeError('given argument was not instance of Core.Window'); + } + console.debug('WindowManager::addWindow()'); + + try { + w.init(this, w._app); + } 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 DialogWindow ) { + setTimeout(() => w._focus(), 10); + } + + return w; + } + + /** + * Remove a Window + * + * @throws {Error} If invalid window is given + * + * @param {Window} w Window reference + * + * @return {Boolean} On success + */ + removeWindow(w) { + if ( !(w instanceof Window) ) { + console.warn('WindowManager::removeWindow()', 'Got', w); + throw new TypeError('given argument was not instance of Core.Window'); + } + + const foundIndex = this._windows + .findIndex((win) => win && win._wid === w._wid); + + console.debug('WindowManager::removeWindow()', w._wid, foundIndex); + + if ( foundIndex !== -1 ) { + this._windows[foundIndex] = null; + return true; + } + return false; + } + + /** + * Set WindowManager settings + * + * OVERRIDE THIS IN YOUR WM IMPLEMENTATION + * + * @param {Object} settings JSON Settings + * @param {Boolean} force If forced, no merging will take place + * @param {Boolean} save Saves settings + * @param {Boolean} [triggerWatch=true] Trigger change event for watchers + * + * @return {Boolean} On success + */ + applySettings(settings, force, save, triggerWatch) { + settings = settings || {}; + console.debug('WindowManager::applySettings()', 'forced?', force); + + const result = force ? settings : Utils.mergeObject(this._settings.get(), settings); + this._settings.set(null, result, save, triggerWatch); + + return true; + } + + /** + * Create Window Manager self-contained CSS from this object + * + * { + * '.classname': { + * 'background-image': 'url()' + * } + * } + * + * @param {Object} styles Style object + * @param {String} [rawStyles] Raw CSS data + */ + createStylesheet(styles, rawStyles) { + this.destroyStylesheet(); + + let innerHTML = []; + Object.keys(styles).forEach((key) => { + let rules = []; + Object.keys(styles[key]).forEach((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; + } + + const style = document.createElement('style'); + style.type = 'text/css'; + style.id = 'WMGeneratedStyles'; + style.innerHTML = innerHTML; + document.getElementsByTagName('head')[0].appendChild(style); + + this._stylesheet = style; + } + + /** + * Destroy Window Manager self-contained CSS + */ + destroyStylesheet() { + if ( this._stylesheet ) { + this._stylesheet.remove(); + } + this._stylesheet = null; + } + + resize(ev, rect) { + // Implement in your WM + this._isResponsive = window.innerWidth <= 1024; + + this.onResize(ev); + } + + /** + * Whenever a window event occurs + * + * THIS IS IMPLEMENTED IN COREWM + * + * @param {String} ev Event name + * @param {Window} win Window ref + * + * @return {Boolean} + */ + eventWindow(ev, win) { + // Implement in your WM + return false; + } + + /** + * Show Settings Window (Application) + * + * THIS IS IMPLEMENTED IN COREWM + */ + showSettings() { + // Implement in your WM + } + + /** + * Toggles fullscreen for given DOM element + * @param {Node} el The element + * @param {Boolean} t Fullscreen state + */ + toggleFullscreen(el, t) { + if ( typeof t === 'boolean' ) { + triggerFullscreen(el, t); + } else { + const prev = this._$fullscreen; + if ( prev && prev !== el ) { + triggerFullscreen(prev, false); + } + triggerFullscreen(el, prev !== el); + } + + this._$fullscreen = el; + } + + ///////////////////////////////////////////////////////////////////////////// + // EVENT HANDLERS + ///////////////////////////////////////////////////////////////////////////// + + /** + * When Key Down Event received + * + * @param {Event} ev DOM Event + * @param {Window} win Active window + */ + onKeyDown(ev, win) { + // Implement in your WM + } + + /** + * When orientation of device has changed + * + * @param {Event} ev DOM Event + * @param {String} orientation Orientation string + */ + onOrientationChange(ev, orientation) { + console.info('ORIENTATION CHANGED', ev, orientation); + + document.body.setAttribute('data-orientation', orientation); + + this._onDisplayChange(); + } + + /** + * When size of the device display has been changed + * + * @param {Event} ev DOM Event + */ + onResize(ev) { + this._onDisplayChange(); + this._emit('resized'); + } + + /** + * When session has been loaded + * + * @return {Boolean} + */ + onSessionLoaded() { + if ( this._sessionLoaded ) { + return false; + } + + this._sessionLoaded = true; + return true; + } + + ///////////////////////////////////////////////////////////////////////////// + // BASE EVENT HANDLERS + ///////////////////////////////////////////////////////////////////////////// + + _onMouseEnter(ev) { + this._mouselock = true; + } + + _onMouseLeave(ev) { + const from = ev.relatedTarget || ev.toElement; + if ( !from || from.nodeName === 'HTML' ) { + this._mouselock = false; + } else { + this._mouselock = true; + } + } + + _onDisplayChange() { + this._dcTimeout = clearTimeout(this._dcTimeout); + this._dcTimeout = setTimeout(() => { + if ( !this._windows ) { + return; + } + + this.getWindows().forEach((w) => { + w._onResize(); + w._emit('resize'); + }); + }, 100); + + document.body.setAttribute('data-responsive', String(this._isResponsive)); + } + + _onOrientationChange(ev) { + let orientation = 'landscape'; + if ( window.screen && window.screen.orientation ) { + if ( window.screen.orientation.type.indexOf('portrait') !== -1 ) { + orientation = 'portrait'; + } + } + + this.onOrientationChange(ev, orientation); + } + + _onHashChange(ev) { + const hash = window.location.hash.substr(1); + const spl = hash.split(/^([\w\.\-_]+)\:(.*)/); + + function getArgs(q) { + const args = {}; + q.split('&').forEach(function(a) { + const b = a.split('='); + const k = decodeURIComponent(b[0]); + args[k] = decodeURIComponent(b[1] || ''); + }); + return args; + } + + if ( spl.length === 4 ) { + const root = spl[1]; + const args = getArgs(spl[2]); + + if ( root ) { + Process.getProcess(root).forEach(function(p) { + p._onMessage('hashchange', { + hash: hash, + args: args + }, {source: null}); + }); + } + } + } + + _onResize(ev) { + clearTimeout(this._resizeTimeout); + this._resizeTimeout = setTimeout(() => { + const space = this.getWindowSpace(); + this.resize(ev, space); + }, 100); + } + + _onScroll(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; + } + + _onFullscreen(ev) { + try { + const notif = Notification.getIcon('_FullscreenNotification'); + if ( notif ) { + if ( !document.fullScreen && !document.mozFullScreen && !document.webkitIsFullScreen && !document.msFullscreenElement ) { + notif.opts._isFullscreen = false; + notif.setImage(Theme.getIcon('actions/view-fullscreen.png', '16x16')); + } else { + notif.opts._isFullscreen = true; + notif.setImage(Theme.getIcon('actions/view-restore.png', '16x16')); + } + } + } catch ( e ) { + console.warn(e.stack, e); + } + } + + _onContextMenu(ev) { + ev.stopPropagation(); + + this.onContextMenu(ev); + if ( !DOM.$isFormElement(ev) ) { + ev.preventDefault(); + return false; + } + + return true; + } + + _onClick(ev) { + const t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + const allowed = ['GUI-MENU-BAR-ENTRY', 'GUI-MENU-ENTRY']; + if ( !t || allowed.indexOf(t.tagName) === -1 ) { + Menu.blur(); + } + + if ( t === document.body ) { + const win = this.getCurrentWindow(); + if ( win ) { + win._blur(); + } + } + + Theme.themeAction('event', [ev]); + } + + _onKeyUp(ev) { + const win = this.getCurrentWindow(); + + this.onKeyUp(ev, win); + + if ( win ) { + return win._onKeyEvent(ev, 'keyup'); + } + + return true; + } + + _onKeyDown(ev) { + const win = this.getCurrentWindow(); + + const reacted = (() => { + const combination = this.onKeyDown(ev, win); + if ( win && !combination ) { + win._onKeyEvent(ev, 'keydown'); + } + return combination; + })(); + + if ( checkPrevent(ev, win) || reacted ) { + ev.preventDefault(); + } + + return true; + } + + _onKeyPress(ev) { + if ( checkForbiddenKeyCombo(ev) ) { + ev.preventDefault(); + } + + const win = this.getCurrentWindow(); + if ( win ) { + return win._onKeyEvent(ev, 'keypress'); + } + return true; + } + + _onBeforeUnload(ev) { + if ( getConfig('ShowQuitWarning') ) { + return _('MSG_SESSION_WARNING'); + } + return null; + } + + _onError(message, url, linenumber, column, exception) { + if ( typeof exception === 'string' ) { + exception = null; + } + + exception = exception || { + name: 'window::onerror()', + fileName: url, + lineNumber: linenumber + ':' + column, + message: message + }; + + console.warn('window::onerror()', arguments); + + OSjs.error(_('ERR_JAVASCRIPT_EXCEPTION'), + _('ERR_JAVACSRIPT_EXCEPTION_DESC'), + _('BUGREPORT_MSG'), + exception, + true ); + + return false; + } + + ///////////////////////////////////////////////////////////////////////////// + // GETTERS AND SETTERS + ///////////////////////////////////////////////////////////////////////////// + + /** + * Get default Settings + * + * @return {Object} JSON Data + */ + getDefaultSetting() { + // Implement in your WM + return null; + } + + /** + * Get panel + * + * @return {OSjs.Applications.CoreWM.Panel} + */ + getPanel() { + // Implement in your WM + return null; + } + + /** + * Gets all panels + * + * @return {OSjs.Packages.CoreWM.Panel[]} Panel List + */ + getPanels() { + // Implement in your WM + return []; + } + + /** + * Sets a setting + * + * @param {String} k Key + * @param {*} v Value + * + * @return {Boolean} On success + */ + setSetting(k, v) { + return this._settings.set(k, v); + } + + /** + * Gets the rectangle for window space + * + * @return {Object} rectangle + */ + getWindowSpace() { + return { + top: 0, + left: 0, + width: document.body.offsetWidth, + height: document.body.offsetHeight + }; + } + + /** + * Get next window position + * + * @return {Object} rectangle + */ + getWindowPosition() { + const winCount = this._windows.reduce(function(count, win) { + return win === null ? count : (count + 1); + }, 0); + return {x: 10 * winCount, y: 10 * winCount}; + } + + /** + * Gets a setting + * + * @param {String} k Key + * + * @return {*} Setting value or 'null' + */ + getSetting(k) { + return this._settings.get(k); + } + + /** + * Gets all settings + * + * @return {Object} JSON With all settings + */ + getSettings() { + return this._settings.get(); + } + + /** + * Gets all Windows + * + * @return {Window[]} List of all Windows + */ + getWindows() { + return this._windows.filter((w) => !!w); + } + + /** + * Gets current Window + * + * @return {Window} Current Window or 'null' + */ + getCurrentWindow() { + return this._currentWin; + } + + /** + * Sets the current Window + * + * @param {Window} w Window + */ + setCurrentWindow(w) { + this._currentWin = w || null; + } + + /** + * Gets previous Window + * + * @return {Window} Current Window or 'null' + */ + getLastWindow() { + return this._lastWin; + } + + /** + * Sets the last Window + * + * @param {Window} w Window + */ + setLastWindow(w) { + this._lastWin = w || null; + } + + /** + * If the pointer is inside the browser window + * + * @return {Boolean} + */ + getMouseLocked() { + return this._mouselock; + } + +} + diff --git a/src/client/javascript/core/window.js b/src/client/javascript/core/window.js index e6d7cbcc55..f05f531c7c 100644 --- a/src/client/javascript/core/window.js +++ b/src/client/javascript/core/window.js @@ -27,635 +27,583 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API, GUI, Process) { - 'use strict'; - /** - * The predefined events are as follows: - *

-   *  init          When window is being inited and rendered  => (root, scheme)
-   *  inited        When window has been inited and rendered  => (scheme)
-   *  focus         When window gets focus                    => ()
-   *  blur          When window loses focus                   => ()
-   *  destroy       When window is closed                     => ()
-   *  maximize      When window is maxmimized                 => ()
-   *  minimize      When window is minimized                  => ()
-   *  restore       When window is restored                   => ()
-   *  resize        When window is resized                    => (w, h)
-   *  resized       Triggers after window is resized          => (w, h)
-   *  move          When window is moved                      => (x, y)
-   *  moved         Triggers after window is moved            => (x, y)
-   *  keydown       When keydown                              => (ev, keyCode, shiftKey, ctrlKey, altKey)
-   *  keyup         When keyup                                => (ev, keyCode, shiftKey, ctrlKey, altKey)
-   *  keypress      When keypress                             => (ev, keyCode, shiftKey, ctrlKey, altKey)
-   *  drop          When a drop event occurs                  => (ev, type, item, args, srcEl)
-   *  drop:upload   When a upload file was dropped            => (ev, , args)
-   *  drop:file     When a internal file object was dropped   => (ev, VFS.File, args, srcEl)
-   * 
- * @typedef WindowEvent - */ +import FileMetadata from 'vfs/file'; +import Application from 'core/application'; +import WindowManager from 'core/window-manager'; +import Element from 'gui/element'; +import GUIScheme from 'gui/scheme'; +import EventHandler from 'helpers/event-handler'; +import Theme from 'core/theme'; +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Events from 'utils/events'; +import * as Compability from 'utils/compability'; +import * as Keycodes from 'utils/keycodes'; +import * as Menu from 'gui/menu'; +import {_} from 'core/locales'; +import {running} from 'core/init'; + +/** + * The predefined events are as follows: + *

+ *  init          When window is being inited and rendered  => (root, scheme)
+ *  inited        When window has been inited and rendered  => (scheme)
+ *  focus         When window gets focus                    => ()
+ *  blur          When window loses focus                   => ()
+ *  destroy       When window is closed                     => ()
+ *  maximize      When window is maxmimized                 => ()
+ *  minimize      When window is minimized                  => ()
+ *  restore       When window is restored                   => ()
+ *  resize        When window is resized                    => (w, h)
+ *  resized       Triggers after window is resized          => (w, h)
+ *  move          When window is moved                      => (x, y)
+ *  moved         Triggers after window is moved            => (x, y)
+ *  keydown       When keydown                              => (ev, keyCode, shiftKey, ctrlKey, altKey)
+ *  keyup         When keyup                                => (ev, keyCode, shiftKey, ctrlKey, altKey)
+ *  keypress      When keypress                             => (ev, keyCode, shiftKey, ctrlKey, altKey)
+ *  drop          When a drop event occurs                  => (ev, type, item, args, srcEl)
+ *  drop:upload   When a upload file was dropped            => (ev, , args)
+ *  drop:file     When a internal file object was dropped   => (ev, VFS.File, args, srcEl)
+ * 
+ * @typedef WindowEvent + */ - function _noEvent(ev) { - OSjs.API.blurMenu(); - ev.preventDefault(); - ev.stopPropagation(); - return false; - } +function _noEvent(ev) { + Menu.blur(); + ev.preventDefault(); + ev.stopPropagation(); + return false; +} + +function camelCased(str) { + return str.replace(/_([a-z])/g, function(g) { + return g[1].toUpperCase(); + }); +} + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +/* + * Get next z-index for Window + * @return integer + */ +const getNextZindex = (function() { + let _lzindex = 1; + let _ltzindex = 100000; - function camelCased(str) { - return str.replace(/_([a-z])/g, function(g) { - return g[1].toUpperCase(); - }); + return function(ontop) { + if ( typeof ontop !== 'undefined' && ontop === true ) { + return (_ltzindex += 2); + } + return (_lzindex += 2); + }; +})(); + +/* + * Get viewport (Wrapper) + * + * @return {Object} + */ +function getWindowSpace() { + const wm = WindowManager.instance; + if ( wm ) { + return wm.getWindowSpace(); } - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// + return { + top: 0, + left: 0, + width: document.body.offsetWidth, + height: document.body.offsetHeight + }; +} - /* - * Get next z-index for Window - * @return integer - */ - var getNextZindex = (function() { - var _lzindex = 1; - var _ltzindex = 100000; +/* + * Wrapper to wait for animations to finish + */ +function waitForAnimation(win, cb) { + const wm = WindowManager.instance; + const anim = wm ? wm.getSetting('animations') : false; + if ( anim ) { + win._animationCallback = cb; + } else { + cb(); + } +} - return function(ontop) { - if ( typeof ontop !== 'undefined' && ontop === true ) { - return (_ltzindex += 2); - } - return (_lzindex += 2); - }; - })(); +/* + * Creates media queries from configuration file + */ +const createMediaQueries = (function() { + let queries; - /* - * Get viewport (Wrapper) - * - * @return {Object} - * @api OSjs.API.getWindowSpace() - */ - function getWindowSpace() { - var wm = OSjs.Core.getWindowManager(); + function _createQueries() { + let result = {}; + + const wm = WindowManager.instance; if ( wm ) { - return wm.getWindowSpace(); + const qs = wm.getDefaultSetting('mediaQueries') || {}; + + Object.keys(qs).forEach(function(k) { + if ( qs[k] ) { + result[k] = function(w, h, ref) { + return w <= qs[k]; + }; + } + }); } - return Utils.getRect(); + + return result; } - /* - * Wrapper to wait for animations to finish - */ - function waitForAnimation(win, cb) { - var wm = OSjs.Core.getWindowManager(); - var anim = wm ? wm.getSetting('animations') : false; - if ( anim ) { - win._animationCallback = cb; - } else { - cb(); + return function() { + if ( !queries ) { + queries = _createQueries(); } - } + return queries; + }; +})(); - /* - * Creates media queries from configuration file - */ - var createMediaQueries = (function() { - var queries; +/* + * Checks window dimensions and makes media queries dynamic + */ +function checkMediaQueries(win) { + const wm = WindowManager.instance; + if ( !win._$element || !wm ) { + return; + } - function _createQueries() { - var result = {}; + let n = ''; + let k; - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - var qs = wm.getDefaultSetting('mediaQueries') || {}; + const qs = win._properties.media_queries || {}; + const w = win._$element.offsetWidth; + const h = win._$element.offsetHeight; - Object.keys(qs).forEach(function(k) { - if ( qs[k] ) { - result[k] = function(w, h, ref) { - return w <= qs[k]; - }; - } - }); + for ( k in qs ) { + if ( qs.hasOwnProperty(k) ) { + if ( qs[k](w, h, win) ) { + n = k; + break; } - - return result; - } - - return function() { - if ( !queries ) { - queries = _createQueries(); - } - return queries; - }; - })(); - - /* - * Checks window dimensions and makes media queries dynamic - */ - function checkMediaQueries(win) { - var wm = OSjs.Core.getWindowManager(); - if ( !win._$element || !wm ) { - return; } + } - var n = ''; - var qs = win._properties.media_queries || {}; - var w = win._$element.offsetWidth; - var h = win._$element.offsetHeight; - var k; + win._$element.setAttribute('data-media', n); +} - for ( k in qs ) { - if ( qs.hasOwnProperty(k) ) { - if ( qs[k](w, h, win) ) { - n = k; - break; - } - } - } +///////////////////////////////////////////////////////////////////////////// +// WINDOW +///////////////////////////////////////////////////////////////////////////// - win._$element.setAttribute('data-media', n); - } +let _WID = 0; +let _DEFAULT_WIDTH = 200; +let _DEFAULT_HEIGHT = 200; +let _DEFAULT_MIN_HEIGHT = 150; +let _DEFAULT_MIN_WIDTH = 150; +let _DEFAULT_SND_VOLUME = 1.0; +let _NAMES = []; - ///////////////////////////////////////////////////////////////////////////// - // WINDOW - ///////////////////////////////////////////////////////////////////////////// +/** + * Base Window Class + * + * @desc Class used for creating windows. + * + * @abstract + * @mixes EventHandler + * @throws {Error} On invalid arguments + */ +export default class Window { /** - * Window Class - * - * @summary Class used for basis as a Window. - * - * @param {String} name Window name (unique) - * @param {Object} opts List of options - * @param {String} opts.title Window Title - * @param {String} opts.icon Window Icon - * @param {Number} [opts.x] X Position - * @param {Number} [opts.y] Y Position - * @param {Number} [opts.w] Width - * @param {Number} [opts.h] Height - * @param {String} [opts.tag] Window Tag - * @param {String} [opts.gravity] Window Gravity - * @param {boolean} [opts.allow_move] Allow movment - * @param {boolean} [opts.allow_resize] Allow resize - * @param {boolean} [opts.allow_minimize] Allow minimize - * @param {boolean} [opts.allow_maximize] Allow maximize - * @param {boolean} [opts.allow_close] Allow closing - * @param {boolean} [opts.allow_windowlist] Allow appear in WindowList (Panel) - * @param {boolean} [opts.allow_drop] Allow DnD - * @param {boolean} [opts.allow_iconmenu] Allow Menu when click on Window Icon - * @param {boolean} [opts.allow_ontop] Allow ontop - * @param {boolean} [opts.allow_hotkeys] Allow usage of hotkeys - * @param {boolean} [opts.allow_session] Allow to store for session - * @param {boolean} [opts.key_capture] Allow key capture (UNSUSED ?!) - * @param {boolean} [opts.min_width] Minimum allowed width - * @param {boolean} [opts.min_height] Minimum allowed height - * @param {boolean} [opts.max_width] Maximum allowed width - * @param {boolean} [opts.max_height] Maximum allowed height - * @param {Object} [opts.media_queries] Media queries to apply CSS attribute => {name: fn(w,h,win) => Boolean } - * @param {String} [opts.sound] Sound name when window is displayed - * @param {Number} [opts.sound_volume] Sound volume - * @param {Function} [opts.translator] Translation method - * @param {OSjs.Core.Application} appRef Application Reference - * @param {OSjs.GUI.Scheme} schemeRef GUI Scheme Reference - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @mixes OSjs.Helpers.EventHandler - * @throws {Error} On invalid arguments + * @param {String} name Window name (unique) + * @param {Object} opts List of options + * @param {String} opts.title Window Title + * @param {String} opts.icon Window Icon + * @param {Number} [opts.x] X Position + * @param {Number} [opts.y] Y Position + * @param {Number} [opts.width] Width + * @param {Number} [opts.height] Height + * @param {String} [opts.tag] Window Tag + * @param {String} [opts.gravity] Window Gravity + * @param {boolean} [opts.auto_size=false] Window automatically fills to content on init + * @param {boolean} [opts.allow_move] Allow movment + * @param {boolean} [opts.allow_resize] Allow resize + * @param {boolean} [opts.allow_minimize] Allow minimize + * @param {boolean} [opts.allow_maximize] Allow maximize + * @param {boolean} [opts.allow_close] Allow closing + * @param {boolean} [opts.allow_windowlist] Allow appear in WindowList (Panel) + * @param {boolean} [opts.allow_drop] Allow DnD + * @param {boolean} [opts.allow_iconmenu] Allow Menu when click on Window Icon + * @param {boolean} [opts.allow_ontop] Allow ontop + * @param {boolean} [opts.allow_hotkeys] Allow usage of hotkeys + * @param {boolean} [opts.allow_session] Allow to store for session + * @param {boolean} [opts.key_capture] Allow key capture (UNSUSED ?!) + * @param {boolean} [opts.min_width] Minimum allowed width + * @param {boolean} [opts.min_height] Minimum allowed height + * @param {boolean} [opts.max_width] Maximum allowed width + * @param {boolean} [opts.max_height] Maximum allowed height + * @param {Object} [opts.media_queries] Media queries to apply CSS attribute => {name: fn(w,h,win) => Boolean } + * @param {String} [opts.sound] Sound name when window is displayed + * @param {Number} [opts.sound_volume] Sound volume + * @param {Function} [opts.translator] Translation method + * @param {Application} appRef Application Reference */ - 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)); - } + constructor(name, opts, appRef) { + + if ( _NAMES.indexOf(name) >= 0 ) { + throw new Error(_('ERR_WIN_DUPLICATE_FMT', name)); + } + + if ( appRef && !(appRef instanceof Application) ) { + throw new TypeError('appRef given was not instance of Application'); + } + + opts = Object.assign({}, { + icon: Theme.getIcon('apps/preferences-system-windows.png'), + width: _DEFAULT_WIDTH, + height: _DEFAULT_HEIGHT, + title: name, + tag: name, + auto_size: false + }, opts); + + console.group('Window::constructor()', _WID, arguments); + + /** + * The outer container + * @type {Node} + */ + this._$element = null; + + /** + * The inner (content) container + * @type {Node} + */ + this._$root = null; + + /** + * The top container + * @type {Node} + */ + this._$top = null; + + /** + * The icon element + * @type {Node} + */ + this._$winicon = null; + + /** + * The loading overlay + * @type {Node} + */ + this._$loading = null; + + /** + * The disabled overlay + * @type {Node} + */ + this._$disabled = null; + + /** + * The resize underlay + * @type {Node} + */ + this._$resize = null; + + /** + * The warning overlay + * @type {Node} + */ + this._$warning = null; + + /** + * Constructor options copy + * @type {Object} + */ + this._opts = opts; + + /** + * Application reference + * @type {Application} + */ + this._app = appRef || null; + + /** + * If Window has been destroyed + * @type {Boolean} + */ + this._destroyed = false; + + /** + * If Window was restored + * @type {Boolean} + */ + this._restored = false; + + /** + * If Window is finished loading + * @type {Boolean} + */ + this._loaded = false; + + /** + * If Window is finished initing + * @type {Boolean} + */ + this._initialized = false; + + /** + * If Window is currently disabled + * @type {Boolean} + */ + this._disabled = true; + + /** + * If Window is currently loading + * @type {Boolean} + */ + this._loading = false; + + /** + * Window ID (Internal) + * @type {Number} + */ + this._wid = _WID; + + /** + * Window Icon + * @type {String} + */ + this._icon = opts.icon; + + /** + * Window Name + * @type {String} + */ + this._name = name; + + /** + * Window Title + * @type {String} + */ + this._title = opts.title; + + /** + * Window Tag (ex. Use this when you have a group of windows) + * @type {String} + */ + this._tag = opts.tag; + + /** + * Window Position With x and y + * @type {Object} + */ + this._position = {x: opts.x, y: opts.y}; + + /** + * Window Dimension With w and h + * @type {Object} + */ + this._dimension = {w: opts.width, h: opts.height}; + + /** + * Children + * @return {Window[]} + */ + this._children = []; - if ( appRef && !(appRef instanceof OSjs.Core.Application) ) { - throw new TypeError('appRef given was not instance of Core.Application'); - } + /** + * Parent + * @type {Window} + */ + this._parent = null; + + /** + * Original Window title (The one set on construct) + * @type {String} + */ + this._origtitle = this._title; + + /** + * Last dimension (before window movement) + * @type {Object} + */ + this._lastDimension = this._dimension; + + /** + * Last position (before window movement) + * @type {Object} + */ + this._lastPosition = this._position; + + /** + * The sound this window makes when it is created + * @type {String} + */ + this._sound = null; + + /** + * The volume of the window sound + * @type {Number} Between 0.0 and 1.0 + */ + this._soundVolume = _DEFAULT_SND_VOLUME; + + /** + * The active GUI Scheme + * @type {GUIScheme} + */ + this._scheme = null; - if ( schemeRef && !(schemeRef instanceof OSjs.GUI.Scheme) ) { - throw new TypeError('schemeRef given was not instance of GUI.Scheme'); - } + /** + * Window Properties + * @type {Object} + */ + 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() + }; - opts = Utils.argumentDefaults(opts, { - icon: API.getThemeResource('wm.png', 'wm'), - width: _DEFAULT_WIDTH, - height: _DEFAULT_HEIGHT, - title: name, - tag: name - }); + /** + * Window State + * @type {Object} + */ + this._state = { + focused: false, + modal: false, + minimized: false, + maximized: false, + ontop: false, + onbottom: false + }; - console.group('Window::constructor()', _WID, arguments); - - /** - * The outer container - * @name _$element - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$element = null; - - /** - * The inner (content) container - * @name _$root - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$root = null; - - /** - * The top container - * @name _$top - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$top = null; - - /** - * The icon element - * @name _$winicon - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$winicon = null; - - /** - * The loading overlay - * @name _$loading - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$loading = null; - - /** - * The disabled overlay - * @name _$disabled - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$disabled = null; - - /** - * The resize underlay - * @name _$resize - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$resize = null; - - /** - * The warning overlay - * @name _$warning - * @memberof OSjs.Core.Window# - * @type {Node} - */ - this._$warning = null; - - /** - * Constructor options copy - * @name _opts - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._opts = opts; - - /** - * Application reference - * @name _app - * @memberof OSjs.Core.Window# - * @type {OSjs.Core.Application} - */ - this._app = appRef || null; - - /** - * Scheme reference - * @name _scheme - * @memberof OSjs.Core.Window# - * @type {OSjs.GUI.Scheme} - */ - this._scheme = schemeRef || null; - - /** - * If Window has been destroyed - * @name _destroyed - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._destroyed = false; - - /** - * If Window was restored - * @name _restored - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._restored = false; - - /** - * If Window is finished loading - * @name _loaded - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._loaded = false; - - /** - * If Window is finished initing - * @name _initialized - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._initialized = false; - - /** - * If Window is currently disabled - * @name _disabled - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._disabled = true; - - /** - * If Window is currently loading - * @name _loading - * @memberof OSjs.Core.Window# - * @type {Boolean} - */ - this._loading = false; - - /** - * Window ID (Internal) - * @name _wid - * @memberof OSjs.Core.Window# - * @type {Number} - */ - this._wid = _WID; - - /** - * Window Icon - * @name _icon - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._icon = opts.icon; - - /** - * Window Name - * @name _name - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._name = name; - - /** - * Window Title - * @name _title - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._title = opts.title; - - /** - * Window Tag (ex. Use this when you have a group of windows) - * @name _title - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._tag = opts.tag; - - /** - * Window Position With x and y - * @name _position - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._position = {x: opts.x, y: opts.y}; - - /** - * Window Dimension With w and h - * @name _dimension - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._dimension = {w: opts.width, h: opts.height}; - - /** - * Children - * @name _children - * @memberof OSjs.Core.Window# - * @return {OSjs.Core.Window[]} - */ - this._children = []; - - /** - * Parent - * @name _parent - * @memberof OSjs.Core.Window# - * @type {OSjs.Core.Window} - */ - this._parent = null; + this._animationCallback = null; - /** - * Original Window title (The one set on construct) - * @name _origtitle - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._origtitle = this._title; - - /** - * Last dimension (before window movement) - * @name _lastDimension - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._lastDimension = this._dimension; - - /** - * Last position (before window movement) - * @name _lastPosition - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._lastPosition = this._position; - - /** - * The sound this window makes when it is created - * @name _sound - * @memberof OSjs.Core.Window# - * @type {String} - */ - this._sound = null; - - /** - * The volume of the window sound - * @name _soundVolume - * @memberof OSjs.Core.Window# - * @type {Number} Between 0.0 and 1.0 - */ - this._soundVolume = _DEFAULT_SND_VOLUME; - - /** - * Window Properties - * @name _properties - * @memberof OSjs.Core.Window# - * @type {Object} - */ - 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() - }; - - /** - * Window State - * @name _state - * @memberof OSjs.Core.Window# - * @type {Object} - */ - this._state = { - focused: false, - modal: false, - minimized: false, - maximized: false, - ontop: false, - onbottom: false - }; - - this._translator = null; - this._animationCallback = null; - - // - // Internals - // - - 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' - ]); - - // - // Inherit properties given in arguments - // - - 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]; - } - }); + // + // Internals + // - // - // Make sure that properties are correct according to requested arguments - // + this._queryTimer = null; - (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}; + this._evHandler = new EventHandler(name, [ + 'focus', 'blur', 'destroy', 'maximize', 'minimize', 'restore', + 'move', 'moved', 'resize', 'resized', + 'keydown', 'keyup', 'keypress', + 'drop', 'drop:upload', 'drop:file' + ]); - position.x = np.x; - position.y = np.y; - } - })(this._properties, this._position); + // + // Inherit properties given in arguments + // - (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; - } + Object.keys(opts).forEach((k) => { + if ( typeof this._properties[k] !== 'undefined' ) { + this._properties[k] = opts[k]; + } else if ( typeof this._state[k] !== 'undefined' && k !== 'focused' ) { + this._state[k] = opts[k]; + } else if ( ('sound', 'sound_volume').indexOf(k) !== -1 ) { + this['_' + camelCased(k)] = opts[k]; + } + }); + + // + // Make sure that properties are correct according to requested arguments + // + + ((properties, position) => { + if ( !properties.gravity && (typeof position.x === 'undefined') || (typeof position.y === 'undefined') ) { + const wm = WindowManager.instance; + const np = wm ? wm.getWindowPosition() : {x: 0, y: 0}; - console.info('RESTORED FROM SESSION', restore); - self._restored = true; + position.x = np.x; + position.y = np.y; + } + })(this._properties, this._position); + + ((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); + + ((position, dimension) => { + if ( appRef && appRef.__args && appRef.__args.__windows__ ) { + appRef.__args.__windows__.forEach((restore) => { + if ( !this._restored && restore.name && restore.name === this._name ) { + position.x = restore.position.x; + position.y = restore.position.y; + if ( this._properties.allow_resize ) { + dimension.w = restore.dimension.w; + dimension.h = restore.dimension.h; } - }); - } - })(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); + + console.info('RESTORED FROM SESSION', restore); + this._restored = true; + } + }); + } + })(this._position, this._dimension); + + ((properties, position, dimension, restored) => { + const grav = properties.gravity; + if ( grav && !restored ) { + if ( grav === 'center' ) { + position.y = (window.innerHeight / 2) - (this._dimension.h / 2); + position.x = (window.innerWidth / 2) - (this._dimension.w / 2); + } else { + const space = getWindowSpace(); + if ( grav.match(/^south/) ) { + position.y = space.height - dimension.h; } 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; - } + 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); + } + })(this._properties, this._position, this._dimension, this._restored); - console.debug('State', this._state); - console.debug('Properties', this._properties); - console.debug('Position', this._position); - console.debug('Dimension', this._dimension); - console.groupEnd(); + console.debug('State', this._state); + console.debug('Properties', this._properties); + console.debug('Position', this._position); + console.debug('Dimension', this._dimension); + console.groupEnd(); - _WID++; - }; - })(); + _WID++; + } /** * Initialize the Window @@ -664,28 +612,22 @@ * If you are looking for move/resize events, they are located in * the WindowManager. * - * @function init - * @memberof OSjs.Core.Window# - * - * @param {OSjs.Core.WindowManager} _wm Window Manager reference - * @param {OSjs.Core.Application} _app Application reference - * @param {OSjs.GUI.Scheme} _scheme UIScheme reference + * @param {WindowManager} _wm Window Manager reference + * @param {Application} _app Application reference * * @return {Node} The Window DOM element */ - Window.prototype.init = function(_wm, _app, _scheme) { - var self = this; - + init(_wm, _app) { if ( this._initialized || this._loaded ) { return this._$root; } // Create DOM - this._$element = Utils.$create('application-window', { - className: (function(n, t) { - var classNames = ['Window', Utils.$safeName(n)]; + this._$element = DOM.$create('application-window', { + className: ((n, t) => { + const classNames = ['Window', DOM.$safeName(n)]; if ( t && (n !== t) ) { - classNames.push(Utils.$safeName(t)); + classNames.push(DOM.$safeName(t)); } return classNames; })(this._name, this._tag).join(' '), @@ -713,10 +655,10 @@ 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'); + ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'].forEach((i) => { + let h = document.createElement('application-window-resize-handle'); h.setAttribute('data-direction', i); - self._$resize.appendChild(h); + this._$resize.appendChild(h); h = null; }); @@ -728,100 +670,100 @@ this._$winicon.setAttribute('aria-haspopup', 'true'); this._$winicon.setAttribute('aria-label', 'Window Menu'); - var windowTitle = document.createElement('application-window-title'); + const windowTitle = document.createElement('application-window-title'); windowTitle.setAttribute('role', 'heading'); // Bind events - Utils.$bind(this._$loading, 'mousedown', _noEvent); - Utils.$bind(this._$disabled, 'mousedown', _noEvent); + Events.$bind(this._$loading, 'mousedown', _noEvent); + Events.$bind(this._$disabled, 'mousedown', _noEvent); - var preventTimeout; - function _onanimationend(ev) { - if ( typeof self._animationCallback === 'function') { + let preventTimeout; + const _onanimationend = (ev) => { + if ( typeof this._animationCallback === 'function') { clearTimeout(preventTimeout); - preventTimeout = setTimeout(function() { - self._animationCallback(ev); - self._animationCallback = false; + preventTimeout = setTimeout(() => { + this._animationCallback(ev); + this._animationCallback = false; preventTimeout = clearTimeout(preventTimeout); }, 10); } - } + }; - Utils.$bind(this._$element, 'transitionend', _onanimationend); - Utils.$bind(this._$element, 'animationend', _onanimationend); + Events.$bind(this._$element, 'transitionend', _onanimationend); + Events.$bind(this._$element, 'animationend', _onanimationend); - Utils.$bind(this._$element, 'mousedown', function(ev) { - self._focus(); + Events.$bind(this._$element, 'mousedown', (ev) => { + this._focus(); }); - Utils.$bind(this._$element, 'contextmenu', function(ev) { - var r = Utils.$isFormElement(ev); + Events.$bind(this._$element, 'contextmenu', (ev) => { + const r = DOM.$isFormElement(ev); if ( !r ) { ev.preventDefault(); ev.stopPropagation(); } - OSjs.API.blurMenu(); + Menu.blur(); return !!r; }); - Utils.$bind(this._$top, 'click', function(ev) { - var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + Events.$bind(this._$top, 'click', (ev) => { + const 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')); + this._onWindowButtonClick(ev, t, t.getAttribute('data-action')); } else if ( t.tagName === 'APPLICATION-WINDOW-ICON' ) { ev.stopPropagation(); - self._onWindowIconClick(ev, t); + this._onWindowIconClick(ev, t); } } }, true); - Utils.$bind(windowTitle, 'mousedown', _noEvent); - Utils.$bind(windowTitle, 'dblclick', function() { - self._maximize(); + Events.$bind(windowTitle, 'mousedown', _noEvent); + Events.$bind(windowTitle, 'dblclick', () => { + this._maximize(); }); - (function _initDnD(properties, main, compability) { + ((properties, main, compability) => { if ( properties.allow_drop && compability.dnd ) { - var border = document.createElement('div'); + const border = document.createElement('div'); border.className = 'WindowDropRect'; - OSjs.GUI.Helpers.createDroppable(main, { - onOver: function(ev, el, args) { + GUI.createDroppable(main, { + onOver: (ev, el, args) => { main.setAttribute('data-dnd-state', 'true'); }, - onLeave: function() { + onLeave: () => { main.setAttribute('data-dnd-state', 'false'); }, - onDrop: function() { + onDrop: () => { main.setAttribute('data-dnd-state', 'false'); }, - onItemDropped: function(ev, el, item, args) { + onItemDropped: (ev, el, item, args) => { main.setAttribute('data-dnd-state', 'false'); - return self._onDndEvent(ev, 'itemDrop', item, args, el); + return this._onDndEvent(ev, 'itemDrop', item, args, el); }, - onFilesDropped: function(ev, el, files, args) { + onFilesDropped: (ev, el, files, args) => { main.setAttribute('data-dnd-state', 'false'); - return self._onDndEvent(ev, 'filesDrop', files, args, el); + return this._onDndEvent(ev, 'filesDrop', files, args, el); } }); } - })(this._properties, this._$element, Utils.getCompability()); + })(this._properties, this._$element, Compability.getCompability()); // Append to DOM windowTitle.appendChild(document.createTextNode(this._title)); this._$top.appendChild(this._$winicon); this._$top.appendChild(windowTitle); - this._$top.appendChild(Utils.$create('application-window-button-minimize', { + this._$top.appendChild(DOM.$create('application-window-button-minimize', { className: 'application-window-button-entry', data: { action: 'minimize' @@ -832,7 +774,7 @@ } })); - this._$top.appendChild(Utils.$create('application-window-button-maximize', { + this._$top.appendChild(DOM.$create('application-window-button-maximize', { className: 'application-window-button-entry', data: { action: 'maximize' @@ -843,7 +785,7 @@ } })); - this._$top.appendChild(Utils.$create('application-window-button-close', { + this._$top.appendChild(DOM.$create('application-window-button-close', { className: 'application-window-button-entry', data: { action: 'close' @@ -859,32 +801,30 @@ this._$element.appendChild(this._$root); this._$element.appendChild(this._$resize); this._$element.appendChild(this._$disabled); + this._$element.appendChild(this._$loading); document.body.appendChild(this._$element); // Final stuff this._onChange('create'); this._toggleLoading(false); this._toggleDisabled(false); - this._setIcon(API.getIcon(this._icon, null, this._app)); + this._setIcon(Theme.getIcon(this._icon)); this._updateMarkup(); if ( this._sound ) { - API.playSound(this._sound, this._soundVolume); + Theme.playSound(this._sound, this._soundVolume); } this._initialized = true; - this._emit('init', [this._$root, _scheme]); + this._emit('init', [this._$root]); return this._$root; - }; + } /** * When window is rendered and inited - * - * @function _inited - * @memberof OSjs.Core.Window# */ - Window.prototype._inited = function() { + _inited() { if ( this._loaded ) { return; } @@ -898,12 +838,30 @@ this._maximize(true); } else if ( this._state.minimized ) { this._minimize(true); + } else { + if ( this._opts.auto_size ) { + let maxWidth = 0; + let maxHeight = 0; + + const traverseTree = (el) => { + el.children.forEach((sel) => { + maxWidth = Math.max(maxWidth, sel.offsetWidth); + maxHeight = Math.max(maxHeight, sel.offsetHeight); + if ( sel.children.length ) { + traverseTree(sel); + } + }); + }; + + traverseTree(this._$root); + + this._resize(maxWidth, maxHeight, true); + } } } - var self = this; - var inittimeout = setTimeout(function() { - self._emit('inited', [self._scheme]); + let inittimeout = setTimeout(() => { + this._emit('inited', []); inittimeout = clearTimeout(inittimeout); }, 10); @@ -912,21 +870,16 @@ } console.debug('Window::_inited()', this._name); - }; + } /** * Destroy the Window * * @param {Boolean} shutdown If the action came from a shutdown procedure * - * @function destroy - * @memberof OSjs.Core.Window# - * * @return Boolean */ - Window.prototype.destroy = function(shutdown) { - var self = this; - + destroy(shutdown) { if ( this._destroyed ) { return false; } @@ -935,88 +888,88 @@ this._destroyed = true; - var wm = OSjs.Core.getWindowManager(); + const wm = WindowManager.instance; console.group('Window::destroy()'); // Nulls out stuff - 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); - } + const _removeDOM = () => { + this._setWarning(null); + + this._$root = null; + this._$top = null; + this._$winicon = null; + this._$loading = null; + this._$disabled = null; + this._$resize = null; + this._$warning = null; + this._$element = DOM.$remove(this._$element); + }; // Removed DOM elements and their referring objects (GUI Elements etc) - function _destroyDOM() { - if ( self._$element ) { + const _destroyDOM = () => { + if ( this._$element ) { // Make sure to remove any remaining event listeners - self._$element.querySelectorAll('*').forEach(function(iter) { + this._$element.querySelectorAll('*').forEach((iter) => { if ( iter ) { - Utils.$unbind(iter); + Events.$unbind(iter); } }); } - if ( self._parent ) { - self._parent._removeChild(self); + if ( this._parent ) { + this._parent._removeChild(this); } - self._parent = null; - self._removeChildren(); - } + this._parent = null; + this._removeChildren(); + }; // Destroys the window - function _destroyWin() { + const _destroyWin = () => { if ( wm ) { - wm.removeWindow(self); + wm.removeWindow(this); } - var curWin = wm ? wm.getCurrentWindow() : null; - if ( curWin && curWin._wid === self._wid ) { + const curWin = wm ? wm.getCurrentWindow() : null; + if ( curWin && curWin._wid === this._wid ) { wm.setCurrentWindow(null); } - var lastWin = wm ? wm.getLastWindow() : null; - if ( lastWin && lastWin._wid === self._wid ) { + const lastWin = wm ? wm.getLastWindow() : null; + if ( lastWin && lastWin._wid === this._wid ) { wm.setLastWindow(null); } - } + }; - function _animateClose(fn) { - if ( API.isShuttingDown() ) { + const _animateClose = (fn) => { + if ( !running() ) { fn(); } else { - if ( self._$element ) { - var anim = wm ? wm.getSetting('animations') : false; + if ( this._$element ) { + const anim = wm ? wm.getSetting('animations') : false; if ( anim ) { - self._$element.setAttribute('data-hint', 'closing'); - self._animationCallback = fn; + this._$element.setAttribute('data-hint', 'closing'); + this._animationCallback = fn; // This prevents windows from sticking when shutting down. // In some cases this would happen when you remove the stylesheet // with animation properties attached. - var animatetimeout = setTimeout(function() { - if ( self._animationCallback ) { - self._animationCallback(); + let animatetimeout = setTimeout(() => { + if ( this._animationCallback ) { + this._animationCallback(); } animatetimeout = clearTimeout(animatetimeout); }, 1000); } else { - self._$element.style.display = 'none'; + this._$element.style.display = 'none'; fn(); } } } - } + }; this._onChange('close'); - _animateClose(function() { + _animateClose(() => { _removeDOM(); }); _destroyDOM(); @@ -1031,16 +984,16 @@ this._evHandler.destroy(); } - this._scheme = null; this._app = null; this._evHandler = null; this._args = {}; this._queryTimer = clearTimeout(this._queryTimer); + this._scheme = this._scheme ? this._scheme.destroy() : null; console.groupEnd(); return true; - }; + } // // GUI And Event Hooks @@ -1049,78 +1002,76 @@ /** * Finds a GUI Element by ID from Scheme. * - * @function _find - * @memberof OSjs.Core.Window# - * * @param {String} id Element ID (data-id) * @param {Node} [root] Root Node * - * @return {OSjs.GUI.Element} + * @return {GUIElement} */ - Window.prototype._find = function(id, root) { - var q = '[data-id="' + id + '"]'; + _find(id, root) { + const q = '[data-id="' + id + '"]'; return this._findByQuery(q, root); - }; + } /** * Renders a scheme into the window * * By default uses the internally assigned scheme file from preload (if any) * - * @function _render - * @memberof OSjs.Core.Window# - * * @param {String} id Scheme fragment ID - * @param {OSjs.GUI.Scheme} [scheme] Scheme reference (defaults to internal) + * @param {String|GUIScheme} scheme Scheme or HTML * @param {Node} [root] Root element (defaults to internal Node) * @param {Object} [args] Arguments to pass to parser + * @return {GUIScheme} */ - Window.prototype._render = function(id, scheme, root, args) { - scheme = scheme || this._scheme; - root = root || this._getRoot(); - args = args || {}; + _render(id, scheme, root, args) { + if ( scheme ) { + root = root || this._getRoot(); + args = args || {}; + + if ( typeof this._opts.translator === 'function' ) { + args._ = this._opts.translator; + } - if ( this._translator ) { - args._ = this._translator; + this._scheme = typeof scheme === 'string' ? GUIScheme.fromString(scheme) : scheme; } - scheme.render(this, id, root, null, null, args); - }; + if ( this._scheme instanceof GUIScheme ) { + this._scheme.render(this, id, root, null, null, args); + } else { + console.warn('Got an invalid scheme in window render()', this._scheme); + } + + return this._scheme; + } /** * Returns given DOMElement by ID * - * @function _findDOM - * @memberof OSjs.Core.Window# - * * @param {String} id Element ID (data-id) * @param {Node} [root] Root Node * * @return {Node} */ - Window.prototype._findDOM = function(id, root) { + _findDOM(id, root) { root = root || this._getRoot(); - var q = '[data-id="' + id + '"]'; + const q = '[data-id="' + id + '"]'; return root.querySelector(q); - }; + } /** * Creates a new GUI Element * - * @function _create - * @memberof OSjs.Core.Window# - * * @param {String} tagName OS.js GUI Element name * @param {Object} params Parameters * @param {Node} [parentNode] Parent Node * @param {Object} [applyArgs] New element parameters * - * @return {OSjs.GUI.Element} + * @return {GUIElement} */ - Window.prototype._create = function(tagName, params, parentNode, applyArgs) { + _create(tagName, params, parentNode, applyArgs) { parentNode = parentNode || this._getRoot(); - return GUI.Element.createInto(tagName, params, parentNode, applyArgs, this); - }; + return Element.createInto(tagName, params, parentNode, applyArgs, this); + } /** * Finds a GUI Element by ID from Scheme. @@ -1129,12 +1080,9 @@ * @param {Node} [root] Root Node * @param {Boolean} [all] Perform `querySelectorAll` * - * @function _findByQuery - * @memberof OSjs.Core.Window# - * - * @return {(Array|OSjs.GUI.Element)} + * @return {(Array|GUIElement)} */ - Window.prototype._findByQuery = function(query, root, all) { + _findByQuery(query, root, all) { root = root || this._getRoot(); if ( !(root instanceof window.Node) ) { @@ -1142,73 +1090,65 @@ } if ( all ) { - return root.querySelectorAll(query).map(function(el) { - return GUI.Element.createFromNode(el, query); + return root.querySelectorAll(query).map((el) => { + return Element.createFromNode(el, query); }); } - var el = root.querySelector(query); - return GUI.Element.createFromNode(el, query); - }; + const el = root.querySelector(query); + return Element.createFromNode(el, query); + } /** * Fire a hook to internal event - * - * @function _emit - * @memberof OSjs.Core.Window# - * @see OSjs.Helpers.EventHandler#emit + * @see EventHandler#emit * * @param {WindowEvent} k Event name * @param {Array} args Send these arguments (fn.apply) * * @return {Boolean} */ - Window.prototype._emit = function(k, args) { + _emit(k, args) { if ( !this._destroyed ) { if ( this._evHandler ) { return this._evHandler.emit(k, args); } } return false; - }; + } /** * Adds a hook to internal event - * - * @function _on - * @memberof OSjs.Core.Window# - * @see OSjs.Helpers.EventHandler#on + * @see EventHandler#on * * @param {WindowEvent} k Event name * @param {Function} func Callback function * * @return {Number} */ - Window.prototype._on = function(k, func) { + _on(k, func) { if ( this._evHandler ) { return this._evHandler.on(k, func, this); } return false; - }; + } /** * Removes a hook to internal event * - * @function _off - * @memberof OSjs.Core.Window# - * @see OSjs.Helpers.EventHandler#off + * @see EventHandler#off * * @param {WindowEvent} k Event name * @param {Number} idx The hook index returned from _on() * * @return {Boolean} */ - Window.prototype._off = function(k, idx) { + _off(k, idx) { if ( this._evHandler ) { return this._evHandler.off(k, idx); } return false; - }; + } // // Children (Windows) @@ -1217,157 +1157,120 @@ /** * Add a child-window * - * @param {OSjs.Core.Window} w Window - * @param {Boolean} [wmAdd=false] Add to window manager - * @param {Boolean} [wmFocus=false] Focus window when added + * @param {Window} w Window + * @param {Boolean} [wmAdd=false] Add to window manager + * @param {Boolean} [wmFocus=false] Focus window when added * - * @function _addChild - * @memberof OSjs.Core.Window# - * @see OSjs.Helpers.EventHandler#off + * @see EventHandler#off * - * @return {OSjs.Core.Window} The added instance + * @return {Window} The added instance */ - Window.prototype._addChild = function(w, wmAdd, wmFocus) { + _addChild(w, wmAdd, wmFocus) { console.debug('Window::_addChild()'); w._parent = this; - var wm = OSjs.Core.getWindowManager(); + const wm = WindowManager.instance; if ( wmAdd && wm ) { wm.addWindow(w, wmFocus); } this._children.push(w); return w; - }; + } /** * Removes a child Window * - * @function _removeChild - * @memberof OSjs.Core.Window# - * - * @param {OSjs.Core.Window} w Widow reference + * @param {Window} w Widow reference * * @return {Boolean} On success */ - Window.prototype._removeChild = function(w) { - var self = this; - - var found = false; - this._children.forEach(function(child, i) { + _removeChild(w) { + let found = false; + this._children.forEach((child, i) => { if ( child && child._wid === w._wid ) { console.debug('Window::_removeChild()'); child.destroy(); - self._children[i] = null; + this._children[i] = null; found = true; } }); return found; - }; + } /** * Get a Window child by X * - * @function _getChild - * @memberof OSjs.Core.Window# - * * @param {String} value Value to look for * @param {String} key Key to look for * - * @return {OSjs.Core.Window} Resulted Window or 'null' + * @return {Window} Resulted Window or 'null' */ - Window.prototype._getChild = function(value, key) { + _getChild(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; + const found = this._getChildren().filter((c) => { + return c['_' + key] === value; }); - return result; - }; + + return key === 'tag' ? found : found[0]; + } /** * Get a Window child by ID - * - * @function _getChildById - * @memberof OSjs.Core.Window# - * @see OSjs.Core.Window#_getChild + * @see Window#_getChild * * @param {Number} id Window id - * @return {OSjs.Core.Window} + * @return {Window} */ - Window.prototype._getChildById = function(id) { + _getChildById(id) { return this._getChild(id, 'wid'); - }; + } /** * Get a Window child by Name - * - * @function _getChildByName - * @memberof OSjs.Core.Window# - * @see OSjs.Core.Window#_getChild + * @see Window#_getChild * * @param {String} name Window name - * @return {OSjs.Core.Window} + * @return {Window} */ - Window.prototype._getChildByName = function(name) { + _getChildByName(name) { return this._getChild(name, 'name'); - }; + } /** * Get Window(s) child by Tag - * - * @function _getChildrenByTag - * @memberof OSjs.Core.Window# - * @see OSjs.Core.Window#_getChild + * @see Window#_getChild * * @param {String} tag Tag name * - * @return {OSjs.Core.Window[]} + * @return {Window[]} */ - Window.prototype._getChildrenByTag = function(tag) { + _getChildrenByTag(tag) { return this._getChild(tag, 'tag'); - }; + } /** * Gets all children Windows * - * @function _getChildren - * @memberof OSjs.Core.Window# - * - * @return {OSjs.Core.Window[]} + * @return {Window[]} */ - Window.prototype._getChildren = function() { - return this._children; - }; + _getChildren() { + return this._children.filter((w) => !!w); + } /** * Removes all children Windows - * - * @function _removeChildren - * @memberof OSjs.Core.Window# */ - Window.prototype._removeChildren = function() { - if ( this._children && this._children.length ) { - this._children.forEach(function(child, i) { - if ( child ) { - child.destroy(); - } - }); - } + _removeChildren() { + this._children.forEach((child, i) => { + if ( child ) { + child.destroy(); + } + }); this._children = []; - }; + } // // Actions @@ -1376,35 +1279,28 @@ /** * Close the Window * - * @function _close - * @memberof OSjs.Core.Window# - * * @return {Boolean} On succes */ - Window.prototype._close = function() { - console.debug('Window::_close()'); + _close() { if ( this._disabled || this._destroyed ) { return false; } + console.debug('Window::_close()'); this._blur(); this.destroy(); return true; - }; + } /** * Minimize the Window * - * @function _minimize - * @memberof OSjs.Core.Window# - * * @param {Boolean} [force=false] Force action * * @return {Boolean} On success */ - Window.prototype._minimize = function(force) { - var self = this; + _minimize(force) { if ( !this._properties.allow_minimize || this._destroyed ) { return false; } @@ -1421,15 +1317,15 @@ this._state.minimized = true; this._$element.setAttribute('data-minimized', 'true'); - waitForAnimation(this, function() { - self._$element.style.display = 'none'; - self._emit('minimize'); + waitForAnimation(this, () => { + this._$element.style.display = 'none'; + this._emit('minimize'); }); this._onChange('minimize'); - var wm = OSjs.Core.getWindowManager(); - var win = wm ? wm.getCurrentWindow() : null; + const wm = WindowManager.instance; + const win = wm ? wm.getCurrentWindow() : null; if ( win && win._wid === this._wid ) { wm.setCurrentWindow(null); } @@ -1437,20 +1333,16 @@ this._updateMarkup(); return true; - }; + } /** * Maximize the Window * - * @function _maximize - * @memberof OSjs.Core.Window# - * * @param {Boolean} [force=false] Force action * * @return {Boolean} On success */ - Window.prototype._maximize = function(force) { - var self = this; + _maximize(force) { if ( !this._properties.allow_maximize || this._destroyed || !this._$element ) { return false; @@ -1467,7 +1359,7 @@ this._lastDimension = {w: this._dimension.w, h: this._dimension.h}; this._state.maximized = true; - var s = this._getMaximizedSize(); + const 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'; @@ -1483,8 +1375,8 @@ this._focus(); - waitForAnimation(this, function() { - self._emit('maximize'); + waitForAnimation(this, () => { + this._emit('maximize'); }); this._onChange('maximize'); @@ -1493,40 +1385,36 @@ this._updateMarkup(); return true; - }; + } /** * Restore the Window * - * @function _restore - * @memberof OSjs.Core.Window# - * * @param {Boolean} max Revert maximize state * @param {Boolean} min Revert minimize state */ - Window.prototype._restore = function(max, min) { - var self = this; + _restore(max, min) { 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'); + const restoreMaximized = () => { + if ( max && this._state.maximized ) { + this._move(this._lastPosition.x, this._lastPosition.y); + this._resize(this._lastDimension.w, this._lastDimension.h); + this._state.maximized = false; + this._$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; + const restoreMinimized = () => { + if ( min && this._state.minimized ) { + this._$element.style.display = 'block'; + this._$element.setAttribute('data-minimized', 'false'); + this._state.minimized = false; } - } + }; console.debug(this._name, '>', 'Window::_restore()'); @@ -1536,8 +1424,8 @@ restoreMaximized(); restoreMinimized(); - waitForAnimation(this, function() { - self._emit('restore'); + waitForAnimation(this, () => { + this._emit('restore'); }); this._onChange('restore'); @@ -1546,19 +1434,16 @@ this._focus(); this._updateMarkup(); - }; + } /** * Focus the window * - * @function _focus - * @memberof OSjs.Core.Window# - * * @param {Boolean} force Forces focus * * @return {Boolean} On success */ - Window.prototype._focus = function(force) { + _focus(force) { if ( !this._$element || this._destroyed ) { return false; } @@ -1568,8 +1453,8 @@ 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; + const wm = WindowManager.instance; + const win = wm ? wm.getCurrentWindow() : null; if ( win && win._wid !== this._wid ) { win._blur(); } @@ -1580,7 +1465,7 @@ } if ( !this._state.focused || force) { - console.debug(this._name, '>', 'Window::_focus()'); + //console.debug(this._name, '>', 'Window::_focus()'); this._onChange('focus'); this._emit('focus'); } @@ -1590,24 +1475,21 @@ this._updateMarkup(); return true; - }; + } /** * Blur the window * - * @function _blur - * @memberof OSjs.Core.Window# - * * @param {Boolean} force Forces blur * * @return {Boolean} On success */ - Window.prototype._blur = function(force) { + _blur(force) { if ( !this._$element || this._destroyed || (!force && !this._state.focused) ) { return false; } - console.debug(this._name, '>', 'Window::_blur()'); + //console.debug(this._name, '>', 'Window::_blur()'); this._$element.setAttribute('data-focused', 'false'); this._state.focused = false; @@ -1618,8 +1500,8 @@ // Force all standard HTML input elements to loose focus this._blurGUI(); - var wm = OSjs.Core.getWindowManager(); - var win = wm ? wm.getCurrentWindow() : null; + const wm = WindowManager.instance; + const win = wm ? wm.getCurrentWindow() : null; if ( win && win._wid === this._wid ) { wm.setCurrentWindow(null); } @@ -1627,19 +1509,16 @@ this._updateMarkup(); return true; - }; + } /** * Blurs the GUI - * - * @function _blurGUI - * @memberof OSjs.Core.Window# */ - Window.prototype._blurGUI = function() { - this._$root.querySelectorAll('input, textarea, select, iframe, button').forEach(function(el) { + _blurGUI() { + this._$root.querySelectorAll('input, textarea, select, iframe, button').forEach((el) => { el.blur(); }); - }; + } /** * Resize Window to given size @@ -1647,9 +1526,6 @@ * Use this method if you want the window to fit into the viewport and not * just set a specific size * - * @function _resizeTo - * @memberof OSjs.Core.Window# - * * @param {Number} dw Width * @param {Number} dh Height * @param {Boolean} [limit=true] Limit to this size @@ -1657,32 +1533,31 @@ * @param {Node} [container=null] Relative to this container * @param {Boolean} [force=false] Force movment */ - Window.prototype._resizeTo = function(dw, dh, limit, move, container, force) { - var self = this; + _resizeTo(dw, dh, limit, move, container, force) { if ( !this._$element || (dw <= 0 || dh <= 0) ) { return; } limit = (typeof limit === 'undefined' || limit === true); - var dx = 0; - var dy = 0; + let dx = 0; + let dy = 0; if ( container ) { - var cpos = Utils.$position(container, this._$root); + const cpos = DOM.$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; + const space = this._getMaximizedSize(); + const cx = this._position.x + dx; + const cy = this._position.y + dy; + let newW = dw; + let newH = dh; + let newX = null; + let newY = null; - function _limitTo() { + const _limitTo = () => { if ( (cx + newW) > space.width ) { if ( move ) { newW = space.width; @@ -1699,33 +1574,33 @@ newH = space.height; newY = space.top; } else { - newH = (space.height - cy + self._$top.offsetHeight) + dy; + newH = (space.height - cy + this._$top.offsetHeight) + dy; } } else { newH += dy; } - } + }; - function _moveTo() { + const _moveTo = () => { if ( newX !== null ) { - self._move(newX, self._position.y); + this._move(newX, this._position.y); } if ( newY !== null ) { - self._move(self._position.x, newY); + this._move(this._position.x, newY); } - } + }; - function _resizeFinished() { - var wm = OSjs.Core.getWindowManager(); - var anim = wm ? wm.getSetting('animations') : false; + const _resizeFinished = () => { + const wm = WindowManager.instance; + const anim = wm ? wm.getSetting('animations') : false; if ( anim ) { - self._animationCallback = function Window_animationCallback() { - self._emit('resized'); + this._animationCallback = () => { + this._emit('resized'); }; } else { - self._emit('resized'); + this._emit('resized'); } - } + }; if ( limit ) { _limitTo(); @@ -1735,52 +1610,31 @@ _moveTo(); _resizeFinished(); - }; + } - // TODO: Optimize - Window.prototype._resize = function(w, h, force) { - if ( !this._$element || this._destroyed ) { + _resize(w, h, force) { + const p = this._properties; + if ( !this._$element || this._destroyed || (!force && !p.allow_resize) ) { 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; - } - } + const getNewSize = (n, min, max) => { + if ( !isNaN(n) && n ) { + n = Math.max(n, min); + if ( max !== null ) { + n = Math.min(n, max); } - })(); - } + } + return n; + }; + w = force ? w : getNewSize(w, p.min_width, p.max_width); if ( !isNaN(w) && w ) { this._$element.style.width = w + 'px'; this._dimension.w = w; } + h = force ? h : getNewSize(h, p.min_height, p.max_height); if ( !isNaN(h) && h ) { this._$element.style.height = h + 'px'; this._dimension.h = h; @@ -1789,25 +1643,22 @@ this._onResize(); return true; - }; + } /** * Move window to position * - * @function _moveTo - * @memberof OSjs.Core.Window# - * * @param {Object} pos Position rectangle */ - Window.prototype._moveTo = function(pos) { - var wm = OSjs.Core.getWindowManager(); + _moveTo(pos) { + const wm = WindowManager.instance; if ( !wm ) { return; } - var s = wm.getWindowSpace(); - var cx = this._position.x; - var cy = this._position.y; + const s = wm.getWindowSpace(); + const cx = this._position.x; + const cy = this._position.y; if ( pos === 'left' ) { this._move(s.left, cy); @@ -1818,20 +1669,17 @@ } else if ( pos === 'bottom' ) { this._move(cx, (s.height - this._dimension.h)); } - }; + } /** * Move window to position * - * @function _move - * @memberof OSjs.Core.Window# - * * @param {Number} x X Position * @param {Number} y Y Position * * @return {Boolean} On success */ - Window.prototype._move = function(x, y) { + _move(x, y) { if ( !this._$element || this._destroyed || !this._properties.allow_move ) { return false; } @@ -1846,18 +1694,15 @@ this._position.y = y; return true; - }; + } /** * Toggle disabled overlay * - * @function _toggleDisabled - * @memberof OSjs.Core.Window# - * * @param {Boolean} t Toggle */ - Window.prototype._toggleDisabled = function(t) { - console.debug(this._name, '>', 'Window::_toggleDisabled()', t); + _toggleDisabled(t) { + //console.debug(this._name, '>', 'Window::_toggleDisabled()', t); if ( this._$disabled ) { this._$disabled.style.display = t ? 'block' : 'none'; } @@ -1865,18 +1710,15 @@ this._disabled = t ? true : false; this._updateMarkup(); - }; + } /** * Toggle loading overlay * - * @function _toggleLoading - * @memberof OSjs.Core.Window# - * * @param {Boolean} t Toggle */ - Window.prototype._toggleLoading = function(t) { - console.debug(this._name, '>', 'Window::_toggleLoading()', t); + _toggleLoading(t) { + //console.debug(this._name, '>', 'Window::_toggleLoading()', t); if ( this._$loading ) { this._$loading.style.display = t ? 'block' : 'none'; } @@ -1884,25 +1726,22 @@ this._loading = t ? true : false; this._updateMarkup(); - }; + } /** * Updates window markup with attributes etc * * @param {Boolean} [ui=false] If action came from UI - * - * @function _updateMarkup - * @memberof OSjs.Core.Window# */ - Window.prototype._updateMarkup = function(ui) { + _updateMarkup(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; + const t = this._loading || this._disabled; + const d = this._disabled; + const h = this._state.minimized; + const f = !this._state.focused; this._$element.setAttribute('aria-busy', String(t)); this._$element.setAttribute('aria-hidden', String(h)); @@ -1913,73 +1752,66 @@ 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'; + const dmax = this._properties.allow_maximize === true ? 'inline-block' : 'none'; + const dmin = this._properties.allow_minimize === true ? 'inline-block' : 'none'; + const 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; + const dres = this._properties.allow_resize === true; this._$element.setAttribute('data-allow-resize', String(dres)); - }; + } /** * Toggle attention * - * @function _toggleAttentionBlink - * @memberof OSjs.Core.Window# - * * @param {Boolean} t Toggle * * @return {Boolean} If activated */ - Window.prototype._toggleAttentionBlink = function(t) { + _toggleAttentionBlink(t) { if ( !this._$element || this._destroyed || this._state.focused ) { return false; } - var el = this._$element; - var self = this; + const el = this._$element; - function _blink(stat) { + const _blink = (stat) => { if ( el ) { if ( stat ) { - Utils.$addClass(el, 'WindowAttentionBlink'); + DOM.$addClass(el, 'WindowAttentionBlink'); } else { - Utils.$removeClass(el, 'WindowAttentionBlink'); + DOM.$removeClass(el, 'WindowAttentionBlink'); } } - self._onChange(stat ? 'attention_on' : 'attention_off'); - } + this._onChange(stat ? 'attention_on' : 'attention_off'); + }; _blink(t); return true; - }; + } /** - * Check next Tab (cycle GUIElement) - * - * @function _nextTabIndex - * @memberof OSjs.Core.Window# + * Check next Tab (cycle Element) * * @param {Event} ev DOM Event */ - Window.prototype._nextTabIndex = function(ev) { - var nextElement = OSjs.GUI.Helpers.getNextElement(ev.shiftKey, document.activeElement, this._$root); + _nextTabIndex(ev) { + const nextElement = GUI.getNextElement(ev.shiftKey, document.activeElement, this._$root); if ( nextElement ) { - if ( Utils.$hasClass(nextElement, 'gui-data-view') ) { - OSjs.GUI.Element.createFromNode(nextElement).focus(); + if ( DOM.$hasClass(nextElement, 'gui-data-view') ) { + Element.createFromNode(nextElement).focus(); } else { try { nextElement.focus(); } catch ( e ) {} } } - }; + } // // Events @@ -1988,9 +1820,6 @@ /** * On Drag-and-drop event * - * @function _onDndEvent - * @memberof OSjs.Core.Window# - * * @param {Event} ev DOM Event * @param {String} type DnD type * @param {Object} item DnD item @@ -1999,7 +1828,7 @@ * * @return {Boolean} On success */ - Window.prototype._onDndEvent = function(ev, type, item, args, el) { + _onDndEvent(ev, type, item, args, el) { if ( this._disabled || this._destroyed ) { return false; } @@ -2012,161 +1841,147 @@ 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]); + this._emit('drop:file', [ev, new FileMetadata(item.data || {}), args, el]); } } return true; - }; + } /** * On Key event * - * @function _onKeyEvent - * @memberof OSjs.Core.Window# - * * @param {Event} ev DOM Event * @param {String} type Key type * * @return {Boolean} If triggered */ - Window.prototype._onKeyEvent = function(ev, type) { + _onKeyEvent(ev, type) { if ( this._destroyed || !this._state.focused) { return false; } - if ( type === 'keydown' && ev.keyCode === Utils.Keys.TAB ) { + if ( type === 'keydown' && ev.keyCode === Keycodes.TAB ) { this._nextTabIndex(ev); } this._emit(type, [ev, ev.keyCode, ev.shiftKey, ev.ctrlKey, ev.altKey]); return true; - }; + } /** * On Window resized - * - * @function _onResize - * @memberof OSjs.Core.Window# */ - Window.prototype._onResize = function() { + _onResize() { clearTimeout(this._queryTimer); - var self = this; - this._queryTimer = setTimeout(function() { - checkMediaQueries(self); - self._queryTimer = clearTimeout(self._queryTimer); + this._queryTimer = setTimeout(() => { + checkMediaQueries(this); + this._queryTimer = clearTimeout(this._queryTimer); }, 20); - }; + } /** * On Window Icon Click * - * @function _onResize - * @memberof OSjs.Core.Window# - * * @param {Event} ev DOM Event * @param {Node} el DOM Element */ - Window.prototype._onWindowIconClick = function(ev, el) { + _onWindowIconClick(ev, el) { if ( !this._properties.allow_iconmenu || this._destroyed ) { return; } console.debug(this._name, '>', 'Window::_onWindowIconClick()'); - var self = this; - var control = [ - [this._properties.allow_minimize, function() { + const control = [ + [this._properties.allow_minimize, () => { return { - title: API._('WINDOW_MINIMIZE'), - icon: API.getIcon('actions/go-up.png'), - onClick: function(name, iter) { - self._minimize(); + title: _('WINDOW_MINIMIZE'), + icon: Theme.getIcon('actions/go-up.png'), + onClick: (name, iter) => { + this._minimize(); } }; }], - [this._properties.allow_maximize, function() { + [this._properties.allow_maximize, () => { return { - title: API._('WINDOW_MAXIMIZE'), - icon: API.getIcon('actions/view-fullscreen.png'), - onClick: function(name, iter) { - self._maximize(); - self._focus(); + title: _('WINDOW_MAXIMIZE'), + icon: Theme.getIcon('actions/view-fullscreen.png'), + onClick: (name, iter) => { + this._maximize(); + this._focus(); } }; }], - [this._state.maximized, function() { + [this._state.maximized, () => { return { - title: API._('WINDOW_RESTORE'), - icon: API.getIcon('actions/view-restore.png'), - onClick: function(name, iter) { - self._restore(); - self._focus(); + title: _('WINDOW_RESTORE'), + icon: Theme.getIcon('actions/view-restore.png'), + onClick: (name, iter) => { + this._restore(); + this._focus(); } }; }], - [this._properties.allow_ontop, function() { - if ( self._state.ontop ) { + [this._properties.allow_ontop, () => { + if ( this._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); + title: _('WINDOW_ONTOP_OFF'), + icon: Theme.getIcon('actions/window-new.png'), + onClick: (name, iter) => { + this._state.ontop = false; + if ( this._$element ) { + this._$element.style.zIndex = getNextZindex(false); } - self._focus(); + this._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); + title: _('WINDOW_ONTOP_ON'), + icon: Theme.getIcon('actions/window-new.png'), + onClick: (name, iter) => { + this._state.ontop = true; + if ( this._$element ) { + this._$element.style.zIndex = getNextZindex(true); } - self._focus(); + this._focus(); } }; }], - [this._properties.allow_close, function() { + [this._properties.allow_close, () => { return { - title: API._('WINDOW_CLOSE'), - icon: API.getIcon('actions/window-close.png'), - onClick: function(name, iter) { - self._close(); + title: _('WINDOW_CLOSE'), + icon: Theme.getIcon('actions/window-close.png'), + onClick: (name, iter) => { + this._close(); } }; }] ]; - var list = []; - control.forEach(function(iter) { + const list = []; + control.forEach((iter) => { if (iter[0] ) { list.push(iter[1]()); } }); - OSjs.API.createMenu(list, ev); - }; + Menu.create(list, ev); + } /** * On Window Button Click * - * @function _onWindowButtonClick - * @memberof OSjs.Core.Window# - * * @param {Event} ev DOM Event * @param {Node} el DOM Element * @param {String} btn Button name */ - Window.prototype._onWindowButtonClick = function(ev, el, btn) { - console.debug(this._name, '>', 'Window::_onWindowButtonClick()', btn); + _onWindowButtonClick(ev, el, btn) { + //console.debug(this._name, '>', 'Window::_onWindowButtonClick()', btn); this._blurGUI(); @@ -2177,27 +1992,24 @@ } else if ( btn === 'maximize' ) { this._maximize(); } - }; + } /** * On Window has changed * - * @function _onChange - * @memberof OSjs.Core.Window# - * * @param {Event} ev DOM Event * @param {Boolean} byUser Performed by user? */ - Window.prototype._onChange = function(ev, byUser) { + _onChange(ev, byUser) { ev = ev || ''; if ( ev ) { - console.debug(this._name, '>', 'Window::_onChange()', ev); - var wm = OSjs.Core.getWindowManager(); + //console.debug(this._name, '>', 'Window::_onChange()', ev); + const wm = WindowManager.instance; if ( wm ) { wm.eventWindow(ev, this); } } - }; + } // // Getters @@ -2206,27 +2018,21 @@ /** * Get Window maximized size * - * @function _getMaximizedSize - * @memberof OSjs.Core.Window# - * * @return {Object} Size in rectangle */ - Window.prototype._getMaximizedSize = function() { - var s = getWindowSpace(); + _getMaximizedSize() { + const s = getWindowSpace(); if ( !this._$element || this._destroyed ) { return s; } - var topMargin = 23; - var borderSize = 0; + let topMargin = 23; + let borderSize = 0; - var wm = OSjs.Core.getWindowManager(); - if ( wm ) { - var theme = wm.getStyleTheme(true, true); - if ( theme && theme.style && theme.style.window ) { - topMargin = theme.style.window.margin; - borderSize = theme.style.window.border; - } + const theme = Theme.getStyleTheme(true, true); + if ( theme && theme.style && theme.style.window ) { + topMargin = theme.style.window.margin; + borderSize = theme.style.window.border; } s.left += borderSize; @@ -2235,66 +2041,61 @@ s.height -= topMargin + (borderSize * 2); return Object.freeze(s); - }; + } /** * Get Window position in DOM - * - * @function _getViewRect - * @memberof OSjs.Core.Window# - * @see OSjs.Utils.position * @return {Object} */ - Window.prototype._getViewRect = function() { - return this._$element ? Object.freeze(Utils.$position(this._$element)) : null; - }; + _getViewRect() { + return this._$element ? Object.freeze(DOM.$position(this._$element)) : null; + } /** * Get Window main DOM element * - * @function _getRoot - * @memberof OSjs.Core.Window# - * * @return {Node} */ - Window.prototype._getRoot = function() { + _getRoot() { return this._$root; - }; + } /** * Get Window z-index * - * @function _getZindex - * @memberof OSjs.Core.Window# - * * @return {Number} */ - Window.prototype._getZindex = function() { + _getZindex() { if ( this._$element ) { return parseInt(this._$element.style.zIndex, 10); } return -1; - }; + } + + /** + * Get the title + * @return {String} + */ + _getTitle() { + return this._title; + } /** * Set Window title * - * @function _setTitle - * @memberof OSjs.Core.Window# - * * @param {String} t Title * @param {Boolean} [append] Append this to original title * @param {String} [delimiter] The delimiter (default is -) */ - Window.prototype._setTitle = function(t, append, delimiter) { + _setTitle(t, append, delimiter) { if ( !this._$element || this._destroyed ) { return; } delimiter = delimiter || '-'; - var tel = this._$element.getElementsByTagName('application-window-title')[0]; - var text = []; + const tel = this._$element.getElementsByTagName('application-window-title')[0]; + let text = []; if ( append ) { text = [this._origtitle, delimiter, t]; } else { @@ -2304,24 +2105,21 @@ this._title = text.join(' ') || this._origtitle; if ( tel ) { - Utils.$empty(tel); + DOM.$empty(tel); tel.appendChild(document.createTextNode(this._title)); } this._onChange('title'); this._updateMarkup(); - }; + } /** * Set Windoc icon * - * @function _setIcon - * @memberof OSjs.Core.Window# - * * @param {String} i Icon path */ - Window.prototype._setIcon = function(i) { + _setIcon(i) { if ( this._$winicon ) { this._$winicon.title = this._title; this._$winicon.style.backgroundImage = 'url(' + i + ')'; @@ -2329,20 +2127,15 @@ this._icon = i; this._onChange('icon'); - }; + } /** * Set Window warning message (Displays as a popup inside window) * - * @function _setWarning - * @memberof OSjs.Core.Window# - * * @param {String} message Warning message */ - Window.prototype._setWarning = function(message) { - var self = this; - - this._$warning = Utils.$remove(this._$warning); + _setWarning(message) { + this._$warning = DOM.$remove(this._$warning); if ( this._destroyed || message === null ) { return; @@ -2350,33 +2143,30 @@ message = message || ''; - var container = document.createElement('application-window-warning'); + let container = document.createElement('application-window-warning'); - var close = document.createElement('div'); + let close = document.createElement('div'); close.innerHTML = 'X'; - Utils.$bind(close, 'click', function() { - self._setWarning(null); + Events.$bind(close, 'click', () => { + this._setWarning(null); }); - var msg = document.createElement('div'); + let msg = document.createElement('div'); msg.appendChild(document.createTextNode(message)); container.appendChild(close); container.appendChild(msg); this._$warning = container; this._$root.appendChild(this._$warning); - }; + } /** * Set a window property * - * @function _setProperty - * @memberof OSjs.Core.Window# - * * @param {String} p Key * @param {String} v Value */ - Window.prototype._setProperty = function(p, v) { + _setProperty(p, v) { if ( (v === '' || v === null) || !this._$element || (typeof this._properties[p] === 'undefined') ) { return; } @@ -2384,12 +2174,6 @@ this._properties[p] = String(v) === 'true'; this._updateMarkup(true); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Core.Window = Object.seal(Window); + } +} -})(OSjs.Utils, OSjs.API, OSjs.GUI, OSjs.Core.Process); diff --git a/src/client/javascript/core/windowmanager.js b/src/client/javascript/core/windowmanager.js deleted file mode 100644 index 4c9c37dbd4..0000000000 --- a/src/client/javascript/core/windowmanager.js +++ /dev/null @@ -1,1188 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -(function(Utils, API, Process, Window) { - 'use strict'; - - var _WM; // Running Window Manager process - - ///////////////////////////////////////////////////////////////////////////// - // WINDOW MOVEMENT BEHAVIOUR - ///////////////////////////////////////////////////////////////////////////// - - /* - * Holds information about current behaviour - */ - 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 = Utils.cloneObject(_WM.getStyleTheme(true, true)); - if ( !theme.style ) { - theme.style = {'window': {margin: 0, border: 0}}; - } - - this.theme = { - topMargin: theme.style.window.margin || 0, // FIXME - 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; - }; - - /* - * Window Behavour Abstraction - */ - function createWindowBehaviour(win, wm) { - var current = null; - var newRect = {}; - - /* - * Resizing action - */ - 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; - } - - /* - * Movement action - */ - 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); - - // 8-directional corner window snapping - 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; - } - } - - // Snapping to other windows - 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}; - } - - /* - * When mouse button is released - */ - 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; - } - - /* - * When mouse is moved - */ - function onMouseMove(ev, action, win, mousePosition) { - if ( !_WM.getMouseLocked() || !action || !current ) { - return; - } - - ev.preventDefault(); - - 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; - } - - /* - * When mouse button is pressed - */ - 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'); - - 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'); - } - - Utils.$bind(document, 'mousemove:movewindow', _onMouseMove, false); - Utils.$bind(document, 'mouseup:movewindowstop', _onMouseUp, false); - } - - /* - * Register a window - */ - 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); - }); - } - } - - ///////////////////////////////////////////////////////////////////////////// - // WINDOW MANAGER - ///////////////////////////////////////////////////////////////////////////// - - /** - * WindowManager Process Class - * The default implementation of this is in apps/CoreWM/main.js - * - *

-   * NEVER CONSTRUCT YOUR OWN INTANCE! To get one use:
-   * OSjs.Core.getWindowManager();
-   * 
- * - * @example - * OSjs.Core.getWindowManager() - * - * @summary Class used for basis as a Window Manager. - * - * @param {String} name Window Manager name - * @param {OSjs.Core.WindowManager} ref Constructed instance ref - * @param {Object} args Constructed arguments - * @param {Object} metadata Package Metadata - * @param {Object} settings Restored settings - * - * @abstract - * @constructor - * @memberof OSjs.Core - * @extends OSjs.Core.Process - */ - function WindowManager(name, ref, args, metadata, settings) { - console.group('WindowManager::constructor()'); - console.debug('Name', name); - console.debug('Arguments', args); - - 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._isResponsive = false; - this._responsiveRes = 800; - this._scheme = null; - - // Important for usage as "Application" - this.__name = (name || 'WindowManager'); - this.__path = metadata.path; - this.__iter = metadata.iter; - - Process.apply(this, [this.__name, args, metadata]); - - _WM = (ref || this); - - console.groupEnd(); - } - - WindowManager.prototype = Object.create(Process.prototype); - - /** - * Destroy the WindowManager - * - * @function destroy - * @memberof OSjs.Core.WindowManager# - * - * @return {Boolean} - */ - WindowManager.prototype.destroy = function() { - var self = this; - console.debug('WindowManager::destroy()'); - - this.destroyStylesheet(); - - Utils.$unbind(document, 'mouseout:windowmanager'); - Utils.$unbind(document, 'mouseenter:windowmanager'); - - // Destroy all windows - 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, []); - }; - - /** - * Initialize the WindowManager - * - * @param {Object} metadata Package metadata - * @param {Object} settings Package settings - * @param {OSjs.GUI.Scheme} [scheme] GUI Scheme instance - * - * @function init - * @memberof OSjs.Core.WindowManager# - */ - WindowManager.prototype.init = function(metadata, settings, scheme) { - console.debug('WindowManager::init()'); - - 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); - }); - - var queries = this.getDefaultSetting('mediaQueries') || {}; - var maxWidth = 0; - Object.keys(queries).forEach(function(q) { - maxWidth = Math.max(maxWidth, queries[q]); - }); - this._responsiveRes = maxWidth || 800; - - this.resize(); - }; - - /** - * Setup features - * - * THIS IS IMPLEMENTED IN COREWM - * - * @function setup - * @memberof OSjs.Core.WindowManager# - * - * @param {Function} cb Callback - */ - WindowManager.prototype.setup = function(cb) { - // Implement in your WM - }; - - /** - * Get a Window by name - * - * @function getWindow - * @memberof OSjs.Core.WindowManager# - * - * @param {String} name Window name - * - * @return {OSjs.Core.Window} - */ - WindowManager.prototype.getWindow = function(name) { - var result = null; - this._windows.every(function(w) { - if ( w && w._name === name ) { - result = w; - } - return result ? false : true; - }); - return result; - }; - - /** - * Add a Window - * - * @function addWindow - * @memberof OSjs.Core.WindowManager# - * @throws {Error} If invalid window is given - * - * @param {OSjs.Core.Window} w Window reference - * @param {Boolean} focus Focus the window - * - * @return {OSjs.Core.Window} The added window - */ - 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'); - } - console.debug('WindowManager::addWindow()'); - - try { - w.init(this, w._app, w._scheme); - } catch ( e ) { - console.error('WindowManager::addWindow()', '=>', 'Window::init()', e, e.stack); - } - - //attachWindowEvents(w, this); - createWindowBehaviour(w, this); - - this._windows.push(w); - w._inited(); - - if ( focus === true || (w instanceof OSjs.Core.DialogWindow) ) { - setTimeout(function() { - w._focus(); - }, 10); - } - - return w; - }; - - /** - * Remove a Window - * - * @function removeWindow - * @memberof OSjs.Core.WindowManager# - * @throws {Error} If invalid window is given - * - * @param {OSjs.Core.Window} w Window reference - * - * @return {Boolean} On success - */ - 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'); - } - console.debug('WindowManager::removeWindow()', w._wid); - - 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; - }; - - /** - * Set WindowManager settings - * - * OVERRIDE THIS IN YOUR WM IMPLEMENTATION - * - * @function applySettings - * @memberof OSjs.Core.WindowManager# - * - * @param {Object} settings JSON Settings - * @param {Boolean} force If forced, no merging will take place - * @param {Boolean} save Saves settings - * @param {Boolean} [triggerWatch=true] Trigger change event for watchers - * - * @return {Boolean} On success - */ - WindowManager.prototype.applySettings = function(settings, force, save, triggerWatch) { - settings = settings || {}; - console.debug('WindowManager::applySettings()', 'forced?', force); - - var result = force ? settings : Utils.mergeObject(this._settings.get(), settings); - this._settings.set(null, result, save, triggerWatch); - - return true; - }; - - /** - * Create Window Manager self-contained CSS from this object - * - * { - * '.classname': { - * 'background-image': 'url()' - * } - * } - * - * @function createStylesheet - * @memberof OSjs.Core.WindowManager# - * - * @param {Object} styles Style object - * @param {String} [rawStyles] Raw CSS data - */ - 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; - }; - - /** - * Destroy Window Manager self-contained CSS - * - * @function destroyStylesheet - * @memberof OSjs.Core.WindowManager# - */ - WindowManager.prototype.destroyStylesheet = function() { - if ( this._stylesheet ) { - if ( this._stylesheet.parentNode ) { - this._stylesheet.parentNode.removeChild(this._stylesheet); - } - } - this._stylesheet = null; - }; - - /** - * When Key Down Event received - * - * @function onKeyDown - * @memberof OSjs.Core.WindowManager# - * - * @param {Event} ev DOM Event - * @param {OSjs.CoreWindow} win Active window - */ - WindowManager.prototype.onKeyDown = function(ev, win) { - // Implement in your WM - }; - - /** - * When orientation of device has changed - * - * @function onOrientationChange - * @memberof OSjs.Core.WindowManager# - * - * @param {Event} ev DOM Event - * @param {String} orientation Orientation string - */ - WindowManager.prototype.onOrientationChange = function(ev, orientation) { - console.info('ORIENTATION CHANGED', ev, orientation); - - this._onDisplayChange(); - }; - - /** - * When size of the device display has been changed - * - * @function onResize - * @memberof OSjs.Core.WindowManager# - * - * @param {Event} ev DOM Event - */ - WindowManager.prototype.onResize = function(ev) { - this._onDisplayChange(); - }; - - /** - * When session has been loaded - * - * @function onSessionLoaded - * @memberof OSjs.Core.WindowManager# - * @return {Boolean} - */ - WindowManager.prototype.onSessionLoaded = function() { - if ( this._sessionLoaded ) { - return false; - } - - this._sessionLoaded = true; - return true; - }; - - WindowManager.prototype.resize = function(ev, rect) { - // Implement in your WM - this._isResponsive = window.innerWidth <= 1024; - - this.onResize(ev); - }; - - /** - * Create a desktop notification. - * - * THIS IS IMPLEMENTED IN COREWM - * - * @function notification - * @memberof OSjs.Core.WindowManager# - * - * @param {Object} opts Notification options - * @param {String} opts.icon What icon to display - * @param {String} opts.title What title to display - * @param {String} opts.message What message to display - * @param {Number} [opts.timeout=5000] Timeout - * @param {Function} opts.onClick Event callback on click => fn(ev) - */ - WindowManager.prototype.notification = function() { - // Implement in your WM - }; - - /** - * Create a panel notification icon. - * - * THIS IS IMPLEMENTED IN COREWM - * - * FOR OPTIONS SEE NotificationAreaItem IN CoreWM ! - * - * @function createNotificationIcon - * @memberof OSjs.Core.WindowManager# - * - * @param {String} name Internal name (unique) - * @param {Object} opts Notification options - * @param {Number} [panelId] Panel ID - * - * @return OSjs.Applications.CoreWM.NotificationAreaItem - */ - WindowManager.prototype.createNotificationIcon = function() { - // Implement in your WM - return null; - }; - - /** - * Remove a panel notification icon. - * - * THIS IS IMPLEMENTED IN COREWM - * - * @function removeNotificationIcon - * @memberof OSjs.Core.WindowManager# - * - * @param {String} name Internal name (unique) - * @param {Number} [panelId] Panel ID - * - * @return {Boolean} - */ - WindowManager.prototype.removeNotificationIcon = function() { - // Implement in your WM - return false; - }; - - /** - * Whenever a window event occurs - * - * THIS IS IMPLEMENTED IN COREWM - * - * @function eventWindow - * @memberof OSjs.Core.WindowManager# - * - * @param {String} ev Event name - * @param {OSjs.Core.Window} win Window ref - * - * @return {Boolean} - */ - WindowManager.prototype.eventWindow = function(ev, win) { - // Implement in your WM - return false; - }; - - /** - * Show Settings Window (Application) - * - * THIS IS IMPLEMENTED IN COREWM - * - * @function showSettings - * @memberof OSjs.Core.WindowManager# - */ - WindowManager.prototype.showSettings = function() { - // Implement in your WM - }; - - 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._onDisplayChange = (function() { - var _timeout; - - return function() { - var self = this; - - _timeout = clearTimeout(_timeout); - _timeout = setTimeout(function() { - if ( !_WM ) { - return; - } - - self._windows.filter(function(w) { - return !!w; - }).forEach(function(w) { - w._onResize(); - w._emit('resize'); - }); - }, 100); - - document.body.setAttribute('data-responsive', String(self._isResponsive)); - }; - - })(); - - /** - * Get default Settings - * - * @function getDefaultSettings - * @memberof OSjs.Core.WindowManager# - * - * @return {Object} JSON Data - */ - WindowManager.prototype.getDefaultSetting = function() { - // Implement in your WM - return null; - }; - - /** - * Get panel - * - * @function getPanel - * @memberof OSjs.Core.WindowManager# - * - * @return {OSjs.Applications.CoreWM.Panel} - */ - WindowManager.prototype.getPanel = function() { - // Implement in your WM - return null; - }; - - /** - * Gets all panels - * - * @function getPanels - * @memberof OSjs.Core.WindowManager# - * - * @return {OSjs.Packages.CoreWM.Panel[]} Panel List - */ - WindowManager.prototype.getPanels = function() { - // Implement in your WM - return []; - }; - - /** - * Gets current Style theme - * - * @function getStyleTheme - * @memberof OSjs.Core.WindowManager# - * - * @param {Boolean} returnMetadata Return theme metadata instead of name - * @param {Boolean} [convert=false] Converts the measures into px - * - * @return {String} Or JSON - */ - WindowManager.prototype.getStyleTheme = function(returnMetadata) { - return returnMetadata ? {} : 'default'; - }; - - /** - * Gets current Sound theme - * - * @function getSoundTheme - * @memberof OSjs.Core.WindowManager# - * - * @return {String} - */ - WindowManager.prototype.getSoundTheme = function() { - return 'default'; - }; - - /** - * Gets sound filename from key - * - * @param {String} k Sound name key - * @function getSoundName - * @memberof OSjs.Core.WindowManager# - * - * @return {String} - */ - WindowManager.prototype.getSoundFilename = function(k) { - return null; - }; - - /** - * Gets current Icon theme - * - * @function getIconTheme - * @memberof OSjs.Core.WindowManager# - * - * @return {String} - */ - WindowManager.prototype.getIconTheme = function() { - return 'default'; - }; - - /** - * Gets a list of Style themes - * - * @function getStyleThemes - * @memberof OSjs.Core.WindowManager# - * - * @return {String[]} The list of themes - */ - WindowManager.prototype.getStyleThemes = function() { - return API.getConfig('Styles', []); - }; - - /** - * Gets a list of Sound themes - * - * @function getSoundThemes - * @memberof OSjs.Core.WindowManager# - * - * @return {String[]} The list of themes - */ - WindowManager.prototype.getSoundThemes = function() { - return API.getConfig('Sounds', []); - }; - - /** - * Gets a list of Icon themes - * - * @function getIconThemes - * @memberof OSjs.Core.WindowManager# - * - * @return {String[]} The list of themes - */ - WindowManager.prototype.getIconThemes = function() { - return API.getConfig('Icons', []); - }; - - /** - * Sets a setting - * - * @function setSetting - * @memberof OSjs.Core.WindowManager# - * - * @param {String} k Key - * @param {Mixed} v Value - * - * @return {Boolean} On success - */ - WindowManager.prototype.setSetting = function(k, v) { - return this._settings.set(k, v); - }; - - /** - * Gets the rectangle for window space - * - * @function getWindowSpace - * @memberof OSjs.Core.WindowManager# - * - * @return {Object} rectangle - */ - WindowManager.prototype.getWindowSpace = function() { - return Utils.getRect(); - }; - - /** - * Get next window position - * - * @function getWindowPosition - * @memberof OSjs.Core.WindowManager# - * - * @return {Object} rectangle - */ - WindowManager.prototype.getWindowPosition = function() { - var winCount = this._windows.reduce(function(count, win) { - return win === null ? count : (count + 1); - }, 0); - return {x: 10 * winCount, y: 10 * winCount}; - }; - - /** - * Gets a setting - * - * @function getSetting - * @memberof OSjs.Core.WindowManager# - * - * @param {String} k Key - * - * @return {Mixed} Setting value or 'null' - */ - WindowManager.prototype.getSetting = function(k) { - return this._settings.get(k); - }; - - /** - * Gets all settings - * - * @function getSettings - * @memberof OSjs.Core.WindowManager# - * - * @return {Object} JSON With all settings - */ - WindowManager.prototype.getSettings = function() { - return this._settings.get(); - }; - - /** - * Gets all Windows - * - * @function getWindows - * @memberof OSjs.Core.WindowManager# - * - * @return {OSjs.Core.Window[]} List of all Windows - */ - WindowManager.prototype.getWindows = function() { - return this._windows; - }; - - /** - * Gets current Window - * - * @function getCurrentWindow - * @memberof OSjs.Core.WindowManager# - * - * @return {OSjs.Core.Window} Current Window or 'null' - */ - WindowManager.prototype.getCurrentWindow = function() { - return this._currentWin; - }; - - /** - * Sets the current Window - * - * @function setCurrentWindow - * @memberof OSjs.Core.WindowManager# - * - * @param {OSjs.Core.Window} w Window - */ - WindowManager.prototype.setCurrentWindow = function(w) { - this._currentWin = w || null; - }; - - /** - * Gets previous Window - * - * @function getLastWindow - * @memberof OSjs.Core.WindowManager# - * - * @return {OSjs.Core.Window} Current Window or 'null' - */ - WindowManager.prototype.getLastWindow = function() { - return this._lastWin; - }; - - /** - * Sets the last Window - * - * @function setLastWindow - * @memberof OSjs.Core.WindowManager# - * - * @param {OSjs.Core.Window} w Window - */ - WindowManager.prototype.setLastWindow = function(w) { - this._lastWin = w || null; - }; - - /** - * If the pointer is inside the browser window - * - * @function getMouseLocked - * @memberof OSjs.Core.WindowManager# - * - * @return {Boolean} - */ - WindowManager.prototype.getMouseLocked = function() { - return this._mouselock; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Core.WindowManager = Object.seal(WindowManager); - - /** - * Get the current WindowManager instance - * - * @function getWindowManager - * @memberof OSjs.Core - * - * @return {OSjs.Core.WindowManager} - */ - OSjs.Core.getWindowManager = function Core_getWindowManager() { - return _WM; - }; - -})(OSjs.Utils, OSjs.API, OSjs.Core.Process, OSjs.Core.Window); diff --git a/src/client/dialogs.html b/src/client/javascript/dialogs.html similarity index 100% rename from src/client/dialogs.html rename to src/client/javascript/dialogs.html diff --git a/src/client/javascript/dialogs/alert.js b/src/client/javascript/dialogs/alert.js index 7a1241ac09..d30b6af646 100644 --- a/src/client/javascript/dialogs/alert.js +++ b/src/client/javascript/dialogs/alert.js @@ -27,48 +27,43 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; + +/** + * An 'Alert' dialog + * + * @example DialogWindow.create('Alert', {}, fn); + * @extends DialogWindow + */ +export default class AlertDialog extends DialogWindow { /** - * An 'Alert' dialog - * - * @example - * - * OSjs.API.createDialog('Alert', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message * @param {CallbackDialog} callback Callback when done - * - * @constructor Alert - * @memberof OSjs.Dialogs */ - function AlertDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); - DialogWindow.apply(this, ['AlertDialog', { - title: args.title || API._('DIALOG_ALERT_TITLE'), + constructor(args, callback) { + args = Object.assign({}, {}, args); + + super('AlertDialog', { + title: args.title || _('DIALOG_ALERT_TITLE'), icon: 'status/dialog-warning.png', width: 400, height: 100 - }, args, callback]); + }, args, callback); } - AlertDialog.prototype = Object.create(DialogWindow.prototype); - AlertDialog.constructor = DialogWindow; + init() { + const root = super.init(...arguments); - AlertDialog.prototype.init = function() { - var root = DialogWindow.prototype.init.apply(this, arguments); root.setAttribute('role', 'alertdialog'); + this._find('Message').set('value', this.args.message, true); - return root; - }; - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + return root; + } - OSjs.Dialogs.Alert = Object.seal(AlertDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/applicationchooser.js b/src/client/javascript/dialogs/applicationchooser.js index 49bfa48557..f86e424dbb 100644 --- a/src/client/javascript/dialogs/applicationchooser.js +++ b/src/client/javascript/dialogs/applicationchooser.js @@ -27,93 +27,92 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import PackageManager from 'core/package-manager'; +import Theme from 'core/theme'; +import * as Utils from 'utils/misc'; +import {_} from 'core/locales'; + +/** + * An 'Application Chooser' dialog + * + * @example DialogWindow.create('ApplicationChooser', {}, fn); + * @extends DialogWindow + */ +export default class ApplicationChooserDialog extends DialogWindow { /** - * An 'Application Chooser' dialog - * - * @example - * - * OSjs.API.createDialog('ApplicationChooser', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message - * @param {OSjs.VFS.File} args.file The file to open + * @param {FileMetadata} args.file The file to open * @param {CallbackDialog} callback Callback when done - * - * @constructor ApplicationChooser - * @memberof OSjs.Dialogs */ - function ApplicationChooserDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); + constructor(args, callback) { + args = Object.assign({}, {}, args); - DialogWindow.apply(this, ['ApplicationChooserDialog', { - title: args.title || API._('DIALOG_APPCHOOSER_TITLE'), + super('ApplicationChooserDialog', { + title: args.title || _('DIALOG_APPCHOOSER_TITLE'), width: 400, height: 400 - }, args, callback]); + }, args, callback); } - ApplicationChooserDialog.prototype = Object.create(DialogWindow.prototype); - ApplicationChooserDialog.constructor = DialogWindow; + init() { + const root = super.init(...arguments); - ApplicationChooserDialog.prototype.init = function() { - var self = this; - var root = DialogWindow.prototype.init.apply(this, arguments); + const cols = [{label: _('LBL_NAME')}]; + const rows = []; + const metadata = PackageManager.getPackages(); - var cols = [{label: API._('LBL_NAME')}]; - var rows = []; - var metadata = OSjs.Core.getPackageManager().getPackages(); - - (this.args.list || []).forEach(function(name) { - var iter = metadata[name]; + (this.args.list || []).forEach((name) => { + const iter = metadata[name]; if ( iter && iter.type === 'application' ) { - var label = [iter.name]; + const 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)} + {label: label.join(' - '), icon: Theme.getIcon(iter.icon, null, name), value: JSON.stringify(iter)} ] }); } }); - this._find('ApplicationList').set('columns', cols).add(rows).on('activate', function(ev) { - self.onClose(ev, 'ok'); + this._find('ApplicationList').set('columns', cols).add(rows).on('activate', (ev) => { + this.onClose(ev, 'ok'); }); - var file = ''; - var label = ''; + let file = ''; + let label = ''; 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); + label = _('DIALOG_APPCHOOSER_SET_DEFAULT', this.args.file.mime); } this._find('FileName').set('value', file); this._find('SetDefault').set('label', label); return root; - }; + } - ApplicationChooserDialog.prototype.onClose = function(ev, button) { - var result = null; + onClose(ev, button) { + let result = null; if ( button === 'ok' ) { - var useDefault = this._find('SetDefault').get('value'); - var selected = this._find('ApplicationList').get('value'); + const useDefault = this._find('SetDefault').get('value'); + const selected = this._find('ApplicationList').get('value'); + if ( selected && selected.length ) { result = selected[0].data.className; } if ( !result ) { - OSjs.API.createDialog('Alert', { - message: API._('DIALOG_APPCHOOSER_NO_SELECTION') + DialogWindow.create('Alert', { + message: _('DIALOG_APPCHOOSER_NO_SELECTION') }, null, this); return; @@ -125,12 +124,7 @@ } this.closeCallback(ev, button, result); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.ApplicationChooser = Object.seal(ApplicationChooserDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/color.js b/src/client/javascript/dialogs/color.js index 1c0760dd3e..145d05f26d 100644 --- a/src/client/javascript/dialogs/color.js +++ b/src/client/javascript/dialogs/color.js @@ -27,106 +27,107 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import * as Utils from 'utils/misc'; +import {_} from 'core/locales'; + +function getColor(rgb) { + let 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); + } + + return [rgb, hex]; +} + +/** + * An 'Color Chooser' dialog + * + * @example DialogWindow.create('Color', {}, fn); + * @extends DialogWindow + */ +export default class ColorDialog extends DialogWindow { /** - * An 'Color Chooser' dialog - * - * @example - * - * OSjs.API.createDialog('Color', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title - * @param {Mixed} args.color Either hex string or rbg object + * @param {String|Object} args.color Either hex string or rbg object * @param {CallbackDialog} callback Callback when done - * - * @constructor Color - * @memberof OSjs.Dialogs */ - function ColorDialog(args, callback) { - args = Utils.argumentDefaults(args, { - }); + constructor(args, callback) { + args = Object.assign({}, {}, 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; - } - } + const [rgb, hex] = getColor(args.color); - 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'), + super('ColorDialog', { + title: args.title || _('DIALOG_COLOR_TITLE'), icon: 'apps/preferences-desktop-theme.png', width: 400, height: rgb.a !== null ? 300 : 220 - }, args, callback]); + }, 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); + init() { + const root = super.init(...arguments); - function updateHex(update) { - self._find('LabelRed').set('value', API._('DIALOG_COLOR_R', self.color.r)); - self._find('LabelGreen').set('value', API._('DIALOG_COLOR_G', self.color.g)); - self._find('LabelBlue').set('value', API._('DIALOG_COLOR_B', self.color.b)); - self._find('LabelAlpha').set('value', API._('DIALOG_COLOR_A', self.color.a)); + const updateHex = (update) => { + this._find('LabelRed').set('value', _('DIALOG_COLOR_R', this.color.r)); + this._find('LabelGreen').set('value', _('DIALOG_COLOR_G', this.color.g)); + this._find('LabelBlue').set('value', _('DIALOG_COLOR_B', this.color.b)); + this._find('LabelAlpha').set('value', _('DIALOG_COLOR_A', this.color.a)); if ( update ) { - self.color.hex = Utils.convertToHEX(self.color.r, self.color.g, self.color.b); + this.color.hex = Utils.convertToHEX(this.color.r, this.color.g, this.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); + let value = this.color.hex; + if ( this.color.a !== null && !isNaN(this.color.a) ) { + value = Utils.format('rgba({0}, {1}, {2}, {3})', this.color.r, this.color.g, this.color.b, this.color.a); } - self._find('ColorPreview').set('value', value); - } - - this._find('ColorSelect').on('change', function(ev) { - self.color = ev.detail; - self._find('Red').set('value', self.color.r); - self._find('Green').set('value', self.color.g); - self._find('Blue').set('value', self.color.b); + this._find('ColorPreview').set('value', value); + }; + + this._find('ColorSelect').on('change', (ev) => { + this.color = ev.detail; + this._find('Red').set('value', this.color.r); + this._find('Green').set('value', this.color.g); + this._find('Blue').set('value', this.color.b); updateHex(true); }); - this._find('Red').on('change', function(ev) { - self.color.r = parseInt(ev.detail, 10); + this._find('Red').on('change', (ev) => { + this.color.r = parseInt(ev.detail, 10); updateHex(true); }).set('value', this.color.r); - this._find('Green').on('change', function(ev) { - self.color.g = parseInt(ev.detail, 10); + this._find('Green').on('change', (ev) => { + this.color.g = parseInt(ev.detail, 10); updateHex(true); }).set('value', this.color.g); - this._find('Blue').on('change', function(ev) { - self.color.b = parseInt(ev.detail, 10); + this._find('Blue').on('change', (ev) => { + this.color.b = parseInt(ev.detail, 10); updateHex(true); }).set('value', this.color.b); - this._find('Alpha').on('change', function(ev) { - self.color.a = parseInt(ev.detail, 10) / 100; + this._find('Alpha').on('change', (ev) => { + this.color.a = parseInt(ev.detail, 10) / 100; updateHex(true); }).set('value', this.color.a * 100); @@ -138,16 +139,11 @@ updateHex(false, this.color.a !== null); return root; - }; + } - ColorDialog.prototype.onClose = function(ev, button) { + onClose(ev, button) { this.closeCallback(ev, button, button === 'ok' ? this.color : null); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.Color = Object.seal(ColorDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/confirm.js b/src/client/javascript/dialogs/confirm.js index 7476b3828d..db57a09595 100644 --- a/src/client/javascript/dialogs/confirm.js +++ b/src/client/javascript/dialogs/confirm.js @@ -27,72 +27,61 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; + +/** + * An 'Confirm' dialog + * + * @example DialogWindow.create('Confirm', {}, fn); + * @extends DialogWindow + */ +export default class ConfirmDialog extends DialogWindow { /** - * An 'Confirm' dialog - * - * @example - * - * OSjs.API.createDialog('Confirm', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message * @param {Array} args.buttons Dialog buttons (default=yes,no,cancel) * @param {CallbackDialog} callback Callback when done - * - * @constructor Confirm - * @memberof OSjs.Dialogs */ - function ConfirmDialog(args, callback) { - args = Utils.argumentDefaults(args, { + constructor(args, callback) { + args = Object.assign({}, { buttons: ['yes', 'no', 'cancel'] - }); + }, args); - DialogWindow.apply(this, ['ConfirmDialog', { - title: args.title || API._('DIALOG_CONFIRM_TITLE'), + super('ConfirmDialog', { + title: args.title || _('DIALOG_CONFIRM_TITLE'), icon: 'status/dialog-question.png', width: 400, height: 100 - }, args, callback]); + }, args, callback); } - ConfirmDialog.prototype = Object.create(DialogWindow.prototype); - ConfirmDialog.constructor = DialogWindow; + init() { + const root = super.init(...arguments); - ConfirmDialog.prototype.init = function() { - var self = this; - var root = DialogWindow.prototype.init.apply(this, arguments); - - var msg = DialogWindow.parseMessage(this.args.message); + const msg = DialogWindow.parseMessage(this.args.message); this._find('Message').empty().append(msg); - var buttonMap = { + const buttonMap = { yes: 'ButtonYes', no: 'ButtonNo', cancel: 'ButtonCancel' }; - var hide = []; - (['yes', 'no', 'cancel']).forEach(function(b) { - if ( self.args.buttons.indexOf(b) < 0 ) { + const hide = []; + (['yes', 'no', 'cancel']).forEach((b) => { + if ( this.args.buttons.indexOf(b) < 0 ) { hide.push(b); } }); - hide.forEach(function(b) { - self._find(buttonMap[b]).hide(); + hide.forEach((b) => { + this._find(buttonMap[b]).hide(); }); return root; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Dialogs.Confirm = Object.seal(ConfirmDialog); + } +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/error.js b/src/client/javascript/dialogs/error.js index 9d518351c6..f7550542d4 100644 --- a/src/client/javascript/dialogs/error.js +++ b/src/client/javascript/dialogs/error.js @@ -27,33 +27,32 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; + +/** + * An 'Error' dialog + * + * @example DialogWindow.create('Error', {}, fn); + * @extends DialogWindow + */ +export default class ErrorDialog extends DialogWindow { /** - * An 'Error' dialog - * - * @example - * - * OSjs.API.createDialog('Error', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message * @param {String} args.error Error message * @param {Error} [args.exception] Exception * @param {CallbackDialog} callback Callback when done - * - * @constructor Error - * @memberof OSjs.Dialogs */ - function ErrorDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); + constructor(args, callback) { + args = Object.assign({}, {}, args); - console.error('ErrorDialog::constructor()', args); + const exception = args.exception || {}; - var exception = args.exception || {}; - var error = ''; + let error = ''; if ( exception.stack ) { error = exception.stack; } else { @@ -68,12 +67,12 @@ } } - DialogWindow.apply(this, ['ErrorDialog', { - title: args.title || API._('DIALOG_ERROR_TITLE'), + super('ErrorDialog', { + title: args.title || _('DIALOG_ERROR_TITLE'), icon: 'status/dialog-error.png', width: 400, height: error ? 400 : 200 - }, args, callback]); + }, args, callback); this._sound = 'ERROR'; this._soundVolume = 1.0; @@ -81,16 +80,11 @@ 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); + init() { + const root = super.init(...arguments); root.setAttribute('role', 'alertdialog'); - var msg = DialogWindow.parseMessage(this.args.message); + const msg = DialogWindow.parseMessage(this.args.message); this._find('Message').empty().append(msg); this._find('Summary').set('value', this.args.error); this._find('Trace').set('value', this.traceMessage); @@ -100,24 +94,24 @@ } if ( this.args.bugreport ) { - this._find('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) { + this._find('ButtonBugReport').on('click', () => { + let title = ''; + let body = []; + + if ( getConfig('BugReporting.options.issue') ) { + const obj = {}; + const keys = ['userAgent', 'platform', 'language', 'appVersion']; + keys.forEach((k) => { obj[k] = navigator[k]; }); - title = API.getConfig('BugReporting.options.title'); + title = getConfig('BugReporting.options.title'); body = [ - '**' + API.getConfig('BugReporting.options.message').replace('%VERSION%', API.getConfig('Version')) + ':**', + '**' + getConfig('BugReporting.options.message').replace('%VERSION%', getConfig('Version')) + ':**', '\n', - '> ' + self.args.message, + '> ' + this.args.message, '\n', - '> ' + (self.args.error || 'Unknown error'), + '> ' + (this.args.error || 'Unknown error'), '\n', '## Expected behaviour', '\n', @@ -130,12 +124,12 @@ '```\n' + JSON.stringify(obj) + '\n```' ]; - if ( self.traceMessage ) { - body.push('\n## Stack Trace \n```\n' + self.traceMessage + '\n```\n'); + if ( this.traceMessage ) { + body.push('\n## Stack Trace \n```\n' + this.traceMessage + '\n```\n'); } } - var url = API.getConfig('BugReporting.url') + const url = getConfig('BugReporting.url') .replace('%TITLE%', encodeURIComponent(title)) .replace('%BODY%', encodeURIComponent(body.join('\n'))); @@ -146,12 +140,7 @@ } return root; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.Error = Object.seal(ErrorDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/file.js b/src/client/javascript/dialogs/file.js index 59ea4ad80c..bd99cc2553 100644 --- a/src/client/javascript/dialogs/file.js +++ b/src/client/javascript/dialogs/file.js @@ -27,38 +27,43 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, VFS, Utils, DialogWindow) { - 'use strict'; - - /** - * An 'File' dialog - * - * @example - * - * OSjs.API.createDialog('File', {}, fn); - * - * @param {Object} args An object with arguments - * @param {String} args.title Dialog title - * @param {String} [args.type=open] Dialog type (alternative=save) - * @param {Boolean} [args.multiple=false] Multiple file selection - * @param {OSjs.VFS.File} [args.file] Current file - * @param {String} [args.path] Default path - * @param {String} [args.filename] Default filename - * @param {String} [args.extension] Default file extension - * @param {String} [args.mime] Default file MIME - * @param {Array} [args.filter] Array of MIMIE filters - * @param {Array} [args.mfilter] Array of function to filter module list - * @param {String} [args.select] Selection type (file/dir) - * @param {CallbackDialog} callback Callback when done - * - * @constructor File - * @memberof OSjs.Dialogs - */ - function FileDialog(args, callback) { - args = Utils.argumentDefaults(args, { +import DialogWindow from 'core/dialog'; +import GUIElement from 'gui/element'; +import FileMetadata from 'vfs/file'; +import SettingsManager from 'core/settings-manager'; +import MountManager from 'core/mount-manager'; +import * as FS from 'utils/fs'; +import * as Utils from 'utils/misc'; +import * as VFS from 'vfs/fs'; +import {_} from 'core/locales'; +import {getDefaultPath} from 'core/config'; + +/** + * An 'File' dialog + * + * @example DialogWindow.create('File', {}, fn); + * @extends DialogWindow + * + * @param {Object} args An object with arguments + * @param {String} args.title Dialog title + * @param {String} [args.type=open] Dialog type (alternative=save) + * @param {Boolean} [args.multiple=false] Multiple file selection + * @param {FileMetadata} [args.file] Current file + * @param {String} [args.path] Default path + * @param {String} [args.filename] Default filename + * @param {String} [args.extension] Default file extension + * @param {String} [args.mime] Default file MIME + * @param {Array} [args.filter] Array of MIMIE filters + * @param {Array} [args.mfilter] Array of function to filter module list + * @param {String} [args.select] Selection type (file/dir) + * @param {CallbackDialog} callback Callback when done + */ +export default class FileDialog extends DialogWindow { + constructor(args, callback) { + args = Object.assign({}, { file: null, type: 'open', - path: OSjs.API.getDefaultPath(), + path: getDefaultPath(), filename: '', filetypes: [], extension: '', @@ -67,128 +72,122 @@ mfilter: [], select: null, multiple: false - }); + }, args); 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.path && args.path instanceof FileMetadata ) { + args.path = FS.dirname(args.path.path); } if ( args.file && args.file.path ) { - args.path = Utils.dirname(args.file.path); + args.path = FS.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); + const setTo = args.filetypes[0]; + args.filename = FS.replaceFileExtension(args.filename, setTo.extension); args.mime = setTo.mime; } } - var title = args.title || API._(args.type === 'save' ? 'DIALOG_FILE_SAVE' : 'DIALOG_FILE_OPEN'); - var icon = args.type === 'open' ? 'actions/document-open.png' : 'actions/documentsave-as.png'; + const title = args.title || _(args.type === 'save' ? 'DIALOG_FILE_SAVE' : 'DIALOG_FILE_OPEN'); + const icon = args.type === 'open' ? 'actions/document-open.png' : 'actions/documentsave-as.png'; - DialogWindow.apply(this, ['FileDialog', { + super('FileDialog', { title: title, icon: icon, width: 600, height: 400 - }, args, callback]); + }, args, callback); this.selected = null; this.path = args.path; - var self = this; - this.settingsWatch = OSjs.Core.getSettingsManager().watch('VFS', function() { - self.changePath(); + this.settingsWatch = SettingsManager.watch('VFS', () => { + this.changePath(); }); } - FileDialog.prototype = Object.create(DialogWindow.prototype); - FileDialog.constructor = DialogWindow; - - FileDialog.prototype.destroy = function() { + destroy() { try { - OSjs.Core.getSettingsManager().unwatch(this.settingsWatch); + SettingsManager.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._find('FileView'); + return super.destroy(...arguments); + } + + init() { + const root = super.init(...arguments); + const view = this._find('FileView'); view.set('filter', this.args.filter); view.set('filetype', this.args.select || ''); view.set('defaultcolumns', 'true'); - var filename = this._find('Filename'); - var home = this._find('HomeButton'); - var mlist = this._find('ModuleSelect'); + const filename = this._find('Filename'); + const home = this._find('HomeButton'); + const mlist = this._find('ModuleSelect'); - function checkEmptyInput() { - var disable = false; - if ( self.args.select !== 'dir' ) { + const checkEmptyInput = () => { + let disable = false; + if ( this.args.select !== 'dir' ) { disable = !filename.get('value').length; } - self._find('ButtonOK').set('disabled', disable); - } + this._find('ButtonOK').set('disabled', disable); + }; this._toggleLoading(true); view.set('multiple', this.args.multiple); filename.set('value', this.args.filename || ''); - this._find('ButtonMkdir').on('click', function() { - API.createDialog('Input', {message: API._('DIALOG_FILE_MKDIR_MSG', self.path), value: 'New folder'}, function(ev, btn, value) { + this._find('ButtonMkdir').on('click', () => { + DialogWindow.create('Input', {message: _('DIALOG_FILE_MKDIR_MSG', this.path), value: 'New folder'}, (ev, btn, value) => { if ( btn === 'ok' && value ) { - var path = Utils.pathJoin(self.path, value); - VFS.mkdir(VFS.file(path, 'dir'), function(err) { - if ( err ) { - API.error(API._('DIALOG_FILE_ERROR'), API._('ERR_VFSMODULE_MKDIR'), err); - } else { - self.changePath(path); - } + const path = FS.pathJoin(this.path, value); + VFS.mkdir(new FileMetadata(path, 'dir')).then(() => { + return this.changePath(path); + }).catch((err) => { + OSjs.error(_('DIALOG_FILE_ERROR'), _('ERR_VFSMODULE_MKDIR'), err); }); } - }, self); + }, this); }); - home.on('click', function() { - var dpath = API.getDefaultPath(); - self.changePath(dpath); + home.on('click', () => { + const dpath = getDefaultPath(); + this.changePath(dpath); }); - view.on('activate', function(ev) { - self.selected = null; - if ( self.args.type !== 'save' ) { + view.on('activate', (ev) => { + this.selected = null; + if ( this.args.type !== 'save' ) { filename.set('value', ''); } if ( ev && ev.detail && ev.detail.entries ) { - var activated = ev.detail.entries[0]; + const 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); + this.selected = new FileMetadata(activated.data); + if ( this.selected.type !== 'dir' ) { + filename.set('value', this.selected.filename); } - self.checkSelection(ev, true); + this.checkSelection(ev, true); } } }); - view.on('select', function(ev) { - self.selected = null; + view.on('select', (ev) => { + this.selected = null; //filename.set('value', ''); if ( ev && ev.detail && ev.detail.entries ) { - var activated = ev.detail.entries[0]; + const activated = ev.detail.entries[0]; if ( activated ) { - self.selected = new VFS.File(activated.data); + this.selected = new FileMetadata(activated.data); - if ( self.selected.type !== 'dir' ) { - filename.set('value', self.selected.filename); + if ( this.selected.type !== 'dir' ) { + filename.set('value', this.selected.filename); } } } @@ -197,31 +196,31 @@ }); if ( this.args.type === 'save' ) { - var filetypes = []; - this.args.filetypes.forEach(function(f) { + const filetypes = []; + this.args.filetypes.forEach((f) => { filetypes.push({ label: Utils.format('{0} (.{1} {2})', f.label, f.extension, f.mime), value: f.extension }); }); - var ft = this._find('Filetype').add(filetypes).on('change', function(ev) { - var newinput = Utils.replaceFileExtension(filename.get('value'), ev.detail); + const ft = this._find('Filetype').add(filetypes).on('change', (ev) => { + const newinput = FS.replaceFileExtension(filename.get('value'), ev.detail); filename.set('value', newinput); }); if ( filetypes.length <= 1 ) { - new OSjs.GUI.Element(ft.$element.parentNode).hide(); + new GUIElement(ft.$element.parentNode).hide(); } - filename.on('enter', function(ev) { - self.selected = null; - self.checkSelection(ev); + filename.on('enter', (ev) => { + this.selected = null; + this.checkSelection(ev); }); - filename.on('change', function(ev) { + filename.on('change', (ev) => { checkEmptyInput(); }); - filename.on('keyup', function(ev) { + filename.on('keyup', (ev) => { checkEmptyInput(); }); } else { @@ -233,31 +232,22 @@ this._find('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; + const rootPath = MountManager.getModuleFromPath(this.path).option('root'); + const modules = MountManager.getModules().filter((m) => { + if ( !this.args.mfilter.length ) { + return true; } - return true; - }).map(function(m) { + return this.args.mfilter.every((fn) => fn(m)); + }).map((m) => { return { - label: m.name + (m.module.readOnly ? Utils.format(' ({0})', API._('LBL_READONLY')) : ''), - value: m.module.root + label: m.option('title') + (m.isReadOnly() ? Utils.format(' ({0})', _('LBL_READONLY')) : ''), + value: m.option('root') }; }); mlist.clear().add(modules).set('value', rootPath); - mlist.on('change', function(ev) { - self.changePath(ev.detail, true); + mlist.on('change', (ev) => { + this.changePath(ev.detail, true); }); this.changePath(); @@ -265,49 +255,47 @@ checkEmptyInput(); return root; - }; + } - FileDialog.prototype.changePath = function(dir, fromDropdown) { - var self = this; - var view = this._find('FileView'); - var lastDir = this.path; + changePath(dir, fromDropdown) { + const view = this._find('FileView'); + const lastDir = this.path; - function resetLastSelected() { - var mm = OSjs.Core.getMountManager(); - var rootPath = mm.getRootFromPath(lastDir); + const resetLastSelected = () => { try { - self._find('ModuleSelect').set('value', rootPath); + const rootPath = MountManager.getModuleFromPath(lastDir).option('root'); + this._find('ModuleSelect').set('value', rootPath); } catch ( e ) { console.warn('FileDialog::changePath()', 'resetLastSelection()', e); } - } + }; this._toggleLoading(true); view.chdir({ path: dir || this.path, - done: function(error) { + done: (error) => { if ( error ) { if ( fromDropdown ) { resetLastSelected(); } } else { if ( dir ) { - self.path = dir; + this.path = dir; } } - self.selected = null; - self._toggleLoading(false); + this.selected = null; + this._toggleLoading(false); } }); - }; + } - FileDialog.prototype.checkFileExtension = function() { - var filename = this._find('Filename'); + checkFileExtension() { + const filename = this._find('Filename'); - var mime = this.args.mime; - var input = filename.get('value'); + let mime = this.args.mime; + let input = filename.get('value'); if ( this.args.filetypes.length ) { if ( !input && this.args.filename ) { @@ -315,10 +303,10 @@ } if ( input.length ) { - var extension = input.split('.').pop(); - var found = false; + const extension = input.split('.').pop(); - this.args.filetypes.forEach(function(f) { + let found = false; + this.args.filetypes.forEach((f) => { if ( f.extension === extension ) { found = f; } @@ -326,7 +314,7 @@ }); found = found || this.args.filetypes[0]; - input = Utils.replaceFileExtension(input, found.extension); + input = FS.replaceFileExtension(input, found.extension); mime = found.mime; } } @@ -335,11 +323,9 @@ filename: input, mime: mime }; - }; - - FileDialog.prototype.checkSelection = function(ev, wasActivated) { - var self = this; + } + checkSelection(ev, wasActivated) { if ( this.selected && this.selected.type === 'dir' ) { if ( wasActivated ) { // this.args.select !== 'dir' && @@ -349,59 +335,61 @@ } if ( this.args.type === 'save' ) { - var check = this.checkFileExtension(); + let check = this.checkFileExtension(); if ( !this.path || !check.filename ) { - API.error(API._('DIALOG_FILE_ERROR'), API._('DIALOG_FILE_MISSING_FILENAME')); + OSjs.error(_('DIALOG_FILE_ERROR'), _('DIALOG_FILE_MISSING_FILENAME')); return false; } - this.selected = new VFS.File(this.path.replace(/^\//, '') + '/' + check.filename, check.mime); + this.selected = new FileMetadata(this.path.replace(/^\//, '') + '/' + check.filename, check.mime); this._toggleDisabled(true); - VFS.exists(this.selected, function(error, result) { - self._toggleDisabled(false); - - if ( self._destroyed ) { - return; + VFS.exists(this.selected).then((result) => { + this._toggleDisabled(false); + if ( this._destroyed ) { + return false; } - 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); + if ( result ) { + this._toggleDisabled(true); + + if ( this.selected ) { + DialogWindow.create('Confirm', { + buttons: ['yes', 'no'], + message: _('DIALOG_FILE_OVERWRITE', this.selected.filename) + }, (ev, button) => { + this._toggleDisabled(false); + + if ( button === 'yes' || button === 'ok' ) { + this.closeCallback(ev, 'ok', this.selected); + } + }, this); } + } else { + this.closeCallback(ev, 'ok', this.selected); } + return true; + }).catch((error) => { + this._toggleDisabled(false); + if ( this._destroyed ) { + return; + } + OSjs.error(_('DIALOG_FILE_ERROR'), _('DIALOG_FILE_MISSING_FILENAME')); }); return false; } else { if ( !this.selected && this.args.select !== 'dir' ) { - API.error(API._('DIALOG_FILE_ERROR'), API._('DIALOG_FILE_MISSING_SELECTION')); + OSjs.error(_('DIALOG_FILE_ERROR'), _('DIALOG_FILE_MISSING_SELECTION')); return false; } - var res = this.selected; + let res = this.selected; if ( !res && this.args.select === 'dir' ) { - res = new VFS.File({ - filename: Utils.filename(this.path), + res = new FileMetadata({ + filename: FS.filename(this.path), path: this.path, type: 'dir' }); @@ -411,20 +399,15 @@ } return true; - }; + } - FileDialog.prototype.onClose = function(ev, button) { + onClose(ev, button) { if ( button === 'ok' && !this.checkSelection(ev) ) { return; } this.closeCallback(ev, button, this.selected); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.File = Object.seal(FileDialog); +} -})(OSjs.API, OSjs.VFS, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/fileinfo.js b/src/client/javascript/dialogs/fileinfo.js index 80c330f99f..ceabad4612 100644 --- a/src/client/javascript/dialogs/fileinfo.js +++ b/src/client/javascript/dialogs/fileinfo.js @@ -27,55 +27,47 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import * as VFS from 'vfs/fs'; +import {_} from 'core/locales'; + +/** + * An 'File Information' dialog + * + * @example DialogWindow.create('FileInfo', {}, fn); + * @extends DialogWindow + */ +export default class FileInfoDialog extends DialogWindow { /** - * An 'File Information' dialog - * - * @example - * - * OSjs.API.createDialog('FileInfo', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title - * @param {OSjs.VFS.File} args.file File to use + * @param {FileMetadata} args.file File to use * @param {CallbackDialog} callback Callback when done - * - * @constructor FileInfo - * @memberof OSjs.Dialogs */ - function FileInfoDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); - DialogWindow.apply(this, ['FileInfoDialog', { - title: args.title || API._('DIALOG_FILEINFO_TITLE'), + constructor(args, callback) { + args = Object.assign({}, {}, args); + + super('FileInfoDialog', { + title: args.title || _('DIALOG_FILEINFO_TITLE'), width: 400, height: 400 - }, args, callback]); + }, 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); + init() { + const root = super.init(...arguments); - var txt = this._find('Info').set('value', API._('LBL_LOADING')); - var file = this.args.file; + const txt = this._find('Info').set('value', _('LBL_LOADING')); + const 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) { + VFS.fileinfo(file).then((data) => { + const info = []; + Object.keys(data).forEach((i) => { if ( i === 'exif' ) { info.push(i + ':\n\n' + data[i]); } else { @@ -83,23 +75,13 @@ } }); txt.set('value', info.join('\n\n')); - } - - VFS.fileinfo(file, function(error, result) { - if ( error ) { - _onError(error); - return; - } - _onSuccess(result || {}); + return true; + }).catch((error) => { + txt.set('value', _('DIALOG_FILEINFO_ERROR_LOOKUP_FMT', file.path)); }); return root; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.FileInfo = Object.seal(FileInfoDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/fileprogress.js b/src/client/javascript/dialogs/fileprogress.js index ed1084964c..1668330502 100644 --- a/src/client/javascript/dialogs/fileprogress.js +++ b/src/client/javascript/dialogs/fileprogress.js @@ -27,74 +27,73 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; + +/** + * An 'File Progress Indicator' dialog + * + * @desc This is only used internally automatically. + * + * @example DialogWindow.create('FileProgress', {}, fn); + * @extends DialogWindow + */ +export default class FileProgressDialog extends DialogWindow { /** - * An 'File Progress Indicator' dialog - * - * This is only used internally automatically. - * - * @example - * - * OSjs.API.createDialog('FileProgress', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message * @param {CallbackDialog} callback Callback when done - * - * @constructor FileProgress - * @memberof OSjs.Dialogs */ - function FileProgressDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); - DialogWindow.apply(this, ['FileProgressDialog', { - title: args.title || API._('DIALOG_FILEPROGRESS_TITLE'), + constructor(args, callback) { + args = Object.assign({}, {}, args); + + super('FileProgressDialog', { + title: args.title || _('DIALOG_FILEPROGRESS_TITLE'), icon: 'actions/document-send.png', width: 400, height: 100 - }, args, callback]); + }, 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); + init() { + const root = super.init(...arguments); if ( this.args.message ) { this._find('Message').set('value', this.args.message, true); } return root; - }; + } - FileProgressDialog.prototype.onClose = function(ev, button) { + onClose(ev, button) { this.closeCallback(ev, button, null); - }; + } - FileProgressDialog.prototype.setProgress = function(p) { - this._find('Progress').set('progress', p); - }; + setProgress(p, close = true) { + const pb = this._find('Progress'); + if ( pb ) { + pb.set('progress', p); + } + + if ( close && p >= 100 ) { + this._close(true); + } + } - FileProgressDialog.prototype._close = function(force) { + _close(force) { if ( !force && this.busy ) { return false; } - return DialogWindow.prototype._close.call(this); - }; + return super._close(); + } - FileProgressDialog.prototype._onKeyEvent = function(ev) { + _onKeyEvent(ev) { if ( !this.busy ) { - DialogWindow.prototype._onKeyEvent.apply(this, arguments); + super._onKeyEvent(...arguments); } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.FileProgress = Object.seal(FileProgressDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/fileupload.js b/src/client/javascript/dialogs/fileupload.js index b9e8c24555..6f0119364b 100644 --- a/src/client/javascript/dialogs/fileupload.js +++ b/src/client/javascript/dialogs/fileupload.js @@ -27,86 +27,83 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, VFS, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import * as VFS from 'vfs/fs'; +import {_} from 'core/locales'; +import {getConfig, getDefaultPath} from 'core/config'; + +/** + * An 'FileUpload' dialog + * + * @example DialogWindow.create('FileUpload', {}, fn); + * @extends DialogWindow + */ +export default class FileUploadDialog extends DialogWindow { /** - * An 'FileUpload' dialog - * - * @example - * - * OSjs.API.createDialog('FileUpload', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.dest VFS destination - * @param {OSjs.VFS.File} [args.file] File to upload + * @param {FileMetadata} [args.file] File to upload * @param {CallbackDialog} callback Callback when done - * - * @constructor FileUpload - * @memberof OSjs.Dialogs */ - function FileUploadDialog(args, callback) { - args = Utils.argumentDefaults(args, { + constructor(args, callback) { + args = Object.assign({}, { + dest: getDefaultPath(), progress: {}, file: null - }); + }, args); if ( args.destination ) { args.dest = args.destination; } if ( !args.dest ) { - args.dest = API.getDefaultPath(); + args.dest = getDefaultPath(); } - DialogWindow.apply(this, ['FileUploadDialog', { - title: args.title || API._('DIALOG_UPLOAD_TITLE'), + super('FileUploadDialog', { + title: args.title || _('DIALOG_UPLOAD_TITLE'), icon: 'actions/document-new.png', width: 400, height: 100 - }, args, callback]); + }, 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._find('Message'); - var maxSize = API.getConfig('VFS.MaxUploadSize'); + init() { + const root = super.init(...arguments); + const message = this._find('Message'); + const maxSize = getConfig('VFS.MaxUploadSize'); - message.set('value', API._('DIALOG_UPLOAD_DESC', this.args.dest, maxSize), true); + message.set('value', _('DIALOG_UPLOAD_DESC', this.args.dest, maxSize), true); - var input = this._find('File'); + const input = this._find('File'); if ( this.args.file ) { this.setFile(this.args.file, input); } else { - input.on('change', function(ev) { - self.setFile(ev.detail, input); + input.on('change', (ev) => { + this.setFile(ev.detail, input); }); } return root; - }; + } - FileUploadDialog.prototype.setFile = function(file, input) { - var self = this; - var progressDialog; + setFile(file, input) { + let 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') + const error = (msg, ev) => { + OSjs.error( + _('DIALOG_UPLOAD_FAILED'), + _('DIALOG_UPLOAD_FAILED_MSG'), + msg || _('DIALOG_UPLOAD_FAILED_UNKNOWN') ); progressDialog._close(true); - self.onClose(ev, 'cancel'); - } + this.onClose(ev, 'cancel'); + }; if ( file ) { - var fileSize = 0; + let fileSize = 0; if ( file.size > 1024 * 1024 ) { fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; } else { @@ -119,55 +116,42 @@ this._find('ButtonCancel').set('disabled', true); - var desc = OSjs.API._('DIALOG_UPLOAD_MSG_FMT', file.name, file.type, fileSize, this.args.dest); + const desc = _('DIALOG_UPLOAD_MSG_FMT', file.name, file.type, fileSize, this.args.dest); - progressDialog = API.createDialog('FileProgress', { + progressDialog = DialogWindow.create('FileProgress', { message: desc, dest: this.args.dest, filename: file.name, mime: file.type, size: fileSize - }, function(ev, button) { + }, (ev, button) => { // Dialog closed }, 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(true); - self.onClose(ev, 'ok', file); - }, { - onprogress: function(ev) { + VFS.upload({files: [file], destination: this.args.dest}, { + onprogress: (ev) => { if ( ev.lengthComputable ) { - var p = Math.round(ev.loaded * 100 / ev.total); + const p = Math.round(ev.loaded * 100 / ev.total); progressDialog.setProgress(p); } } - }); + }).then(() => { + progressDialog._close(true); + return this.onClose(null, 'ok', file); + }).catch(error); - setTimeout(function() { + setTimeout(() => { if ( progressDialog ) { progressDialog._focus(); } }, 100); } - }; + } - FileUploadDialog.prototype.onClose = function(ev, button, result) { + onClose(ev, button, result) { result = result || null; this.closeCallback(ev, button, result); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.FileUpload = Object.seal(FileUploadDialog); +} -})(OSjs.API, OSjs.VFS, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/font.js b/src/client/javascript/dialogs/font.js index ca00c6520e..84d72d2ddf 100644 --- a/src/client/javascript/dialogs/font.js +++ b/src/client/javascript/dialogs/font.js @@ -27,16 +27,19 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; + +/** + * An 'Font Selection' dialog + * + * @example DialogWindow.create('Font', {}, fn); + * @extends DialogWindow + */ +export default class FontDialog extends DialogWindow { /** - * An 'Font Selection' dialog - * - * @example - * - * OSjs.API.createDialog('Font', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} [args.fontName=internal] Current font name @@ -49,32 +52,29 @@ * @param {String} [args.text] Preview text * @param {String} [args.unit=px] Size unit * @param {CallbackDialog} callback Callback when done - * - * @constructor Font - * @memberof OSjs.Dialogs */ - function FontDialog(args, callback) { - args = Utils.argumentDefaults(args, { - fontName: API.getConfig('Fonts.default'), + constructor(args, callback) { + args = Object.assign({}, { + fontName: getConfig('Fonts.default'), fontSize: 12, fontColor: '#000000', backgroundColor: '#ffffff', - fonts: API.getConfig('Fonts.list'), + fonts: getConfig('Fonts.list'), minSize: 6, maxSize: 30, text: 'The quick brown fox jumps over the lazy dog', unit: 'px' - }); + }, args); if ( args.unit === 'null' || args.unit === 'unit' ) { args.unit = ''; } - DialogWindow.apply(this, ['FontDialog', { - title: args.title || API._('DIALOG_FONT_TITLE'), + super('FontDialog', { + title: args.title || _('DIALOG_FONT_TITLE'), width: 400, height: 300 - }, args, callback]); + }, args, callback); this.selection = { fontName: args.fontName, @@ -82,40 +82,36 @@ }; } - FontDialog.prototype = Object.create(DialogWindow.prototype); - FontDialog.constructor = DialogWindow; - - FontDialog.prototype.init = function() { - var root = DialogWindow.prototype.init.apply(this, arguments); + init() { + const root = super.init(...arguments); - var self = this; - var preview = this._find('FontPreview'); - var sizes = []; - var fonts = []; + const preview = this._find('FontPreview'); + const sizes = []; + const fonts = []; - for ( var i = this.args.minSize; i < this.args.maxSize; i++ ) { + for ( let 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++ ) { + for ( let 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; - } + const updatePreview = () => { + preview.querySelector('textarea').style.fontFamily = this.selection.fontName; + preview.querySelector('textarea').style.fontSize = this.selection.fontSize; + }; - var listFonts = this._find('FontName'); + const listFonts = this._find('FontName'); listFonts.add(fonts).set('value', this.args.fontName); - listFonts.on('change', function(ev) { - self.selection.fontName = ev.detail; + listFonts.on('change', (ev) => { + this.selection.fontName = ev.detail; updatePreview(); }); - var listSizes = this._find('FontSize'); + const listSizes = this._find('FontSize'); listSizes.add(sizes).set('value', this.args.fontSize); - listSizes.on('change', function(ev) { - self.selection.fontSize = ev.detail + self.args.unit; + listSizes.on('change', (ev) => { + this.selection.fontSize = ev.detail + this.args.unit; updatePreview(); }); @@ -130,17 +126,12 @@ updatePreview(); return root; - }; + } - FontDialog.prototype.onClose = function(ev, button) { - var result = button === 'ok' ? this.selection : null; + onClose(ev, button) { + const result = button === 'ok' ? this.selection : null; this.closeCallback(ev, button, result); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.Font = Object.seal(FontDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/dialogs/input.js b/src/client/javascript/dialogs/input.js index adae5160f8..c49d0ccd10 100644 --- a/src/client/javascript/dialogs/input.js +++ b/src/client/javascript/dialogs/input.js @@ -27,83 +27,73 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, DialogWindow) { - 'use strict'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; + +/** + * An 'Input' dialog + * + * @example DialogWindow.create('Input', {}, fn); + * @extends DialogWindow + */ +export default class InputDialog extends DialogWindow { /** - * An 'Input' dialog - * - * @example - * - * OSjs.API.createDialog('Input', {}, fn); - * * @param {Object} args An object with arguments * @param {String} args.title Dialog title * @param {String} args.message Dialog message * @param {String} [args.value] Input value * @param {String} [args.placeholder] Input placeholder * @param {CallbackDialog} callback Callback when done - * - * @constructor Input - * @memberof OSjs.Dialogs */ - function InputDialog(args, callback) { - args = Utils.argumentDefaults(args, {}); + constructor(args, callback) { + args = Object.assign({}, {}, args); - DialogWindow.apply(this, ['InputDialog', { - title: args.title || API._('DIALOG_INPUT_TITLE'), + super('InputDialog', { + title: args.title || _('DIALOG_INPUT_TITLE'), icon: 'status/dialog-information.png', width: 400, height: 120 - }, args, callback]); + }, 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); + init() { + const root = super.init(...arguments); if ( this.args.message ) { - var msg = DialogWindow.parseMessage(this.args.message); + const msg = DialogWindow.parseMessage(this.args.message); this._find('Message').empty().append(msg); } - var input = this._find('Input'); + const input = this._find('Input'); input.set('placeholder', this.args.placeholder || ''); input.set('value', this.args.value || ''); - input.on('enter', function(ev) { - self.onClose(ev, 'ok'); + input.on('enter', (ev) => { + this.onClose(ev, 'ok'); }); return root; - }; + } - InputDialog.prototype._focus = function() { - if ( DialogWindow.prototype._focus.apply(this, arguments) ) { + _focus() { + if ( super._focus(...arguments) ) { this._find('Input').focus(); return true; } return false; - }; + } - InputDialog.prototype.onClose = function(ev, button) { - var result = this._find('Input').get('value'); + onClose(ev, button) { + const result = this._find('Input').get('value'); this.closeCallback(ev, button, button === 'ok' ? result : null); - }; + } - InputDialog.prototype.setRange = function(range) { - var input = this._find('Input'); + setRange(range) { + const input = this._find('Input'); if ( input.$element ) { input.$element.querySelector('input').select(range); } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - OSjs.Dialogs.Input = Object.seal(InputDialog); +} -})(OSjs.API, OSjs.Utils, OSjs.Core.DialogWindow); diff --git a/src/client/javascript/gui/dataview.js b/src/client/javascript/gui/dataview.js index 3d39ebc95e..260db46f4b 100644 --- a/src/client/javascript/gui/dataview.js +++ b/src/client/javascript/gui/dataview.js @@ -27,756 +27,750 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +import * as GUI from 'utils/gui'; +import * as DOM from 'utils/dom'; +import * as Menu from 'gui/menu'; +import * as Events from 'utils/events'; +import * as Clipboard from 'utils/clipboard'; +import * as Keycodes from 'utils/keycodes'; +import FileMetadata from 'vfs/file'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// ABSTRACTION HELPERS +///////////////////////////////////////////////////////////////////////////// + +const _classMap = { // Defaults to (foo-bar)-entry + 'gui-list-view': 'gui-list-view-row' +}; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function getEntryTagName(type) { + if ( typeof type !== 'string' ) { + type = type.tagName.toLowerCase(); + } - ///////////////////////////////////////////////////////////////////////////// - // ABSTRACTION HELPERS - ///////////////////////////////////////////////////////////////////////////// + let className = _classMap[type]; + if ( !className ) { + className = type + '-entry'; + } - var _classMap = { // Defaults to (foo-bar)-entry - 'gui-list-view': 'gui-list-view-row' - }; + return className; +} - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// +function getEntryFromEvent(ev, header) { + const t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + const tn = t.tagName.toLowerCase(); - function getEntryTagName(type) { - if ( typeof type !== 'string' ) { - type = type.tagName.toLowerCase(); - } + if ( tn.match(/(view|textarea|body)$/) ) { + return null; + } else if ( tn === 'gui-list-view-column' && !header ) { + return t.parentNode; + } - var className = _classMap[type]; - if ( !className ) { - className = type + '-entry'; - } + return t; +} - return className; +function isHeader(ev, row) { + row = row || getEntryFromEvent(ev); + return row && row.parentNode.tagName === 'GUI-LIST-VIEW-HEAD'; +} + +function handleItemSelection(ev, item, idx, className, selected, root, multipleSelect) { + root = root || item.parentNode; + if ( isHeader(null, item) ) { + return multipleSelect ? [] : null; } - function getEntryFromEvent(ev, header) { - var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); - var tn = t.tagName.toLowerCase(); + if ( idx === -1 ) { + root.querySelectorAll(getEntryTagName(root)).forEach(function(e) { + DOM.$removeClass(e, 'gui-active'); + }); + selected = []; + } else { + if ( !multipleSelect || !ev.shiftKey ) { + root.querySelectorAll(className).forEach(function(i) { + DOM.$removeClass(i, 'gui-active'); + }); + selected = []; + } - if ( tn.match(/(view|textarea|body)$/) ) { - return null; - } else if ( tn === 'gui-list-view-column' && !header ) { - return t.parentNode; + const findex = selected.indexOf(idx); + if ( findex >= 0 ) { + selected.splice(findex, 1); + DOM.$removeClass(item, 'gui-active'); + } else { + selected.push(idx); + DOM.$addClass(item, 'gui-active'); } + } + + selected.sort(function(a, b) { + return a - b; + }); - return t; + return selected; +} + +function handleKeyPress(cls, el, ev) { + const map = {}; + const key = ev.keyCode; + const type = el.tagName.toLowerCase(); + const className = getEntryTagName(type); + const root = el.querySelector(type + '-body'); + const entries = root.querySelectorAll(className); + const count = entries.length; + + if ( !count ) { + return; } - function isHeader(ev, row) { - row = row || getEntryFromEvent(ev); - return row && row.parentNode.tagName === 'GUI-LIST-VIEW-HEAD'; + if ( key === Keycodes.ENTER ) { + el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: cls.values()}})); + return; } - function handleItemSelection(ev, item, idx, className, selected, root, multipleSelect) { - root = root || item.parentNode; - if ( isHeader(null, item) ) { - return multipleSelect ? [] : null; - } + map[Keycodes.C] = function(ev) { + if ( ev.ctrlKey ) { + const selected = cls.values(); + if ( selected && selected.length ) { + const data = []; - 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.forEach(function(s) { + if ( s && s.data ) { + data.push(new FileMetadata(s.data.path, s.data.mime)); + } }); - 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'); + Clipboard.setClipboard(data); } } + }; - selected.sort(function(a, b) { - return a - b; - }); + const selected = el._selected.concat() || []; + const first = selected.length ? selected[0] : 0; + const last = selected.length > 1 ? selected[selected.length - 1] : first; - return selected; - } - - function handleKeyPress(cls, 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; - } + let current = 0; - if ( key === Utils.Keys.ENTER ) { - el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: cls.values()}})); - return; + function select() { + const item = entries[current]; + if ( item ) { + el._selected = handleItemSelection(ev, item, current, className, selected, root, ev.shiftKey); + cls.scrollIntoView(item); } + } - map[Utils.Keys.C] = function(ev) { - if ( ev.ctrlKey ) { - var selected = cls.values(); - 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); - } + function getRowSize() { + /* NOT ACCURATE! + var ew = entries[0].offsetWidth; + var tw = root.offsetWidth; + var d = Math.floor(tw/ew); + */ + let d = 0; + let lastTop = -1; + + entries.forEach(function(e) { + if ( lastTop === -1 ) { + lastTop = e.offsetTop; } - }; - - 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); - cls.scrollIntoView(item); + if ( lastTop !== e.offsetTop ) { + return false; } - } - - function getRowSize() { - /* NOT ACCURATE! - var ew = entries[0].offsetWidth; - var tw = root.offsetWidth; - var d = Math.floor(tw/ew); - */ - 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++; - lastTop = e.offsetTop; - d++; + return true; + }); - return true; - }); + return d; + } - return d; + function handleKey() { + function next() { + current = Math.min(last + 1, count); + select(); + } + function prev() { + current = Math.max(0, first - 1); + select(); } - function handleKey() { - function next() { - current = Math.min(last + 1, count); + if ( type === 'gui-tree-view' || type === 'gui-list-view' ) { + map[Keycodes.UP] = prev; + map[Keycodes.DOWN] = next; + } else { + map[Keycodes.UP] = function() { + current = Math.max(0, first - getRowSize()); select(); - } - function prev() { - current = Math.max(0, first - 1); + }; + map[Keycodes.DOWN] = function() { + current = Math.max(last, last + getRowSize()); 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); - } + }; + map[Keycodes.LEFT] = prev; + map[Keycodes.RIGHT] = next; } - handleKey(); + if ( map[key] ) { + map[key](ev); + } } - function getValueParameter(r) { - var value = r.getAttribute('data-value'); + handleKey(); +} + +function getValueParameter(r) { + const value = r.getAttribute('data-value'); + try { + return JSON.parse(value); + } catch ( e ) {} + + return value; +} + +function matchValueByKey(r, val, key, idx) { + const value = r.getAttribute('data-value'); + if ( !key && (val === idx || val === value) ) { + return r; + } else { try { - return JSON.parse(value); + const json = JSON.parse(value); + if ( typeof json[key] === 'object' ? json[key] === val : String(json[key]) === String(val) ) { + return r; + } } catch ( e ) {} - - return value; } + return false; +} - 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; - } +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// +/** + * Element: '_dataview' + * + * @desc + * This is an abstraction layer for Icon, Tree and List views. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     Mixed         The value/currently selected
+ *   getter    selected  Mixed         Alias of 'value'
+ *   getter    entry     Mixed         Gets an etnry by value, key
+ *   setter    value     Mixed         The value/currently selected
+ *   property  multiple  boolean       If multiple elements are selectable
+ *   event     select                  When entry was selected => fn(ev)
+ *   event     activate                When entry was activated => fn(ev)
+ *   action    add                     Add elements(s) => fn(entries)
+ *   action    patch                   Patch/Update elements => fn(entries)
+ *   action    remove                  Removes element => fn(arg)
+ *   action    clear                   Clear elements => fn()
+ * 
+ * + * @abstract + * @extends GUIElement + */ +export default class UIDataView extends GUIElement { /** - * Element: '_dataview' + * Clears the view * - * This is an abstraction layer for Icon, Tree and List views. + * @param {Node} [body] The body to clear * - * See `ev.detail` for data on events (like on 'change'). + * @return {GUIElement} this + */ + clear(body) { + const el = this.$element; + if ( !arguments.length ) { + body = el; + } + + el.querySelectorAll(getEntryTagName(el)).forEach((row) => { + Events.$unbind(row); + }); + + DOM.$empty(body); + body.scrollTop = 0; + el._selected = []; + + return this; + } + + /** + * Adds one or more elements * - *

-   *   getter    value     Mixed         The value/currently selected
-   *   getter    selected  Mixed         Alias of 'value'
-   *   getter    entry     Mixed         Gets an etnry by value, key
-   *   setter    value     Mixed         The value/currently selected
-   *   property  multiple  boolean       If multiple elements are selectable
-   *   event     select                  When entry was selected => fn(ev)
-   *   event     activate                When entry was activated => fn(ev)
-   *   action    add                     Add elements(s) => fn(entries)
-   *   action    patch                   Patch/Update elements => fn(entries)
-   *   action    remove                  Removes element => fn(arg)
-   *   action    clear                   Clear elements => fn()
-   * 
+ * @param {Array|Object} entries Entry list, or a single entry + * @param {Function} [oncreate] Callback on creation => fn(this, node) * - * @constructor DataView - * @memberof OSjs.GUI - * @extends OSjs.GUI.Element - * @abstract + * @return {GUIElement} this */ - var UIDataView = Utils.inherit(GUI.Element, null, { - /** - * Clears the view - * - * @param {Node} [body] The body to clear - * - * @function clear - * @memberof OSjs.GUI.DataView# - * @return {OSjs.GUI.Element} this - */ - clear: function(body) { - var el = this.$element; - if ( !arguments.length ) { - body = el; - } + add(entries, oncreate) { + oncreate = oncreate || function() {}; - el.querySelectorAll(getEntryTagName(el)).forEach(function(row) { - Utils.$unbind(row); - }); + if ( !(entries instanceof Array) ) { + entries = [entries]; + } - Utils.$empty(body); - body.scrollTop = 0; - el._selected = []; - - return this; - }, - - /** - * Adds one or more elements - * - * @param {Array|Object} entries Entry list, or a single entry - * @param {Function} [oncreate] Callback on creation => fn(this, node) - * - * @function add - * @memberof OSjs.GUI.DataView# - * @return {OSjs.GUI.Element} this - */ - add: function(entries, oncreate) { - oncreate = oncreate || function() {}; - - if ( !(entries instanceof Array) ) { - entries = [entries]; - } + entries.forEach((el) => { + oncreate(this, el); + }); - var self = this; - entries.forEach(function(el) { - oncreate(self, el); - }); + return this; + } - return this; - }, - - /** - * Do a diffed render - * - * @param {Array|Object} entries Entry list, or a single entry - * @param {String} className Classname of entry - * @param {Node} body The body container - * @param {Function} [oncreate] Callback on creation => fn(this, node) - * @param {Function} [oninit] Callback on init => fn(this, node) - * - * @function patch - * @memberof OSjs.GUI.DataView# - * @return {OSjs.GUI.Element} this - */ - patch: function(entries, className, body, oncreate, oninit) { - var self = this; - var single = false; - var remove = GUI.DataView.prototype.remove; - - if ( !(entries instanceof Array) ) { - entries = [entries]; - single = true; + /** + * Do a diffed render + * + * @param {Array|Object} entries Entry list, or a single entry + * @param {String} className Classname of entry + * @param {Node} body The body container + * @param {Function} [oncreate] Callback on creation => fn(this, node) + * @param {Function} [oninit] Callback on init => fn(this, node) + * + * @return {GUIElement} this + */ + patch(entries, className, body, oncreate, oninit) { + let single = false; + + if ( !(entries instanceof Array) ) { + entries = [entries]; + single = true; + } + + let inView = {}; + body.querySelectorAll(className).forEach((row) => { + const id = row.getAttribute('data-id'); + if ( id !== null ) { + inView[id] = row; } + }); - var inView = {}; - body.querySelectorAll(className).forEach(function(row) { - var id = row.getAttribute('data-id'); - if ( id !== null ) { - inView[id] = row; + entries.forEach((entry) => { + let insertBefore; + if ( typeof entry.id !== 'undefined' && entry.id !== null ) { + if ( inView[entry.id] ) { + insertBefore = inView[entry.id]; + delete inView[entry.id]; } - }); - 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(self, entry); - if ( row ) { - if ( insertBefore ) { - if ( Utils.$hasClass(insertBefore, 'gui-active') ) { - Utils.$addClass(row, 'gui-active'); - } - - body.insertBefore(row, insertBefore); - remove.call(self, null, className, insertBefore, body); - } else { - body.appendChild(row); + const row = oncreate(this, entry); + if ( row ) { + if ( insertBefore ) { + if ( DOM.$hasClass(insertBefore, 'gui-active') ) { + DOM.$addClass(row, 'gui-active'); } - oninit(self, row); + + body.insertBefore(row, insertBefore); + //this.remove(null, className, insertBefore, body); + UIDataView.prototype.remove.call(this, null, className, insertBefore, body); + } else { + body.appendChild(row); } + oninit(this, row); } + } + }); + + if ( !single ) { + Object.keys(inView).forEach((k) => { + //this.remove(null, className, inView[k]); + UIDataView.prototype.remove.call(this, null, className, inView[k]); }); + } - if ( !single ) { - Object.keys(inView).forEach(function(k) { - remove.call(self, null, className, inView[k]); - }); - } + inView = {}; + this.updateActiveSelection(className); - inView = {}; - this.updateActiveSelection(className); - - return this; - }, - - /** - * Remove element - * - * @param {Array} [args] id, key pair - * @param {String} [className] Classname of entry - * @param {Node} [target] Remove this target instead of using args - * @param {Node} [parentEl] Entry parent node - * - * @function remove - * @memberof OSjs.GUI.DataView# - * @return {OSjs.GUI.Element} this - */ - remove: function(args, className, target, parentEl) { - - args = args || []; - parentEl = parentEl || this.$element; - - if ( target ) { - Utils.$remove(target); - } else if ( typeof args[1] === 'undefined' && typeof args[0] === 'number' ) { - Utils.$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(Utils.$remove); - } + return this; + } - this.updateActiveSelection(className); + /** + * Remove element + * + * @param {Array} [args] id, key pair + * @param {String} [className] Classname of entry + * @param {Node} [target] Remove this target instead of using args + * @param {Node} [parentEl] Entry parent node + * + * @return {GUIElement} this + */ + remove(args, className, target, parentEl) { - return this; - }, + args = args || []; + parentEl = parentEl || this.$element; - /* - * Update active selection - */ - updateActiveSelection: function(className) { - var active = []; - this.$element.querySelectorAll(className + '.gui-active').forEach(function(cel) { - active.push(Utils.$index(cel)); - }); - this.$element._active = active; - }, - - /* - * Scroll given element into view - * TODO: Use native method ? - */ - scrollIntoView: function(element) { - var el = this.$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; - } - } + if ( target ) { + DOM.$remove(target); + } else if ( typeof args[1] === 'undefined' && typeof args[0] === 'number' ) { + DOM.$remove(parentEl.querySelectorAll(className)[args[0]]); + } else { + const findId = args[0]; + const findKey = args[1] || 'id'; + const q = 'data-' + findKey + '="' + findId + '"'; + parentEl.querySelectorAll(className + '[' + q + ']').forEach(DOM.$remove); + } - var scrollSpace = (el.scrollTop + el.offsetHeight) - marginTop; - var scrollTop = el.scrollTop + marginTop; - var elTop = pos.top - marginTop; + this.updateActiveSelection(className); - if ( pos !== null && (elTop > scrollSpace || elTop < scrollTop) ) { - el.scrollTop = elTop; - return true; + return this; + } + + /* + * Update active selection + */ + updateActiveSelection(className) { + const active = []; + this.$element.querySelectorAll(className + '.gui-active').forEach((cel) => { + active.push(DOM.$index(cel)); + }); + this.$element._active = active; + } + + /* + * Scroll given element into view + */ + scrollIntoView(element) { + const el = this.$element; + const pos = DOM.$position(element, el); + + let marginTop = 0; + if ( el.tagName.toLowerCase() === 'gui-list-view' ) { + const header = el.querySelector('gui-list-view-head'); + if ( header ) { + marginTop = header.offsetHeight; } + } - return false; - }, - - /* - * Binds events and such for an entry - */ - bindEntryEvents: function(row, className) { - var el = this.$element; - - function createDraggable() { - var value = row.getAttribute('data-value'); - if ( value !== null ) { - try { - value = JSON.parse(value); - } catch ( e ) {} - } + const scrollSpace = (el.scrollTop + el.offsetHeight) - marginTop; + const scrollTop = el.scrollTop + marginTop; + const elTop = pos.top - marginTop; - var source = row.getAttribute('data-draggable-source'); - if ( source === null ) { - source = GUI.Helpers.getWindowId(el); - if ( source !== null ) { - source = {wid: source}; - } - } + if ( pos !== null && (elTop > scrollSpace || elTop < scrollTop) ) { + el.scrollTop = elTop; + return true; + } - GUI.Helpers.createDraggable(row, { - type: el.getAttribute('data-draggable-type') || row.getAttribute('data-draggable-type'), - source: source, - data: value - }); + return false; + } + + /* + * Binds events and such for an entry + */ + bindEntryEvents(row, className) { + const el = this.$element; + + function createDraggable() { + let value = row.getAttribute('data-value'); + if ( value !== null ) { + try { + value = JSON.parse(value); + } catch ( e ) {} + } - var tooltip = row.getAttribute('data-tooltip'); - if ( tooltip && !row.getAttribute('title') ) { - row.setAttribute('title', tooltip); + let source = row.getAttribute('data-draggable-source'); + if ( source === null ) { + source = GUI.getWindowId(el); + if ( source !== null ) { + source = {wid: source}; } } - el.dispatchEvent(new CustomEvent('_render', {detail: { - element: row, - data: GUI.Helpers.getViewNodeValue(row) - }})); + GUI.createDraggable(row, { + type: el.getAttribute('data-draggable-type') || row.getAttribute('data-draggable-type'), + source: source, + data: value + }); - if ( el.getAttribute('data-draggable') === 'true' ) { - createDraggable(); + let tooltip = row.getAttribute('data-tooltip'); + if ( tooltip && !row.getAttribute('title') ) { + row.setAttribute('title', tooltip); } - }, - - /* - * Get selected from array of nodes - */ - getSelected: function(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; - }, - - /* - * Get entry from an array of nodes - */ - getEntry: function(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; + el.dispatchEvent(new CustomEvent('_render', {detail: { + element: row, + data: GUI.getViewNodeValue(row) + }})); + + if ( el.getAttribute('data-draggable') === 'true' ) { + createDraggable(); + } + } + + /* + * Get selected from array of nodes + */ + getSelected(entries) { + const selected = []; + entries.forEach((iter, idx) => { + if ( DOM.$hasClass(iter, 'gui-active') ) { + selected.push({ + index: idx, + data: GUI.getViewNodeValue(iter) + }); } + }); + return selected; + } - return !asValue ? entries : (entries || []).map(function(iter) { - return getValueParameter(iter); + /* + * Get entry from an array of nodes + */ + getEntry(entries, val, key, asValue) { + if ( val ) { + let result = null; + entries.forEach((r, idx) => { + if ( !result && matchValueByKey(r, val, key, idx) ) { + result = r; + } }); - }, - - /* - * Set selected from array of nodes - */ - setSelected: function(body, entries, val, key, opts) { - var self = this; - var select = []; - var scrollIntoView = false; - var el = this.$element; - - if ( typeof opts === 'object' ) { - scrollIntoView = opts.scroll === true; + + return (asValue && result) ? getValueParameter(result) : result; + } + + return !asValue ? entries : (entries || []).map((iter) => { + return getValueParameter(iter); + }); + } + + /* + * Set selected from array of nodes + */ + setSelected(body, entries, val, key, opts) { + const select = []; + const el = this.$element; + + let scrollIntoView = false; + if ( typeof opts === 'object' ) { + scrollIntoView = opts.scroll === true; + } + + const sel = (r, idx) => { + select.push(idx); + DOM.$addClass(r, 'gui-active'); + if ( scrollIntoView ) { + this.scrollIntoView(r); } + }; - function sel(r, idx) { - select.push(idx); - Utils.$addClass(r, 'gui-active'); - if ( scrollIntoView ) { - self.scrollIntoView(r); - } + entries.forEach((r, idx) => { + DOM.$removeClass(r, 'gui-active'); + if ( matchValueByKey(r, val, key, idx) ) { + sel(r, idx); } + }); - entries.forEach(function(r, idx) { - Utils.$removeClass(r, 'gui-active'); - if ( matchValueByKey(r, val, key, idx) ) { - sel(r, idx); - } - }); + el._selected = select; + } - el._selected = select; - }, + /* + * Builds element + */ + build(applyArgs) { + const el = this.$element; + el._selected = []; + el.scrollTop = 0; - /* - * Builds element - */ - build: function(applyArgs) { - var self = this; - var el = this.$element; - el._selected = []; - el.scrollTop = 0; + DOM.$addClass(el, 'gui-data-view'); - Utils.$addClass(el, 'gui-data-view'); + const singleClick = el.getAttribute('data-single-click') === 'true'; - var wasResized = false; - var singleClick = el.getAttribute('data-single-click') === 'true'; - var multipleSelect = el.getAttribute('data-multiple'); - multipleSelect = multipleSelect === null || multipleSelect === 'true'; + let wasResized = false; + let multipleSelect = el.getAttribute('data-multiple'); + multipleSelect = multipleSelect === null || multipleSelect === 'true'; - function select(ev) { - ev.stopPropagation(); - API.blurMenu(); + const select = (ev) => { + ev.stopPropagation(); + Menu.blur(); - if ( wasResized ) { - return false; - } + if ( wasResized ) { + return false; + } - var row = getEntryFromEvent(ev); - if ( !row ) { - return false; - } + const row = getEntryFromEvent(ev); + if ( !row ) { + return false; + } - var className = row.tagName.toLowerCase(); - if ( isHeader(null, row) ) { - var col = getEntryFromEvent(ev, true); - if ( col ) { - var sortBy = col.getAttribute('data-sortby'); - if ( sortBy ) { - var sortDir = col.getAttribute('data-sortdir'); - var resetDir = sortDir === 'desc'; - sortDir = sortDir === 'asc' ? 'desc' : (resetDir ? null : 'asc'); - sortBy = resetDir ? null : sortBy; - - col.setAttribute('data-sortdir', sortDir); - - el.setAttribute('data-sortby', sortBy || ''); - el.setAttribute('data-sortdir', sortDir || ''); - - el.dispatchEvent(new CustomEvent('_sort', {detail: { - sortDir: sortDir, - sortBy: sortBy - }})); - } + const className = row.tagName.toLowerCase(); + if ( isHeader(null, row) ) { + const col = getEntryFromEvent(ev, true); + if ( col ) { + let sortBy = col.getAttribute('data-sortby'); + if ( sortBy ) { + let sortDir = col.getAttribute('data-sortdir'); + let resetDir = sortDir === 'desc'; + sortDir = sortDir === 'asc' ? 'desc' : (resetDir ? null : 'asc'); + sortBy = resetDir ? null : sortBy; + + col.setAttribute('data-sortdir', sortDir); + + el.setAttribute('data-sortby', sortBy || ''); + el.setAttribute('data-sortdir', sortDir || ''); + + el.dispatchEvent(new CustomEvent('_sort', {detail: { + sortDir: sortDir, + sortBy: sortBy + }})); } - return false; } + return false; + } - if ( className === 'gui-tree-view-expander' ) { - self.expand({ - ev: ev, - entry: row.parentNode - }); - return true; - } - - var idx = Utils.$index(row); - el._selected = handleItemSelection(ev, row, idx, className, el._selected, el, multipleSelect); - el.dispatchEvent(new CustomEvent('_select', {detail: {entries: self.values()}})); - + if ( className === 'gui-tree-view-expander' ) { + this.expand({ + ev: ev, + entry: row.parentNode + }); return true; } - function activate(ev) { - ev.stopPropagation(); - API.blurMenu(); + const idx = DOM.$index(row); + el._selected = handleItemSelection(ev, row, idx, className, el._selected, el, multipleSelect); + el.dispatchEvent(new CustomEvent('_select', {detail: {entries: this.values()}})); - if ( isHeader(ev) ) { - return; - } + return true; + }; - if ( singleClick ) { - if ( select(ev) === false ) { - return; - } - } else { - if ( !getEntryFromEvent(ev) ) { - return; - } - } + const activate = (ev) => { + ev.stopPropagation(); + Menu.blur(); - el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: self.values()}})); + if ( isHeader(ev) ) { + return; } - function context(ev) { - if ( isHeader(ev) ) { + if ( singleClick ) { + if ( select(ev) === false ) { + return; + } + } else { + if ( !getEntryFromEvent(ev) ) { return; } - - select(ev); - el.dispatchEvent(new CustomEvent('_contextmenu', {detail: {entries: self.values(), x: ev.clientX, y: ev.clientY}})); } - function mousedown(ev) { - var target = ev.target; - wasResized = target && target.tagName === 'GUI-LIST-VIEW-COLUMN-RESIZER'; - } + el.dispatchEvent(new CustomEvent('_activate', {detail: {entries: this.values()}})); + }; - 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(self, el, ev); - }); - Utils.$bind(underlay, 'keypress', function(ev) { - ev.preventDefault(); - }); + const context = (ev) => { + if ( isHeader(ev) ) { + return; + } - Utils.$bind(el, 'mousedown', mousedown, true); + select(ev); + el.dispatchEvent(new CustomEvent('_contextmenu', {detail: {entries: this.values(), x: ev.clientX, y: ev.clientY}})); + }; - if ( singleClick ) { - Utils.$bind(el, 'click', activate, true); - } else { - Utils.$bind(el, 'click', select, true); - Utils.$bind(el, 'dblclick', activate, true); - } + function mousedown(ev) { + const target = ev.target; + wasResized = target && target.tagName === 'GUI-LIST-VIEW-COLUMN-RESIZER'; + } - Utils.$bind(el, 'contextmenu', function(ev) { - ev.preventDefault(); - context(ev); - return false; - }, true); + if ( !el.querySelector('textarea.gui-focus-element') && !el.getAttribute('no-selection') ) { + const underlay = document.createElement('textarea'); + underlay.setAttribute('aria-label', ''); + underlay.setAttribute('aria-hidden', 'true'); + underlay.setAttribute('readonly', 'true'); + underlay.className = 'gui-focus-element'; + Events.$bind(underlay, 'focus', (ev) => { + ev.preventDefault(); + DOM.$addClass(el, 'gui-element-focused'); + }); + Events.$bind(underlay, 'blur', (ev) => { + ev.preventDefault(); + DOM.$removeClass(el, 'gui-element-focused'); + }); + Events.$bind(underlay, 'keydown', (ev) => { + ev.preventDefault(); + handleKeyPress(this, el, ev); + }); + Events.$bind(underlay, 'keypress', (ev) => { + ev.preventDefault(); + }); - this.on('select', function(ev) { - if ( Utils.$hasClass(el, 'gui-element-focused') ) { - return; - } - // NOTE: This is a fix for Firefox stupid behaviour when focusing/blurring textboxes - // (which is used to have a focusable area in this case, called underlay) - var oldTop = el.scrollTop; - underlay.focus(); - el.scrollTop = oldTop; - setTimeout(function() { - el.scrollTop = oldTop; - }, 2); - }, true); + Events.$bind(el, 'mousedown', mousedown, true); - el.appendChild(underlay); + if ( singleClick ) { + Events.$bind(el, 'click', activate, true); + } else { + Events.$bind(el, 'click', select, true); + Events.$bind(el, 'dblclick', activate, true); } - }, - - /* - * Focuses element - */ - focus: function() { - try { - var underlay = this.$element.querySelector('.gui-focus-element'); + + Events.$bind(el, 'contextmenu', (ev) => { + ev.preventDefault(); + context(ev); + return false; + }, true); + + this.on('select', (ev) => { + if ( DOM.$hasClass(el, 'gui-element-focused') ) { + return; + } + // NOTE: This is a fix for Firefox stupid behaviour when focusing/blurring textboxes + // (which is used to have a focusable area in this case, called underlay) + const oldTop = el.scrollTop; underlay.focus(); - } catch ( e ) { - console.warn(e, e.stack); - } - }, - - /* - * Blurs element - */ - blur: function() { - try { - var underlay = this.$element.querySelector('.gui-focus-element'); - underlay.blur(); - } catch ( e ) { - console.warn(e, e.stack); - } - }, - - /* - * Gets values from selected entries - */ - values: function() { - return []; - }, - - /* - * Binds an event - */ - on: function(evName, callback, params) { - if ( (['activate', 'select', 'expand', 'contextmenu', 'render', 'drop', 'sort']).indexOf(evName) !== -1 ) { - evName = '_' + evName; - } - Utils.$bind(this.$element, evName, callback.bind(this), params); - return this; + el.scrollTop = oldTop; + setTimeout(() => { + el.scrollTop = oldTop; + }, 2); + }, true); + + el.appendChild(underlay); } + } - }); + /* + * Focuses element + */ + focus() { + try { + const underlay = this.$element.querySelector('.gui-focus-element'); + underlay.focus(); + } catch ( e ) { + console.warn(e, e.stack); + } + } + + /* + * Blurs element + */ + blur() { + try { + const underlay = this.$element.querySelector('.gui-focus-element'); + underlay.blur(); + } catch ( e ) { + console.warn(e, e.stack); + } + } + + /* + * Gets values from selected entries + */ + values() { + return []; + } + + /* + * Binds an event + */ + on(evName, callback, params) { + if ( (['activate', 'select', 'expand', 'contextmenu', 'render', 'drop', 'sort']).indexOf(evName) !== -1 ) { + evName = '_' + evName; + } + Events.$bind(this.$element, evName, callback.bind(this), params); + return this; + } - GUI.DataView = Object.seal(UIDataView); +} -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/gui/element.js b/src/client/javascript/gui/element.js index 34da32d24f..a8387688a3 100644 --- a/src/client/javascript/gui/element.js +++ b/src/client/javascript/gui/element.js @@ -27,124 +27,121 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import {_} from 'core/locales'; +import PackageManager from 'core/package-manager'; - /** - * @namespace Elements - * @memberof OSjs.GUI - */ +let REGISTRY = {}; - var REGISTRY = {}; +/* + * Wrapper for getting which element to focus/blur + */ +function getFocusElement(inst) { + const tagMap = { + 'gui-switch': 'button', + 'gui-list-view': 'textarea', + 'gui-tree-view': 'textarea', + 'gui-icon-view': 'textarea', + 'gui-input-modal': 'button' + }; - /* - * Wrapper for getting which element to focus/blur - */ - 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; + if ( tagMap[inst.tagName] ) { + return inst.$element.querySelector(tagMap[inst.tagName]); } + return inst.$element.firstChild || inst.$element; +} - /* - * Internal for parsing GUI elements - */ - function parseDynamic(node, win, args) { - args = args || {}; +/* + * Internal for parsing GUI elements + */ +function parseDynamic(node, win, args) { + args = args || {}; - var translator = args._ || API._; + const translator = args._ || _; - 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('*[data-label]').forEach(function(el) { + const label = translator(el.getAttribute('data-label')); + el.setAttribute('data-label', label); + }); - node.querySelectorAll('gui-button').forEach(function(el) { - var label = GUI.Helpers.getValueLabel(el); - if ( label ) { - el.appendChild(document.createTextNode(API._(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') ) { + const lbl = GUI.getValueLabel(el); + el.appendChild(document.createTextNode(translator(lbl))); + } + }); - node.querySelectorAll('*[data-icon]').forEach(function(el) { - var image = GUI.Helpers.getIcon(el, win); - el.setAttribute('data-icon', image); - }); + node.querySelectorAll('gui-button').forEach(function(el) { + const label = GUI.getValueLabel(el); + if ( label ) { + el.appendChild(document.createTextNode(_(label))); + } + }); + + node.querySelectorAll('*[data-icon], *[data-stock-icon]').forEach(function(el) { + const image = GUI.getIcon(el, win); + el.setAttribute('data-icon', image); + }); + + node.querySelectorAll('*[data-src],*[src]').forEach(function(el) { + const isNative = el.hasAttribute('src'); + const src = isNative + ? el.getAttribute('src') + : el.getAttribute('data-src') || ''; + + if ( win && win._app && !src.match(/^(https?:)?\//) ) { + const source = PackageManager.getPackageResource(win._app, src); + el.setAttribute(isNative ? 'src' : 'data-src', source); + } + }); +} - 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); - } - }); +/* + * Wrapper for creating a new element instance + */ +function createElementInstance(tagName, el, q, buildArgs) { + tagName = tagName || el.tagName.toLowerCase(); + + let instance; + if ( REGISTRY[tagName] ) { + /*eslint new-cap: 0*/ + instance = new REGISTRY[tagName].component(el, q); + if ( buildArgs ) { + instance.build.apply(instance, buildArgs); + } } - /* - * Wrapper for creating a new element instance - */ - function createElementInstance(tagName, el, q, buildArgs) { - tagName = tagName || el.tagName.toLowerCase(); - - var instance; - if ( REGISTRY[tagName] ) { - /*eslint new-cap: 0*/ - instance = new REGISTRY[tagName].component(el, q); - if ( buildArgs ) { - instance.build.apply(instance, buildArgs); - } - } + return instance; +} - return instance; - } +///////////////////////////////////////////////////////////////////////////// +// GUI ELEMENT CLASS +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // GUI ELEMENT CLASS - ///////////////////////////////////////////////////////////////////////////// +/** + * Base GUIElement Class + * + * @desc The Class used for all UI Elements. + * + * @link https://manual.os-js.org/packages/scheme/ + */ +export default class GUIElement { /** - * Base UIElement Class - * - * @summary The Class used for all UI Elements. - * * @param {Node} el DOM Node * @param {String} [q] Query that element came from - * - * @link https://os-js.org/manual/gui/elements/ - * - * @constructor Element - * @memberof OSjs.GUI */ - function UIElement(el, q) { + constructor(el, q) { /** * The DOM Node - * @name $element - * @memberof OSjs.GUI.Element# * @type {Node} */ this.$element = el || null; /** * The DOM Tag Name - * @name tagName - * @memberof OSjs.GUI.Element# * @type {String} */ this.tagName = el ? el.tagName.toLowerCase() : null; @@ -152,110 +149,89 @@ this.oldDisplay = null; if ( !el ) { - console.warn('UIElement() was constructed without a DOM element', q); + console.warn('GUIElement() was constructed without a DOM element', q); } } /** * Builds the DOM nodes etc * - * @function build - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.build = function() { + build() { return this; - }; + } /** * Removes element from the DOM * - * @function remove - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.remove = function() { - this.$element = Utils.$remove(this.$element); + remove() { + this.$element = DOM.$remove(this.$element); return this; - }; + } /** * Empties the DOM element * - * @function empty - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.empty = function() { - Utils.$empty(this.$element); + empty() { + DOM.$empty(this.$element); return this; - }; + } /** * Blur (unfocus) * - * @function blur - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.blur = function() { + blur() { if ( this.$element ) { - var firstChild = getFocusElement(this); + const firstChild = getFocusElement(this); if ( firstChild ) { firstChild.blur(); } } return this; - }; + } /** * Focus (focus) * - * @function focus - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.focus = function() { + focus() { if ( this.$element ) { - var firstChild = getFocusElement(this); + const firstChild = getFocusElement(this); if ( firstChild ) { firstChild.focus(); } } return this; - }; + } /** * Show * - * @function show - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.show = function() { + show() { if ( this.$element && !this.$element.offsetParent ) { if ( this.$element ) { this.$element.style.display = this.oldDisplay || ''; } } return this; - }; + } /** * Hide * - * @function hide - * @memberof OSjs.GUI.Element# - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.hide = function() { + hide() { if ( this.$element && this.$element.offsetParent ) { if ( !this.oldDisplay ) { this.oldDisplay = this.$element.style.display; @@ -263,14 +239,11 @@ this.$element.style.display = 'none'; } return this; - }; + } /** * Register Event * - * @function on - * @memberof OSjs.GUI.Element# - * * @example * element.on('click', function() {}); * @@ -278,11 +251,11 @@ * @param {CallbackEvent} callback Callback function * @param {Object} [args] Binding arguments * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.on = function(evName, callback, args) { + on(evName, callback, args) { return this; - }; + } /** * Register Event with scope @@ -307,114 +280,100 @@ * // obj = 'element' * } * - * @function son - * @memberof OSjs.GUI.Element# - * @see OSjs.GUI.Element#on + * @see GUIElement#on * * @param {String} evName Event Name * @param {Object} thisArg Which object instance to bind to * @param {CallbackEvent} callback Callback function * @param {Object} [args] Binding arguments * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.son = function(evName, thisArg, callback, args) { + son(evName, thisArg, callback, args) { return this.on(evName, function() { /* eslint no-invalid-this: "off" */ - var args = Array.prototype.slice.call(arguments); + const args = Array.prototype.slice.call(arguments); args.unshift(this); callback.apply(thisArg, args); }, args); - }; + } /** * Sets a parameter/property by name * - * @function set - * @memberof OSjs.GUI.Element# - * * @param {String} param Parameter name - * @param {Mixed} value Parameter value - * @param {Mixed} [arg] Extra argument ... - * @param {Mixed} [arg2] Extra argument ... + * @param {*} value Parameter value + * @param {*} [arg] Extra argument ... + * @param {*} [arg2] Extra argument ... * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.set = function(param, value, arg, arg2) { + set(param, value, arg, arg2) { if ( this.$element ) { - GUI.Helpers.setProperty(this.$element, param, value, arg, arg2); + GUI.setProperty(this.$element, param, value, arg, arg2); } return this; - }; + } /** * Get a parameter/property by name * - * @function get - * @memberof OSjs.GUI.Element# - * * @param {String} param Parameter name * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.get = function(param) { + get(param) { if ( this.$element ) { - return GUI.Helpers.getProperty(this.$element, param); + return GUI.getProperty(this.$element, param); } return null; - }; + } /** * Appends a childNode to this element * - * @function append - * @memberof OSjs.GUI.Element# + * @param {(Node|GUIElement)} el Element * - * @param {(Node|OSjs.GUI.Element)} el Element - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.append = function(el) { - if ( el instanceof UIElement ) { + append(el) { + if ( el instanceof GUIElement ) { el = el.$element; } else if ( typeof el === 'string' || typeof el === 'number' ) { el = document.createTextNode(String(el)); } - var outer = document.createElement('div'); + let outer = document.createElement('div'); outer.appendChild(el); this._append(outer); outer = null; return this; - }; + } /** * Appends (and builds) HTML into the node * - * @function appendHTML - * @memberof OSjs.GUI.Element# + * @param {String} html HTML code + * @param {Window} [win] Reference to the Window + * @param {Object} [args] List of arguments to send to the parser * - * @param {String} html HTML code - * @param {OSjs.Core.Window} [win] Reference to the Window - * @param {Object} [args] List of arguments to send to the parser - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.appendHTML = function(html, win, args) { - var el = document.createElement('div'); + appendHTML(html, win, args) { + const el = document.createElement('div'); el.innerHTML = html; return this._append(el, win, args); - }; + } /* * Internal method for appending a Node */ - UIElement.prototype._append = function(el, win, args) { + _append(el, win, args) { if ( el instanceof Element ) { - UIElement.parseNode(win, el, null, args); + GUIElement.parseNode(win, el, null, args); } // Move elements over @@ -425,47 +384,41 @@ el = null; return this; - }; + } /** * Perform `querySelector` * - * @function querySelector - * @memberof OSjs.GUI.Element# - * * @param {String} q Query * @param {Boolean} [rui=false] Return UI Element if possible * - * @return {(Node|OSjs.GUI.Element)} Depending on arguments + * @return {(Node|GUIElement)} Depending on arguments */ - UIElement.prototype.querySelector = function(q, rui) { - var el = this.$element.querySelector(q); + querySelector(q, rui) { + const el = this.$element.querySelector(q); if ( rui ) { - return GUI.Element.createFromNode(el, q); + return GUIElement.createFromNode(el, q); } return el; - }; + } /** * Perform `querySelectorAll` * - * @function querySelectorAll - * @memberof OSjs.GUI.Element# - * * @param {String} q Query * @param {Boolean} [rui=false] Return UI Element if possible * - * @return {OSjs.GUI.Element[]} + * @return {GUIElement[]} */ - UIElement.prototype.querySelectorAll = function(q, rui) { - var el = this.$element.querySelectorAll(q); + querySelectorAll(q, rui) { + let el = this.$element.querySelectorAll(q); if ( rui ) { - el = el.map(function(i) { - return GUI.Element.createFromNode(i, q); + el = el.map((i) => { + return GUIElement.createFromNode(i, q); }); } return el; - }; + } /** * Set or get CSS attributes @@ -473,30 +426,23 @@ * @param {String} k CSS key * @param {(String|Number)} v CSS value * - * @function css - * @memberof OSjs.GUI.Element# - * @see OSjs.Utils.$css - * - * @return {OSjs.GUI.Element} The current instance (this) + * @return {GUIElement} The current instance (this) */ - UIElement.prototype.css = function(k, v) { - Utils.$css(this.$element, k, v); + css(k, v) { + DOM.$css(this.$element, k, v); return this; - }; + } /** * Get position - * @function position - * @memberof OSjs.GUI.Element# - * @see OSjs.Utils.$position * @return {Object} */ - UIElement.prototype.position = function() { - return Utils.$position(this.$element); - }; + position() { + return DOM.$position(this.$element); + } // NOTE: DEPRECATED - UIElement.prototype._call = function(method, args, thisArg) { + _call(method, args, thisArg) { if ( arguments.length < 3 ) { console.warn('Element::_call("methodName") is DEPRECATED, use "instance.methodName()" instead'); } @@ -509,16 +455,16 @@ console.warn(e.stack, e); } return null; - }; + } // NOTE: DEPRECATED - UIElement.prototype.fn = function(name, args, thisArg) { + fn(name, args, thisArg) { console.warn('Element::fn("methodName") is DEPRECATED, use "instance.methodName()" instead'); args = args || []; thisArg = thisArg || this; return this.fn(name, args, thisArg); - }; + } ///////////////////////////////////////////////////////////////////////////// // GUI ELEMENT STATIC METHODS @@ -527,25 +473,23 @@ /** * Creates a new GUI Element into given parent * - * @param {String} tagName OS.js GUI Element name - * @param {Object} params Parameters - * @param {Node} [parentNode] Parent Node - * @param {Object} [applyArgs] New element parameters - * @param {OSjs.Core.Window} [win] OS.js Window + * @param {String} tagName OS.js GUI Element name + * @param {Object} params Parameters + * @param {Node} [parentNode] Parent Node + * @param {Object} [applyArgs] New element parameters + * @param {Window} [win] OS.js Window * - * @return {OSjs.GUI.Element} - * @function createInto - * @memberof OSjs.GUI.Element + * @return {GUIElement} */ - UIElement.createInto = function createGUIElementInto(tagName, params, parentNode, applyArgs, win) { - if ( parentNode instanceof GUI.Element ) { + static createInto(tagName, params, parentNode, applyArgs, win) { + if ( parentNode instanceof GUIElement ) { parentNode = parentNode.$element; } - var gel = GUI.Element.create(tagName, params, applyArgs, win); + const gel = GUIElement.create(tagName, params, applyArgs, win); parentNode.appendChild(gel.$element); return gel; - }; + } /** * Creates a new GUI.Element from Node @@ -554,40 +498,36 @@ * @param {String} [q] DOM Element query * @param {String} [tagName] Custom tag name * - * @return {OSjs.GUI.Element} - * @function createFromNode - * @memberof OSjs.GUI.Element + * @return {GUIElement} */ - UIElement.createFromNode = function createGUIElementFromNode(el, q, tagName) { + static createFromNode(el, q, tagName) { if ( el ) { - var instance = createElementInstance(null, el, q); + const instance = createElementInstance(null, el, q); if ( instance ) { return instance; } } - return new GUI.Element(el, q); - }; + return new GUIElement(el, q); + } /** * Creates a new GUI.Element * - * @param {String} tagName OS.js GUI Element name - * @param {Object} params Parameters - * @param {Object} [applyArgs] New element parameters - * @param {OSjs.Core.Window} [win] OS.js Window + * @param {String} tagName OS.js GUI Element name + * @param {Object} params Parameters + * @param {Object} [applyArgs] New element parameters + * @param {Window} [win] OS.js Window * - * @return {OSjs.GUI.Element} - * @function create - * @memberof OSjs.GUI.Element + * @return {GUIElement} */ - UIElement.create = function createGUIElement(tagName, params, applyArgs, win) { + static create(tagName, params, applyArgs, win) { tagName = tagName || ''; applyArgs = applyArgs || {}; params = params || {}; - var el = GUI.Helpers.createElement(tagName, params); + const el = GUI.createElement(tagName, params); return createElementInstance(null, el, null, [applyArgs, win]); - }; + } /** * Creates a new GUI.Element instance from Node @@ -598,38 +538,33 @@ * @param {String} [q] DOM Element query * @param {String} [tagName] Custom tag name * - * @function createInstance - * @memberof OSjs.GUI.Element - * @return {OSjs.GUI.Element} + * @return {GUIElement} */ - UIElement.createInstance = function(el, q, tagName) { + static createInstance(el, q, tagName) { console.warn('Element::createInstance() is DEPRECATED, use Element::createFromNode() instead'); return this.createFromNode(el, q, tagName); - }; + } /** * Parses the given HTML node and makes OS.js compatible markup * - * @function parseNode - * @memberof OSjs.GUI.Element - * - * @param {OSjs.Core.Window} win Reference to the Window - * @param {Node} node The HTML node to parse - * @param {String} [type=snipplet] Node type - * @param {Object} [args] List of arguments to send to the parser - * @param {Function} [onparse] Method to signal when parsing has started - * @param {Mixed} [id] The id of the source (for debugging) + * @param {Window} win Reference to the Window + * @param {Node} node The HTML node to parse + * @param {String} [type=snipplet] Node type + * @param {Object} [args] List of arguments to send to the parser + * @param {Function} [onparse] Method to signal when parsing has started + * @param {*} [id] The id of the source (for debugging) */ - UIElement.parseNode = function(win, node, type, args, onparse, id) { + static parseNode(win, node, type, args, onparse, id) { onparse = onparse || function() {}; args = args || {}; type = type || 'snipplet'; // Apply a default className to non-containers - node.querySelectorAll('*').forEach(function(el) { - var lcase = el.tagName.toLowerCase(); + node.querySelectorAll('*').forEach((el) => { + const 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'); + DOM.$addClass(el, 'gui-element'); } }); @@ -639,9 +574,9 @@ // Lastly render elements onparse(node); - Object.keys(REGISTRY).forEach(function(key) { - node.querySelectorAll(key).forEach(function(pel) { - if ( pel._wasParsed || Utils.$hasClass(pel, 'gui-data-view') ) { + Object.keys(REGISTRY).forEach((key) => { + node.querySelectorAll(key).forEach((pel) => { + if ( pel._wasParsed || DOM.$hasClass(pel, 'gui-data-view') ) { return; } @@ -654,35 +589,28 @@ pel._wasParsed = true; }); }); - }; + } /** * Register a GUI Element * - * @function register - * @memberof OSjs.GUI.Element - * - * @param {Object} data GUI Element Metadata - * @param {String} data.tagName Node tagName - * @param {Function} [data.parent] Base class to extend from - * @param {Object} classRef An object used as a class + * @param {Object} data GUI Element Metadata + * @param {String} data.tagName Node tagName + * @param {GUIElement} classRef An object used as a class */ - UIElement.register = function(data, classRef) { - var name = data.tagName; + static register(data, classRef) { + const name = data.tagName; if ( REGISTRY[name] ) { throw new Error('GUI Element "' + name + '" already exists'); } - var base = data.parent || GUI.Element; - var target = Utils.inherit(base, null, classRef); - - REGISTRY[name] = (function() { - var metadata = Utils.argumentDefaults(Utils.cloneObject(data, true), { + REGISTRY[name] = (() => { + const metadata = Object.assign({}, { type: 'element', allowedChildren: [], allowedParents: [] - }); + }, data); if ( metadata.parent ) { delete metadata.parent; @@ -696,19 +624,19 @@ return { metadata: metadata, - component: target + component: classRef }; })(); - }; + } - UIElement.getRegisteredElement = function(tagName) { + /** + * Get Element from registry + * @param {String} tagName HTML Tag Name + * @return {Object} + */ + static getRegisteredElement(tagName) { return REGISTRY[tagName]; - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + } - GUI.Element = Object.seal(UIElement); +} -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/gui/elements/containers.js b/src/client/javascript/gui/elements/containers.js index 330c8e1f44..2db7844e96 100644 --- a/src/client/javascript/gui/elements/containers.js +++ b/src/client/javascript/gui/elements/containers.js @@ -27,404 +27,395 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-paned-view' - * - * A view with resizable content boxes - * - * @constructor PanedView - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIPanedView = { - on: function(evName, callback, params) { - var el = this.$element; - if ( evName === 'resize' ) { - evName = '_' + evName; - } - Utils.$bind(el, evName, callback.bind(this), params); +import * as GUI from 'utils/gui'; +import * as Events from 'utils/events'; +import GUIElement from 'gui/element'; + +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; +} + +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// + +/** + * Element: 'gui-paned-view' + * + * A view with resizable content boxes + */ +class GUIPanedView extends GUIElement { + + static register() { + return super.register({ + tagName: 'gui-paned-view', + type: 'container', + allowedChildren: ['gui-paned-view-container'] + }, this); + } + + on(evName, callback, params) { + const el = this.$element; + if ( evName === 'resize' ) { + evName = '_' + evName; + } + Events.$bind(el, evName, callback.bind(this), params); - return this; - }, + return this; + } - build: function() { - var el = this.$element; - var orient = el.getAttribute('data-orientation') || 'horizontal'; + build() { + const el = this.$element; + const orient = el.getAttribute('data-orientation') || 'horizontal'; - function bindResizer(resizer, idx, cel) { - var resizeEl = resizer.previousElementSibling; - if ( !resizeEl ) { - return; - } + function bindResizer(resizer, idx, cel) { + const resizeEl = resizer.previousElementSibling; + if ( !resizeEl ) { + return; + } - var startWidth = resizeEl.offsetWidth; - var startHeight = resizeEl.offsetHeight; - var minSize = 16; - var maxSize = Number.MAX_VALUE; + let startWidth = resizeEl.offsetWidth; + let startHeight = resizeEl.offsetHeight; + let minSize = 16; + let 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; + GUI.createDrag(resizer, (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 totalSize = resizer.parentNode[(orient === 'horizontal' ? 'offsetWidth' : 'offsetHeight')]; - var totalContainers = resizer.parentNode.querySelectorAll('gui-paned-view-container').length; - var totalSpacers = resizer.parentNode.querySelectorAll('gui-paned-view-handle').length; + const max = parseInt(cel.getAttribute('data-max-size'), 10); + if ( !max ) { + const totalSize = resizer.parentNode[(orient === 'horizontal' ? 'offsetWidth' : 'offsetHeight')]; + const totalContainers = resizer.parentNode.querySelectorAll('gui-paned-view-container').length; + const totalSpacers = resizer.parentNode.querySelectorAll('gui-paned-view-handle').length; - maxSize = totalSize - (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'; - } + maxSize = totalSize - (totalContainers * 16) - (totalSpacers * 8); + } + }, (ev, diff) => { + const newWidth = startWidth + diff.x; + const newHeight = startHeight + diff.y; + + let flex; + if ( orient === 'horizontal' ) { + if ( !isNaN(newWidth) && newWidth > 0 && newWidth >= minSize && newWidth <= maxSize ) { + flex = newWidth.toString() + 'px'; } - - if ( flex ) { - resizeEl.style.webkitFlexBasis = flex; - resizeEl.style.mozFflexBasis = flex; - resizeEl.style.msFflexBasis = flex; - resizeEl.style.oFlexBasis = flex; - resizeEl.style.flexBasis = flex; + } else { + if ( !isNaN(newHeight) && newHeight > 0 && newHeight >= minSize && newHeight <= maxSize ) { + flex = newHeight.toString() + 'px'; } - }, 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); + if ( flex ) { + resizeEl.style.webkitFlexBasis = flex; + resizeEl.style.mozFflexBasis = flex; + resizeEl.style.msFflexBasis = flex; + resizeEl.style.oFlexBasis = flex; + resizeEl.style.flexBasis = flex; } + }, (ev) => { + el.dispatchEvent(new CustomEvent('_resize', {detail: {index: idx}})); }); - return this; } - }; - - /** - * Element: 'gui-paned-view-container' - * - *

-   *   property  base      String        CSS base flexbox property
-   *   property  grow      integer       CSS grow flexbox property
-   *   property  shrink    integer       CSS shrink flexbox property
-   *   property  min-size  integer       Minimum size in pixels
-   *   property  max-size  integer       Maxmimum size in pixels
-   * 
- * - * @constructor PanedViewContainer - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIPanedViewContainer = { - build: function() { - GUI.Helpers.setFlexbox(this.$element); - return this; - } - }; - - /** - * Element: 'gui-button-bar' - * - * @constructor ButtonBar - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIButtonBar = { - build: function() { - this.$element.setAttribute('role', 'toolbar'); - return this; - } - }; - - /** - * Element: 'gui-toolbar' - * - * @constructor ToolBar - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIToolBar = { - build: function() { - this.$element.setAttribute('role', 'toolbar'); - return this; - } - }; - - /** - * Element: 'gui-grid' - * - * A grid-type container with equal-sized containers - * - * @constructor Grid - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIGrid = { - build: function() { - var rows = this.$element.querySelectorAll('gui-grid-row'); - var p = 100 / rows.length; - - rows.forEach(function(r) { - r.style.height = String(p) + '%'; - }); - return this; - } - }; - - /** - * Element: 'gui-grid-row' - * - * @constructor GridRow - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIGridRow = {}; - - /** - * Element: 'gui-grid-entry' - * - * @constructor GridEntry - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIGridEntry = {}; - - /** - * Element: 'gui-vbox' - * - * Vertical boxed layout - * - * @constructor VBox - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIVBox = {}; - - /** - * Element: 'gui-vbox-container' - * - * Vertical boxed layout container - * - *

-   *   property  base      String        CSS base flexbox property
-   *   property  grow      integer       CSS grow flexbox property
-   *   property  shrink    integer       CSS shrink flexbox property
-   *   property  expand    boolean       Make content expand to full width
-   *   property  fill      boolean       Make content fill up entire space
-   * 
- * - * @constructor VBoxContainer - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIVBoxContainer = { - build: function() { - GUI.Helpers.setFlexbox(this.$element); - - return this; - } - }; - - /** - * Element: 'gui-hbox' - * - * Horizontal boxed layout - * - * @constructor HBox - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIHBox = {}; - - /** - * Element: 'gui-hbox-container' - * - * Horizontal boxed layout container - * - *

-   *   property  base      String        CSS base flexbox property
-   *   property  grow      integer       CSS grow flexbox property
-   *   property  shrink    integer       CSS shrink flexbox property
-   *   property  expand    boolean       Make content expand to full width
-   *   property  fill      boolean       Make content fill up entire space
-   * 
- * - * @constructor HBoxContainer - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIHBoxContainer = { - build: function() { - GUI.Helpers.setFlexbox(this.$element); - - return this; - } - }; - - /** - * Element: 'gui-expander' - * - * A expandable/collapsable container with label and indicator - * - *

-   *   property  label     String        The label
-   *   property  expanded  boolean       Expanded state (default=true)
-   * 
- * - * @constructor Expander - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIExpander = (function() { - function toggleState(el, expanded) { - if ( typeof expanded === 'undefined' ) { - expanded = el.getAttribute('data-expanded') !== 'false'; - expanded = !expanded; + el.querySelectorAll('gui-paned-view-container').forEach((cel, idx) => { + if ( idx % 2 ) { + const resizer = document.createElement('gui-paned-view-handle'); + resizer.setAttribute('role', 'separator'); + cel.parentNode.insertBefore(resizer, cel); + bindResizer(resizer, idx, cel); } + }); + + return this; + } +} + +/** + * Element: 'gui-paned-view-container' + * + *

+ *   property  base      String        CSS base flexbox property
+ *   property  grow      integer       CSS grow flexbox property
+ *   property  shrink    integer       CSS shrink flexbox property
+ *   property  min-size  integer       Minimum size in pixels
+ *   property  max-size  integer       Maxmimum size in pixels
+ * 
+ */ +class GUIPanedViewContainer extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-paned-view-container', + type: 'container', + allowedParents: ['gui-paned-view'] + }, this); + } + + build() { + GUI.setFlexbox(this.$element); + return this; + } +} + +/** + * Element: 'gui-button-bar' + */ +class GUIButtonBar extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-button-bar', + type: 'container' + }, this); + } + + build() { + this.$element.setAttribute('role', 'toolbar'); + return this; + } +} + +/** + * Element: 'gui-toolbar' + */ +class GUIToolBar extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-toolbar', + type: 'container' + }, this); + } + + build() { + this.$element.setAttribute('role', 'toolbar'); + return this; + } +} + +/** + * Element: 'gui-grid' + * + * A grid-type container with equal-sized containers + */ +class GUIGrid extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-grid', + type: 'container', + allowedChildren: ['gui-grid-row'] + }, this); + } + + build() { + const rows = this.$element.querySelectorAll('gui-grid-row'); + const p = 100 / rows.length; + + rows.forEach((r) => { + r.style.height = String(p) + '%'; + }); + + return this; + } +} + +/** + * Element: 'gui-grid-row' + */ +class GUIGridRow extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-grid-row', + type: 'container', + allowedChildren: ['gui-grid-entry'], + allowedParents: ['gui-grid-row'] + }, this); + } +} + +/** + * Element: 'gui-grid-entry' + */ +class GUIGridEntry extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-grid-entry', + type: 'container', + allowedParents: ['gui-grid-row'] + }, this); + } +} + +/** + * Element: 'gui-vbox' + * + * Vertical boxed layout + */ +class GUIVBox extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-vbox', + type: 'container', + allowedChildren: ['gui-vbox-container'] + }, this); + } +} + +/** + * Element: 'gui-vbox-container' + * + * Vertical boxed layout container + * + *

+ *   property  base      String        CSS base flexbox property
+ *   property  grow      integer       CSS grow flexbox property
+ *   property  shrink    integer       CSS shrink flexbox property
+ *   property  expand    boolean       Make content expand to full width
+ *   property  fill      boolean       Make content fill up entire space
+ * 
+ */ +class GUIVBoxContainer extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-vbox-container', + type: 'container', + allowedParents: ['gui-vbox'] + }, this); + } + + build() { + GUI.setFlexbox(this.$element); + + return this; + } +} + +/** + * Element: 'gui-hbox' + * + * Horizontal boxed layout + */ +class GUIHBox extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-hbox', + type: 'container', + allowedChildren: ['gui-hbox-container'] + }, this); + } +} + +/** + * Element: 'gui-hbox-container' + * + * Horizontal boxed layout container + * + *

+ *   property  base      String        CSS base flexbox property
+ *   property  grow      integer       CSS grow flexbox property
+ *   property  shrink    integer       CSS shrink flexbox property
+ *   property  expand    boolean       Make content expand to full width
+ *   property  fill      boolean       Make content fill up entire space
+ * 
+ */ +class GUIHBoxContainer extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-hbox-container', + type: 'container', + allowedParents: ['gui-hbox'] + }, this); + } + + build() { + GUI.setFlexbox(this.$element); + + return this; + } +} + +/** + * Element: 'gui-expander' + * + * A expandable/collapsable container with label and indicator + * + *

+ *   property  label     String        The label
+ *   property  expanded  boolean       Expanded state (default=true)
+ * 
+ */ - el.setAttribute('aria-expanded', String(expanded)); - el.setAttribute('data-expanded', String(expanded)); - return expanded; +class GUIExpander extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-expander', + type: 'container' + }, this); + } + + set(param, value) { + if ( param === 'expanded' ) { + return toggleState(this.$element, value === true); } + return super.set(...arguments); + } - return { - set: function(param, value) { - if ( param === 'expanded' ) { - return toggleState(this.$element, value === true); - } - return GUI.Element.prototype.set.apply(this, arguments); - }, + on(evName, callback, params) { + if ( (['change']).indexOf(evName) !== -1 ) { + evName = '_' + evName; + } + Events.$bind(this.$element, evName, callback.bind(this), params); - on: function(evName, callback, params) { - if ( (['change']).indexOf(evName) !== -1 ) { - evName = '_' + evName; - } - Utils.$bind(this.$element, evName, callback.bind(this), params); + return this; + } - return this; - }, + build() { + const el = this.$element; + const lbltxt = el.getAttribute('data-label') || ''; + const label = document.createElement('gui-expander-label'); - build: function() { - var el = this.$element; - var lbltxt = el.getAttribute('data-label') || ''; - var label = document.createElement('gui-expander-label'); + Events.$bind(label, 'click', (ev) => { + el.dispatchEvent(new CustomEvent('_change', {detail: {expanded: toggleState(el)}})); + }, false); - Utils.$bind(label, 'click', function(ev) { - el.dispatchEvent(new CustomEvent('_change', {detail: {expanded: toggleState(el)}})); - }, false); + label.appendChild(document.createTextNode(lbltxt)); - 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); + } - 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); - } + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUIPanedView: GUIPanedView, + GUIPanedViewContainer: GUIPanedViewContainer, + GUIButtonBar: GUIButtonBar, + GUIToolBar: GUIToolBar, + GUIGrid: GUIGrid, + GUIGridRow: GUIGridRow, + GUIGridEntry: GUIGridEntry, + GUIVBox: GUIVBox, + GUIVBoxContainer: GUIVBoxContainer, + GUIHBox: GUIHBox, + GUIHBoxContainer: GUIHBoxContainer, + GUIExpander: GUIExpander +}; - return this; - } - }; - })(); - - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// - - GUI.Element.register({ - tagName: 'gui-paned-view', - type: 'container', - allowedChildren: ['gui-paned-view-container'] - }, GUIPanedView); - - GUI.Element.register({ - tagName: 'gui-paned-view-container', - type: 'container', - allowedParents: ['gui-paned-view'] - }, GUIPanedViewContainer); - - GUI.Element.register({ - tagName: 'gui-button-bar', - type: 'container' - }, GUIButtonBar); - - GUI.Element.register({ - tagName: 'gui-toolbar', - type: 'container' - }, GUIToolBar); - - GUI.Element.register({ - tagName: 'gui-grid', - type: 'container', - allowedChildren: ['gui-grid-row'] - }, GUIGrid); - - GUI.Element.register({ - tagName: 'gui-grid-row', - type: 'container', - allowedChildren: ['gui-grid-entry'], - allowedParents: ['gui-grid-row'] - }, GUIGridRow); - - GUI.Element.register({ - tagName: 'gui-grid-entry', - type: 'container', - allowedParents: ['gui-grid-row'] - }, GUIGridEntry); - - GUI.Element.register({ - tagName: 'gui-vbox', - type: 'container', - allowedChildren: ['gui-vbox-container'] - }, GUIVBox); - - GUI.Element.register({ - tagName: 'gui-vbox-container', - type: 'container', - allowedParents: ['gui-vbox'] - }, GUIVBoxContainer); - - GUI.Element.register({ - tagName: 'gui-hbox', - type: 'container', - allowedChildren: ['gui-hbox-container'] - }, GUIHBox); - - GUI.Element.register({ - tagName: 'gui-hbox-container', - type: 'container', - allowedParents: ['gui-hbox'] - }, GUIHBoxContainer); - - GUI.Element.register({ - tagName: 'gui-expander', - type: 'container' - }, GUIExpander); - -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/gui/elements/fileview.js b/src/client/javascript/gui/elements/fileview.js index 503d9f29a8..06ff54f290 100644 --- a/src/client/javascript/gui/elements/fileview.js +++ b/src/client/javascript/gui/elements/fileview.js @@ -27,550 +27,564 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // ABSTRACTION HELPERS - ///////////////////////////////////////////////////////////////////////////// - - var _iconSizes = { // Defaults to 16x16 - 'gui-icon-view': '32x32' - }; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - function getFileIcon(iter, size) { - if ( iter.icon && typeof iter.icon === 'object' ) { - return API.getIcon(iter.icon.filename, size, iter.icon.application); +import * as FS from 'utils/fs'; +import * as VFS from 'vfs/fs'; +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Utils from 'utils/misc'; +import * as Events from 'utils/events'; +import * as Menu from 'gui/menu'; +import GUIElement from 'gui/element'; +import GUIDataView from 'gui/dataview'; +import PackageManager from 'core/package-manager'; +import SettingsManager from 'core/settings-manager'; +import FileMetadata from 'vfs/file'; +import DateExtended from 'helpers/date'; +import Theme from 'core/theme'; +import {_} from 'core/locales'; +import {getConfig, getDefaultPath} from 'core/config'; + +///////////////////////////////////////////////////////////////////////////// +// ABSTRACTION HELPERS +///////////////////////////////////////////////////////////////////////////// + +let _iconSizes = { // Defaults to 16x16 + 'gui-icon-view': '32x32' +}; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function getFileIcon(iter, size) { + if ( iter.icon && typeof iter.icon === 'object' ) { + if ( iter.icon.application ) { + return PackageManager.getPackageResource(iter.icon.filename, iter.icon.application); } - - var icon = 'status/dialog-question.png'; - return API.getFileIcon(iter, size, icon); + return Theme.getIcon(iter.icon.filename, size, iter.icon.application); } - function getFileSize(iter) { - var filesize = ''; - if ( iter.type !== 'dir' && iter.size >= 0 ) { - filesize = Utils.humanFileSize(iter.size); - } - return filesize; + const icon = 'status/dialog-question.png'; + return Theme.getFileIcon(iter, size, icon); +} + +function getFileSize(iter) { + let filesize = ''; + if ( iter.type !== 'dir' && iter.size >= 0 ) { + filesize = FS.humanFileSize(iter.size); } + return filesize; +} - var removeExtension = (function() { - var mimeConfig; +const removeExtension = (() => { + let mimeConfig; - return function(str, opts) { - if ( !mimeConfig ) { - mimeConfig = API.getConfig('MIME.mapping'); - } + return (str, opts) => { + if ( !mimeConfig ) { + mimeConfig = 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); - } + if ( opts.extensions === false ) { + let ext = FS.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); - //date = new Date(stamp.replace('T', ' ').replace(/\..+/, '')); - } catch ( e ) {} - - if ( date ) { - return OSjs.Helpers.Date.format(date); - } } - return stamp; + return str; + }; +})(); + +function getDateFromStamp(stamp) { + if ( typeof stamp === 'string' ) { + let date = null; + try { + date = new Date(stamp); + //date = new Date(stamp.replace('T', ' ').replace(/\..+/, '')); + } catch ( e ) {} + + if ( date ) { + return DateExtended.format(date); + } } + return stamp; +} - function getListViewColumns(cls, iter, opts) { - opts = opts || {}; +function getListViewColumns(cls, iter, opts) { + opts = opts || {}; - var columnMapping = { - filename: { - label: 'LBL_FILENAME', - icon: function() { - return getFileIcon(iter); - }, - value: function() { - return removeExtension(iter.filename, opts); - } + const columnMapping = { + filename: { + label: 'LBL_FILENAME', + icon: () => { + return getFileIcon(iter); }, - mime: { - label: 'LBL_MIME', - size: '100px', - icon: function() { - return null; - }, - value: function() { - return iter.mime; - } + value: () => { + return removeExtension(iter.filename, opts); + } + }, + mime: { + label: 'LBL_MIME', + size: '100px', + icon: () => { + return null; }, - mtime: { - label: 'LBL_MODIFIED', - size: '160px', - icon: function() { - return null; - }, - value: function() { - return getDateFromStamp(iter.mtime); - } + value: () => { + return iter.mime; + } + }, + mtime: { + label: 'LBL_MODIFIED', + size: '160px', + icon: () => { + return null; }, - ctime: { - label: 'LBL_CREATED', - size: '160px', - icon: function() { - return null; - }, - value: function() { - return getDateFromStamp(iter.ctime); - } + value: () => { + return getDateFromStamp(iter.mtime); + } + }, + ctime: { + label: 'LBL_CREATED', + size: '160px', + icon: () => { + return null; }, - size: { - label: 'LBL_SIZE', - size: '120px', - icon: function() { - return null; - }, - value: function() { - return getFileSize(iter); - } + value: () => { + return getDateFromStamp(iter.ctime); + } + }, + size: { + label: 'LBL_SIZE', + size: '120px', + icon: () => { + return null; + }, + value: () => { + 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 = []; - var sortBy = cls.$element.getAttribute('data-sortby'); - var sortDir = cls.$element.getAttribute('data-sortdir'); - - useColumns.forEach(function(key, idx) { - var map = columnMapping[key]; + let defColumns = ['filename', 'mime', 'size']; + let useColumns = defColumns; - if ( iter ) { - columns.push({ - sortBy: key, - label: map.value(), - icon: map.icon(), - textalign: idx === 0 ? 'left' : 'right' - }); - } else { - columns.push({ - sortBy: key, - sortDir: key === sortBy ? sortDir : null, - label: API._(map.label), - size: map.size || '', - resizable: idx > 0, - textalign: idx === 0 ? 'left' : 'right' - }); - } - }); - - return columns; + if ( !opts.defaultcolumns ) { + const vfsOptions = Utils.cloneObject(SettingsManager.get('VFS') || {}); + const scandirOptions = vfsOptions.scandir || {}; + useColumns = scandirOptions.columns || defColumns; } - function scandir(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, - sortBy: opts.sortby, - sortDir: opts.sortdir - }; + const columns = []; + const sortBy = cls.$element.getAttribute('data-sortby'); + const sortDir = cls.$element.getAttribute('data-sortdir'); - try { - VFS.scandir(file, function(error, result) { - if ( error ) { - cb(error); return; - } + useColumns.forEach((key, idx) => { + const map = columnMapping[key]; - var list = []; - var summary = {size: 0, directories: 0, files: 0, hidden: 0}; + if ( iter ) { + columns.push({ + sortBy: key, + label: map.value(), + icon: map.icon(), + textalign: idx === 0 ? 'left' : 'right' + }); + } else { + columns.push({ + sortBy: key, + sortDir: key === sortBy ? sortDir : null, + label: _(map.label), + size: map.size || '', + resizable: idx > 0, + textalign: idx === 0 ? 'left' : 'right' + }); + } + }); - function isHidden(iter) { - return (iter.filename || '').substr(0) === '.'; - } + return columns; +} + +function scandir(dir, opts, cb, oncreate) { + const file = new FileMetadata(dir); + file.type = 'dir'; + + const scanopts = { + backlink: opts.backlink, + showDotFiles: opts.dotfiles === true, + showFileExtensions: opts.extensions === true, + mimeFilter: opts.filter || [], + typeFilter: opts.filetype || null, + sortBy: opts.sortby, + sortDir: opts.sortdir + }; - (result || []).forEach(function(iter) { - list.push(oncreate(iter)); + VFS.scandir(file, scanopts).then((result) => { + const list = []; + const summary = {size: 0, directories: 0, files: 0, hidden: 0}; - 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 isHidden(iter) { + return (iter.filename || '').substr(0) === '.'; } - } - function readdir(cls, dir, done, sopts) { - var childView = cls.getChildView(); - if ( !childView ) { - return; - } - sopts = sopts || {}; - - var vfsOptions = Utils.cloneObject(OSjs.Core.getSettingsManager().get('VFS') || {}); - var scandirOptions = vfsOptions.scandir || {}; - - var el = cls.$element; - var target = childView.$element; - 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() {})(); - } - } + (result || []).forEach((iter) => { + list.push(oncreate(iter)); - setOption('data-sortby', 'sortby', function(val) { - return val; - }); - setOption('data-sortdir', 'sortdir', function(val) { - return val; - }); - 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'; + 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; }); - try { - opts.filter = JSON.parse(el.getAttribute('data-filter')); - } catch ( e ) { + cb(false, list, summary); + }).catch(cb); +} + +function readdir(cls, dir, done, sopts) { + const childView = cls.getChildView(); + if ( !childView ) { + return; + } + sopts = sopts || {}; + + const vfsOptions = Utils.cloneObject(SettingsManager.get('VFS') || {}); + const scandirOptions = vfsOptions.scandir || {}; + + const el = cls.$element; + const target = childView.$element; + const tagName = target.tagName.toLowerCase(); + el.setAttribute('data-path', dir); + + const 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() {})(); } + } - scandir(dir, opts, function(error, result, summary) { - if ( tagName === 'gui-list-view' ) { - cls.getChildView().set('zebra', true); - if ( sopts.headers !== false ) { - cls.getChildView().set('columns', getListViewColumns(cls, null, opts)); - } - } + setOption('data-sortby', 'sortby', (val) => { + return val; + }); + setOption('data-sortdir', 'sortdir', (val) => { + return val; + }); + setOption('data-dotfiles', 'dotfiles', (val) => { + return val === 'true'; + }, () => { + return scandirOptions.showHiddenFiles === true; + }); + setOption('data-extensions', 'extensions', (val) => { + return val === 'true'; + }, () => { + return scandirOptions.showFileExtensions === true; + }); + setOption('data-filetype', 'filetype', (val) => { + return val; + }); + setOption('data-defaultcolumns', 'defaultcolumns', (val) => { + return val === 'true'; + }); - 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...' - }]; - } - } + try { + opts.filter = JSON.parse(el.getAttribute('data-filter')); + } catch ( e ) { + } - return row; + scandir(dir, opts, (error, result, summary) => { + if ( tagName === 'gui-list-view' ) { + cls.getChildView().set('zebra', true); + if ( sopts.headers !== false ) { + cls.getChildView().set('columns', getListViewColumns(cls, null, opts)); } + } - // List view works a little differently - if ( tagName !== 'gui-list-view' ) { - return _createEntry(); - } + done(error, result, summary); + }, (iter) => { + const tooltip = Utils.format('{0}\n{1}\n{2} {3}', iter.type.toUpperCase(), iter.filename, getFileSize(iter), iter.mime || ''); - return { + function _createEntry() { + const row = { value: iter, - id: iter.id || iter.filename, + id: iter.id || removeExtension(iter.filename, opts), + label: iter.filename, tooltip: tooltip, - columns: getListViewColumns(cls, iter, opts) + icon: getFileIcon(iter, _iconSizes[tagName] || '16x16') }; - }); - } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-file-view' - * - * Abstraction layer for displaying files within Icon-, Tree- or List Views - * - * For more properties and events etc, see 'dataview' - * - *

-   *   property  multiple    boolean       If multiple elements are selectable
-   *   property  type        String        Child type
-   *   property  filter      Array         MIME Filters
-   *   property  dotfiles    boolean       Show dotfiles (default=true)
-   *   property  extensions  boolean       Show file extensions (default=true)
-   *   action    chdir                     Change directory => fn(args)  (args = {path: '', done: function() })
-   * 
- * - * @constructor FileView - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - * @see OSjs.GUI.Elements.GUIListView - * @see OSjs.GUI.Elements.GUITreeView - * @see OSjs.GUI.Elements.GUIIconView - */ - GUI.Element.register({ - tagName: 'gui-file-view' - }, { - on: function(evName, callback, params) { - if ( (['activate', 'select', 'contextmenu', 'sort']).indexOf(evName) !== -1 ) { - evName = '_' + evName; + if ( tagName === 'gui-tree-view' && iter.type === 'dir' ) { + if ( iter.filename !== '..' ) { + row.entries = [{ + label: 'Loading...' + }]; + } } - var el = this.$element; - if ( evName === '_contextmenu' ) { - el.setAttribute('data-has-contextmenu', 'true'); - } + return row; + } - Utils.$bind(el, evName, callback.bind(this), params); - return this; - }, + // List view works a little differently + if ( tagName !== 'gui-list-view' ) { + return _createEntry(); + } - set: function(param, value, arg, arg2) { - var el = this.$element; + return { + value: iter, + id: iter.id || iter.filename, + tooltip: tooltip, + columns: getListViewColumns(cls, iter, opts) + }; + }); +} - if ( param === 'type' ) { - var firstChild = el.children[0]; - if ( firstChild && firstChild.tagName.toLowerCase() === value ) { - return true; - } +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// - el.setAttribute('data-type', value); - this.buildChildView(); +/** + * Element: 'gui-file-view' + * + * Abstraction layer for displaying files within Icon-, Tree- or List Views + * + * For more properties and events etc, see 'dataview' + * + *

+ *   property  multiple    boolean       If multiple elements are selectable
+ *   property  type        String        Child type
+ *   property  filter      Array         MIME Filters
+ *   property  dotfiles    boolean       Show dotfiles (default=true)
+ *   property  extensions  boolean       Show file extensions (default=true)
+ *   action    chdir                     Change directory => fn(args)  (args = {path: '', done: function() })
+ * 
+ * + * @see GUIListView + * @see GUITreeView + * @see GUIIconView + */ +class GUIFileView extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-file-view' + }, this); + } - if ( typeof arg === 'undefined' || arg === true ) { - this.chdir({ - path: el.getAttribute('data-path') - }); - } - return this; - } else if ( (['filter', 'dotfiles', 'filetype', 'extensions', 'defaultcolumns', 'sortby', 'sortdir']).indexOf(param) >= 0 ) { - GUI.Helpers.setProperty(el, param, value); - return this; - } + on(evName, callback, params) { + if ( (['activate', 'select', 'contextmenu', 'sort']).indexOf(evName) !== -1 ) { + evName = '_' + evName; + } - var childView = this.getChildView(); - if ( childView ) { - return childView.set.apply(childView, arguments); - } - return GUI.DataView.prototype.set.apply(this, arguments); - }, + const el = this.$element; + if ( evName === '_contextmenu' ) { + el.setAttribute('data-has-contextmenu', 'true'); + } - build: function() { - if ( this.childView ) { - return this; + Events.$bind(el, evName, callback.bind(this), params); + return this; + } + + set(param, value, arg, arg2) { + const el = this.$element; + + if ( param === 'type' ) { + const firstChild = el.children[0]; + if ( firstChild && firstChild.tagName.toLowerCase() === value ) { + return true; } + el.setAttribute('data-type', value); this.buildChildView(); - var el = this.$element; - var self = this; + if ( typeof arg === 'undefined' || arg === true ) { + this.chdir({ + path: el.getAttribute('data-path') + }); + } + return this; + } else if ( (['filter', 'dotfiles', 'filetype', 'extensions', 'defaultcolumns', 'sortby', 'sortdir']).indexOf(param) >= 0 ) { + GUI.setProperty(el, param, value); + return this; + } - Utils.$bind(el, '_expand', function(ev) { - var target = ev.detail.element; - if ( target.getAttribute('data-was-rendered') ) { - return; - } + const childView = this.getChildView(); + if ( childView ) { + return childView.set.apply(childView, arguments); + } + return GUIDataView.prototype.set.apply(this, arguments); + } - if ( ev.detail.expanded ) { - var entry = ev.detail.entries[0].data; - target.setAttribute('data-was-rendered', String(true)); - readdir(self, entry.path, function(error, result, summary) { - if ( !error ) { - target.querySelectorAll('gui-tree-view-entry').forEach(function(e) { - Utils.$remove(e); - }); + build() { + if ( this.childView ) { + return this; + } - var childView = self.getChildView(); - if ( childView ) { - childView.add({ - entries: result, - parentNode: target - }); - } - } - }, {backlink: false}); - } - }); + this.buildChildView(); - return this; - }, + const el = this.$element; - values: function() { - var childView = this.getChildView(); - if ( childView ) { - return childView.values(); + Events.$bind(el, '_expand', (ev) => { + const target = ev.detail.element; + if ( target.getAttribute('data-was-rendered') ) { + return; } - 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); + if ( ev.detail.expanded ) { + const entry = ev.detail.entries[0].data; + target.setAttribute('data-was-rendered', String(true)); + readdir(this, entry.path, (error, result, summary) => { + if ( !error ) { + target.querySelectorAll('gui-tree-view-entry').forEach((e) => { + DOM.$remove(e); + }); + + const childView = this.getChildView(); + if ( childView ) { + childView.add({ + entries: result, + parentNode: target + }); + } + } + }, {backlink: false}); } + }); - 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); - }, + return this; + } - chdir: function(args) { - var childView = this.getChildView(); - if ( !childView ) { - childView = this.buildChildView(); - } + values() { + const childView = this.getChildView(); + if ( childView ) { + return childView.values(); + } + return null; + } - var self = this; - var cb = args.done || function() {}; - var dir = args.path || OSjs.API.getDefaultPath(); - var child = childView; - var el = this.$element; - - clearTimeout(el._readdirTimeout); - el._readdirTimeout = setTimeout(function() { - readdir(self, dir, function(error, result, summary) { - if ( error ) { - API.error(API._('ERR_VFSMODULE_XHR_ERROR'), API._('ERR_VFSMODULE_SCANDIR_FMT', dir), error); - } else { - child.clear(); - child.add(result); - } - cb(error, summary); - }, args.opts); - }, 50); // Prevent exessive calls - }, + contextmenu(ev) { + const vfsOptions = SettingsManager.instance('VFS'); + const scandirOptions = (vfsOptions.get('scandir') || {}); + + function setOption(opt, toggle) { + const opts = {scandir: {}}; + opts.scandir[opt] = toggle; + vfsOptions.set(null, opts, true); + } - getChildViewType: function() { - var type = this.$element.getAttribute('data-type') || 'list-view'; - if ( !type.match(/^gui\-/) ) { - type = 'gui-' + type; + Menu.create([{ + title: _('LBL_SHOW_HIDDENFILES'), + type: 'checkbox', + checked: scandirOptions.showHiddenFiles === true, + onClick: () => { + setOption('showHiddenFiles', !scandirOptions.showHiddenFiles); } - return type; - }, + }, { + title: _('LBL_SHOW_FILEEXTENSIONS'), + type: 'checkbox', + checked: scandirOptions.showFileExtensions === true, + onClick: () => { + setOption('showFileExtensions', !scandirOptions.showFileExtensions); + } + }], ev); + } - getChildView: function() { - return GUI.Element.createFromNode(this.$element.children[0]); - }, + chdir(args) { + let childView = this.getChildView(); + if ( !childView ) { + childView = this.buildChildView(); + } - buildChildView: function() { - var self = this; - var el = this.$element; - var type = this.getChildViewType(); - var childView = this.getChildView(); + const cb = args.done || function() {}; + const dir = args.path || getDefaultPath(); + const child = childView; + const el = this.$element; - if ( childView ) { - if ( childView.$element && childView.$element.tagName.toLowerCase() === type ) { - return null; + clearTimeout(el._readdirTimeout); + el._readdirTimeout = setTimeout(() => { + readdir(this, dir, (error, result, summary) => { + if ( error ) { + OSjs.error(_('ERR_VFSMODULE_XHR_ERROR'), _('ERR_VFSMODULE_SCANDIR_FMT', dir), error); + } else { + child.clear(); + child.add(result); } + cb(error, summary); + }, args.opts); + }, 50); // Prevent exessive calls + } + + getChildViewType() { + let type = this.$element.getAttribute('data-type') || 'list-view'; + if ( !type.match(/^gui\-/) ) { + type = 'gui-' + type; + } + return type; + } + + getChildView() { + return GUIElement.createFromNode(this.$element.children[0]); + } + + buildChildView() { + const el = this.$element; + const type = this.getChildViewType(); + const childView = this.getChildView(); + + if ( childView ) { + if ( childView.$element && childView.$element.tagName.toLowerCase() === type ) { + return null; } + } - Utils.$empty(el); + DOM.$empty(el); - var nel = GUI.Element.create(type, {'draggable': true, 'draggable-type': 'file'}); - nel.build(); + const nel = GUIElement.create(type, {'draggable': true, 'draggable-type': 'file'}); + nel.build(); - 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('sort', function(ev) { - el.setAttribute('data-sortby', String(ev.detail.sortBy)); - el.setAttribute('data-sortdir', String(ev.detail.sortDir)); - - self.chdir({ - sopts: { - headers: false - }, - path: el.getAttribute('data-path') - }); + nel.on('select', (ev) => { + el.dispatchEvent(new CustomEvent('_select', {detail: ev.detail})); + }); + nel.on('activate', (ev) => { + el.dispatchEvent(new CustomEvent('_activate', {detail: ev.detail})); + }); + nel.on('sort', (ev) => { + el.setAttribute('data-sortby', String(ev.detail.sortBy)); + el.setAttribute('data-sortdir', String(ev.detail.sortDir)); - el.dispatchEvent(new CustomEvent('_sort', {detail: ev.detail})); - }); - nel.on('contextmenu', function(ev) { - if ( !el.hasAttribute('data-has-contextmenu') || el.hasAttribute('data-has-contextmenu') === 'false' ) { - self.contextmenu(ev); - } - el.dispatchEvent(new CustomEvent('_contextmenu', {detail: ev.detail})); + this.chdir({ + sopts: { + headers: false + }, + path: el.getAttribute('data-path') }); - if ( type === 'gui-tree-view' ) { - nel.on('expand', function(ev) { - el.dispatchEvent(new CustomEvent('_expand', {detail: ev.detail})); - }); + el.dispatchEvent(new CustomEvent('_sort', {detail: ev.detail})); + }); + nel.on('contextmenu', (ev) => { + if ( !el.hasAttribute('data-has-contextmenu') || el.hasAttribute('data-has-contextmenu') === 'false' ) { + this.contextmenu(ev); } + el.dispatchEvent(new CustomEvent('_contextmenu', {detail: ev.detail})); + }); - el.setAttribute('role', 'region'); - el.appendChild(nel.$element); - - return nel; + if ( type === 'gui-tree-view' ) { + nel.on('expand', (ev) => { + el.dispatchEvent(new CustomEvent('_expand', {detail: ev.detail})); + }); } - }); + el.setAttribute('role', 'region'); + el.appendChild(nel.$element); + + return nel; + } + +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUIFileView: GUIFileView +}; -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/gui/elements/iconview.js b/src/client/javascript/gui/elements/iconview.js index d94c4b69ff..2fc0e33d20 100644 --- a/src/client/javascript/gui/elements/iconview.js +++ b/src/client/javascript/gui/elements/iconview.js @@ -27,142 +27,145 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +import * as GUI from 'utils/gui'; +import GUIDataView from 'gui/dataview'; - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// - function createEntry(cls, e) { - var entry = GUI.Helpers.createElement('gui-icon-view-entry', e); - return entry; - } +function createEntry(cls, e) { + const entry = GUI.createElement('gui-icon-view-entry', e); + return entry; +} + +function initEntry(cls, cel) { + const icon = cel.getAttribute('data-icon'); + const label = GUI.getLabel(cel); + + const dicon = document.createElement('div'); + const dimg = document.createElement('img'); + dimg.src = icon; + dicon.appendChild(dimg); - function initEntry(cls, cel) { - var icon = cel.getAttribute('data-icon'); - var label = GUI.Helpers.getLabel(cel); + const dlabel = document.createElement('div'); + const dspan = document.createElement('span'); + dspan.appendChild(document.createTextNode(label)); + dlabel.appendChild(dspan); - var dicon = document.createElement('div'); - var dimg = document.createElement('img'); - dimg.src = icon; - dicon.appendChild(dimg); + cls.bindEntryEvents(cel, 'gui-icon-view-entry'); - var dlabel = document.createElement('div'); - var dspan = document.createElement('span'); - dspan.appendChild(document.createTextNode(label)); - dlabel.appendChild(dspan); + cel.setAttribute('role', 'listitem'); + cel.appendChild(dicon); + cel.appendChild(dlabel); +} - cls.bindEntryEvents(cel, 'gui-icon-view-entry'); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +/** + * Element: 'gui-icon-view' + * + * A container for displaying icons with labels + * + * For more properties and events etc, see 'dataview' + * + *

+ *   property  icon-size   integer       Icon size (default=16)
+ * 
+ * + * @example + * .add([{ + * label: "Label", + * icon: "Optional icon path", + * value: "something or JSON or whatever" + * }]) + */ +class GUIIconView extends GUIDataView { + static register() { + return super.register({ + parent: GUIDataView, + tagName: 'gui-icon-view' + }, this); + } - cel.setAttribute('role', 'listitem'); - cel.appendChild(dicon); - cel.appendChild(dlabel); + values() { + return this.getSelected(this.$element.querySelectorAll('gui-icon-view-entry')); } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-icon-view' - * - * A container for displaying icons with labels - * - * For more properties and events etc, see 'dataview' - * - *

-   *   property  icon-size   integer       Icon size (default=16)
-   * 
- * - * @example - * .add([{ - * label: "Label", - * icon: "Optional icon path", - * value: "something or JSON or whatever" - * }]) - * - * @constructor IconView - * @extends OSjs.GUI.DataView - * @memberof OSjs.GUI.Elements - */ - GUI.Element.register({ - parent: GUI.DataView, - tagName: 'gui-icon-view' - }, { - values: function() { - return this.getSelected(this.$element.querySelectorAll('gui-icon-view-entry')); - }, - - build: function() { - var el = this.$element; - var body = el.querySelector('gui-icon-view-body'); - var found = !!body; - var self = this; + build() { + const el = this.$element; + let body = el.querySelector('gui-icon-view-body'); + const found = !!body; + + if ( !found ) { + body = document.createElement('gui-icon-view-body'); + el.appendChild(body); + } + el.querySelectorAll('gui-icon-view-entry').forEach((cel, idx) => { if ( !found ) { - body = document.createElement('gui-icon-view-body'); - el.appendChild(body); + body.appendChild(cel); } + initEntry(this, cel); + }); - el.querySelectorAll('gui-icon-view-entry').forEach(function(cel, idx) { - if ( !found ) { - body.appendChild(cel); - } - initEntry(self, cel); - }); + el.setAttribute('role', 'list'); - el.setAttribute('role', 'list'); + return super.build(...arguments); + } - return GUI.DataView.prototype.build.apply(this, arguments); - }, + get(param, value, arg, asValue) { + if ( param === 'entry' ) { + const body = this.$element.querySelector('gui-icon-view-body'); + const rows = body.querySelectorAll('gui-icon-view-entry'); + return this.getEntry(rows, value, arg, asValue); + } + return super.get(...arguments); + } - get: function(param, value, arg, asValue) { - if ( param === 'entry' ) { - var body = this.$element.querySelector('gui-icon-view-body'); - var rows = body.querySelectorAll('gui-icon-view-entry'); - return this.getEntry(rows, value, arg, asValue); - } - return GUI.DataView.prototype.get.apply(this, arguments); - }, - - set: function(param, value, arg) { - var body = this.$element.querySelector('gui-icon-view-body'); - if ( param === 'selected' || param === 'value' ) { - if ( body ) { - this.setSelected(body, body.querySelectorAll('gui-icon-view-entry'), value, arg); - } - return this; + set(param, value, arg) { + const body = this.$element.querySelector('gui-icon-view-body'); + if ( param === 'selected' || param === 'value' ) { + if ( body ) { + this.setSelected(body, body.querySelectorAll('gui-icon-view-entry'), value, arg); } + return this; + } - return GUI.DataView.prototype.set.apply(this, arguments); - }, + return super.set(...arguments); + } - add: function(entries) { - var body = this.$element.querySelector('gui-icon-view-body'); - var self = this; + add(entries) { + const body = this.$element.querySelector('gui-icon-view-body'); + return super.add(entries, (cls, e) => { + const entry = createEntry(this, e); + body.appendChild(entry); + initEntry(this, entry); + }); + } - return GUI.DataView.prototype.add.call(this, entries, function(cls, e) { - var entry = createEntry(self, e); - body.appendChild(entry); - initEntry(self, entry); - }); - }, + clear() { + const body = this.$element.querySelector('gui-icon-view-body'); + return super.clear(body); + } - clear: function() { - var body = this.$element.querySelector('gui-icon-view-body'); - return GUI.DataView.prototype.clear.call(this, body); - }, + remove(entries) { + return super.remove(entries, 'gui-icon-view-entry'); + } - remove: function(entries) { - return GUI.DataView.prototype.remove.call(this, entries, 'gui-icon-view-entry'); - }, + patch(entries) { + const body = this.$element.querySelector('gui-icon-view-body'); + return super.patch(entries, 'gui-icon-view-entry', body, createEntry, initEntry); + } - patch: function(entries) { - var body = this.$element.querySelector('gui-icon-view-body'); - return GUI.DataView.prototype.patch.call(this, entries, 'gui-icon-view-entry', body, createEntry, initEntry); - } +} - }); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); +export default { + GUIIconView: GUIIconView +}; diff --git a/src/client/javascript/gui/elements/inputs.js b/src/client/javascript/gui/elements/inputs.js index 46bd74e3d1..1325b6d541 100644 --- a/src/client/javascript/gui/elements/inputs.js +++ b/src/client/javascript/gui/elements/inputs.js @@ -27,119 +27,222 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - var _buttonCount = 0; - - ///////////////////////////////////////////////////////////////////////////// - // INPUT HELPERS - ///////////////////////////////////////////////////////////////////////////// - - 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 - }; +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Clipboard from 'utils/clipboard'; +import * as Events from 'utils/events'; +import Keycodes from 'utils/keycodes'; +import GUIElement from 'gui/element'; +import {_} from 'core/locales'; + +let _buttonCount = 0; + +///////////////////////////////////////////////////////////////////////////// +// INPUT HELPERS +///////////////////////////////////////////////////////////////////////////// + +function createInputOfType(el, type) { + const group = el.getAttribute('data-group'); + const placeholder = el.getAttribute('data-placeholder'); + const disabled = String(el.getAttribute('data-disabled')) === 'true'; + const value = el.childNodes.length ? el.childNodes[0].nodeValue : null; + DOM.$empty(el); + + const input = document.createElement(type === 'textarea' ? 'textarea' : 'input'); + + const 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'; - }); + (['autocomplete', 'autocorrect', 'autocapitalize', 'spellcheck']).forEach((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 || ''; + } - 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'; + Object.keys(attribs).forEach((a) => { + if ( attribs[a] !== null ) { + if ( a === 'value' ) { + input.value = attribs[a]; + } else { + input.setAttribute(a, attribs[a]); } - } else if ( ['text', 'password', 'textarea'].indexOf(type) >= 0 ) { - attribs.value = value || ''; } + }); + } + function _bindEvents() { + if ( type === 'text' || type === 'password' || type === 'textarea' ) { + Events.$bind(input, 'keydown', (ev) => { + if ( ev.keyCode === Keycodes.ENTER ) { + input.dispatchEvent(new CustomEvent('_enter', {detail: input.value})); + } else if ( ev.keyCode === Keycodes.C && ev.ctrlKey ) { + Clipboard.setClipboard(input.value); + } - Object.keys(attribs).forEach(function(a) { - if ( attribs[a] !== null ) { - if ( a === 'value' ) { - input.value = attribs[a]; - } else { - input.setAttribute(a, attribs[a]); - } + if ( type === 'textarea' && ev.keyCode === Keycodes.TAB ) { + ev.preventDefault(); + input.value += '\t'; } - }); + }, false); } - 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.createInputLabel(el, type, input); + + const rolemap = { + 'TEXTAREA': () => { + return 'textbox'; + }, + 'INPUT': (i) => { + const 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)); - function _create() { - _bindDefaults(); - _bindEvents(); + Events.$bind(input, 'change', (ev) => { + let value = input.value; + if ( type === 'radio' || type === 'checkbox' ) { + //value = input.getAttribute('checked') === 'checked'; + value = input.checked; //input.value === 'on'; + } + input.dispatchEvent(new CustomEvent('_change', {detail: value})); + }, false); + } - GUI.Helpers.createInputLabel(el, type, input); + _create(); +} - var rolemap = { - 'TEXTAREA': function() { - return 'textbox'; - }, - 'INPUT': function(i) { - var typemap = { - 'range': 'slider', - 'text': 'textbox', - 'password': 'textbox' - }; +///////////////////////////////////////////////////////////////////////////// +// SELECT HELPERS +///////////////////////////////////////////////////////////////////////////// - return typemap[i.type] || i.type; - } - }; +function addToSelectBox(el, entries) { + const target = el.querySelector('select'); + if ( !(entries instanceof Array) ) { + entries = [entries]; + } - 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.getAttribute('checked') === 'checked'; - value = input.checked; //input.value === 'on'; - } - input.dispatchEvent(new CustomEvent('_change', {detail: value})); - }, false); + entries.forEach((e) => { + const 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) { + const target = el.querySelector('select'); + target.querySelectorAll('option').forEach((opt) => { + if ( String(opt.value) === String(what) ) { + DOM.$remove(opt); + return false; } + return true; + }); +} + +function createSelectInput(el, multiple) { + const disabled = el.getAttribute('data-disabled') !== null; + const selected = el.getAttribute('data-selected'); + + const select = document.createElement('select'); + if ( multiple ) { + select.setAttribute('size', el.getAttribute('data-size') || 2); + multiple = el.getAttribute('data-multiple') === 'true'; + } - _create(); + if ( multiple ) { + select.setAttribute('multiple', 'multiple'); + } + if ( disabled ) { + select.setAttribute('disabled', 'disabled'); + } + if ( selected !== null ) { + select.selectedIndex = selected; } - function bindInputEvents(evName, callback, params) { + el.querySelectorAll('gui-select-option').forEach((sel) => { + const value = sel.getAttribute('data-value') || ''; + const label = sel.childNodes.length ? sel.childNodes[0].nodeValue : ''; + + const 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); + }); + + Events.$bind(select, 'change', (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); +} + +///////////////////////////////////////////////////////////////////////////// +// OTHER HELPERS +///////////////////////////////////////////////////////////////////////////// + +function setSwitchValue(val, input, button) { + if ( val !== true ) { + input.removeAttribute('checked'); + DOM.$removeClass(button, 'gui-active'); + button.innerHTML = '0'; + } else { + input.setAttribute('checked', 'checked'); + DOM.$addClass(button, 'gui-active'); + button.innerHTML = '1'; + } +} + +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// + +class _GUIInput extends GUIElement { + on(evName, callback, params) { /* eslint no-invalid-this: "off" */ if ( evName === 'enter' ) { evName = '_enter'; @@ -147,810 +250,689 @@ evName = '_change'; } - var target = this.$element.querySelector('textarea, input, select'); - Utils.$bind(target, evName, callback.bind(this), params); + const target = this.$element.querySelector('textarea, input, select'); + Events.$bind(target, evName, callback.bind(this), params); return this; } +} - ///////////////////////////////////////////////////////////////////////////// - // SELECT HELPERS - ///////////////////////////////////////////////////////////////////////////// +/** + * Element: 'gui-label' + * + * Just a normal label. + * + *

+ *   getter    value     String        The value/contents
+ *   setter    value     String        The value/contents
+ *   setter    label     String        The label text
+ *   property  disabled  boolean       Disabled state
+ * 
+ */ +class GUILabel extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-label' + }, this); + } - function addToSelectBox(el, entries) { - var target = el.querySelector('select'); - if ( !(entries instanceof Array) ) { - entries = [entries]; + set(param, value, isHTML) { + const el = this.$element; + if ( param === 'value' || param === 'label' ) { + el.setAttribute('data-label', String(value)); + + const lbl = el.querySelector('label'); + DOM.$empty(lbl); + if ( isHTML ) { + lbl.innerHTML = value; + } else { + lbl.appendChild(document.createTextNode(value)); + } + return this; } + return super.set(...arguments); + } - entries.forEach(function(e) { - var opt = document.createElement('option'); - opt.setAttribute('role', 'option'); - opt.setAttribute('value', e.value); - opt.appendChild(document.createTextNode(e.label)); + build() { + const el = this.$element; + const label = GUI.getValueLabel(el, true); + const lbl = document.createElement('label'); + lbl.appendChild(document.createTextNode(label)); + el.setAttribute('role', 'heading'); + el.setAttribute('data-label', String(label)); + el.appendChild(lbl); - target.appendChild(opt); - }); + return this; } +} - 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; - }); +/** + * Element: 'gui-textarea' + * + * Text area input (multi-line) + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value         String        The value/contents
+ *   setter    value         String        The value/contents
+ *   setter    label         String        The label text
+ *   setter    disabled      boolean       Set disabled state
+ *   property  disabled      boolean       Disabled state
+ *   property  value         String        The input value
+ *   property  placeholder   String        An optional placeholder
+ *   event     change                      When input has changed => fn(ev)
+ * 
+ */ +class GUITextarea extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-textarea', + type: 'input' + }, this); } - function createSelectInput(el, multiple) { - var disabled = el.getAttribute('data-disabled') !== null; - var selected = el.getAttribute('data-selected'); + build() { + createInputOfType(this.$element, 'textarea'); - var select = document.createElement('select'); - if ( multiple ) { - select.setAttribute('size', el.getAttribute('data-size') || 2); - multiple = el.getAttribute('data-multiple') === 'true'; - } + return this; + } - if ( multiple ) { - select.setAttribute('multiple', 'multiple'); - } - if ( disabled ) { - select.setAttribute('disabled', 'disabled'); - } - if ( selected !== null ) { - select.selectedIndex = selected; + set(param, value) { + const el = this.$element; + if ( el && param === 'scrollTop' ) { + if ( typeof value !== 'number' ) { + value = el.firstChild.scrollHeight; + } + el.firstChild.scrollTop = value; + return this; } + return super.set(...arguments); + } +} - el.querySelectorAll('gui-select-option').forEach(function(sel) { - var value = sel.getAttribute('data-value') || ''; - var label = sel.childNodes.length ? sel.childNodes[0].nodeValue : ''; +/** + * Element: 'gui-text' + * + * Text input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value         String        The value/contents
+ *   setter    value         String        The value/contents
+ *   setter    disabled      boolean       Set disabled state
+ *   property  disabled      boolean       Disabled state
+ *   property  value         String        The input value
+ *   property  placeholder   String        An optional placeholder
+ *   event     change                      When input has changed => fn(ev)
+ *   event     enter                       When enter key was pressed => fn(ev)
+ * 
+ */ +class GUIText extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-text', + type: 'input' + }, this); + } - 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); - }); + build() { + createInputOfType(this.$element, 'text'); + return this; + } +} - Utils.$bind(select, 'change', function(ev) { - select.dispatchEvent(new CustomEvent('_change', {detail: select.value})); - }, false); +/** + * Element: 'gui-password' + * + * Password input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value         String        The value/contents
+ *   setter    value         String        The value/contents
+ *   setter    disabled      boolean       Set disabled state
+ *   property  disabled      boolean       Disabled state
+ *   property  value         String        The input value
+ *   property  placeholder   String        An optional placeholder
+ *   event     change                      When input has changed => fn(ev)
+ *   event     enter                       When enter key was pressed => fn(ev)
+ * 
+ */ +class GUIPassword extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-password', + type: 'input' + }, this); + } - select.setAttribute('role', 'listbox'); - select.setAttribute('aria-label', el.getAttribute('title') || ''); - el.setAttribute('aria-disabled', String(disabled)); - el.setAttribute('role', 'region'); - el.appendChild(select); - } - - ///////////////////////////////////////////////////////////////////////////// - // OTHER HELPERS - ///////////////////////////////////////////////////////////////////////////// - - 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'; - } + build() { + createInputOfType(this.$element, 'password'); + return this; } +} - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-label' - * - * Just a normal label. - * - *

-   *   getter    value     String        The value/contents
-   *   setter    value     String        The value/contents
-   *   setter    label     String        The label text
-   *   property  disabled  boolean       Disabled state
-   * 
- * - * @constructor Label - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUILabel = { - set: function(param, value, isHTML) { - var el = this.$element; - 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 this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - build: function() { - var el = this.$element; - 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); +/** + * Element: 'gui-file-upload' + * + * File upload selector. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     String        The value/contents
+ *   setter    value     String        The value/contents
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   event     change                  When input has changed => fn(ev)
+ * 
+ */ +class GUIFileUpload extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-file-upload', + type: 'input' + }, this); + } - return this; - } - }; + build() { + const input = document.createElement('input'); + input.setAttribute('role', 'button'); + input.setAttribute('type', 'file'); + input.onchange = (ev) => { + input.dispatchEvent(new CustomEvent('_change', {detail: input.files[0]})); + }; + this.$element.appendChild(input); - /** - * Element: 'gui-textarea' - * - * Text area input (multi-line) - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value         String        The value/contents
-   *   setter    value         String        The value/contents
-   *   setter    label         String        The label text
-   *   setter    disabled      boolean       Set disabled state
-   *   property  disabled      boolean       Disabled state
-   *   property  value         String        The input value
-   *   property  placeholder   String        An optional placeholder
-   *   event     change                      When input has changed => fn(ev)
-   * 
- * - * @constructor Textarea - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUITextarea = { - on: bindInputEvents, - - build: function() { - createInputOfType(this.$element, 'textarea'); + return this; + } +} - return this; - }, +/** + * Element: 'gui-radio' + * + * Radio selection input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     boolean       The value/checked state
+ *   setter    value     boolean       The value/checked state
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   property  label     String        (Optional) Set a label on the input element
+ *   property  group     String        (Optional) A group identificator
+ *   event     change                  When input has changed => fn(ev)
+ * 
+ */ +class GUIRadio extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-radio', + type: 'input' + }, this); + } - set: function(param, value) { - var el = this.$element; - if ( el && param === 'scrollTop' ) { - if ( typeof value !== 'number' ) { - value = el.firstChild.scrollHeight; - } - el.firstChild.scrollTop = value; - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - } - }; + build() { + createInputOfType(this.$element, 'radio'); + return this; + } +} - /** - * Element: 'gui-text' - * - * Text input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value         String        The value/contents
-   *   setter    value         String        The value/contents
-   *   setter    disabled      boolean       Set disabled state
-   *   property  disabled      boolean       Disabled state
-   *   property  value         String        The input value
-   *   property  placeholder   String        An optional placeholder
-   *   event     change                      When input has changed => fn(ev)
-   *   event     enter                       When enter key was pressed => fn(ev)
-   * 
- * - * @constructor Text - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIText = { - on: bindInputEvents, - build: function() { - createInputOfType(this.$element, 'text'); +/** + * Element: 'gui-checbox' + * + * Checkbox selection input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     boolean       The value/checked state
+ *   setter    value     boolean       The value/checked state
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   property  label     String        (Optional) Set a label on the input element
+ *   property  group     String        (Optional) A group identificator
+ *   event     change                  When input has changed => fn(ev)
+ * 
+ */ +class GUICheckbox extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-checkbox', + type: 'input' + }, this); + } - return this; - } - }; + build() { + createInputOfType(this.$element, 'checkbox'); + return this; + } +} - /** - * Element: 'gui-password' - * - * Password input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value         String        The value/contents
-   *   setter    value         String        The value/contents
-   *   setter    disabled      boolean       Set disabled state
-   *   property  disabled      boolean       Disabled state
-   *   property  value         String        The input value
-   *   property  placeholder   String        An optional placeholder
-   *   event     change                      When input has changed => fn(ev)
-   *   event     enter                       When enter key was pressed => fn(ev)
-   * 
- * - * @constructor Password - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIPassword = { - on: bindInputEvents, - build: function() { - createInputOfType(this.$element, 'password'); +/** + * Element: 'gui-switch' + * + * A switch (on/off) input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     String        The value/enabled state
+ *   setter    value     String        The value/enabled state
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   event     change                  When input has changed => fn(ev)
+ * 
+ */ +class GUISwitch extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-switch', + type: 'input' + }, this); + } - return this; - } - }; + set(param, value) { + if ( param === 'value' ) { + const input = this.$element.querySelector('input'); + const button = this.$element.querySelector('button'); - /** - * Element: 'gui-file-upload' - * - * File upload selector. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     String        The value/contents
-   *   setter    value     String        The value/contents
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   event     change                  When input has changed => fn(ev)
-   * 
- * - * @constructor FileUpload - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIFileUpload = { - on: bindInputEvents, - build: function() { - 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]})); - }; - this.$element.appendChild(input); + setSwitchValue(value, input, button); return this; } - }; + return super.set(...arguments); + } - /** - * Element: 'gui-radio' - * - * Radio selection input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     boolean       The value/checked state
-   *   setter    value     boolean       The value/checked state
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   property  label     String        (Optional) Set a label on the input element
-   *   property  group     String        (Optional) A group identificator
-   *   event     change                  When input has changed => fn(ev)
-   * 
- * - * @constructor Radio - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIRadio = { - on: bindInputEvents, - build: function() { - createInputOfType(this.$element, 'radio'); + build() { + const el = this.$element; + const input = document.createElement('input'); + input.type = 'checkbox'; + el.appendChild(input); + + const inner = document.createElement('div'); + + const button = document.createElement('button'); + inner.appendChild(button); + GUI.createInputLabel(el, 'switch', inner); + + function toggleValue(v) { + let val = false; + if ( typeof v === 'undefined' ) { + val = !!input.checked; + val = !val; + } else { + val = v; + } - return this; + setSwitchValue(val, input, button); } - }; - /** - * Element: 'gui-checbox' - * - * Checkbox selection input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     boolean       The value/checked state
-   *   setter    value     boolean       The value/checked state
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   property  label     String        (Optional) Set a label on the input element
-   *   property  group     String        (Optional) A group identificator
-   *   event     change                  When input has changed => fn(ev)
-   * 
- * - * @constructor Checkbox - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUICheckbox = { - on: bindInputEvents, - build: function() { - createInputOfType(this.$element, 'checkbox'); + Events.$bind(inner, 'click', (ev) => { + ev.preventDefault(); + const disabled = el.getAttribute('data-disabled') !== null; + if ( !disabled ) { + toggleValue(); + } + }, false); - return this; - } - }; + toggleValue(false); - /** - * Element: 'gui-switch' - * - * A switch (on/off) input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     String        The value/enabled state
-   *   setter    value     String        The value/enabled state
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   event     change                  When input has changed => fn(ev)
-   * 
- * - * @constructor Button - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUISwitch = { - on: bindInputEvents, - - set: function(param, value) { - if ( param === 'value' ) { - var input = this.$element.querySelector('input'); - var button = this.$element.querySelector('button'); - - setSwitchValue(value, input, button); - - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - build: function() { - var el = this.$element; - 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; - } + return this; + } +} - setSwitchValue(val, input, button); - } +/** + * Element: 'gui-button' + * + * A normal button + * + *

+ *   getter    value     String        The value
+ *   setter    value     String        The value
+ *   setter    icon      String        Icon source
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   property  icon      String        Icon source
+ *   event     click                   When input was clicked => fn(ev)
+ * 
+ */ +class GUIButton extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-button', + type: 'input' + }, this); + } - Utils.$bind(inner, 'click', function(ev) { - ev.preventDefault(); - var disabled = el.getAttribute('data-disabled') !== null; - if ( !disabled ) { - toggleValue(); - } - }, false); + set(param, value, isHTML) { + if ( param === 'value' || param === 'label' ) { + const lbl = this.$element.querySelector('button'); + DOM.$empty(lbl); + if ( isHTML ) { + lbl.innerHTML = value; + } else { + lbl.appendChild(document.createTextNode(value)); + } - toggleValue(false); + lbl.setAttribute('aria-label', value); return this; } - }; - - /** - * Element: 'gui-button' - * - * A normal button - * - *

-   *   getter    value     String        The value
-   *   setter    value     String        The value
-   *   setter    icon      String        Icon source
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   property  icon      String        Icon source
-   *   event     click                   When input was clicked => fn(ev)
-   * 
- * - * @constructor Button - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIButton = { - set: function(param, value, isHTML) { - if ( param === 'value' || param === 'label' ) { - var lbl = this.$element.querySelector('button'); - Utils.$empty(lbl); - if ( isHTML ) { - lbl.innerHTML = value; - } else { - lbl.appendChild(document.createTextNode(value)); - } - - lbl.setAttribute('aria-label', value); + return super.set(...arguments); + } - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, + create(params) { + const label = params.label; + if ( params.label ) { + delete params.label; + } - create: function(params) { - var label = params.label; - if ( params.label ) { - delete params.label; - } + const el = GUI.createElement('gui-button', params); + if ( label ) { + el.appendChild(document.createTextNode(label)); + } + return el; + } - var el = GUI.Helpers.createElement('gui-button', params); - if ( label ) { - el.appendChild(document.createTextNode(label)); - } - return el; - }, + on(evName, callback, params) { + const target = this.$element.querySelector('button'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } - on: function(evName, callback, params) { - var target = this.$element.querySelector('button'); - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, - - build: function() { - var el = this.$element; - 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() { - // NOTE: This is probably a bit slow - var root = el; - while ( root.parentNode ) { - if ( root.tagName.toLowerCase() === 'application-window-content' ) { - break; - } - root = root.parentNode; + build() { + const el = this.$element; + const icon = el.getAttribute('data-icon'); + const disabled = el.getAttribute('data-disabled') !== null; + const group = el.getAttribute('data-group'); + const label = GUI.getValueLabel(el); + const input = document.createElement('button'); + + function setGroup(g) { + if ( g ) { + input.setAttribute('name', g + '[' + _buttonCount + ']'); + + Events.$bind(input, 'click', () => { + // NOTE: This is probably a bit slow + let 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'); - }); + DOM.$addClass(input, 'gui-active'); + root.querySelectorAll('gui-button[data-group="' + g + '"] > button').forEach((b) => { + if ( b.name === input.name ) { + return; + } + DOM.$removeClass(b, 'gui-active'); }); - } + }); } + } - function setImage() { - if ( icon && icon !== 'null' ) { - var tip = API._(el.getAttribute('data-tooltip') || ''); - var img = document.createElement('img'); - img.src = icon; - img.alt = tip; - img.title = tip; - - if ( input.firstChild ) { - input.insertBefore(img, input.firstChild); - } else { - input.appendChild(img); - } - Utils.$addClass(el, 'gui-has-image'); - } - } + function setImage() { + if ( icon && icon !== 'null' ) { + const tip = _(el.getAttribute('data-tooltip') || ''); + const img = document.createElement('img'); + img.src = icon; + img.alt = tip; + img.title = tip; - function setLabel() { - if ( label ) { - Utils.$addClass(el, 'gui-has-label'); + if ( input.firstChild ) { + input.insertBefore(img, input.firstChild); + } else { + input.appendChild(img); } - input.appendChild(document.createTextNode(label)); - input.setAttribute('aria-label', label); + DOM.$addClass(el, 'gui-has-image'); } + } - if ( disabled ) { - input.setAttribute('disabled', 'disabled'); + function setLabel() { + if ( label ) { + DOM.$addClass(el, 'gui-has-label'); } + input.appendChild(document.createTextNode(label)); + input.setAttribute('aria-label', label); + } - setLabel(); - setImage(); - setGroup(group); - _buttonCount++; + if ( disabled ) { + input.setAttribute('disabled', 'disabled'); + } - el.setAttribute('role', 'navigation'); - el.appendChild(input); + setLabel(); + setImage(); + setGroup(group); + _buttonCount++; - return this; - } - }; + el.setAttribute('role', 'navigation'); + el.appendChild(input); - /** - * Element: 'gui-select' - * - * A selection dropdown. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     String        The value
-   *   setter    value     String        The value
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   event     change                  When input has changed => fn(ev)
-   *   action    add                     Add elements(s) => fn(entries)
-   *   action    clear                   Clear elements => fn()
-   *   action    remove                  Removes element => fn(arg)
-   * 
- * - * @example - * add({ - * label: "Label", - * value: "Value" - * }) - * - * @constructor SelectList - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUISelect = { - on: bindInputEvents, - - add: function(arg) { - addToSelectBox(this.$element, arg); - return this; - }, + return this; + } +} - remove: function(arg) { - removeFromSelectBox(this.$element, arg); - return this; - }, +class _GUISelect extends _GUIInput { + add(arg) { + addToSelectBox(this.$element, arg); + return this; + } - clear: function() { - var target = this.$element.querySelector('select'); - Utils.$empty(target); - return this; - }, + remove(arg) { + removeFromSelectBox(this.$element, arg); + return this; + } - build: function() { - var el = this.$element; - var multiple = (el.tagName.toLowerCase() === 'gui-select-list'); - createSelectInput(el, multiple); + clear() { + const target = this.$element.querySelector('select'); + DOM.$empty(target); + return this; + } - return this; - } - }; + build() { + const el = this.$element; + const multiple = (el.tagName.toLowerCase() === 'gui-select-list'); + createSelectInput(el, multiple); - /** - * Element: 'gui-select-list' - * - * A selection list (same as dropdown except multiple) - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     String        The value
-   *   setter    value     String        The value
-   *   setter    disabled  boolean       Set disabled state
-   *   property  disabled  boolean       Disabled state
-   *   event     change                  When input has changed => fn(ev)
-   *   action    add                     Add elements(s) => fn(entries)
-   *   action    clear                   Clear elements => fn()
-   *   action    remove                  Removes element => fn(arg)
-   * 
- * - * @constructor SelectList - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUISelectList = GUISelect; - - /** - * Element: 'gui-slider' - * - * A slider input. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value     String        The value
-   *   setter    value     String        The value
-   *   setter    disabled  boolean       Set disabled state
-   *   property  min       integer       The minimum value
-   *   property  max       integer       The maxmimum value
-   *   property  disabled  boolean       Disabled state
-   *   event     change                  When input has changed => fn(ev)
-   * 
- * - * @constructor Slider - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUISlider = { - on: bindInputEvents, - - get: function(param) { - var val = GUI.Helpers.getProperty(this.$element, param); - if ( param === 'value' ) { - return parseInt(val, 10); - } - return val; - }, + return this; + } - build: function() { - createInputOfType(this.$element, 'range'); +} - return this; - } - }; +/** + * Element: 'gui-select' + * + * A selection dropdown. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     String        The value
+ *   setter    value     String        The value
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   event     change                  When input has changed => fn(ev)
+ *   action    add                     Add elements(s) => fn(entries)
+ *   action    clear                   Clear elements => fn()
+ *   action    remove                  Removes element => fn(arg)
+ * 
+ * + * @example + * add({ + * label: "Label", + * value: "Value" + * }) + */ +class GUISelect extends _GUISelect { + static register() { + return super.register({ + tagName: 'gui-select', + type: 'input' + }, this); + } +} - /** - * Element: 'gui-input-modal' - * - * A text area displaying current value with a button to open a modal/dialog etc. - * - *

-   *   getter    value     String        The value
-   *   setter    value     String        The value
-   *   event     open                    When button was pressed => fn(ev)
-   * 
- * - * @constructor InputModal - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIInputModal = { - on: function(evName, callback, params) { - if ( evName === 'open' ) { - evName = '_open'; - } - Utils.$bind(this.$element, evName, callback.bind(this), params); - return this; - }, +/** + * Element: 'gui-select-list' + * + * A selection list (same as dropdown except multiple) + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     String        The value
+ *   setter    value     String        The value
+ *   setter    disabled  boolean       Set disabled state
+ *   property  disabled  boolean       Disabled state
+ *   event     change                  When input has changed => fn(ev)
+ *   action    add                     Add elements(s) => fn(entries)
+ *   action    clear                   Clear elements => fn()
+ *   action    remove                  Removes element => fn(arg)
+ * 
+ */ +class GUISelectList extends _GUISelect { + static register() { + return super.register({ + tagName: 'gui-select-list', + type: 'input' + }, this); + } +} - get: function(param) { - if ( param === 'value' ) { - var input = this.$element.querySelector('input'); - return input.value; - } - return GUI.Element.prototype.get.apply(this, arguments); - }, - - set: function(param, value) { - if ( param === 'value' ) { - var input = this.$element.querySelector('input'); - input.removeAttribute('disabled'); - input.value = value; - input.setAttribute('disabled', 'disabled'); - input.setAttribute('aria-disabled', 'true'); - - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, +/** + * Element: 'gui-slider' + * + * A slider input. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value     String        The value
+ *   setter    value     String        The value
+ *   setter    disabled  boolean       Set disabled state
+ *   property  min       integer       The minimum value
+ *   property  max       integer       The maxmimum value
+ *   property  disabled  boolean       Disabled state
+ *   event     change                  When input has changed => fn(ev)
+ * 
+ */ +class GUISlider extends _GUIInput { + static register() { + return super.register({ + tagName: 'gui-slider', + type: 'input' + }, this); + } - build: function() { - var el = this.$element; - var container = document.createElement('div'); + get(param) { + const val = GUI.getProperty(this.$element, param); + if ( param === 'value' ) { + return parseInt(val, 10); + } + return val; + } - var input = document.createElement('input'); - input.type = 'text'; - input.setAttribute('disabled', 'disabled'); + build() { + createInputOfType(this.$element, 'range'); - var button = document.createElement('button'); - button.innerHTML = '...'; + return this; + } +} - Utils.$bind(button, 'click', function(ev) { - el.dispatchEvent(new CustomEvent('_open', {detail: input.value})); - }, false); +/** + * Element: 'gui-input-modal' + * + * A text area displaying current value with a button to open a modal/dialog etc. + * + *

+ *   getter    value     String        The value
+ *   setter    value     String        The value
+ *   event     open                    When button was pressed => fn(ev)
+ * 
+ */ +class GUIInputModal extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-input-modal', + type: 'input' + }, this); + } - container.appendChild(input); - container.appendChild(button); - el.appendChild(container); + on(evName, callback, params) { + if ( evName === 'open' ) { + evName = '_open'; + } + Events.$bind(this.$element, evName, callback.bind(this), params); + return this; + } + + get(param) { + if ( param === 'value' ) { + const input = this.$element.querySelector('input'); + return input.value; + } + return super.get(...arguments); + } + + set(param, value) { + if ( param === 'value' ) { + const input = this.$element.querySelector('input'); + input.removeAttribute('disabled'); + input.value = value; + input.setAttribute('disabled', 'disabled'); + input.setAttribute('aria-disabled', 'true'); return this; } - }; + return super.set(...arguments); + } + + build() { + const el = this.$element; + const container = document.createElement('div'); + + const input = document.createElement('input'); + input.type = 'text'; + input.setAttribute('disabled', 'disabled'); + + const button = document.createElement('button'); + button.innerHTML = '...'; + + Events.$bind(button, 'click', (ev) => { + el.dispatchEvent(new CustomEvent('_open', {detail: input.value})); + }, false); + + container.appendChild(input); + container.appendChild(button); + el.appendChild(container); + + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUILabel: GUILabel, + GUITextarea: GUITextarea, + GUIText: GUIText, + GUIPassword: GUIPassword, + GUIFileUpload: GUIFileUpload, + GUIRadio: GUIRadio, + GUICheckbox: GUICheckbox, + GUISwitch: GUISwitch, + GUIButton: GUIButton, + GUISelect: GUISelect, + GUISelectList: GUISelectList, + GUISlider: GUISlider, + GUIInputModal: GUIInputModal +}; - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// - - GUI.Element.register({ - tagName: 'gui-label' - }, GUILabel); - - GUI.Element.register({ - tagName: 'gui-textarea', - type: 'input' - }, GUITextarea); - - GUI.Element.register({ - tagName: 'gui-text', - type: 'input' - }, GUIText); - - GUI.Element.register({ - tagName: 'gui-password', - type: 'input' - }, GUIPassword); - - GUI.Element.register({ - tagName: 'gui-file-upload', - type: 'input' - }, GUIFileUpload); - - GUI.Element.register({ - tagName: 'gui-radio', - type: 'input' - }, GUIRadio); - - GUI.Element.register({ - tagName: 'gui-checkbox', - type: 'input' - }, GUICheckbox); - - GUI.Element.register({ - tagName: 'gui-switch', - type: 'input' - }, GUISwitch); - - GUI.Element.register({ - tagName: 'gui-button', - type: 'input' - }, GUIButton); - - GUI.Element.register({ - tagName: 'gui-select', - type: 'input' - }, GUISelect); - - GUI.Element.register({ - tagName: 'gui-select-list', - type: 'input' - }, GUISelectList); - - GUI.Element.register({ - tagName: 'gui-slider', - type: 'input' - }, GUISlider); - - GUI.Element.register({ - tagName: 'gui-input-modal', - type: 'input' - }, GUIInputModal); - -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/gui/elements/listview.js b/src/client/javascript/gui/elements/listview.js index 718d33d900..497ee2a471 100644 --- a/src/client/javascript/gui/elements/listview.js +++ b/src/client/javascript/gui/elements/listview.js @@ -27,370 +27,377 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - /* - * This is the function that applies a "fake" header to the table - * floating on top, containing the resizers. - * - * There's no other way to do this perfectly using tables. - * First attempt was using flexboxes, but it has a severe performance penalty - * when resizing because you have to repaint ALL the rows manually - */ - 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); - }); +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Events from 'utils/events'; +import GUIDataView from 'gui/dataview'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +/* + * This is the function that applies a "fake" header to the table + * floating on top, containing the resizers. + * + * There's no other way to do this perfectly using tables. + * First attempt was using flexboxes, but it has a severe performance penalty + * when resizing because you have to repaint ALL the rows manually + */ +function createFakeHeader(el) { - 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); - }); - } - }); + function createResizers() { + const fhead = el.querySelector('gui-list-view-fake-head'); + const head = el.querySelector('gui-list-view-head'); + const fcols = fhead.querySelectorAll('gui-list-view-column'); + const cols = head.querySelectorAll('gui-list-view-column'); + + fhead.querySelectorAll('gui-list-view-column-resizer').forEach((rel) => { + DOM.$remove(rel); + }); + + cols.forEach((col, idx) => { + const attr = col.getAttribute('data-resizable'); + if ( attr === 'true' ) { + const fcol = fcols[idx]; + + const resizer = document.createElement('gui-list-view-column-resizer'); + fcol.appendChild(resizer); + + let startWidth = 0; + let maxWidth = 0; + let widthOffset = 16; + let minWidth = widthOffset; + let tmpEl = null; + + GUI.createDrag(resizer, (ev) => { + startWidth = col.offsetWidth; + minWidth = widthOffset;//calculateWidth(); + maxWidth = el.offsetWidth - (el.children.length * widthOffset); + }, (ev, diff) => { + const newWidth = startWidth - diff.x; + + if ( !isNaN(newWidth) && newWidth > minWidth && newWidth < maxWidth ) { + col.style.width = String(newWidth) + 'px'; + fcol.style.width = String(newWidth) + 'px'; + } + + tmpEl = DOM.$remove(tmpEl); + }); + } + }); + } + + const fh = el.querySelector('gui-list-view-fake-head gui-list-view-head'); + DOM.$empty(fh); + + const row = el.querySelector('gui-list-view-head gui-list-view-row'); + if ( row ) { + fh.appendChild(row.cloneNode(true)); + createResizers(); + } +} + +/* + * Applies DOM changes for a row to be rendered properly + */ +function initRow(cls, row) { + const el = cls.$element; + + row.querySelectorAll('gui-list-view-column').forEach((cel, idx) => { + const icon = cel.getAttribute('data-icon'); + if ( icon && icon !== 'null' ) { + DOM.$addClass(cel, 'gui-has-image'); + cel.style.backgroundImage = 'url(' + icon + ')'; } - var fh = el.querySelector('gui-list-view-fake-head gui-list-view-head'); - Utils.$empty(fh); + const text = cel.firstChild; + if ( text && text.nodeType === 3 ) { + const span = document.createElement('span'); + span.appendChild(document.createTextNode(text.nodeValue)); + cel.insertBefore(span, text); + cel.removeChild(text); + } - var row = el.querySelector('gui-list-view-head gui-list-view-row'); - if ( row ) { - fh.appendChild(row.cloneNode(true)); - createResizers(); + if ( el._columns[idx] && !el._columns[idx].visible ) { + cel.style.display = 'none'; } - } - /* - * Applies DOM changes for a row to be rendered properly - */ - function initRow(cls, row) { - var el = cls.$element; - - 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 + ')'; - } + cel.setAttribute('role', 'listitem'); + }); - 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); - } + cls.bindEntryEvents(row, 'gui-list-view-row'); +} - if ( el._columns[idx] && !el._columns[idx].visible ) { - cel.style.display = 'none'; - } +/* + * Creates a new `gui-list-view-column` + */ +function createEntry(cls, v, head) { + const label = v.label || ''; - cel.setAttribute('role', 'listitem'); - }); + if ( v.label ) { + delete v.label; + } - cls.bindEntryEvents(row, 'gui-list-view-row'); + let setSize = null; + if ( v.size ) { + setSize = v.size; + delete v.size; } - /* - * Creates a new `gui-list-view-column` - */ - function createEntry(cls, v, head) { - var label = v.label || ''; + const nel = GUI.createElement('gui-list-view-column', v); + if ( setSize ) { + nel.style.width = setSize; + } - if ( v.label ) { - delete v.label; - } - var setSize = null; - if ( v.size ) { - setSize = v.size; - delete v.size; - } + if ( typeof label === 'function' ) { + nel.appendChild(label.call(nel, nel, v)); + } else { + const span = document.createElement('span'); + span.appendChild(document.createTextNode(label)); + nel.appendChild(span); + } - 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; +} - return nel; +/* + * Creates a new `gui-list-view-row` from iter + */ +function createRow(cls, e) { + e = e || {}; + if ( e.columns ) { + const row = GUI.createElement('gui-list-view-row', e, ['columns']); + + e.columns.forEach((se) => { + row.appendChild(createEntry(cls, se)); + }); + + return row; } + return null; +} - /* - * Creates a new `gui-list-view-row` from iter - */ - function createRow(cls, e) { - e = e || {}; - if ( e.columns ) { - var row = GUI.Helpers.createElement('gui-list-view-row', e, ['columns']); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// - e.columns.forEach(function(se) { - row.appendChild(createEntry(cls, se)); - }); +/** + * Element: 'gui-list-view' + * + * A list view with columns. + * + *

+ *   Parameters:
+ *    zebra     boolean       Enable zebra stripes
+ *
+ *   Setters:
+ *    columns(arr)  Sets the columns
+ * 
+ * + * @example + * + * .set('columns', [ + * {label: "Column 1", size: "100px"}, + * {label: "Column 2", size: "100px", visible: false}, + * {label: "Column 3", size: "100px", textalign: "right"}, + * {label: "Column 4", size: "100px", textalign: "right"} + * ]) + * + * @example + * + * .add([ + * { + * value: "something or JSON or whatever", + * columns: [ + * {label: "Value for column 1", icon: "Optional icon"}, + * {label: "Value for column 2", icon: "Optional icon"}, + * {label: "Value for column 3", icon: "Optional icon"}, + * {label: "Value for column 4", icon: "Optional icon"}, + * ] + * } + * ]) + */ +class GUIListView extends GUIDataView { + static register() { + return super.register({ + parent: GUIDataView, + tagName: 'gui-list-view' + }, this); + } + + values() { + const body = this.$element.querySelector('gui-list-view-body'); + const values = this.getSelected(body.querySelectorAll('gui-list-view-row')); + return values; + } - return row; + get(param, value, arg, asValue) { + if ( param === 'entry' ) { + const body = this.$element.querySelector('gui-list-view-body'); + const rows = body.querySelectorAll('gui-list-view-row'); + return this.getEntry(rows, value, arg, asValue); } - return null; + return super.get(...arguments); } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-list-view' - * - * A list view with columns. - * - *

-   *   Parameters:
-   *    zebra     boolean       Enable zebra stripes
-   *
-   *   Setters:
-   *    columns(arr)  Sets the columns
-   * 
- * - * @example - * - * .set('columns', [ - * {label: "Column 1", size: "100px"}, - * {label: "Column 2", size: "100px", visible: false}, - * {label: "Column 3", size: "100px", textalign: "right"}, - * {label: "Column 4", size: "100px", textalign: "right"} - * ]) - * - * @example - * - * .add([ - * { - * value: "something or JSON or whatever", - * columns: [ - * {label: "Value for column 1", icon: "Optional icon"}, - * {label: "Value for column 2", icon: "Optional icon"}, - * {label: "Value for column 3", icon: "Optional icon"}, - * {label: "Value for column 4", icon: "Optional icon"}, - * ] - * } - * ]) - * - * @constructor ListView - * @extends OSjs.GUI.DataView - * @memberof OSjs.GUI.Elements - */ - GUI.Element.register({ - parent: GUI.DataView, - tagName: 'gui-list-view' - }, { - - values: function() { - var body = this.$element.querySelector('gui-list-view-body'); - var values = this.getSelected(body.querySelectorAll('gui-list-view-row')); - return values; - }, - - get: function(param, value, arg, asValue) { - if ( param === 'entry' ) { - var body = this.$element.querySelector('gui-list-view-body'); - var rows = body.querySelectorAll('gui-list-view-row'); - return this.getEntry(rows, value, arg, asValue); - } - return GUI.DataView.prototype.get.apply(this, arguments); - }, + set(param, value, arg, arg2) { + const el = this.$element; - set: function(param, value, arg, arg2) { - var el = this.$element; - var self = this; + if ( param === 'columns' ) { + const head = el.querySelector('gui-list-view-head'); + const row = document.createElement('gui-list-view-row'); + DOM.$empty(head); - if ( param === 'columns' ) { - var head = el.querySelector('gui-list-view-head'); - var row = document.createElement('gui-list-view-row'); - Utils.$empty(head); + el._columns = []; - el._columns = []; + value.forEach((v) => { + v.visible = (typeof v.visible === 'undefined') || v.visible === true; - value.forEach(function(v) { - v.visible = (typeof v.visible === 'undefined') || v.visible === true; + const nel = createEntry(this, v, true); - var nel = createEntry(self, v, true); + el._columns.push(v); - el._columns.push(v); + if ( !v.visible ) { + nel.style.display = 'none'; + } + row.appendChild(nel); + }); - if ( !v.visible ) { - nel.style.display = 'none'; - } - row.appendChild(nel); - }); + head.appendChild(row); - head.appendChild(row); + createFakeHeader(el); + return this; + } else if ( param === 'selected' || param === 'value' ) { + const body = el.querySelector('gui-list-view-body'); + this.setSelected(body, body.querySelectorAll('gui-list-view-row'), value, arg, arg2); + return this; + } - createFakeHeader(el); - return this; - } else if ( param === 'selected' || param === 'value' ) { - var body = el.querySelector('gui-list-view-body'); - this.setSelected(body, body.querySelectorAll('gui-list-view-row'), value, arg, arg2); - return this; + return super.set(...arguments); + } + + add(entries) { + const body = this.$element.querySelector('gui-list-view-body'); + + return super.add(entries, (cls, e) => { + const cbCreated = e.onCreated || function() {}; + const row = createRow(this, e); + if ( row ) { + body.appendChild(row); + initRow(this, row); } - return GUI.DataView.prototype.set.apply(this, arguments); - }, + cbCreated(row); + }); + } - add: function(entries) { - var body = this.$element.querySelector('gui-list-view-body'); - var self = this; + clear() { + const body = this.$element.querySelector('gui-list-view-body'); + return super.clear(body); + } - return GUI.DataView.prototype.add.call(this, entries, function(cls, e) { - var cbCreated = e.onCreated || function() {}; - var row = createRow(self, e); - if ( row ) { - body.appendChild(row); - initRow(self, row); - } + remove(entries) { + const body = this.$element.querySelector('gui-list-view-body'); + return super.remove(entries, 'gui-list-view-row', null, body); + } - cbCreated(row); - }); - }, - - clear: function() { - var body = this.$element.querySelector('gui-list-view-body'); - return GUI.DataView.prototype.clear.call(this, body); - }, - - remove: function(entries) { - var body = this.$element.querySelector('gui-list-view-body'); - return GUI.DataView.prototype.remove.call(this, entries, 'gui-list-view-row', null, body); - }, - - patch: function(entries) { - var body = this.$element.querySelector('gui-list-view-body'); - return GUI.DataView.prototype.patch.call(this, entries, 'gui-list-view-row', body, createRow, initRow); - }, - - build: function() { - var el = this.$element; - el._columns = []; - - // Make sure base elements are in the dom - 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) { - // So user can forget adding the inner - if ( cel.parentNode.tagName !== 'GUI-LIST-VIEW-INNER' ) { - inner.appendChild(cel); - } - } + patch(entries) { + const body = this.$element.querySelector('gui-list-view-body'); + return super.patch(entries, 'gui-list-view-row', body, createRow, initRow); + } - 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); + build() { + const el = this.$element; + el._columns = []; + + // Make sure base elements are in the dom + let inner = el.querySelector('gui-list-view-inner'); + let head = el.querySelector('gui-list-view-head'); + let body = el.querySelector('gui-list-view-body'); + + function moveIntoInner(cel) { + // So user can forget adding the inner + if ( cel.parentNode.tagName !== 'GUI-LIST-VIEW-INNER' ) { + inner.appendChild(cel); } + } + + let fakeHead = el.querySelector('gui-list-view-fake-head'); + if ( !fakeHead ) { + fakeHead = document.createElement('gui-list-view-fake-head'); + const 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); + } - 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); + + Events.$bind(el, 'scroll', (ev) => { + fakeHead.style.top = el.scrollTop + 'px'; + }, false); + + // Create scheme defined header + const hcols = el.querySelectorAll('gui-list-view-head gui-list-view-column'); + hcols.forEach((cel, idx) => { + const vis = cel.getAttribute('data-visible'); + const iter = { + visible: vis === null || vis === 'true', + size: cel.getAttribute('data-size') + }; + + if ( iter.size ) { + cel.style.width = iter.size; } - (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); - - // Create scheme defined header - 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); - el._columns.push(iter); + if ( !iter.visible ) { + cel.style.display = 'none'; + } + }); - if ( !iter.visible ) { - cel.style.display = 'none'; - } - }); + createFakeHeader(el); - createFakeHeader(el); + // Create scheme defined rows + el.querySelectorAll('gui-list-view-body gui-list-view-row').forEach((row) => { + initRow(this, row); + }); - // Create scheme defined rows - el.querySelectorAll('gui-list-view-body gui-list-view-row').forEach(function(row) { - initRow(self, row); - }); + return super.build(...arguments); + } +} - return GUI.DataView.prototype.build.apply(this, arguments); - } - }); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); +export default { + GUIListView: GUIListView +}; diff --git a/src/client/javascript/gui/elements/menus.js b/src/client/javascript/gui/elements/menus.js index d48b42417c..f2afb03890 100644 --- a/src/client/javascript/gui/elements/menus.js +++ b/src/client/javascript/gui/elements/menus.js @@ -27,372 +27,379 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Events from 'utils/events'; +import * as Compability from 'utils/compability'; +import * as Menu from 'gui/menu'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function getSelectionEventAttribs(mel, didx) { + const id = mel.getAttribute('data-id'); + + let idx = DOM.$index(mel); + if ( !didx ) { + idx = parseInt(mel.getAttribute('data-index'), 10); + } - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// + const result = {index: idx, id: id}; + Array.prototype.slice.call(mel.attributes).forEach((item) => { + if ( item.name.match(/^data\-/) ) { + const an = item.name.replace(/^data\-/, ''); + if ( typeof result[an] === 'undefined' ) { + result[an] = item.value; + } + } + }); - function getSelectionEventAttribs(mel, didx) { - var id = mel.getAttribute('data-id'); - var idx = Utils.$index(mel); + return result; +} - if ( !didx ) { - idx = parseInt(mel.getAttribute('data-index'), 10); - } +function getEventName(evName) { + if ( ['select', 'click'].indexOf(evName) !== -1 ) { + return '_select'; + } + return evName; +} - 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; - } +function runChildren(pel, level, winRef, cb) { + level = level || 0; + cb = cb || function() {}; + + (pel.children || []).forEach((child, i) => { + if ( child && child.tagName.toLowerCase() === 'gui-menu-entry') { + GUIElement.createFromNode(child).build(null, winRef); + + cb(child, level); + } + }); +} + +function onEntryClick(ev, pos, target, original) { + const isExpander = !!target.querySelector('gui-menu'); + + if ( !isExpander ) { + Menu.blur(ev); + + const hasInput = target.querySelector('input'); + if ( hasInput ) { + if ( !Compability.isIE() && window.MouseEvent ) { + hasInput.dispatchEvent(new MouseEvent('click', { + clientX: pos.x, + clientY: pos.y + })); + } else { + const 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); } - }); + } - return result; + const dispatcher = (original || target).querySelector('label'); + dispatcher.dispatchEvent(new CustomEvent('_select', {detail: getSelectionEventAttribs(target, true)})); } - - function getEventName(evName) { - if ( ['select', 'click'].indexOf(evName) !== -1 ) { - return '_select'; +} + +function createTyped(child, par) { + const type = child.getAttribute('data-type'); + const value = child.getAttribute('data-checked') === 'true'; + + let input = null; + if ( type ) { + const group = child.getAttribute('data-group'); + input = document.createElement('input'); + input.type = type; + input.name = group ? group + '[]' : ''; + if ( value ) { + input.setAttribute('checked', 'checked'); } - return evName; + + par.setAttribute('role', 'menuitem' + type); + par.appendChild(input); } +} - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-menu-entry' - * - * An entry for a menu. - * - *

-   *   Events:
-   *    select        When an entry was selected (click) => fn(ev)
-   * 

-   *
-   * @constructor MenuEntry
-   * @extends OSjs.GUI.Element
-   * @memberof OSjs.GUI.Elements
-   */
-  (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');
-        }
+/////////////////////////////////////////////////////////////////////////////
+// EXPORTS
+/////////////////////////////////////////////////////////////////////////////
 
-        par.setAttribute('role', 'menuitem' + type);
-        par.appendChild(input);
-      }
+/**
+ * Element: 'gui-menu-entry'
+ *
+ * An entry for a menu.
+ *
+ * 

+ *   Events:
+ *    select        When an entry was selected (click) => fn(ev)
+ * 

+ */
+class GUIMenuEntry extends GUIElement {
+  static register() {
+    return super.register({
+      tagName: 'gui-menu-entry'
+    }, this);
+  }
+
+  on(evName, callback, params) {
+    evName = getEventName(evName);
+    const target = this.$element.querySelector('gui-menu-entry > label');
+    Events.$bind(target, evName, callback.bind(this), params);
+    return this;
+  }
+
+  build(arg, winRef) {
+    const child = this.$element;
+    if ( arguments.length < 2 ) {
+      return this;
     }
+    child.setAttribute('role', 'menuitem' + (child.getAttribute('data-type') || ''));
 
-    GUI.Element.register({
-      tagName: 'gui-menu-entry'
-    }, {
-      on: function(evName, callback, params) {
-        evName = getEventName(evName);
-        var target = this.$element.querySelector('gui-menu-entry > label');
-        Utils.$bind(target, evName, callback.bind(this), params);
-        return this;
-      },
-
-      build: function(arg, winRef) {
-        var child = this.$element;
-        if ( arguments.length < 2 ) {
-          return this;
-        }
-        child.setAttribute('role', 'menuitem' + (child.getAttribute('data-type') || ''));
+    const label = GUI.getLabel(child);
+    const icon = GUI.getIcon(child, winRef);
+    child.setAttribute('aria-label', label);
 
-        var label = GUI.Helpers.getLabel(child);
-        var icon = GUI.Helpers.getIcon(child, winRef);
-        child.setAttribute('aria-label', label);
+    const span = document.createElement('label');
+    if ( icon ) {
+      child.style.backgroundImage = 'url(' + icon + ')';
+      DOM.$addClass(span, 'gui-has-image');
+    }
+    child.appendChild(span);
 
-        var span = document.createElement('label');
-        if ( icon ) {
-          child.style.backgroundImage = 'url(' + icon + ')';
-          Utils.$addClass(span, 'gui-has-image');
-        }
-        child.appendChild(span);
+    createTyped(child, span);
 
-        createTyped(child, span);
+    if ( child.getAttribute('data-labelhtml') === 'true' ) {
+      span.innerHTML = label;
+    } else {
+      span.appendChild(document.createTextNode(label));
+    }
 
-        if ( child.getAttribute('data-labelhtml') === 'true' ) {
-          span.innerHTML = label;
-        } else {
-          span.appendChild(document.createTextNode(label));
-        }
+    if ( child.querySelector('gui-menu') ) {
+      DOM.$addClass(child, 'gui-menu-expand');
+      child.setAttribute('aria-haspopup', 'true');
+    } else {
+      child.setAttribute('aria-haspopup', 'false');
+    }
 
-        if ( child.querySelector('gui-menu') ) {
-          Utils.$addClass(child, 'gui-menu-expand');
-          child.setAttribute('aria-haspopup', 'true');
-        } else {
-          child.setAttribute('aria-haspopup', 'false');
-        }
+    return this;
+  }
+}
 
-        return this;
+/**
+ * Element: 'gui-menu'
+ *
+ * A normal menu (also contextmenu)
+ *
+ * 

+ *   Events:
+ *    select        When an entry was selected (click) => fn(ev)
+ *
+ *   Setters:
+ *    checked       Set checkbox/option checked value
+ * 
+ */ +class GUIMenu extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-menu' + }, this); + } + + on(evName, callback, params) { + evName = getEventName(evName); + + Events.$bind(this.$element, evName, function(ev) { + const t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + if ( t.tagName === 'LABEL' ) { + callback.apply(new GUIElement(t.parentNode), arguments); } - }); - })(); - - /** - * Element: 'gui-menu' - * - * A normal menu (also contextmenu) - * - *

-   *   Events:
-   *    select        When an entry was selected (click) => fn(ev)
-   *
-   *   Setters:
-   *    checked       Set checkbox/option checked value
-   * 
- * - * @constructor Menu - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - (function() { - - 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.Element.createFromNode(child).build(null, winRef); - - cb(child, level); - } - }); - } + }, true); - function onEntryClick(ev, pos, target, original) { - var isExpander = !!target.querySelector('gui-menu'); + return this; + } - if ( !isExpander ) { - OSjs.GUI.Helpers.blurMenu(ev); + show(ev) { + ev.stopPropagation(); + ev.preventDefault(); - var hasInput = target.querySelector('input'); - if ( hasInput ) { - if ( !Utils.isIE() && window.MouseEvent ) { - hasInput.dispatchEvent(new MouseEvent('click', { - clientX: pos.x, - clientY: pos.y - })); + // This is to use a menu-bar > menu as a contextmenu + const newNode = this.$element.cloneNode(true); + const el = this.$element; + Menu.create(null, ev, newNode); + + Events.$bind(newNode, 'click', (ev, pos) => { + Menu.clickWrapper(ev, pos, onEntryClick, el); + }, true); + } + + set(param, value, arg) { + if ( param === 'checked' ) { + const found = this.$element.querySelector('gui-menu-entry[data-id="' + value + '"]'); + if ( found ) { + const input = found.querySelector('input'); + if ( input ) { + if ( arg ) { + input.setAttribute('checked', 'checked'); } 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); + input.removeAttribute('checked'); } } - - var dispatcher = (original || target).querySelector('label'); - dispatcher.dispatchEvent(new CustomEvent('_select', {detail: getSelectionEventAttribs(target, true)})); } + return this; } + return super.set(...arguments); + } - GUI.Element.register({ - tagName: 'gui-menu' - }, { - on: function(evName, callback, params) { - evName = getEventName(evName); - - Utils.$bind(this.$element, evName, function(ev) { - var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); - if ( t.tagName === 'LABEL' ) { - callback.apply(new GUI.Element(t.parentNode), arguments); - } - }, true); - - return this; - }, - - show: function(ev) { - ev.stopPropagation(); - ev.preventDefault(); - - // This is to use a menu-bar > menu as a contextmenu - var newNode = this.$element.cloneNode(true); - var el = this.$element; - OSjs.GUI.Helpers.createMenu(null, ev, newNode); - - Utils.$bind(newNode, 'click', function(ev, pos) { - OSjs.GUI.Helpers._menuClickWrapper(ev, pos, onEntryClick, el); - }, true); - }, - - set: function(param, value, arg) { - if ( param === 'checked' ) { - var found = this.$element.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'); - } + build(customMenu, winRef) { + const el = this.$element; + el.setAttribute('role', 'menu'); + + runChildren(el, 0, winRef, (child, level) => { + if ( customMenu ) { + if ( child ) { + const submenus = child.getElementsByTagName('gui-menu'); + submenus.forEach((sub) => { + if ( sub ) { + runChildren(sub, level + 1, winRef); } - } - return this; + }); } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - build: function(customMenu, winRef) { - var el = this.$element; - el.setAttribute('role', 'menu'); - - runChildren(el, 0, winRef, function(child, level) { - if ( customMenu ) { - if ( child ) { - var submenus = child.getElementsByTagName('gui-menu'); - submenus.forEach(function(sub) { - if ( sub ) { - runChildren(sub, level + 1, winRef); - } - }); - } - } - }); + } + }); - if ( !customMenu ) { - Utils.$bind(el, 'click', function(ev, pos) { - OSjs.GUI.Helpers._menuClickWrapper(ev, pos, onEntryClick); - }, true); - } + if ( !customMenu ) { + Events.$bind(el, 'click', (ev, pos) => { + Menu.clickWrapper(ev, pos, onEntryClick); + }, true); + } - return this; - } + return this; + } +} + +/** + * Element: 'gui-menu-bar' + * + * A menubar with sub-menus + * + *

+ *   event     select               When an entry was selected (click) => fn(ev)
+ * 
+ */ +class GUIMenuBar extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-menu-bar' + }, this); + } + + on(evName, callback, params) { + evName = getEventName(evName); + + this.$element.querySelectorAll('gui-menu-bar-entry').forEach((target) => { + Events.$bind(target, evName, callback.bind(this), params); }); - })(); - - /** - * Element: 'gui-menu-bar' - * - * A menubar with sub-menus - * - *

-   *   event     select               When an entry was selected (click) => fn(ev)
-   * 
- * - * @constructor MenuBar - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - GUI.Element.register({ - tagName: 'gui-menu-bar' - }, { - on: function(evName, callback, params) { - evName = getEventName(evName); - var self = this; - - this.$element.querySelectorAll('gui-menu-bar-entry').forEach(function(target) { - Utils.$bind(target, evName, callback.bind(self), params); - }); - return this; - }, - - build: function() { - var el = this.$element; - 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); - } + return this; + } + + build() { + const el = this.$element; + el.setAttribute('role', 'menubar'); + + function updateChildren(sm, level) { + if ( sm && sm.children ) { + const children = sm.children; + + let child; + for ( let 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) { - OSjs.GUI.Helpers.blurMenu(ev); + function _onClick(ev, mel) { + Menu.blur(ev); - ev.preventDefault(); - ev.stopPropagation(); + ev.preventDefault(); + ev.stopPropagation(); - var submenu = mel.querySelector('gui-menu'); + const submenu = mel.querySelector('gui-menu'); - if ( mel.getAttribute('data-disabled') === 'true' ) { - return; - } + if ( mel.getAttribute('data-disabled') === 'true' ) { + return; + } - mel.querySelectorAll('gui-menu-entry').forEach(function(c) { - Utils.$removeClass(c, 'gui-hover'); + mel.querySelectorAll('gui-menu-entry').forEach((c) => { + DOM.$removeClass(c, 'gui-hover'); + }); + + if ( submenu ) { + Menu.setActive((ev) => { + if ( ev ) { + ev.stopPropagation(); + } + DOM.$removeClass(mel, 'gui-active'); }); + } + if ( DOM.$hasClass(mel, 'gui-active') ) { if ( submenu ) { - OSjs.GUI.Helpers._menuSetActive(function(ev) { - if ( ev ) { - ev.stopPropagation(); - } - Utils.$removeClass(mel, 'gui-active'); - }); + DOM.$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)})); + } else { + if ( submenu ) { + DOM.$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); + el.querySelectorAll('gui-menu-bar-entry').forEach((mel, idx) => { + const label = GUI.getLabel(mel); - var span = document.createElement('span'); - span.appendChild(document.createTextNode(label)); + const span = document.createElement('span'); + span.appendChild(document.createTextNode(label)); - mel.setAttribute('role', 'menuitem'); + mel.setAttribute('role', 'menuitem'); - mel.insertBefore(span, mel.firstChild); + mel.insertBefore(span, mel.firstChild); - var submenu = mel.querySelector('gui-menu'); + const submenu = mel.querySelector('gui-menu'); - OSjs.GUI.Helpers._menuClamp(submenu); + Menu.clamp(submenu); - mel.setAttribute('aria-haspopup', String(!!submenu)); - mel.setAttribute('data-index', String(idx)); + mel.setAttribute('aria-haspopup', String(!!submenu)); + mel.setAttribute('data-index', String(idx)); - updateChildren(submenu, 2); - }); + updateChildren(submenu, 2); + }); - Utils.$bind(el, 'mousedown', function(ev) { - ev.preventDefault(); - var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); - if ( t && t.tagName === 'GUI-MENU-BAR-ENTRY' ) { - _onClick(ev, t); - } - }, true); + Events.$bind(el, 'mousedown', (ev) => { + ev.preventDefault(); + const t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + if ( t && t.tagName === 'GUI-MENU-BAR-ENTRY' ) { + _onClick(ev, t); + } + }, true); - return this; - } - }); + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); +export default { + GUIMenuEntry: GUIMenuEntry, + GUIMenuBar: GUIMenuBar, + GUIMenu: GUIMenu +}; diff --git a/src/client/javascript/gui/elements/misc.js b/src/client/javascript/gui/elements/misc.js index a1b02061b3..4248931805 100644 --- a/src/client/javascript/gui/elements/misc.js +++ b/src/client/javascript/gui/elements/misc.js @@ -27,325 +27,324 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-color-box' - * - * A box that displays a color. - * - *

-   *   getter    value   String        The value (color)
-   *   setter    value   String        The value (color)
-   * 
- * - * @constructor ColorBox - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIColorBox = { - on: function(evName, callback, params) { - var el = this.$element; - var target = el.querySelector('div'); - Utils.$bind(target, evName, callback.bind(this), params); +import * as DOM from 'utils/dom'; +import * as Utils from 'utils/misc'; +import * as Events from 'utils/events'; +import {getConfig} from 'core/config'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// + +/** + * Element: 'gui-color-box' + * + * A box that displays a color. + * + *

+ *   getter    value   String        The value (color)
+ *   setter    value   String        The value (color)
+ * 
+ */ +class GUIColorBox extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-color-box' + }, this); + } + + on(evName, callback, params) { + const el = this.$element; + const target = el.querySelector('div'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } + + set(param, value) { + if ( param === 'value' ) { + this.$element.firstChild.style.backgroundColor = value; return this; - }, + } + return super.set(...arguments); + } - set: function(param, value) { - if ( param === 'value' ) { - this.$element.firstChild.style.backgroundColor = value; - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, + build() { + const inner = document.createElement('div'); + this.$element.appendChild(inner); - build: function() { - var inner = document.createElement('div'); - this.$element.appendChild(inner); + return this; + } +} - return this; +/** + * Element: 'gui-color-swatch' + * + * A box for selecting color(s) in the rainbow. + * + * See `ev.detail` for data on events (like on 'change'). + * + *

+ *   getter    value   String        The value (color)
+ *   setter    value   String        The value (color)
+ *   event     change                When input has changed => fn(ev)
+ * 
+ */ +class GUIColorSwatch extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-color-swatch' + }, this); + } + + on(evName, callback, params) { + const el = this.$element; + const target = el.querySelector('canvas'); + if ( evName === 'select' || evName === 'change' ) { + evName = '_change'; } - }; - - /** - * Element: 'gui-color-swatch' - * - * A box for selecting color(s) in the rainbow. - * - * See `ev.detail` for data on events (like on 'change'). - * - *

-   *   getter    value   String        The value (color)
-   *   setter    value   String        The value (color)
-   *   event     change                When input has changed => fn(ev)
-   * 
- * - * @constructor ColorSwatch - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIColorSwatch = { - on: function(evName, callback, params) { - var el = this.$element; - var target = el.querySelector('canvas'); - if ( evName === 'select' || evName === 'change' ) { - evName = '_change'; - } - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, + Events.$bind(target, evName, callback.bind(this), params); + return this; + } - build: function() { - var el = this.$element; - var cv = document.createElement('canvas'); - cv.width = 100; - cv.height = 100; + build() { + const el = this.$element; + const 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); + const ctx = cv.getContext('2d'); - 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; + let gradient = ctx.createLinearGradient(0, 0, ctx.canvas.width, 0); - if ( isNaN(cx) || isNaN(cy) ) { - return null; - } + function getColor(ev) { + const pos = DOM.$position(cv); + const cx = typeof ev.offsetX === 'undefined' ? (ev.clientX - pos.left) : ev.offsetX; + const cy = typeof ev.offsetY === 'undefined' ? (ev.clientY - pos.top) : ev.offsetY; - 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]) - }; + if ( isNaN(cx) || isNaN(cy) ) { + return null; } - 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); + const 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]) + }; + } - el.appendChild(cv); + 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); + + Events.$bind(cv, 'click', (ev) => { + const c = getColor(ev); + if ( c ) { + cv.dispatchEvent(new CustomEvent('_change', {detail: c})); + } + }, false); - return this; - } - }; - - /** - * Element: 'gui-iframe' - * - * IFrame container. On NW/Electron/X11 this is a "webview" - * - *

-   *   property  src     String        The source (src)
-   * 
- * - * @constructor Iframe - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIIframe = (function() { - var tagName = 'iframe'; - if ( (['nw', 'electron', 'x11']).indexOf(API.getConfig('Connection.Type')) >= 0 ) { + el.appendChild(cv); + + return this; + } +} + +/** + * Element: 'gui-iframe' + * + * IFrame container. On NW/Electron/X11 this is a "webview" + * + *

+ *   property  src     String        The source (src)
+ * 
+ */ +class GUIIframe extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-iframe' + }, this); + } + + static get _tagName() { + let tagName = 'iframe'; + if ( (['nw', 'electron', 'x11']).indexOf(getConfig('Connection.Authenticator')) >= 0 ) { // FIXME: re-implement tagName = 'webview'; } + return tagName; + } - return { + set(key, val) { + if ( key === 'src' ) { + this.$element.querySelector(GUIIframe._tagName).src = val; + return this; + } + return super.set(...arguments); + } + + build() { + const el = this.$element; + const src = el.getAttribute('data-src') || 'about:blank'; + const iframe = document.createElement(GUIIframe._tagName); + iframe.src = src; + iframe.setAttribute('border', 0); + el.appendChild(iframe); + + return this; + } +} + +/** + * Element: 'gui-progress-bar' + * + * Progress bar element. + * + *

+ *   setter    progress    integer     Progress value (percentage)
+ *   property  progress    integer     Progress value (percentage)
+ * 
+ */ +class GUIProgressBar extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-progress-bar' + }, this); + } + + set(param, value) { + const el = this.$element; + 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 this; + } - set: function(key, val) { - if ( key === 'src' ) { - this.$element.querySelector(tagName).src = val; - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - build: function() { - var el = this.$element; - var src = el.getAttribute('data-src') || 'about:blank'; - var iframe = document.createElement(tagName); - iframe.src = src; - iframe.setAttribute('border', 0); - el.appendChild(iframe); - - return this; - } - }; - - })(); - - /** - * Element: 'gui-progress-bar' - * - * Progress bar element. - * - *

-   *   setter    progress    integer     Progress value (percentage)
-   *   property  progress    integer     Progress value (percentage)
-   * 
- * - * @constructor ProgressBar - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIProgressBar = { - set: function(param, value) { - var el = this.$element; - 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 this; - } + return super.set(...arguments); + } - return GUI.Element.prototype.set.apply(this, arguments); - }, + build() { + const el = this.$element; - build: function() { - var el = this.$element; + let p = (el.getAttribute('data-progress') || 0); + p = Math.max(0, Math.min(100, p)); - var p = (el.getAttribute('data-progress') || 0); - p = Math.max(0, Math.min(100, p)); + const percentage = p.toString() + '%'; - var percentage = p.toString() + '%'; + const progress = document.createElement('div'); + progress.style.width = percentage; - var progress = document.createElement('div'); - progress.style.width = percentage; + const span = document.createElement('span'); + span.appendChild(document.createTextNode(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.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); - el.appendChild(progress); - el.appendChild(span); + return this; + } +} +/** + * Element: 'gui-statusbar' + * + * Status bar element. + * + *

+ *   setter    value       String      Content to set
+ *   setter    label       String      Alias of 'value'
+ * 
+ */ +class GUIStatusBar extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-statusbar' + }, this); + } + + set(param, value) { + if ( param === 'label' || param === 'value' ) { + const span = this.$element.getElementsByTagName('gui-statusbar-label')[0]; + if ( span ) { + DOM.$empty(span); + span.innerHTML = value; + } return this; } - }; - - /** - * Element: 'gui-statusbar' - * - * Status bar element. - * - *

-   *   setter    value       String      Content to set
-   *   setter    label       String      Alias of 'value'
-   * 
- * - * @constructor StatusBar - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIStatusBar = { - set: function(param, value) { - if ( param === 'label' || param === 'value' ) { - var span = this.$element.getElementsByTagName('gui-statusbar-label')[0]; - if ( span ) { - Utils.$empty(span); - span.innerHTML = value; - } - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - build: function(args, win) { - var el = this.$element; - 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 super.set(...arguments); + } + + build(args, win) { + const el = this.$element; + const span = document.createElement('gui-statusbar-label'); + + let lbl = el.getAttribute('data-label') || el.getAttribute('data-value'); + if ( !lbl ) { + lbl = (() => { + let textNodes = []; + let node, value; + for ( let 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); } - } - - return textNodes.join(' '); - })(); - } - span.innerHTML = lbl; - el.setAttribute('role', 'log'); - el.appendChild(span); + el.removeChild(node); + i++; + } + } - return this; + return textNodes.join(' '); + })(); } - }; - - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// - - GUI.Element.register({ - tagName: 'gui-color-box' - }, GUIColorBox); - - GUI.Element.register({ - tagName: 'gui-color-swatch' - }, GUIColorSwatch); - - GUI.Element.register({ - tagName: 'gui-iframe' - }, GUIIframe); - - GUI.Element.register({ - tagName: 'gui-progress-bar' - }, GUIProgressBar); - - GUI.Element.register({ - tagName: 'gui-statusbar' - }, GUIStatusBar); -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); + span.innerHTML = lbl; + el.setAttribute('role', 'log'); + el.appendChild(span); + + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUIColorBox: GUIColorBox, + GUIColorSwatch: GUIColorSwatch, + GUIIframe: GUIIframe, + GUIProgressBar: GUIProgressBar, + GUIStatusBar: GUIStatusBar +}; diff --git a/src/client/javascript/gui/elements/richtext.js b/src/client/javascript/gui/elements/richtext.js index 51117c6f21..7f330e1135 100644 --- a/src/client/javascript/gui/elements/richtext.js +++ b/src/client/javascript/gui/elements/richtext.js @@ -27,206 +27,206 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +import * as DOM from 'utils/dom'; +import * as Events from 'utils/events'; +import Theme from 'core/theme'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function getDocument(el, iframe) { + iframe = iframe || el.querySelector('iframe'); + return iframe.contentDocument || iframe.contentWindow.document; +} + +function getDocumentData(el) { + try { + const doc = getDocument(el); + return doc.body.innerHTML; + } catch ( error ) { + console.error('gui-richtext', 'getDocumentData()', error.stack, error); + } + return ''; +} - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// +function destroyFixInterval(el) { + el._fixTry = 0; + el._fixInterval = clearInterval(el._fixInterval); +} - function getDocument(el, iframe) { - iframe = iframe || el.querySelector('iframe'); - return iframe.contentDocument || iframe.contentWindow.document; +function createFixInterval(el, doc, text) { + if ( el._fixTry > 10 ) { + el._fixTry = 0; + return; } - function getDocumentData(el) { + el._fixInterval = setInterval(() => { try { - var doc = getDocument(el); - return doc.body.innerHTML; + if ( text ) { + doc.body.innerHTML = text; + } + destroyFixInterval(el); } catch ( error ) { - console.error('gui-richtext', 'getDocumentData()', error.stack, error); + console.warn('gui-richtext', 'setDocumentData()', error.stack, error, '... trying again'); + } + el._fixTry++; + }, 100); +} + +function setDocumentData(el, text) { + destroyFixInterval(el); + + text = text || ''; + + const themeName = Theme.getStyleTheme(); + const themeSrc = '/themes.css'; + let editable = el.getAttribute('data-editable'); + editable = editable === null || editable === 'true'; + + function onMouseDown(ev) { + function insertTextAtCursor(text) { + let 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; + } } - return ''; - } - function destroyFixInterval(el) { - el._fixTry = 0; - el._fixInterval = clearInterval(el._fixInterval); + if ( ev.keyCode === 9 ) { + /* + const t = ev.shiftKey ? "outdent" : "indent"; + document.execCommand("styleWithCSS",true,null); + document.execCommand(t, false, null) + */ + insertTextAtCursor('\u00A0'); + ev.preventDefault(); + } } - function createFixInterval(el, doc, text) { - if ( el._fixTry > 10 ) { - el._fixTry = 0; - return; - } + const script = onMouseDown.toString() + ';window.addEventListener("keydown", onMouseDown)'; - 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); + let template = ''; + if ( !editable ) { + template = template.replace(' contentEditable="true"', ''); } - 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; - } - } + const doc = getDocument(el); + doc.open(); + doc.write(template); + doc.close(); + createFixInterval(el, doc, text); +} - if ( ev.keyCode === 9 ) { - /* - var t = ev.shiftKey ? "outdent" : "indent"; - document.execCommand("styleWithCSS",true,null); - document.execCommand(t, false, null) - */ - insertTextAtCursor('\u00A0'); - ev.preventDefault(); - } - } +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// - var script = onMouseDown.toString() + ';window.addEventListener("keydown", onMouseDown)'; +/** + * Element: 'gui-richtext' + * + * "Richt text" input area. + * + *

+ *   getter    value   String        The value/contents
+ *   setter    value   String        The value/contents
+ * 
+ */ +class GUIRichText extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-richtext' + }, this); + } - var template = ''; - if ( !editable ) { - template = template.replace(' contentEditable="true"', ''); + on(evName, callback, params) { + if ( (['selection']).indexOf(evName) !== -1 ) { + evName = '_' + evName; } - - var doc = getDocument(el); - doc.open(); - doc.write(template); - doc.close(); - createFixInterval(el, doc, text); + Events.$bind(this.$element, evName, callback.bind(this), params); + return this; } - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-richtext' - * - * "Richt text" input area. - * - *

-   *   getter    value   String        The value/contents
-   *   setter    value   String        The value/contents
-   * 
- * - * @constructor RichText - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIRichText = { - on: function(evName, callback, params) { - if ( (['selection']).indexOf(evName) !== -1 ) { - evName = '_' + evName; - } - Utils.$bind(this.$element, evName, callback.bind(this), params); - return this; - }, - - build: function() { - var el = this.$element; - 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); - - return this; - }, - - command: function() { + build() { + const el = this.$element; + const text = el.childNodes.length ? el.childNodes[0].nodeValue : ''; + + DOM.$empty(el); + + const iframe = document.createElement('iframe'); + iframe.setAttribute('border', 0); + iframe.onload = () => { + iframe.contentWindow.addEventListener('selectstart', () => { + el.dispatchEvent(new CustomEvent('_selection', {detail: {}})); + }); + iframe.contentWindow.addEventListener('mouseup', () => { + el.dispatchEvent(new CustomEvent('_selection', {detail: {}})); + }); + }; + el.appendChild(iframe); + + setTimeout(() => { try { - var doc = getDocument(this.$element); - if ( doc && doc.execCommand ) { - return doc.execCommand.apply(doc, arguments); - } + setDocumentData(el, text); } catch ( e ) { - console.warn('gui-richtext call() warning', e.stack, e); + console.warn('gui-richtext', 'build()', e); } - return this; - }, + }, 1); - query: function() { - try { - var doc = getDocument(this.$element); - if ( doc && doc.queryCommandValue ) { - return doc.queryCommandValue.apply(doc, arguments); - } - } catch ( e ) { - console.warn('gui-richtext call() warning', e.stack, e); - } - return null; - }, + return this; + } - get: function(param, value) { - if ( param === 'value' ) { - return getDocumentData(this.$element); + command() { + try { + const doc = getDocument(this.$element); + if ( doc && doc.execCommand ) { + return doc.execCommand.apply(doc, arguments); } - return GUI.Element.prototype.get.apply(this, arguments); - }, + } catch ( e ) { + console.warn('gui-richtext call() warning', e.stack, e); + } + return this; + } - set: function(param, value) { - if ( param === 'value' ) { - setDocumentData(this.$element, value); - return this; + query() { + try { + const doc = getDocument(this.$element); + if ( doc && doc.queryCommandValue ) { + return doc.queryCommandValue.apply(doc, arguments); } - return GUI.Element.prototype.set.apply(this, arguments); + } catch ( e ) { + console.warn('gui-richtext call() warning', e.stack, e); } - }; + return null; + } - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// + get(param, value) { + if ( param === 'value' ) { + return getDocumentData(this.$element); + } + return super.get(...arguments); + } + + set(param, value) { + if ( param === 'value' ) { + setDocumentData(this.$element, value); + return this; + } + return super.set(...arguments); + } +} - GUI.Element.register({ - tagName: 'gui-richtext' - }, GUIRichText); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); +export default { + GUIRichText: GUIRichText +}; diff --git a/src/client/javascript/gui/elements/tabs.js b/src/client/javascript/gui/elements/tabs.js index ae46e6b8e2..db06fbf615 100644 --- a/src/client/javascript/gui/elements/tabs.js +++ b/src/client/javascript/gui/elements/tabs.js @@ -27,192 +27,194 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - function toggleActive(el, eidx, idx) { - Utils.$removeClass(el, 'gui-active'); - if ( eidx === idx ) { - Utils.$addClass(el, 'gui-active'); - } +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import * as Events from 'utils/events'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function toggleActive(el, eidx, idx) { + DOM.$removeClass(el, 'gui-active'); + if ( eidx === idx ) { + DOM.$addClass(el, 'gui-active'); } - - function selectTab(el, tabs, ev, idx, tab) { - tabs.querySelectorAll('li').forEach(function(tel, eidx) { - toggleActive(tel, eidx, idx); - }); - - el.querySelectorAll('gui-tab-container').forEach(function(tel, eidx) { - toggleActive(tel, eidx, idx); +} + +function selectTab(el, tabs, ev, idx, tab) { + tabs.querySelectorAll('li').forEach((tel, eidx) => { + toggleActive(tel, eidx, idx); + }); + + el.querySelectorAll('gui-tab-container').forEach((tel, eidx) => { + toggleActive(tel, eidx, idx); + }); + + DOM.$addClass(tab, 'gui-active'); + + el.dispatchEvent(new CustomEvent('_change', {detail: {index: idx}})); +} + +function findTab(el, tabs, idx) { + let found = null; + if ( typeof idx === 'number' ) { + found = idx; + } else { + tabs.querySelectorAll('li').forEach((iter, i) => { + if ( found === null && iter.firstChild.textContent === idx ) { + found = i; + } }); + } + return found; +} + +function removeTab(el, tabs, idx) { + const found = findTab(el, tabs, idx); + if ( found !== null ) { + tabs.children[found].remove(); + el.querySelectorAll('gui-tab-container')[found].remove(); + } +} + +function createTab(el, tabs, label, prog) { + const tab = document.createElement('li'); + const idx = tabs.children.length; + + Events.$bind(tab, 'click', (ev) => { + selectTab(el, tabs, ev, idx, tab); + }, false); + + tab.setAttribute('role', 'tab'); + tab.setAttribute('aria-label', label); + tab.appendChild(document.createTextNode(label)); + tabs.appendChild(tab); + + if ( prog ) { + const tel = document.createElement('gui-tab-container'); + tel.setAttribute('data-label', label); + tel.setAttribute('role', 'tabpanel'); + el.appendChild(tel); + } +} - Utils.$addClass(tab, 'gui-active'); +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// - el.dispatchEvent(new CustomEvent('_change', {detail: {index: idx}})); +/** + * Element: 'gui-tabs' + * + * A container with tabs for displaying content. + * + *

+ *   event     select                    When tab has changed => fn(ev)
+ *   event     activate                  Alias of 'select'
+ * 
+ */ +class GUITabs extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-tabs' + }, this); } - function findTab(el, tabs, idx) { - var found = null; - if ( typeof idx === 'number' ) { - found = idx; - } else { - tabs.querySelectorAll('li').forEach(function(iter, i) { - if ( found === null && iter.firstChild.textContent === idx ) { - found = i; - } - }); + on(evName, callback, params) { + if ( (['select', 'activate']).indexOf(evName) !== -1 ) { + evName = 'change'; } - return found; - } - - function removeTab(el, tabs, idx) { - var found = findTab(el, tabs, idx); - if ( found !== null ) { - tabs.children[found].remove(); - el.querySelectorAll('gui-tab-container')[found].remove(); + if ( evName === 'change' ) { + evName = '_' + evName; } - } - - function createTab(el, tabs, label, prog) { - var tab = document.createElement('li'); - var idx = tabs.children.length; - Utils.$bind(tab, 'click', function(ev) { - selectTab(el, tabs, ev, idx, tab); - }, false); + Events.$bind(this.$element, evName, callback.bind(this), params); - tab.setAttribute('role', 'tab'); - tab.setAttribute('aria-label', label); - tab.appendChild(document.createTextNode(label)); - tabs.appendChild(tab); - - if ( prog ) { - var tel = document.createElement('gui-tab-container'); - tel.setAttribute('data-label', label); - tel.setAttribute('role', 'tabpanel'); - el.appendChild(tel); - } + return this; } - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-tabs' - * - * A container with tabs for displaying content. - * - *

-   *   event     select                    When tab has changed => fn(ev)
-   *   event     activate                  Alias of 'select'
-   * 
- * - * @constructor Tabs - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUITabs = { - on: function(evName, callback, params) { - if ( (['select', 'activate']).indexOf(evName) !== -1 ) { - evName = 'change'; + set(param, value) { + if ( ['current', 'selected', 'active'].indexOf(param) !== -1 ) { + const el = this.$element; + const tabs = el.querySelector('ul'); + const found = findTab(el, tabs, value); + if ( found !== null ) { + selectTab(el, tabs, null, found, tabs[found]); } - if ( evName === 'change' ) { - evName = '_' + evName; - } - - Utils.$bind(this.$element, evName, callback.bind(this), params); return this; - }, - - set: function(param, value) { - if ( ['current', 'selected', 'active'].indexOf(param) !== -1 ) { - var el = this.$element; - var tabs = el.querySelector('ul'); - var found = findTab(el, tabs, value); - if ( found !== null ) { - selectTab(el, tabs, null, found, tabs[found]); - } - - return this; - } - return GUI.Element.prototype.set.apply(this, arguments); - }, - - get: function(param, value) { - if ( ['current', 'selected', 'active'].indexOf(param) !== -1 ) { - var cur = this.$element.querySelector('ul > li[class="gui-active"]'); - return Utils.$index(cur); - } - return GUI.Element.prototype.get.apply(this, arguments); - }, - - add: function(newtabs) { - var el = this.$element; - var tabs = el.querySelector('ul'); + } + return super.set(...arguments); + } - if ( !(newtabs instanceof Array) ) { - newtabs = [newtabs]; - } + get(param, value) { + if ( ['current', 'selected', 'active'].indexOf(param) !== -1 ) { + const cur = this.$element.querySelector('ul > li[class="gui-active"]'); + return DOM.$index(cur); + } + return super.get(...arguments); + } - newtabs.forEach(function(label) { - createTab(el, tabs, label, true); - }); + add(newtabs) { + const el = this.$element; + const tabs = el.querySelector('ul'); - return this; - }, + if ( !(newtabs instanceof Array) ) { + newtabs = [newtabs]; + } - remove: function(removetabs) { - var el = this.$element; - var tabs = el.querySelector('ul'); + newtabs.forEach((label) => { + createTab(el, tabs, label, true); + }); - if ( !(removetabs instanceof Array) ) { - removetabs = [removetabs]; - } + return this; + } - removetabs.forEach(function(id) { - removeTab(el, tabs, id); - }); + remove(removetabs) { + const el = this.$element; + const tabs = el.querySelector('ul'); - return this; - }, + if ( !(removetabs instanceof Array) ) { + removetabs = [removetabs]; + } - build: function() { - var el = this.$element; - var tabs = document.createElement('ul'); + removetabs.forEach((id) => { + removeTab(el, tabs, id); + }); - el.querySelectorAll('gui-tab-container').forEach(function(tel, idx) { - createTab(el, tabs, GUI.Helpers.getLabel(tel)); - tel.setAttribute('role', 'tabpanel'); - }); + return this; + } - tabs.setAttribute('role', 'tablist'); - el.setAttribute('role', 'navigation'); + build() { + const el = this.$element; + const tabs = document.createElement('ul'); - if ( el.children.length ) { - el.insertBefore(tabs, el.children[0]); - } else { - el.appendChild(tabs); - } + el.querySelectorAll('gui-tab-container').forEach((tel, idx) => { + createTab(el, tabs, GUI.getLabel(tel)); + tel.setAttribute('role', 'tabpanel'); + }); - var currentTab = parseInt(el.getAttribute('data-selected-index'), 10) || 0; - selectTab(el, tabs, null, currentTab); + tabs.setAttribute('role', 'tablist'); + el.setAttribute('role', 'navigation'); - return this; + if ( el.children.length ) { + el.insertBefore(tabs, el.children[0]); + } else { + el.appendChild(tabs); } - }; - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// + const currentTab = parseInt(el.getAttribute('data-selected-index'), 10) || 0; + selectTab(el, tabs, null, currentTab); + + return this; + } +} - GUI.Element.register({ - tagName: 'gui-tabs' - }, GUITabs); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); +export default { + GUITabs: GUITabs +}; diff --git a/src/client/javascript/gui/elements/treeview.js b/src/client/javascript/gui/elements/treeview.js index 7d63b3834f..7920bb82bc 100644 --- a/src/client/javascript/gui/elements/treeview.js +++ b/src/client/javascript/gui/elements/treeview.js @@ -27,265 +27,270 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// +import * as DOM from 'utils/dom'; +import * as GUI from 'utils/gui'; +import GUIDataView from 'gui/dataview'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +function createEntry(cls, e) { + const entry = GUI.createElement('gui-tree-view-entry', e, ['entries']); + return entry; +} + +function handleItemExpand(ev, el, root, expanded) { + if ( typeof expanded === 'undefined' ) { + expanded = !DOM.$hasClass(root, 'gui-expanded'); + } - function createEntry(cls, e) { - var entry = GUI.Helpers.createElement('gui-tree-view-entry', e, ['entries']); - return entry; + DOM.$removeClass(root, 'gui-expanded'); + if ( expanded ) { + DOM.$addClass(root, 'gui-expanded'); } - function handleItemExpand(ev, el, root, expanded) { - if ( typeof expanded === 'undefined' ) { - expanded = !Utils.$hasClass(root, 'gui-expanded'); + const children = root.children; + for ( let i = 0; i < children.length; i++ ) { + if ( children[i].tagName.toLowerCase() === 'gui-tree-view-entry' ) { + children[i].style.display = expanded ? 'block' : 'none'; } + } - Utils.$removeClass(root, 'gui-expanded'); - if ( expanded ) { - Utils.$addClass(root, 'gui-expanded'); - } + const selected = { + index: DOM.$index(root), + data: GUI.getViewNodeValue(root) + }; - 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'; - } - } + root.setAttribute('data-expanded', String(expanded)); + root.setAttribute('aria-expanded', String(expanded)); - var selected = { - index: Utils.$index(root), - data: GUI.Helpers.getViewNodeValue(root) - }; + el.dispatchEvent(new CustomEvent('_expand', {detail: {entries: [selected], expanded: expanded, element: root}})); +} // handleItemExpand() - root.setAttribute('data-expanded', String(expanded)); - root.setAttribute('aria-expanded', String(expanded)); +function initEntry(cls, sel) { + const el = cls.$element; + if ( sel._rendered ) { + return; + } + sel._rendered = true; + + const icon = sel.getAttribute('data-icon'); + const label = GUI.getLabel(sel); + const expanded = el.getAttribute('data-expanded') === 'true'; + const next = sel.querySelector('gui-tree-view-entry'); + const container = document.createElement('div'); + const dspan = document.createElement('span'); + + function onDndEnter(ev) { + ev.stopPropagation(); + DOM.$addClass(sel, 'dnd-over'); + } - el.dispatchEvent(new CustomEvent('_expand', {detail: {entries: [selected], expanded: expanded, element: root}})); - } // handleItemExpand() + function onDndLeave(ev) { + DOM.$removeClass(sel, 'dnd-over'); + } - function initEntry(cls, sel) { - var el = cls.$element; - 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'); - } + if ( icon ) { + dspan.style.backgroundImage = 'url(' + icon + ')'; + DOM.$addClass(dspan, 'gui-has-image'); + } + dspan.appendChild(document.createTextNode(label)); - function onDndLeave(ev) { - Utils.$removeClass(sel, 'dnd-over'); - } + container.appendChild(dspan); - if ( icon ) { - dspan.style.backgroundImage = 'url(' + icon + ')'; - Utils.$addClass(dspan, 'gui-has-image'); - } - dspan.appendChild(document.createTextNode(label)); + if ( next ) { + DOM.$addClass(sel, 'gui-expandable'); + const expander = document.createElement('gui-tree-view-expander'); + sel.insertBefore(container, next); + sel.insertBefore(expander, container); + } else { + sel.appendChild(container); + } - container.appendChild(dspan); + if ( String(sel.getAttribute('data-draggable')) === 'true' ) { + GUI.createDraggable(container, (() => { + let data = {}; + try { + data = JSON.parse(sel.getAttribute('data-value')); + } catch ( e ) {} - 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); - } + return {data: data}; + })()); + } - if ( String(sel.getAttribute('data-draggable')) === 'true' ) { - GUI.Helpers.createDraggable(container, (function() { - var data = {}; + if ( String(sel.getAttribute('data-droppable')) === 'true' ) { + let timeout; + GUI.createDroppable(container, { + onEnter: onDndEnter, + onOver: onDndEnter, + onLeave: onDndLeave, + onDrop: onDndLeave, + onItemDropped: (ev, eel, item) => { + ev.stopPropagation(); + ev.preventDefault(); + + timeout = clearTimeout(timeout); + timeout = setTimeout(() => { + DOM.$removeClass(sel, 'dnd-over'); + }, 10); + + let dval = {}; try { - data = JSON.parse(sel.getAttribute('data-value')); + dval = JSON.parse(eel.parentNode.getAttribute('data-value')); } catch ( e ) {} - return {data: data}; - })()); - } + el.dispatchEvent(new CustomEvent('_drop', {detail: { + src: item.data, + dest: dval + }})); + } + }); + } - 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); - handleItemExpand(null, el, sel, expanded); + cls.bindEntryEvents(sel, 'gui-tree-view-entry'); +} - cls.bindEntryEvents(sel, 'gui-tree-view-entry'); +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +/** + * Element: 'gui-tree-view' + * + * A tree view for nested content + * + * For more properties and events etc, see 'dataview' + * + * @example + * + * .add({ + * label: "Label", + * icon: "Optional icon path", + * value: "something or JSON or whatever", + * entries: [] // Recurse :) + * }) + */ +class GUITreeView extends GUIDataView { + static register() { + return super.register({ + parent: GUIDataView, + tagName: 'gui-tree-view' + }, this); } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-tree-view' - * - * A tree view for nested content - * - * For more properties and events etc, see 'dataview' - * - * @example - * - * .add({ - * label: "Label", - * icon: "Optional icon path", - * value: "something or JSON or whatever", - * entries: [] // Recurse :) - * }) - * - * @constructor TreeView - * @extends OSjs.GUI.DataView - * @memberof OSjs.GUI.Elements - */ - GUI.Element.register({ - parent: GUI.DataView, - tagName: 'gui-tree-view' - }, { - - values: function() { - var el = this.$element; - return this.getSelected(el.querySelectorAll('gui-tree-view-entry')); - }, - - build: function(applyArgs) { - var el = this.$element; - var body = el.querySelector('gui-tree-view-body'); - var found = !!body; - var self = this; - - if ( !body ) { - body = document.createElement('gui-tree-view-body'); - el.appendChild(body); - } + values() { + const el = this.$element; + return this.getSelected(el.querySelectorAll('gui-tree-view-entry')); + } - body.setAttribute('role', 'group'); - el.setAttribute('role', 'tree'); - el.setAttribute('aria-multiselectable', body.getAttribute('data-multiselect') || 'false'); + build(applyArgs) { + const el = this.$element; - el.querySelectorAll('gui-tree-view-entry').forEach(function(sel, idx) { - sel.setAttribute('aria-expanded', 'false'); + let body = el.querySelector('gui-tree-view-body'); + let found = !!body; - if ( !found ) { - body.appendChild(sel); - } + if ( !body ) { + body = document.createElement('gui-tree-view-body'); + el.appendChild(body); + } - sel.setAttribute('role', 'treeitem'); - initEntry(self, sel); - }); + body.setAttribute('role', 'group'); + el.setAttribute('role', 'tree'); + el.setAttribute('aria-multiselectable', body.getAttribute('data-multiselect') || 'false'); - return GUI.DataView.prototype.build.apply(this, arguments); - }, + el.querySelectorAll('gui-tree-view-entry').forEach((sel, idx) => { + sel.setAttribute('aria-expanded', 'false'); - get: function(param, value, arg) { - if ( param === 'entry' ) { - var body = this.$element.querySelector('gui-tree-view-body'); - return this.getEntry(body.querySelectorAll('gui-tree-view-entry'), value, arg); - } - return GUI.DataView.prototype.get.apply(this, arguments); - }, - - set: function(param, value, arg, arg2) { - var el = this.$element; - var body = el.querySelector('gui-tree-view-body'); - if ( param === 'selected' || param === 'value' ) { - this.setSelected(body, body.querySelectorAll('gui-tree-view-entry'), value, arg, arg2); - return this; - } - return GUI.DataView.prototype.set.apply(this, arguments); - }, - - clear: function() { - var body = this.$element.querySelector('gui-tree-view-body'); - return GUI.DataView.prototype.clear.call(this, body); - }, - - add: function(entries) { - var body = this.$element.querySelector('gui-tree-view-body'); - var parentNode = body; - var adder = GUI.DataView.prototype.add; - var self = this; - - function recurse(a, root, level) { - adder.call(self, a, function(cls, e) { - if ( e ) { - if ( e.parentNode ) { - delete e.parentNode; - } - - var entry = createEntry(self, e); - root.appendChild(entry); - - if ( e.entries ) { - recurse(e.entries, entry, level + 1); - } - - initEntry(self, entry); - } - }); + if ( !found ) { + body.appendChild(sel); } - if ( typeof entries === 'object' && !(entries instanceof Array) && Object.keys(entries).length ) { - parentNode = entries.parentNode || body; - entries = entries.entries || []; - } + sel.setAttribute('role', 'treeitem'); + initEntry(this, sel); + }); - recurse(entries, parentNode, 0); + return super.build(...arguments); + } + + get(param, value, arg) { + if ( param === 'entry' ) { + const body = this.$element.querySelector('gui-tree-view-body'); + return this.getEntry(body.querySelectorAll('gui-tree-view-entry'), value, arg); + } + return super.get(...arguments); + } + set(param, value, arg, arg2) { + const el = this.$element; + const body = el.querySelector('gui-tree-view-body'); + if ( param === 'selected' || param === 'value' ) { + this.setSelected(body, body.querySelectorAll('gui-tree-view-entry'), value, arg, arg2); return this; - }, + } + return super.set(...arguments); + } - remove: function(entries) { - return GUI.DataView.prototype.remove.call(this, entries, 'gui-tree-view-entry'); - }, + clear() { + const body = this.$element.querySelector('gui-tree-view-body'); + return super.clear(body); + } - patch: function(entries) { - var body = this.$element.querySelector('gui-tree-view-body'); - return GUI.DataView.prototype.patch.call(this, entries, 'gui-list-view-entry', body, createEntry, initEntry); - }, + add(entries) { + const body = this.$element.querySelector('gui-tree-view-body'); - expand: function(entry) { - handleItemExpand(entry.ev, this.$element, entry.entry); - return this; + let parentNode = body; + + const recurse = (a, root, level) => { + super.add(a, (cls, e) => { + if ( e ) { + if ( e.parentNode ) { + delete e.parentNode; + } + + const entry = createEntry(this, e); + root.appendChild(entry); + + if ( e.entries ) { + recurse(e.entries, entry, level + 1); + } + + initEntry(this, entry); + } + }); + }; + + if ( typeof entries === 'object' && !(entries instanceof Array) && Object.keys(entries).length ) { + parentNode = entries.parentNode || body; + entries = entries.entries || []; } - }); -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); + recurse(entries, parentNode, 0); + + return this; + } + + remove(entries) { + return super.remove(entries, 'gui-tree-view-entry'); + } + + patch(entries) { + const body = this.$element.querySelector('gui-tree-view-body'); + return super.patch(entries, 'gui-list-view-entry', body, createEntry, initEntry); + } + + expand(entry) { + handleItemExpand(entry.ev, this.$element, entry.entry); + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUITreeView: GUITreeView +}; diff --git a/src/client/javascript/gui/elements/visual.js b/src/client/javascript/gui/elements/visual.js index 7f0759bdce..06716390f9 100644 --- a/src/client/javascript/gui/elements/visual.js +++ b/src/client/javascript/gui/elements/visual.js @@ -27,190 +27,187 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - function createVisualElement(el, nodeType, applyArgs) { - applyArgs = applyArgs || {}; - if ( typeof applyArgs !== 'object' ) { - console.error('Derp', 'applyArgs was not an object ?!'); - applyArgs = {}; - } +import * as Events from 'utils/events'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +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'); - } + const img = document.createElement(nodeType); + const src = el.getAttribute('data-src'); + const controls = el.getAttribute('data-controls'); + if ( controls ) { + img.setAttribute('controls', 'controls'); + } + const 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); + Object.keys(applyArgs).forEach(function(k) { + let val = applyArgs[k]; + if ( typeof val === 'function' ) { + k = k.replace(/^on/, ''); + if ( (nodeType === 'video' || nodeType === 'audio') && k === 'load' ) { + k = 'loadedmetadata'; } - }); + Events.$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); +} - img.src = src || 'about:blank'; - el.appendChild(img); +///////////////////////////////////////////////////////////////////////////// +// CLASSES +///////////////////////////////////////////////////////////////////////////// + +/** + * Element: 'gui-audio' + * + * HTML5 Audio Element. + * + *

+ *   getter    src   String        The source (src)
+ *   setter    src   String        The source (src)
+ *   property  src   String        The source (src)
+ * 
+ */ +class GUIAudio extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-audio' + }, this); } - ///////////////////////////////////////////////////////////////////////////// - // CLASSES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Element: 'gui-audio' - * - * HTML5 Audio Element. - * - *

-   *   getter    src   String        The source (src)
-   *   setter    src   String        The source (src)
-   *   property  src   String        The source (src)
-   * 
- * - * @constructor Audio - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIAudio = { - on: function(evName, callback, params) { - var target = this.$element.querySelector('audio'); - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, - - build: function(applyArgs) { - createVisualElement(this.$element, 'audio', applyArgs); - - return this; - } - }; - - /** - * Element: 'gui-video' - * - * HTML5 Video Element. - * - *

-   *   getter    src   String        The source (src)
-   *   setter    src   String        The source (src)
-   *   property  src   String        The source (src)
-   * 
- * - * @constructor Video - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIVideo = { - on: function(evName, callback, params) { - var target = this.$element.querySelector('video'); - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, - - build: function(applyArgs) { - createVisualElement(this.$element, 'video', applyArgs); - - return this; - } - }; - - /** - * Element: 'gui-image' - * - * Normal Image Element. - * - *

-   *   getter    src   String        The source (src)
-   *   setter    src   String        The source (src)
-   *   property  src   String        The source (src)
-   * 
- * - * @constructor Image - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUIImage = { - on: function(evName, callback, params) { - var target = this.$element.querySelector('img'); - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, - - build: function(applyArgs) { - createVisualElement(this.$element, 'img', applyArgs); - - return this; - } - }; - - /** - * Element: 'gui-canvas' - * - * Canvas Element. - * - *

-   *   getter    src   String        The source (src)
-   *   setter    src   String        The source (src)
-   *   property  src   String        The source (src)
-   * 
- * - * @constructor Canvas - * @extends OSjs.GUI.Element - * @memberof OSjs.GUI.Elements - */ - var GUICanvas = { - on: function(evName, callback, params) { - var target = this.$element.querySelector('canvas'); - Utils.$bind(target, evName, callback.bind(this), params); - return this; - }, - - build: function() { - var canvas = document.createElement('canvas'); - this.$element.appendChild(canvas); - - return this; - } - }; + on(evName, callback, params) { + const target = this.$element.querySelector('audio'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } - ///////////////////////////////////////////////////////////////////////////// - // REGISTRATION - ///////////////////////////////////////////////////////////////////////////// + build(applyArgs) { + createVisualElement(this.$element, 'audio', applyArgs); - GUI.Element.register({ - tagName: 'gui-audio' - }, GUIAudio); + return this; + } +} - GUI.Element.register({ - tagName: 'gui-video' - }, GUIVideo); +/** + * Element: 'gui-video' + * + * HTML5 Video Element. + * + *

+ *   getter    src   String        The source (src)
+ *   setter    src   String        The source (src)
+ *   property  src   String        The source (src)
+ * 
+ */ +class GUIVideo extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-video' + }, this); + } - GUI.Element.register({ - tagName: 'gui-image' - }, GUIImage); + on(evName, callback, params) { + const target = this.$element.querySelector('video'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } + + build(applyArgs) { + createVisualElement(this.$element, 'video', applyArgs); + + return this; + } +} + +/** + * Element: 'gui-image' + * + * Normal Image Element. + * + *

+ *   getter    src   String        The source (src)
+ *   setter    src   String        The source (src)
+ *   property  src   String        The source (src)
+ * 
+ */ +class GUIImage extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-image' + }, this); + } + + on(evName, callback, params) { + const target = this.$element.querySelector('img'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } - GUI.Element.register({ - tagName: 'gui-canvas' - }, GUICanvas); + build(applyArgs) { + createVisualElement(this.$element, 'img', applyArgs); -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); + return this; + } +} + +/** + * Element: 'gui-canvas' + * + * Canvas Element. + * + *

+ *   getter    src   String        The source (src)
+ *   setter    src   String        The source (src)
+ *   property  src   String        The source (src)
+ * 
+ */ +class GUICanvas extends GUIElement { + static register() { + return super.register({ + tagName: 'gui-canvas' + }, this); + } + + on(evName, callback, params) { + const target = this.$element.querySelector('canvas'); + Events.$bind(target, evName, callback.bind(this), params); + return this; + } + + build() { + const canvas = document.createElement('canvas'); + this.$element.appendChild(canvas); + + return this; + } +} + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +export default { + GUIAudio: GUIAudio, + GUIVideo: GUIVideo, + GUIImage: GUIImage, + GUICanvas: GUICanvas +}; diff --git a/src/client/javascript/gui/helpers.js b/src/client/javascript/gui/helpers.js deleted file mode 100644 index 5f99288b6c..0000000000 --- a/src/client/javascript/gui/helpers.js +++ /dev/null @@ -1,1016 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ -(function(API, Utils, VFS, GUI) { - 'use strict'; - - GUI.Helpers = GUI.Helpers || {}; - - /** - * @namespace GUI - * @memberof OSjs - */ - - /** - * @namespace Helpers - * @memberof OSjs.GUI - */ - - var lastMenu; - - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Gets window id from upper parent element - * - * @function getWindowId - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el Child element (can be anything) - * - * @return {Number} - */ - 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; - }; - - /** - * Gets "label" from a node - * - * @function getLabel - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el The element - * - * @return {String} - */ - GUI.Helpers.getLabel = function getLabel(el) { - var label = el.getAttribute('data-label'); - return label || ''; - }; - - /** - * Gets "label" from a node (Where it can be innerHTML and parameter) - * - * @function getValueLabel - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el The element - * @param {Boolean} [attr=false] Get from attribute istead of node text - * - * @return {String} - */ - 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 || ''; - }; - - /** - * Gets "value" from a node - * - * @function getViewNodeValue - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el The element - * - * @return {String} - */ - 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; - }; - - /** - * Internal for getting - * - * @function getIcon - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el Element - * @param {OSjs.Core.Window} [win] Window Reference - * - * @return {String} - */ - 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; - }; - - /** - * Wrapper for getting custom dom element property value - * - * @function getProperty - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el Element - * @param {String} param Parameter name - * @param {String} [tagName] What tagname is in use? Automatic - * - * @return {Mixed} - */ - 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 el.querySelector('input').value === 'on'; - } - return null; - } - - if ( (param === 'value' || param === 'selected') && isDataView ) { - return GUI.Element.createFromNode(el).values(); - } - - return el.getAttribute('data-' + param); - }; - - /** - * Wrapper for setting custom dom element property value - * - * @function setProperty - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el Element - * @param {String} param Parameter name - * @param {Mixed} value Parameter value - * @param {String} [tagName] What tagname is in use? Automatic - */ - 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)); - } - - // Generics for input elements - 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 || ''); - } - } - } - })(); - - // Other types of elements - accept = ['gui-image', 'gui-audio', 'gui-video']; - if ( (['src', 'controls', 'autoplay', 'alt']).indexOf(param) >= 0 && accept.indexOf(tagName) >= 0 ) { - inner[param] = value; - } - - // Normal DOM attributes - if ( (['_id', '_class', '_style']).indexOf(param) >= 0 ) { - inner.setAttribute(param.replace(/^_/, ''), value); - return; - } - - // Set the actual root element property value - if ( param !== 'value' ) { - _setValueAttribute(el, 'data-' + param, value); - } - }; - - /** - * Creates a label for given input element - * - * @function createInputLabel - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el Element root - * @param {String} type Input element type - * @param {Node} input The input element - * @param {String} [label] Used when updating - */ - 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); - } - }; - - /** - * Create a new custom DOM element - * - * @function createElement - * @memberof OSjs.GUI.Helpers - * - * @param {String} tagName Tag Name - * @param {Object} params Dict with data-* properties - * @param {Array} [ignoreParams] List of arguments to ignore - * - * @return {Node} - */ - 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; - }; - - /** - * Sets the flexbox CSS style properties for given container - * - * @function setFlexbox - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el The container - * @param {Number} grow Grow factor - * @param {Number} shrink Shrink factor - * @param {String} [basis=auto] Basis - * @param {Node} [checkel] Take defaults from this node - */ - 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); - } - }; - - /** - * Wrapper for creating a draggable container - * - * @function createDrag - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el The container - * @param {Function} onDown On down action callback - * @param {Function} onMove On move action callback - * @param {Function} onUp On up action callback - */ - 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 _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'); - } - - 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); - } - - Utils.$bind(el, 'mousedown', _onMouseDown, false); - }; - - /** - * Method for getting the next (or previous) element in sequence - * - * If you don't supply a current element, the first one will be taken! - * - * @function getNextElement - * @memberof OSjs.GUI.Helpers - * - * @param {Boolean} prev Get previous element instead of next - * @param {Node} current The current element - * @param {Node} root The root container - * - * @return {Node} - */ - 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) { - // Ignore focused and disabled elements, and certain aria roles - if ( Utils.$hasClass(e, 'gui-focus-element') || ignore_roles.indexOf(e.getAttribute('role')) >= 0 || e.getAttribute('data-disabled') === 'true' ) { - return; - } - - // Elements without offsetParent are invisible - if ( e.offsetParent ) { - list.push(e); - } - }); - return list; - } - - function getCurrentIndex(els, m) { - var found = -1; - - // Simply get index from array, it seems indexOf is a bit iffy here ?! - 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; - } - - // When we dont have a initial element, take the first one - return els[0]; - } - - function getNextIndex(els, p, i) { - // This could probably be prettier, but it does the job - 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]; - - // Get "real" elements from input wrappers - if ( next.tagName.match(/^GUI\-(BUTTON|TEXT|PASSWORD|SWITCH|CHECKBOX|RADIO|SELECT)/) ) { - next = next.querySelectorAll('input, textarea, button, select')[0]; - } - - // Special case for elements that wraps - 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; - }; - - /** - * Create a draggable DOM element - * - * @function createDraggable - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el DOMElement - * @param {Object} args JSON of draggable params - * @param {Object} args.data The data (JSON by default) - * @param {String} [args.type] A custom drag event 'type' - * @param {String} [args.effect=move] The draggable effect (cursor) - * @param {String} [args.mime=application/json] The mime type of content - * @param {Function} args.onStart Callback when drag started => fn(ev, el, args) - * @param {Function} args.onEnd Callback when drag ended => fn(ev, el, args) - */ - GUI.Helpers.createDraggable = function createDraggable(el, args) { - /* eslint no-invalid-this: "off" */ - - 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); - }; - - /** - * Create a droppable DOM element - * - * @function createDroppable - * @memberof OSjs.GUI.Helpers - * - * @param {Node} el DOMElement - * @param {Object} args JSON of droppable params - * @param {String} [args.accept] Accept given drag event 'type' - * @param {String} [args.effect=move] The draggable effect (cursor) - * @param {String} [args.mime=application/json] The mime type of content - * @param {Boolean} [args.files=true] Support file drops from OS - * @param {Function} args.onEnter Callback when drag entered => fn(ev, el) - * @param {Function} args.onOver Callback when drag over => fn(ev, el) - * @param {Function} args.onLeave Callback when drag leave => fn(ev, el) - * @param {Function} args.onDrop Callback when drag drop all => fn(ev, el) - * @param {Function} args.onFilesDropped Callback when drag drop file => fn(ev, el, files, args) - * @param {Function} args.onItemDropped Callback when drag drop internal object => fn(ev, el, item, args) - */ - GUI.Helpers.createDroppable = function createDroppable(el, args) { - /* eslint no-invalid-this: "off" */ - - 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 _doDrop(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); - } - } - - try { - var data = ev.dataTransfer.getData(args.mime); - var item = JSON.parse(data); - if ( args.accept === null || args.accept === item.type ) { - return args.onItemDropped(ev, el, item, args); - } - } catch ( e ) { - console.warn('Failed to drop: ' + e); - } - - return false; - } - - function _onDrop(ev, el) { - ev.stopPropagation(); - ev.preventDefault(); - - var result = _doDrop(ev, el); - args.onDrop(ev, el); - return result; - } - - el.setAttribute('aria-dropeffect', args.effect); - - Utils.$bind(el, 'drop', function(ev) { - //Utils.$removeClass(el, 'onDragEnter'); - return _onDrop(ev, this); - }, false); - - Utils.$bind(el, 'dragenter', function(ev) { - //Utils.$addClass(el, 'onDragEnter'); - 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) { - //Utils.$removeClass(el, 'onDragEnter'); - return args.onLeave.call(this, ev, this, args); - }, false); - }; - - OSjs.GUI.Helpers._menuSetActive = function(menu) { - lastMenu = menu; - }; - - OSjs.GUI.Helpers._menuClickWrapper = function(ev, pos, onclick, original) { - var t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); - - if ( t && t.tagName === 'LABEL' ) { - t = t.parentNode; - } - - ev.preventDefault(); - if ( t && t.tagName === 'GUI-MENU-ENTRY' ) { - var subMenu = t.querySelector('gui-menu'); - var isExpander = !!subMenu; - var hasInput = t.querySelector('input'); - - if ( hasInput || isExpander ) { - ev.stopPropagation(); - } - - try { - if ( isExpander ) { - t.parentNode.querySelectorAll('gui-menu-entry').forEach(function(pn) { - Utils.$removeClass(pn, 'active'); - }); - - Utils.$addClass(t, 'active'); - } - } catch ( e ) { - console.warn(e); - } - - onclick(ev, pos, t, original); - } - }; - - OSjs.GUI.Helpers._menuClamp = function(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); - } - - // this class is used in caclulations (DOM needs to be visible for that) - Utils.$addClass(r, 'gui-showing'); - }; - - /** - * Blur the currently open menu (aka hiding) - * - * @param {Event} [ev] Browser event - * @function blurMenu - * @memberof OSjs.GUI.Helpers - */ - OSjs.GUI.Helpers.blurMenu = function blurMenu(ev) { - if ( lastMenu ) { - lastMenu(ev); - } - lastMenu = null; - - API.triggerHook('onBlurMenu'); - }; - - /** - * Create and show a new menu - * - * @example - * createMenu([ - * { - * title: "Title", - * icon: "Icon", - * onClick: function() {}, // Callback - * menu: [] // Recurse :) - * } - * ]) - * - * @param {Array} items Array of items - * @param {(Event|Object)} ev DOM Event or dict with x/y - * @param {Mixed} [customInstance] Show a custom created menu - * - * @function createMenu - * @memberof OSjs.GUI.Helpers - */ - OSjs.GUI.Helpers.createMenu = function createMenu(items, ev, customInstance) { - items = items || []; - - OSjs.GUI.Helpers.blurMenu(ev); - - 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.Element.createFromNode(root, null, 'gui-menu').build(true); - - Utils.$bind(root, 'mousedown', function(ev, pos) { - OSjs.GUI.Helpers._menuClickWrapper(ev, pos, function(ev, pos, t) { - var index = parseInt(t.getAttribute('data-callback-id'), 10); - if ( callbackMap[index] ) { - callbackMap[index](ev, pos); - - OSjs.GUI.Helpers.blurMenu(ev); // !last! - } - }); - }, true); - - Utils.$bind(root, 'touchstart', function(ev) { - ev.preventDefault(); - }, true); - } - - 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); - - // Make sure it stays within viewport - 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'; - } - } - - OSjs.GUI.Helpers._menuClamp(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); diff --git a/src/client/javascript/gui/menu.js b/src/client/javascript/gui/menu.js new file mode 100644 index 0000000000..c4efc78898 --- /dev/null +++ b/src/client/javascript/gui/menu.js @@ -0,0 +1,215 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import * as GUI from 'utils/gui'; +import * as DOM from 'utils/dom'; +import * as Events from 'utils/events'; +import GUIElement from 'gui/element'; +import WindowManager from 'core/window-manager'; +import {triggerHook} from 'helpers/hooks'; + +let lastMenu; + +export function clickWrapper(ev, pos, onclick, original) { + let t = ev.isTrusted ? ev.target : (ev.relatedTarget || ev.target); + + if ( t && t.tagName === 'LABEL' ) { + t = t.parentNode; + } + + ev.preventDefault(); + if ( t && t.tagName === 'GUI-MENU-ENTRY' ) { + let subMenu = t.querySelector('gui-menu'); + let isExpander = !!subMenu; + let hasInput = t.querySelector('input'); + + if ( hasInput || isExpander ) { + ev.stopPropagation(); + } + + try { + if ( isExpander ) { + t.parentNode.querySelectorAll('gui-menu-entry').forEach(function(pn) { + DOM.$removeClass(pn, 'active'); + }); + + DOM.$addClass(t, 'active'); + } + } catch ( e ) { + console.warn(e); + } + + onclick(ev, pos, t, original); + } +} + +export function clamp(r) { + function _clamp(rm) { + rm.querySelectorAll('gui-menu-entry').forEach(function(srm) { + const sm = srm.querySelector('gui-menu'); + if ( sm ) { + sm.style.left = String(-parseInt(sm.offsetWidth, 10)) + 'px'; + _clamp(sm); + } + }); + } + + const pos = DOM.$position(r); + if ( pos && (window.innerWidth - pos.right) < r.offsetWidth ) { + DOM.$addClass(r, 'gui-overflowing'); + _clamp(r); + } + + // this class is used in caclulations (DOM needs to be visible for that) + DOM.$addClass(r, 'gui-showing'); +} + +/** + * Blur the currently open menu (aka hiding) + * + * @param {Event} [ev] Browser event + */ +export function blur(ev) { + if ( lastMenu ) { + lastMenu(ev); + } + lastMenu = null; + + triggerHook('onBlurMenu'); +} + +/** + * Create and show a new menu + * + * @example + * create([ + * { + * title: "Title", + * icon: "Icon", + * onClick: function() {}, // Callback + * menu: [] // Recurse :) + * } + * ]) + * + * @param {Array} items Array of items + * @param {(Event|Object)} ev DOM Event or dict with x/y + * @param {Object} [customInstance] Show a custom created menu + */ +export function create(items, ev, customInstance) { + items = items || []; + + blur(ev); + + let root = customInstance; + let callbackMap = []; + + function resolveItems(arr, par) { + arr.forEach(function(iter) { + const props = {label: iter.title, icon: iter.icon, disabled: iter.disabled, labelHTML: iter.titleHTML, type: iter.type, checked: iter.checked}; + const entry = GUI.createElement('gui-menu-entry', props); + if ( iter.menu ) { + const nroot = GUI.createElement('gui-menu', {}); + resolveItems(iter.menu, nroot); + entry.appendChild(nroot); + } + if ( iter.onClick ) { + const index = callbackMap.push(iter.onClick); + entry.setAttribute('data-callback-id', String(index - 1)); + } + par.appendChild(entry); + }); + } + + if ( !root ) { + root = GUI.createElement('gui-menu', {}); + resolveItems(items || [], root); + + GUIElement.createFromNode(root, null, 'gui-menu').build(true); + + Events.$bind(root, 'mousedown', function(ev, pos) { + clickWrapper(ev, pos, function(ev, pos, t) { + const index = parseInt(t.getAttribute('data-callback-id'), 10); + if ( callbackMap[index] ) { + callbackMap[index](ev, pos); + + blur(ev); // !last! + } + }); + }, true); + + Events.$bind(root, 'touchstart', function(ev) { + ev.preventDefault(); + }, true); + } + + if ( root.$element ) { + root = root.$element; + } + + const wm = WindowManager.instance; + const space = wm.getWindowSpace(true); + const pos = Events.mousePosition(ev); + + DOM.$addClass(root, 'gui-root-menu'); + root.style.left = pos.x + 'px'; + root.style.top = pos.y + 'px'; + document.body.appendChild(root); + + // Make sure it stays within viewport + setTimeout(function() { + const pos = DOM.$position(root); + if ( pos ) { + if ( pos.right > space.width ) { + const newLeft = Math.round(space.width - pos.width); + root.style.left = Math.max(0, newLeft) + 'px'; + } + if ( pos.bottom > space.height ) { + const newTop = Math.round(space.height - pos.height); + root.style.top = Math.max(0, newTop) + 'px'; + } + } + + clamp(root); + }, 1); + + lastMenu = function() { + callbackMap = null; + if ( root ) { + root.querySelectorAll('gui-menu-entry').forEach(function(el) { + Events.$unbind(el); + }); + Events.$unbind(root); + } + root = DOM.$remove(root); + }; +} + +export function setActive(menu) { + lastMenu = menu; +} diff --git a/src/client/javascript/gui/notification.js b/src/client/javascript/gui/notification.js new file mode 100644 index 0000000000..5bf9ed73fc --- /dev/null +++ b/src/client/javascript/gui/notification.js @@ -0,0 +1,234 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +import * as Events from 'utils/events'; +import WindowManager from 'core/window-manager'; + +/** + * Class for creating notifications + */ +class Notification { + + constructor() { + this.$notifications = null; + this.visibles = 0; + } + + /** + * Creates a new popup notification + * + * @param {Object} opts Notification options + * @param {String} opts.icon What icon to display + * @param {String} opts.title What title to display + * @param {String} opts.message What message to display + * @param {Number} [opts.timeout=5000] Timeout + * @param {Function} opts.onClick Event callback on click => fn(ev) + */ + create(opts) { + opts = opts || {}; + opts.icon = opts.icon || null; + opts.title = opts.title || null; + opts.message = opts.message || ''; + opts.onClick = opts.onClick || function() {}; + + if ( !this.$notifications ) { + this.$notifications = document.createElement('corewm-notifications'); + this.$notifications.setAttribute('role', 'log'); + document.body.appendChild(this.$notifications); + } + + if ( typeof opts.timeout === 'undefined' ) { + opts.timeout = 5000; + } + + console.debug('CoreWM::notification()', opts); + + const container = document.createElement('corewm-notification'); + let classNames = ['']; + let timeout = null; + let animationCallback = null; + + const _remove = () => { + if ( timeout ) { + clearTimeout(timeout); + timeout = null; + } + + container.onclick = null; + const _removeDOM = () => { + Events.$unbind(container); + if ( container.parentNode ) { + container.parentNode.removeChild(container); + } + this.visibles--; + if ( this.visibles <= 0 ) { + this.$notifications.style.display = 'none'; + } + }; + + const anim = WindowManager.instance.getSetting('animations'); + if ( anim ) { + container.setAttribute('data-hint', 'closing'); + animationCallback = () => _removeDOM(); + } else { + container.style.display = 'none'; + _removeDOM(); + } + }; + + if ( opts.icon ) { + const icon = document.createElement('img'); + icon.alt = ''; + icon.src = opts.icon; + classNames.push('HasIcon'); + container.appendChild(icon); + } + + if ( opts.title ) { + const title = document.createElement('div'); + title.className = 'Title'; + title.appendChild(document.createTextNode(opts.title)); + classNames.push('HasTitle'); + container.appendChild(title); + } + + if ( opts.message ) { + const message = document.createElement('div'); + message.className = 'Message'; + const lines = opts.message.split('\n'); + lines.forEach(function(line, idx) { + message.appendChild(document.createTextNode(line)); + if ( idx < (lines.length - 1) ) { + message.appendChild(document.createElement('br')); + } + }); + classNames.push('HasMessage'); + container.appendChild(message); + } + + this.visibles++; + if ( this.visibles > 0 ) { + this.$notifications.style.display = 'block'; + } + + container.setAttribute('aria-label', String(opts.title)); + container.setAttribute('role', 'alert'); + + container.className = classNames.join(' '); + container.onclick = function(ev) { + _remove(); + + opts.onClick(ev); + }; + + let preventTimeout; + function _onanimationend(ev) { + if ( typeof animationCallback === 'function') { + clearTimeout(preventTimeout); + preventTimeout = setTimeout(function() { + animationCallback(ev); + animationCallback = false; + }, 10); + } + } + + Events.$bind(container, 'transitionend', _onanimationend); + Events.$bind(container, 'animationend', _onanimationend); + + const space = WindowManager.instance.getWindowSpace(true); + this.$notifications.style.marginTop = String(space.top) + 'px'; + this.$notifications.appendChild(container); + + if ( opts.timeout ) { + timeout = setTimeout(function() { + _remove(); + }, opts.timeout); + } + } + + /** + * Creates a new Notification Icon + * @param {String} name Internal name (unique) + * @param {Object} opts Notification options + * @param {Object} [opts.icon] Icon to display + * @param {Object} [opts.onCreated] Event: when created + * @param {Object} [opts.onInited] Event: when inited + * @param {Object} [opts.onDestroy] Event: when destroyed + * @param {Object} [opts.onClick] Event: when clicked + * @param {Object} [opts.onContextMenu] Event: on context menu + * @return {Boolean} + */ + createIcon(name, opts) { + const wm = WindowManager.instance; + if ( wm && typeof wm.getNotificationArea === 'function' ) { + const pitem = wm.getNotificationArea(); + if ( pitem ) { + return pitem.createNotification(name, opts); + } + } + return null; + } + + /** + * Removes a Notification Icon + * @param {String} name Internal name (unique) + * @return {Boolean} + */ + destroyIcon() { + const wm = WindowManager.instance; + if ( wm && typeof wm.getNotificationArea === 'function' ) { + const pitem = wm.getNotificationArea(); + if ( pitem ) { + pitem.removeNotification(name); + return true; + } + } + return false; + } + + /** + * Get a notification icon + * @param {String} name Internal name (unique) + * @return {object} + */ + getIcon(name) { + const wm = WindowManager.instance; + if ( wm && typeof wm.getNotificationArea === 'function' ) { + const pitem = wm.getNotificationArea(); + if ( pitem ) { + return pitem.getNotification(name); + } + } + return null; + } + +} + +export default (new Notification()); diff --git a/src/client/javascript/gui/scheme.js b/src/client/javascript/gui/scheme.js index dff82b652f..02deb91c06 100644 --- a/src/client/javascript/gui/scheme.js +++ b/src/client/javascript/gui/scheme.js @@ -27,158 +27,169 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(API, Utils, VFS, GUI) { - 'use strict'; +//import Promise from 'bluebird'; +import axios from 'axios'; - ///////////////////////////////////////////////////////////////////////////// - // INTERNAL HELPERS - ///////////////////////////////////////////////////////////////////////////// +//import * as FS from 'utils/fs'; +import * as DOM from 'utils/dom'; +import * as Utils from 'utils/misc'; +import GUIElement from 'gui/element'; +import {getConfig, getBrowserPath} from 'core/config'; - /* - * Method for adding children (moving) - */ - 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++; +///////////////////////////////////////////////////////////////////////////// +// INTERNAL HELPERS +///////////////////////////////////////////////////////////////////////////// + +/* + * Method for adding children (moving) + */ +function addChildren(frag, root, before) { + if ( frag ) { + const children = frag.children; + + let i = 0; + while ( children.length && i < 10000 ) { + if ( before ) { + root.parentNode.insertBefore(children[0], root); + } else { + root.appendChild(children[0]); } + i++; } } +} - /* - * Makes sure "include" fragments are rendered correctly - */ - 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'); - } +/* + * Makes sure "include" fragments are rendered correctly + */ +function resolveFragments(scheme, node) { + function _resolve() { + const nodes = node.querySelectorAll('gui-fragment'); + if ( nodes.length ) { + nodes.forEach(function(el) { + const id = el.getAttribute('data-fragment-id'); + if ( id ) { + const 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(); - } + } + DOM.$remove(el); // Or else we'll never get out of the loop! + }); + return true; } + return false; } - /* - * Removes self-closing tags from HTML string - */ - 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] + '>'; + if ( scheme ) { + let resolving = true; + while ( resolving ) { + resolving = _resolve(); } - return newhtml + split[split.length - 1]; } +} - /* - * Cleans a HTML string - */ - function cleanScheme(html) { - return Utils.cleanHTML(removeSelfClosingTags(html)); +/* + * Removes self-closing tags from HTML string + */ +function removeSelfClosingTags(str) { + const split = (str || '').split('/>'); + + let newhtml = ''; + for (let i = 0; i < split.length - 1;i++) { + const edsplit = split[i].split('<'); + newhtml += split[i] + '>'; } + return newhtml + split[split.length - 1]; +} - /* - * Makes sure "external include" fragments are rendered correctly. - * - * Currently this only supports one level deep. - * - * This occurs on the load() function instead on runtime due to - * performance concerns. - */ - 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 asyncIter(iter, index, next) { - var uri = iter.uri.replace(/^\//, ''); +/* + * Cleans a HTML string + */ +function cleanScheme(html) { + return Utils.cleanHTML(removeSelfClosingTags(html)); +} + +/* FIXME: This is no longer used because of Webpack, but I might + * need this for the IDE ?! + * + * Makes sure "external include" fragments are rendered correctly. + * + * Currently this only supports one level deep. + * + * This occurs on the load() function instead on runtime due to + * performance concerns. +function resolveExternalFragments(root, html, cb) { + let doc = document.createElement('div'); + doc.innerHTML = html; + + let nodes = doc.querySelectorAll('gui-fragment[data-fragment-external]'); + + Promise.each(nodes.map(function(el) { + return { + element: el, + uri: el.getAttribute('data-fragment-external') + }; + }), (iter) => { + return new Promise((next) => { + const uri = iter.uri.replace(/^\//, ''); if ( uri.length < 3 ) { console.warn('resolveExternalFragments()', 'invalid', iter); next(); return; } - 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(); - } + axios({ + url: FS.pathJoin(root, uri), + method: 'GET' + }).then((response) => { + let tmp = document.createElement('div'); + tmp.innerHTML = cleanScheme(response.data); + addChildren(tmp, iter.element, iter.element); + tmp = next(); + }).catch((err) => { + next(); }); - }, function asyncDone() { - cb(doc.innerHTML); - - doc = null; - nodes = null; }); - } - ///////////////////////////////////////////////////////////////////////////// - // SCHEME - ///////////////////////////////////////////////////////////////////////////// + }).then(() => { + cb(doc.innerHTML); + + doc = null; + nodes = null; + + return true; + }); +} + */ + +///////////////////////////////////////////////////////////////////////////// +// SCHEME +///////////////////////////////////////////////////////////////////////////// + +/** + * The class for loading and parsing UI Schemes + * + * @desc Class for loading, parsing and manipulating Scheme files. + */ +export default class GUIScheme { /** - * The class for loading and parsing UI Schemes - * - * @summary Class for loading, parsing and manipulating Scheme files. - * * @param {String} url Scheme URL - * - * @constructor Scheme - * @memberof OSjs.GUI */ - function UIScheme(url) { - console.debug('UIScheme::construct()', url); + constructor(url) { + console.debug('GUIScheme::construct()', url); /** * The URL of the Scheme file - * @name url - * @memberof OSjs.GUI.Scheme# * @type {String} */ this.url = url; /** * The Scheme DOM Node - * @name scheme - * @memberof OSjs.GUI.Scheme# * @type {DocumentFragment} */ this.scheme = null; @@ -188,78 +199,71 @@ /** * Destroys the instance - * - * @function destroy - * @memberof OSjs.GUI.Scheme# */ - UIScheme.prototype.destroy = function() { - Utils.$empty(this.scheme); + destroy() { + DOM.$empty(this.scheme); this.scheme = null; this.triggers = {}; - }; + } /** * Register event * - * @function on - * @memberof OSjs.GUI.Scheme# - * * @param {String} f Event name * @param {Function} fn Function/callback */ - UIScheme.prototype.on = function(f, fn) { + on(f, fn) { this.triggers[f].push(fn); - }; + } /* * Trigger event */ - UIScheme.prototype._trigger = function(f, args) { + _trigger(f, args) { args = args || []; - var self = this; if ( this.triggers[f] ) { - this.triggers[f].forEach(function(fn) { - fn.apply(self, args); + this.triggers[f].forEach((fn) => { + fn.apply(this, args); }); } - }; + } /* * Content loading wrapper */ - UIScheme.prototype._load = function(html, src) { - var doc = document.createDocumentFragment(); - var wrapper = document.createElement('div'); + _load(html, src) { + let doc = document.createDocumentFragment(); + let wrapper = document.createElement('div'); wrapper.innerHTML = html; doc.appendChild(wrapper); this.scheme = doc.cloneNode(true); - if ( API.getConfig('DebugScheme') ) { + if ( getConfig('DebugScheme') ) { console.group('Scheme::_load() validation', src); - this.scheme.querySelectorAll('*').forEach(function(node) { - var tagName = node.tagName.toLowerCase(); - var gelData = GUI.Element.getRegisteredElement(tagName); + this.scheme.querySelectorAll('*').forEach((node) => { + const tagName = node.tagName.toLowerCase(); + const gelData = GUIElement.getRegisteredElement(tagName); if ( gelData ) { - var ac = gelData.metadata.allowedChildren; + const ac = gelData.metadata.allowedChildren; if ( ac instanceof Array && ac.length ) { - var childrenTagNames = node.children.map(function(sNode) { + const childrenTagNames = node.children.map((sNode) => { return sNode.tagName.toLowerCase(); }); - childrenTagNames.forEach(function(chk, idx) { - var found = ac.indexOf(chk); + childrenTagNames.forEach((chk, idx) => { + const found = ac.indexOf(chk); if ( found === -1 ) { console.warn(chk, node.children[idx], 'is not a valid child of type', tagName); } }); } - var ap = gelData.metadata.allowedParents; + const ap = gelData.metadata.allowedParents; if ( ap instanceof Array && ap.length ) { - var parentTagName = node.parentNode.tagName.toLowerCase(); + const parentTagName = node.parentNode.tagName.toLowerCase(); if ( ap.indexOf(parentTagName) === -1 ) { console.warn(parentTagName, node.parentNode, 'is in an invalid parent of type', tagName); } @@ -271,82 +275,59 @@ wrapper = null; doc = null; - }; - - /** - * Load Scheme from given String - * - * @function loadString - * @memberof OSjs.GUI.Scheme# - * - * @param {String} html HTML data - * @param {Function} cb callback => fn(error, scheme) - */ - UIScheme.prototype.loadString = function(html, cb) { - console.debug('UIScheme::loadString()'); - this._load(cleanScheme(html), ''); - if ( cb ) { - cb(false, this.scheme); - } - }; + } /** * Load Scheme from URL * - * @function load - * @memberof OSjs.GUI.Scheme# - * * @param {Function} cb callback => fn(error, DocumentFragment) * @param {Function} [cbxhr] callback on ajax => fn(error, html) */ - UIScheme.prototype.load = function(cb, cbxhr) { + load(cb, cbxhr) { cbxhr = cbxhr || function() {}; - console.debug('UIScheme::load()', this.url); + console.debug('GUIScheme::load()', this.url); - var self = this; - var src = this.url; + let src = this.url; if ( src.substr(0, 1) !== '/' && !src.match(/^(https?|ftp)/) ) { - src = API.getBrowserPath(src); + src = getBrowserPath(src); } - var root = Utils.dirname(src); - Utils.ajax({ + //const root = FS.dirname(src); + + axios({ url: src, - onsuccess: function(html) { - html = cleanScheme(html); - - resolveExternalFragments(root, html, function onFragmentResolved(result) { - // This is normally used for the preloader for caching - cbxhr(false, result); - - // Then we run some manipulations - self._load(result, src); - - // And finally, finish - cb(false, self.scheme); - }); - }, - onerror: function() { - cb('Failed to fetch scheme'); - cbxhr(true); - } + method: 'GET' + }).then((response) => { + const html = cleanScheme(response.data); + /* + resolveExternalFragments(root, html, (result) => { + }); + */ + // This is normally used for the preloader for caching + cbxhr(false, html); + + // Then we run some manipulations + this._load(html, src); + + // And finally, finish + cb(false, this.scheme); + }).catch((err) => { + cb('Failed to fetch scheme: ' + err.message); + cbxhr(true); }); - }; + } /** * Get fragment from ID (and/or type) * - * @function getFragment - * @memberof OSjs.GUI.Scheme# - * * @param {String} id ID * @param {String} [type] Type (application-window | application-fragment) * * @return {Node} */ - UIScheme.prototype.getFragment = function(id, type) { - var content = null; + getFragment(id, type) { + let content = null; if ( id ) { if ( type ) { content = this.scheme.querySelector(type + '[data-id="' + id + '"]'); @@ -356,29 +337,26 @@ } } return content; - }; + } /** * Parses the given fragment * - * @function parse - * @memberof OSjs.GUI.Scheme# - * * @param {String} id Fragment ID * @param {String} [type] Fragment Type - * @param {OSjs.Core.Window} [win] OS.js Window + * @param {Window} [win] OS.js Window * @param {Function} [onparse] Callback on parsed * @param {Object} [args] Parameters * * @return {Node} */ - UIScheme.prototype.parse = function(id, type, win, onparse, args) { - var content = this.getFragment(id, type); + parse(id, type, win, onparse, args) { + const content = this.getFragment(id, type); - console.debug('UIScheme::parse()', id); + console.debug('GUIScheme::parse()', id); if ( !content ) { - console.error('UIScheme::parse()', 'No fragment found', id + '@' + type); + console.error('GUIScheme::parse()', 'No fragment found', id + '@' + type); return null; } @@ -386,48 +364,45 @@ args = args || {}; if ( content ) { - var node = content.cloneNode(true); + const node = content.cloneNode(true); // Resolve fragment includes before dynamic rendering if ( args.resolve !== false ) { resolveFragments(this, node); } - GUI.Element.parseNode(win, node, type, args, onparse, id); + GUIElement.parseNode(win, node, type, args, onparse, id); return node; } return null; - }; + } /** * Renders the given fragment into Window * - * @function render - * @memberof OSjs.GUI.Scheme# - * - * @param {OSjs.Core.Window} win OS.js Window - * @param {String} id Fragment ID - * @param {Node} [root] Root HTML Node - * @param {String} [type] Fragment Type - * @param {Function} [onparse] Callback on parsed - * @param {Object} [args] Parameters + * @param {Window} win OS.js Window + * @param {String} id Fragment ID + * @param {Node} [root] Root HTML Node + * @param {String} [type] Fragment Type + * @param {Function} [onparse] Callback on parsed + * @param {Object} [args] Parameters */ - UIScheme.prototype.render = function(win, id, root, type, onparse, args) { + render(win, id, root, type, onparse, args) { root = root || win._getRoot(); - if ( root instanceof GUI.Element ) { + if ( root instanceof GUIElement ) { 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'); + const width = parseInt(frag.getAttribute('data-width'), 10) || 0; + const height = parseInt(frag.getAttribute('data-height'), 10) || 0; + const allow_maximize = frag.getAttribute('data-allow_maximize'); + const allow_minimize = frag.getAttribute('data-allow_minimize'); + const allow_close = frag.getAttribute('data-allow_close'); + const allow_resize = frag.getAttribute('data-allow_resize'); if ( (!isNaN(width) && width > 0) || (!isNaN(height) && height > 0) ) { win._resize(width, height); @@ -440,13 +415,13 @@ } } - console.debug('UIScheme::render()', id); + console.debug('GUIScheme::render()', id); - var content = this.parse(id, type, win, onparse, args); + const content = this.parse(id, type, win, onparse, args); addChildren(content, root); - root.querySelectorAll('application-fragment').forEach(function(e) { - Utils.$remove(e); + root.querySelectorAll('application-fragment').forEach((e) => { + DOM.$remove(e); }); if ( !win._restored ) { @@ -454,147 +429,28 @@ } this._trigger('render', [root]); - }; - - UIScheme.prototype.create = function(win, tagName, params, parentNode, applyArgs) { - console.warn('UIScheme::create() is deprecated, use Window::_create() or Element::createInto() instead'); - if ( win ) { - return win._create(tagName, params, parentNode, applyArgs); - } - return GUI.Element.createInto(tagName, params, parentNode, applyArgs); - }; - - UIScheme.prototype.find = function(win, id, root) { - console.warn('UIScheme::find() is deprecated, use Window::_find() instead'); - return win._find(id, root); - }; - - UIScheme.prototype.findByQuery = function(win, query, root, all) { - console.warn('UIScheme::findByQuery() is deprecated, use Window::_findByQuery() instead'); - return win._findByQuery(query, root, all); - }; - - UIScheme.prototype.findDOM = function(win, id, root) { - console.warn('UIScheme::findDOM() is deprecated, use Window::_findDOM() instead'); - return win._findDOM(id, root); - }; + } /** * Get HTML from Scheme * - * @function getHTML - * @memberof OSjs.GUI.Scheme# - * * @return {String} */ - UIScheme.prototype.getHTML = function() { + getHTML() { return this.scheme.firstChild.innerHTML; - }; - - ///////////////////////////////////////////////////////////////////////////// - // DialogScheme - ///////////////////////////////////////////////////////////////////////////// - - /** - * Shortcut for creating a new UIScheme class - * - * @summary Helper for loading Dialog scheme files. - * - * @constructor DialogScheme - * @memberof OSjs.GUI - */ - var DialogScheme = (function() { - var dialogScheme; - - return { - - /** - * Get the Dialog scheme - * - * @function get - * @memberof OSjs.GUI.DialogScheme# - * - * @return {OSjs.GUI.Scheme} - */ - get: function() { - return dialogScheme; - }, - - /** - * Destroy the Dialog scheme - * - * @function destroy - * @memberof OSjs.GUI.DialogScheme# - */ - destroy: function() { - if ( dialogScheme ) { - dialogScheme.destroy(); - } - dialogScheme = null; - }, - - /** - * Initialize the Dialog scheme - * - * @function init - * @memberof OSjs.GUI.DialogScheme# - * - * @param {Function} cb Callback function - */ - 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 + 'dialogs.html'; - - dialogScheme = GUI.createScheme(url); - dialogScheme.load(function(error) { - if ( error ) { - console.warn('OSjs.GUI.initDialogScheme()', 'error loading dialog schemes', error); - } - cb(); - }); - } - - }; - - })(); - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// + } /** - * Shortcut for creating a new UIScheme class - * - * @function createScheme - * @memberof OSjs.GUI - * - * @param {String} url URL to scheme file - * - * @return {OSjs.GUI.Scheme} + * Creates a new Scheme from a string + * @param {String} str The string (HTML) + * @return GUIScheme */ - function createScheme(url) { - return new UIScheme(url); + static fromString(str) { + const inst = new GUIScheme(null); + const cleaned = cleanScheme(str); + inst._load(cleaned, ''); + return inst; } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - GUI.Scheme = Object.seal(UIScheme); - GUI.DialogScheme = DialogScheme; - GUI.createScheme = createScheme; +} -})(OSjs.API, OSjs.Utils, OSjs.VFS, OSjs.GUI); diff --git a/src/client/javascript/vfs/transports/http.js b/src/client/javascript/gui/splash.js similarity index 55% rename from src/client/javascript/vfs/transports/http.js rename to src/client/javascript/gui/splash.js index c88c7874a8..5438208713 100644 --- a/src/client/javascript/vfs/transports/http.js +++ b/src/client/javascript/gui/splash.js @@ -27,51 +27,69 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function(Utils, API, VFS) { - 'use strict'; + +/** + * Splash Screen Class + * @desc Builds the splash screen + */ +class SplashScreen { + + constructor() { + this.$el = document.getElementById('LoadingScreen'); + this.$progress = this.$el ? this.$el.querySelector('.progress') : null; + } /** - * @namespace HTTP - * @memberof OSjs.VFS.Transports + * Applies the watermark + * @param {Object} config Configuration tree */ + watermark(config) { + if ( config.Watermark.enabled ) { + var ver = config.Version || 'unknown version'; + var html = config.Watermark.lines || []; + + var el = document.createElement('osjs-watermark'); + el.setAttribute('aria-hidden', 'true'); + el.innerHTML = html.join('
').replace(/%VERSION%/, ver); - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + document.body.appendChild(el); + } + } - /* - * Default HTTP VFS Transport Module + /** + * Show the splash */ - VFS.Transports.HTTP = { - module: { - read: function(item, callback, options) { - VFS.Transports.OSjs.fetch(item.path, item.mime, callback, options); - } + show() { + if ( this.$el ) { + this.$el.style.display = 'block'; + } + } + + /** + * Hide the splash + */ + hide() { + if ( this.$el ) { + this.$el.style.display = 'none'; } - }; + } - /* - * A hidden mountpoint for making HTTP requests via VFS + /** + * Update the splash + * @param {Number} p Step x of... + * @param {Number} c ... y */ - 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?\:\/\// - }); + update(p, c) { + if ( this.$progress ) { + let per = c ? 0 : 100; + if ( c ) { + per = (p / c) * 100; + } + + this.$progress.style.width = String(per) + '%'; + } + } + +} -})(OSjs.Utils, OSjs.API, OSjs.VFS); +export default (new SplashScreen()); diff --git a/src/client/javascript/helpers/date.js b/src/client/javascript/helpers/date.js index e8a5f783ee..6debb5a282 100644 --- a/src/client/javascript/helpers/date.js +++ b/src/client/javascript/helpers/date.js @@ -29,69 +29,67 @@ */ /*eslint valid-jsdoc: "off"*/ -(function(Utils, VFS, API) { - 'use strict'; - ///////////////////////////////////////////////////////////////////////////// - // HELPERS - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// - 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 filter(from, index, shrt, toindex) { + const list = []; + for ( let i = (shrt ? 0 : toindex); i < from.length; i++ ) { + list.push(from[i]); } - - function format(fmt, date) { - /*eslint no-use-before-define: "off"*/ - var utc; - - if ( typeof fmt === 'undefined' || !fmt ) { - fmt = ExtendedDate.config.defaultFormat; + return list; +} + +function format(fmt, date) { + /*eslint no-use-before-define: "off"*/ + let utc; + + if ( typeof fmt === 'undefined' || !fmt ) { + fmt = ExtendedDate.config.defaultFormat; + } else { + if ( typeof fmt !== 'string' ) { + utc = fmt.utc; + fmt = fmt.format; } else { - if ( typeof fmt !== 'string' ) { - utc = fmt.utc; - fmt = fmt.format; - } else { - utc = ExtendedDate.config.utc; - } + utc = ExtendedDate.config.utc; } - - return formatDate(date, fmt, utc); } - function _now(now) { - /*eslint no-use-before-define: "off"*/ - return now ? (now instanceof ExtendedDate ? now.date : now) : new Date(); - } + return formatDate(date, fmt, utc); +} - function _y(y, now) { - return (typeof y === 'undefined' || y === null || y < 0 ) ? now.getFullYear() : y; - } +function _now(now) { + /*eslint no-use-before-define: "off"*/ + return now ? (now instanceof ExtendedDate ? now.date : now) : new Date(); +} - function _m(m, now) { - return (typeof m === 'undefined' || m === null || m < 0 ) ? now.getMonth() : m; - } +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; +} - ///////////////////////////////////////////////////////////////////////////// - // EXTENDED DATE - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// EXTENDED DATE +///////////////////////////////////////////////////////////////////////////// + +/** + * Extended Date Helper + * + * Works just like 'Date', but has some extended methods + * + * @desc Class for date manipulation and formatting. + */ +export default class ExtendedDate { /** - * Extended Date Helper - * - * Works just like 'Date', but has some extended methods - * - * @summary Class for date manipulation and formatting. - * - * @param {(Date|Ojs.Helpers.Date)} [date] Create new instance from this date - * - * @constructor Date - * @memberof OSjs.Helpers + * @param {(Date|ExtendedDate)} [date] Create new instance from this date */ - function ExtendedDate(date) { + constructor(date) { if ( date ) { if ( date instanceof Date ) { this.date = date; @@ -110,85 +108,26 @@ // // Global Configuration // - ExtendedDate.config = { - defaultFormat: 'isoDateTime' - //utc: true - }; - - 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' - ]; + static get config() { + return { + defaultFormat: 'isoDateTime' + //utc: true + }; + } - // - // Date Methods - // + static get dayNames() { + return [ + 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' + ]; + } - 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); - }; - }); + static get monthNames() { + return [ + 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', + 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' + ]; + } // // Extended Methods @@ -197,21 +136,15 @@ /** * Get the 'Date' Object * - * @function get - * @memberof OSjs.Helpers.Date# - * - * @return {OSjs.Helpers.Date} + * @return {DateExtended} */ - ExtendedDate.prototype.get = function() { + get() { return this.date; - }; + } /** * Format date * - * @function format - * @memberof OSjs.Helpers.Date# - * * @param {String} fmt Format (ex: "Y/m/d") * * @return {String} Formatted date @@ -248,112 +181,92 @@ *
*/ - ExtendedDate.prototype.format = function(fmt) { + format(fmt) { return ExtendedDate.format(this, fmt); - }; + } /** * Get First day in month * - * @function getFirstDayInMonth - * @memberof OSjs.Helpers.Date# - * @see OSjs.Helpers.Date#format + * @see DateExtended#format * * @param {String} [fmt] Date format * - * @return {Mixed} If no format is given it will return ExtendedDate + * @return {String|ExtendedDate} If no format is given it will return ExtendedDate */ - ExtendedDate.prototype.getFirstDayInMonth = function(fmt) { + getFirstDayInMonth(fmt) { return ExtendedDate.getFirstDayInMonth(fmt, null, null, this); - }; + } /** * Get Last day in month * - * @function getLastDayInMonth - * @memberof OSjs.Helpers.Date# - * @see OSjs.Helpers.Date#format + * @see DateExtended#format * * @param {String} [fmt] Date format * - * @return {Mixed} If no format is given it will return ExtendedDate + * @return {String|ExtendedDate} If no format is given it will return ExtendedDate */ - ExtendedDate.prototype.getLastDayInMonth = function(fmt) { + getLastDayInMonth(fmt) { return ExtendedDate.getLastDayInMonth(fmt, null, null, this); - }; + } /** * Get numbers of day in month * - * @function getDaysInMonth - * @memberof OSjs.Helpers.Date# - * * @return {Number} Number of days */ - ExtendedDate.prototype.getDaysInMonth = function() { + getDaysInMonth() { return ExtendedDate.getDaysInMonth(null, null, this); - }; + } /** * Get week number * - * @function getWeekNumber - * @memberof OSjs.Helpers.Date# - * * @return {Number} Week */ - ExtendedDate.prototype.getWeekNumber = function() { + getWeekNumber() { return ExtendedDate.getWeekNumber(this); - }; + } /** * Check if given range is within Month * - * @function isWithinMonth - * @memberof OSjs.Helpers.Date# - * - * @param {(Date|OSjs.Helpers.Date)} from From date (can be Date) - * @param {(Date|OSjs.Helpers.Date)} to To date (can be Date) + * @param {(Date|DateExtended)} from From date (can be Date) + * @param {(Date|DateExtended)} to To date (can be Date) * * @return {Boolean} */ - ExtendedDate.prototype.isWithinMonth = function(from, to) { + isWithinMonth(from, to) { return ExtendedDate.isWithinMonth(this, from, to); - }; + } /** * Check if given range is within Year * - * @function isWithinYear - * @memberof OSjs.Helpers.Date# - * * @return {Boolean} */ - ExtendedDate.prototype.getDayOfTheYear = function() { + getDayOfTheYear() { return ExtendedDate.getDayOfTheYear(); - }; + } // // Static Methods // /** - * @function format - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#format + * @see DateExtended#format */ - ExtendedDate.format = function(date, fmt) { + static format(date, fmt) { return format(fmt, date); - }; + } /** - * @function getPreviousMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getPreviousMonth + * @see DateExtended#getPreviousMonth */ - ExtendedDate.getPreviousMonth = function(now) { + static getPreviousMonth(now) { now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date(); - var current; + let current; if (now.getMonth() === 0) { current = new Date(now.getFullYear() - 1, 11, now.getDate()); @@ -362,16 +275,14 @@ } return new ExtendedDate(current); - }; + } /** - * @function getNextMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getNextMonth + * @see DateExtended#getNextMonth */ - ExtendedDate.getNextMonth = function(now) { + static getNextMonth(now) { now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date(); - var current; + let current; if (now.getMonth() === 11) { current = new Date(now.getFullYear() + 1, 0, now.getDate()); @@ -380,363 +291,405 @@ } return new ExtendedDate(current); - }; + } /** - * @function getFirstDayInMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getFirstDayInMonth + * @see DateExtended#getFirstDayInMonth */ - ExtendedDate.getFirstDayInMonth = function(fmt, y, m, now) { + static getFirstDayInMonth(fmt, y, m, now) { now = _now(now); y = _y(y, now); m = _m(m, now); - var date = new Date(); + const date = new Date(); date.setFullYear(y, m, 1); if ( fmt === true ) { return date.getDate(); } return fmt ? format(fmt, date) : new ExtendedDate(date); - }; + } /** - * @function getLastDayInMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getLastDayInMonth + * @see DateExtended#getLastDayInMonth */ - ExtendedDate.getLastDayInMonth = function(fmt, y, m, now) { + static getLastDayInMonth(fmt, y, m, now) { now = _now(now); y = _y(y, now); m = _m(m, now); - var date = new Date(); + const date = new Date(); date.setFullYear(y, m, 0); if ( fmt === true ) { return date.getDate(); } return fmt ? format(fmt, date) : new ExtendedDate(date); - }; + } /** - * @function getDaysInMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getDaysInMonth + * @see DateExtended#getDaysInMonth */ - ExtendedDate.getDaysInMonth = function(y, m, now) { + static getDaysInMonth(y, m, now) { now = _now(now); y = _y(y, now); m = _m(m, now); - var date = new Date(); + const date = new Date(); date.setFullYear(y, m, 0); return parseInt(date.getDate(), 10); - }; + } /** - * @function getWeekNumber - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getWeekNumber + * @see DateExtended#getWeekNumber */ - ExtendedDate.getWeekNumber = function(now) { + static getWeekNumber(now) { now = now ? (now instanceof ExtendedDate ? now.date : now) : new Date(); - var d = new Date(+now); + const 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); - }; + } /** - * @function getDayName - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getDayName + * @see DateExtended#getDayName */ - ExtendedDate.getDayName = function(index, shrt) { + static getDayName(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); + const idx = index + (shrt + 7); return ExtendedDate.dayNames[idx]; - }; + } /** - * @function getMonthName - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getMonthName + * @see DateExtended#getMonthName */ - ExtendedDate.getMonthName = function(index, shrt) { + static getMonthName(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); + const idx = index + (shrt + 12); return ExtendedDate.monthNames[idx]; - }; + } /** - * @function isWithinMonth - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#isWithinMonth + * @see DateExtended#isWithinMonth */ - ExtendedDate.isWithinMonth = function(now, from, to) { + static isWithinMonth(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; - }; + } /** - * @function getDayOfTheYear - * @memberof OSjs.Helpers.Date - * @see OSjs.Helpers.Date#getDayOfTheYear + * @see DateExtended#getDayOfTheYear */ - 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; + static getDayOfTheYear() { + const now = new Date(); + const start = new Date(now.getFullYear(), 0, 0); + const diff = now - start; + const oneDay = 1000 * 60 * 60 * 24; return Math.floor(diff / oneDay); + } +} + +// +// Date Methods +// + +const 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); }; +}); - ///////////////////////////////////////////////////////////////////////////// - // DATE FORMATTING - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// DATE FORMATTING +///////////////////////////////////////////////////////////////////////////// - /** - * Inspired by: "Date Format" by Steven Levithan - */ - 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; +/** + * Inspired by: "Date Format" by Steven Levithan + */ +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' - }; + const 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; + format = defaultFormats[format] || format; - if ( !(date instanceof ExtendedDate) ) { - date = new ExtendedDate(date); - } + if ( !(date instanceof ExtendedDate) ) { + date = new ExtendedDate(date); + } - var map = { - /*eslint new-cap: "warn"*/ - - // - // DAY - // - - // Day of the month, 2 digits with leading zeros (01 to 31) - d: function(s) { - return pad(map.j(s)); - }, - - // A textual representation of a day, three letters (Mon through Sun) - D: function(s) { - return ExtendedDate.dayNames[utc ? date.getUTCDay() : date.getDay()]; - }, - - // Day of the month without leading zeros (1 to 31) - j: function(s) { - return (utc ? date.getUTCDate() : date.getDate()); - }, - - // A full textual representation of the day of the week (Sunday through Saturday) - l: function(s) { - return ExtendedDate.dayNames[(utc ? date.getUTCDay() : date.getDay()) + 7]; - }, - - // Numeric representation of the day of the week (0 (for Sunday) through 6 (for Saturday)) - w: function(s) { - return (utc ? date.getUTCDay() : date.getDay()); - }, - - // The day of the year (starting from 0) (0 through 365) - z: function(s) { - return date.getDayOfTheYear(); - }, - - // S English ordinal suffix for the day of the month, 2 characters (st, nd, rd or th. Works well with j) - 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]; - }, - - // - // WEEK - // - - // ISO-8601 week number of year, weeks starting on Monday (Example: 42 (the 42nd week in the year)) - W: function(s) { - return date.getWeekNumber(); - }, - - // - // MONTH - // - - // A full textual representation of a month, such as January or March (January through December) - F: function(s) { - return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth()) + 12]; - }, - - // Numeric representation of a month, with leading zeros (01 through 12) - m: function(s) { - return pad(map.n(s)); - }, - - // A short textual representation of a month, three letters (Jan through Dec) - M: function(s) { - return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth())]; - }, - - // Numeric representation of a month, without leading zeros (1 through 12) - n: function(s) { - return (utc ? date.getUTCMonth() : date.getMonth()) + 1; - }, - - // Number of days in the given month (28 through 31) - t: function(s) { - return date.getDaysInMonth(); - }, - - // - // YEAR - // - - // A full numeric representation of a year, 4 digits (Examples: 1999 or 2003) - Y: function(s) { - return (utc ? date.getUTCFullYear() : date.getFullYear()); - }, - - // A two digit representation of a year (Examples: 99 or 03) - y: function(s) { - /*eslint new-cap: "off"*/ - return String(map.Y(s)).slice(2); - }, - - // - // TIME - // - - // Lowercase Ante meridiem and Post meridiem (am or pm) - a: function(s) { - /*eslint new-cap: "off"*/ - return map.G(s) < 12 ? 'am' : 'pm'; - }, - - // Uppercase Ante meridiem and Post meridiem (AM or PM) - A: function(s) { - return map.a(s).toUpperCase(); - }, - - // 12-hour format of an hour without leading zeros (1 through 12) - g: function(s) { - /*eslint new-cap: "off"*/ - return map.G(s) % 12 || 12; - }, - - // 24-hour format of an hour without leading zeros (0 through 23) - G: function(s) { - return (utc ? date.getUTCHours() : date.getHours()); - }, - - // 12-hour format of an hour with leading zeros (01 through 12) - h: function(s) { - return pad(map.g(s)); - }, - - // 24-hour format of an hour with leading zeros (00 through 23) - H: function(s) { - /*eslint new-cap: "off"*/ - return pad(map.G(s)); - }, - - // Minutes with leading zeros (00 to 59) - i: function(s) { - return pad(utc ? date.getUTCMinutes() : date.getMinutes()); - }, - - // Seconds, with leading zeros (00 through 59) - s: function(s) { - return pad(utc ? date.getUTCSeconds() : date.getSeconds()); - }, - - // - // ZONE - // - - // Difference to Greenwich time (GMT) in hours (Example: +0200) - 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; - }, - - // Timezone abbreviation (Examples: EST, MDT ...) - 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]+$/, ''); - }, - - // - // MISC - // - - // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) - U: function(s) { - return date.getTime(); + const map = { + /*eslint new-cap: "warn"*/ + + // + // DAY + // + + // Day of the month, 2 digits with leading zeros (01 to 31) + d: function(s) { + return pad(map.j(s)); + }, + + // A textual representation of a day, three letters (Mon through Sun) + D: function(s) { + return ExtendedDate.dayNames[utc ? date.getUTCDay() : date.getDay()]; + }, + + // Day of the month without leading zeros (1 to 31) + j: function(s) { + return (utc ? date.getUTCDate() : date.getDate()); + }, + + // A full textual representation of the day of the week (Sunday through Saturday) + l: function(s) { + return ExtendedDate.dayNames[(utc ? date.getUTCDay() : date.getDay()) + 7]; + }, + + // Numeric representation of the day of the week (0 (for Sunday) through 6 (for Saturday)) + w: function(s) { + return (utc ? date.getUTCDay() : date.getDay()); + }, + + // The day of the year (starting from 0) (0 through 365) + z: function(s) { + return date.getDayOfTheYear(); + }, + + // S English ordinal suffix for the day of the month, 2 characters (st, nd, rd or th. Works well with j) + S: function(s) { + const d = utc ? date.getUTCDate() : date.getDate(); + return ['th', 'st', 'nd', 'rd'][d % 10 > 3 ? 0 : (d % 100 - d % 10 !== 10) * d % 10]; + }, + + // + // WEEK + // + + // ISO-8601 week number of year, weeks starting on Monday (Example: 42 (the 42nd week in the year)) + W: function(s) { + return date.getWeekNumber(); + }, + + // + // MONTH + // + + // A full textual representation of a month, such as January or March (January through December) + F: function(s) { + return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth()) + 12]; + }, + + // Numeric representation of a month, with leading zeros (01 through 12) + m: function(s) { + return pad(map.n(s)); + }, + + // A short textual representation of a month, three letters (Jan through Dec) + M: function(s) { + return ExtendedDate.monthNames[(utc ? date.getUTCMonth() : date.getMonth())]; + }, + + // Numeric representation of a month, without leading zeros (1 through 12) + n: function(s) { + return (utc ? date.getUTCMonth() : date.getMonth()) + 1; + }, + + // Number of days in the given month (28 through 31) + t: function(s) { + return date.getDaysInMonth(); + }, + + // + // YEAR + // + + // A full numeric representation of a year, 4 digits (Examples: 1999 or 2003) + Y: function(s) { + return (utc ? date.getUTCFullYear() : date.getFullYear()); + }, + + // A two digit representation of a year (Examples: 99 or 03) + y: function(s) { + /*eslint new-cap: "off"*/ + return String(map.Y(s)).slice(2); + }, + + // + // TIME + // + + // Lowercase Ante meridiem and Post meridiem (am or pm) + a: function(s) { + /*eslint new-cap: "off"*/ + return map.G(s) < 12 ? 'am' : 'pm'; + }, + + // Uppercase Ante meridiem and Post meridiem (AM or PM) + A: function(s) { + return map.a(s).toUpperCase(); + }, + + // 12-hour format of an hour without leading zeros (1 through 12) + g: function(s) { + /*eslint new-cap: "off"*/ + return map.G(s) % 12 || 12; + }, + + // 24-hour format of an hour without leading zeros (0 through 23) + G: function(s) { + return (utc ? date.getUTCHours() : date.getHours()); + }, + + // 12-hour format of an hour with leading zeros (01 through 12) + h: function(s) { + return pad(map.g(s)); + }, + + // 24-hour format of an hour with leading zeros (00 through 23) + H: function(s) { + /*eslint new-cap: "off"*/ + return pad(map.G(s)); + }, + + // Minutes with leading zeros (00 to 59) + i: function(s) { + return pad(utc ? date.getUTCMinutes() : date.getMinutes()); + }, + + // Seconds, with leading zeros (00 through 59) + s: function(s) { + return pad(utc ? date.getUTCSeconds() : date.getSeconds()); + }, + + // + // ZONE + // + + // Difference to Greenwich time (GMT) in hours (Example: +0200) + O: function(s) { + const tzo = -date.getTimezoneOffset(); + const dif = tzo >= 0 ? '+' : '-'; + + function ppad(num) { + const norm = Math.abs(Math.floor(num)); + return (norm < 10 ? '0' : '') + norm; } - }; - var result = []; - format.split('').forEach(function(s) { - result.push(map[s] ? map[s]() : s); - }); - return result.join(''); - } + const str = dif + ppad(tzo / 60) + ':' + ppad(tzo % 60); + return str; + }, - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + // Timezone abbreviation (Examples: EST, MDT ...) + T: function(s) { + if ( utc ) { + return 'UTC'; + } - OSjs.Helpers.Date = ExtendedDate; + const timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g; + const zones = String(date.date).match(timezone) || ['']; + return zones.pop().replace(/(\+|\-)[0-9]+$/, ''); + }, -})(OSjs.Utils, OSjs.VFS, OSjs.API); + // + // MISC + // + + // Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) + U: function(s) { + return date.getTime(); + } + }; + + const result = []; + format.split('').forEach(function(s) { + result.push(map[s] ? map[s]() : s); + }); + return result.join(''); +} diff --git a/src/client/javascript/helpers/default-application-window.js b/src/client/javascript/helpers/default-application-window.js index b47c58cb1b..6b694878b5 100644 --- a/src/client/javascript/helpers/default-application-window.js +++ b/src/client/javascript/helpers/default-application-window.js @@ -29,80 +29,73 @@ */ /*eslint valid-jsdoc: "off"*/ -(function(Application, Window, Utils, VFS, API, GUI) { - 'use strict'; +import FileMetadata from 'vfs/file'; +import Window from 'core/window'; +import DialogWindow from 'core/dialog'; +import {_} from 'core/locales'; - ///////////////////////////////////////////////////////////////////////////// - // Default Application Window Helper - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Default Application Window Helper +///////////////////////////////////////////////////////////////////////////// - /** - * This is a helper to more easily create an application. - * - * Use in combination with 'DefaultApplication' - * - * @summary Helper for making Applications with file interaction. - * - * @constructor - * @memberof OSjs.Helpers - * @see OSjs.Helpers.DefaultApplication - * @see OSjs.Core.Window - */ - function DefaultApplicationWindow(name, app, args, scheme, file) { - Window.apply(this, arguments); +/** + * This is a helper to more easily create an application. + * + * Use in combination with 'DefaultApplication' + * + * @desc Helper for making Applications with file interaction. + */ +export default class DefaultApplicationWindow extends Window { + constructor(name, args, app, file) { + super(...arguments); this.hasClosingDialog = false; - this.currentFile = file ? new VFS.File(file) : null; + this.currentFile = file ? new FileMetadata(file) : null; this.hasChanged = false; } - DefaultApplicationWindow.prototype = Object.create(Window.prototype); - DefaultApplicationWindow.constructor = Window; - /* * Destroy */ - DefaultApplicationWindow.prototype.destroy = function() { - Window.prototype.destroy.apply(this, arguments); - + destroy() { + super.destroy(...arguments); this.currentFile = null; - }; + } /* * Initialize */ - DefaultApplicationWindow.prototype.init = function(wm, app, scheme) { - var root = Window.prototype.init.apply(this, arguments); + init(wm, app) { + const root = super.init(...arguments); return root; - }; + } /* * Applies default Window GUI stuff */ - DefaultApplicationWindow.prototype._inited = function() { - var result = Window.prototype._inited.apply(this, arguments); - var self = this; - var app = this._app; + _inited() { + const result = Window.prototype._inited.apply(this, arguments); + const app = this._app; - var menuMap = { - MenuNew: function() { - app.newDialog(self.currentFile, self); + const menuMap = { + MenuNew: () => { + app.newDialog(this.currentFile, this); }, - MenuSave: function() { - app.saveDialog(self.currentFile, self); + MenuSave: () => { + app.saveDialog(this.currentFile, this); }, - MenuSaveAs: function() { - app.saveDialog(self.currentFile, self, true); + MenuSaveAs: () => { + app.saveDialog(this.currentFile, this, true); }, - MenuOpen: function() { - app.openDialog(self.currentFile, self); + MenuOpen: () => { + app.openDialog(this.currentFile, this); }, - MenuClose: function() { - self._close(); + MenuClose: () => { + this._close(); } }; - this._find('SubmenuFile').on('select', function(ev) { + this._find('SubmenuFile').on('select', (ev) => { if ( menuMap[ev.detail.id] ) { menuMap[ev.detail.id](); } @@ -118,61 +111,57 @@ } return result; - }; + } /* * On Drag-And-Drop Event */ - DefaultApplicationWindow.prototype._onDndEvent = function(ev, type, item, args) { + _onDndEvent(ev, type, item, args) { if ( !Window.prototype._onDndEvent.apply(this, arguments) ) { return; } if ( type === 'itemDrop' && item ) { - var data = item.data; + const data = item.data; if ( data && data.type === 'file' && data.mime ) { - this._app.openFile(new VFS.File(data), this); + this._app.openFile(new FileMetadata(data), this); } } - }; + } /* * On Close */ - DefaultApplicationWindow.prototype._close = function() { - var self = this; + _close() { if ( this.hasClosingDialog ) { return; } if ( this.hasChanged ) { this.hasClosingDialog = true; - this.checkHasChanged(function(discard) { - self.hasClosingDialog = false; + this.checkHasChanged((discard) => { + this.hasClosingDialog = false; if ( discard ) { - self.hasChanged = false; // IMPORTANT - self._close(); + this.hasChanged = false; // IMPORTANT + this._close(); } }); return; } Window.prototype._close.apply(this, arguments); - }; + } /** * Checks if current file has changed * - * @function checkHasChanged - * @memberof OSjs.Helpers.DefaultApplicationWindow# - * * @param {Function} cb Callback => fn(discard_changes) */ - DefaultApplicationWindow.prototype.checkHasChanged = function(cb) { + checkHasChanged(cb) { if ( this.hasChanged ) { - API.createDialog('Confirm', { + DialogWindow.create('Confirm', { buttons: ['yes', 'no'], - message: API._('MSG_GENERIC_APP_DISCARD') + message: _('MSG_GENERIC_APP_DISCARD') }, function(ev, button) { cb(button === 'ok' || button === 'yes'); }, {parent: this, modal: true}); @@ -180,36 +169,30 @@ } cb(true); - }; + } /** * Show opened/created file * * YOU SHOULD EXTEND THIS METHOD IN YOUR WINDOW TO ACTUALLY DISPLAY CONTENT * - * @function showFile - * @memberof OSjs.Helpers.DefaultApplicationWindow# - * - * @param {OSjs.VFS.File} file File - * @param {Mixed} content File contents + * @param {FileMetadata} file File + * @param {String|Object} content File contents */ - DefaultApplicationWindow.prototype.showFile = function(file, content) { + showFile(file, content) { this.updateFile(file); - }; + } /** * Updates current view for given File * - * @function updateFile - * @memberof OSjs.Helpers.DefaultApplicationWindow# - * - * @param {OSjs.VFS.File} file File + * @param {FileMetadata} file File */ - DefaultApplicationWindow.prototype.updateFile = function(file) { + updateFile(file) { this.currentFile = file || null; this.hasChanged = false; - if ( this._scheme && (this._scheme instanceof GUI.Scheme) ) { + if ( this._scheme ) { this._find('MenuSave').set('disabled', !file); } @@ -218,26 +201,23 @@ } else { this._setTitle(); } - }; + } /** * Gets file data * * YOU SHOULD IMPLEMENT THIS METHOD IN YOUR WINDOW TO RETURN FILE CONTENTS * - * @function getFileData - * @memberof OSjs.Helpers.DefaultApplicationWindow# - * - * @return {Mixed} File contents + * @return {*} File contents */ - DefaultApplicationWindow.prototype.getFileData = function() { + getFileData() { return null; - }; + } /** * Window key */ - DefaultApplicationWindow.prototype._onKeyEvent = function(ev, type, shortcut) { + _onKeyEvent(ev, type, shortcut) { if ( shortcut === 'SAVE' ) { this._app.saveDialog(this.currentFile, this, !this.currentFile); return false; @@ -250,13 +230,6 @@ } return Window.prototype._onKeyEvent.apply(this, arguments); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.DefaultApplicationWindow = DefaultApplicationWindow; - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.API, OSjs.GUI); + } +} diff --git a/src/client/javascript/helpers/default-application.js b/src/client/javascript/helpers/default-application.js index 2939d11a81..749257fa0b 100644 --- a/src/client/javascript/helpers/default-application.js +++ b/src/client/javascript/helpers/default-application.js @@ -29,116 +29,109 @@ */ /*eslint valid-jsdoc: "off"*/ -(function(Application, Window, Utils, VFS, API, GUI) { - 'use strict'; +import Application from 'core/application'; +import DialogWindow from 'core/dialog'; +import FileMetadata from 'vfs/file'; +import * as VFS from 'vfs/fs'; +import * as FS from 'utils/fs'; +import {_} from 'core/locales'; + +///////////////////////////////////////////////////////////////////////////// +// Default Application Helper +///////////////////////////////////////////////////////////////////////////// + +/** + * This is a helper to more easily create an application. + * + * Handles opening, saving and creation of files. + * + * @desc Helper for making Applications with file interaction. + */ +export default class DefaultApplication extends Application { - ///////////////////////////////////////////////////////////////////////////// - // Default Application Helper - ///////////////////////////////////////////////////////////////////////////// + constructor(name, args, metadata, opts) { + super(...arguments); - /** - * This is a helper to more easily create an application. - * - * Handles opening, saving and creation of files. - * - * @summary Helper for making Applications with file interaction. - * - * @constructor - * @memberof OSjs.Helpers - * @see OSjs.Helpers.DefaultApplicationWindow - * @see OSjs.Core.Application - */ - function DefaultApplication(name, args, metadata, opts) { - this.defaultOptions = Utils.argumentDefaults(opts, { + this.defaultOptions = Object.assign({}, { readData: true, rawData: false, extension: '', mime: 'application/octet-stream', filetypes: [], filename: 'New file' - }); - - Application.apply(this, [name, args, metadata]); + }, opts); } - DefaultApplication.prototype = Object.create(Application.prototype); - DefaultApplication.constructor = Application; - /* * Destroy */ - DefaultApplication.prototype.destroy = function() { - Application.prototype.destroy.apply(this, arguments); - }; + destroy() { + super.destroy(...arguments); + } /* * On Message */ - DefaultApplication.prototype._onMessage = function(msg, obj, args) { - Application.prototype._onMessage.apply(this, arguments); + _onMessage(msg, obj, args) { + super._onMessage(...arguments); - var self = this; - var current = this._getArgument('file'); - var win = this._getWindow(this.__mainwindow); + const current = this._getArgument('file'); + const 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 ) { - API.createDialog('Confirm', { + DialogWindow.create('Confirm', { buttons: ['yes', 'no'], - message: API._('MSG_FILE_CHANGED') - }, function(ev, button) { + message: _('MSG_FILE_CHANGED') + }, (ev, button) => { if ( button === 'ok' || button === 'yes' ) { - self.openFile(new VFS.File(args.file), win); + this.openFile(new FileMetadata(args.file), win); } }, {parent: win, modal: true}); } } - }; + } /** * Open given File * - * @function openFile - * @memberof OSjs.Helpers.DefaultApplication# - * - * @param {OSjs.VFS.File} file File - * @param {OSjs.Core.Window} win Window reference + * @param {FileMetadata} file File + * @param {Window} win Window reference */ - DefaultApplication.prototype.openFile = function(file, win) { - var self = this; + openFile(file, win) { if ( !file ) { return false; } - function onError(error) { + const onError = (error) => { if ( error ) { - API.error(self.__label, - API._('ERR_FILE_APP_OPEN'), - API._('ERR_FILE_APP_OPEN_ALT_FMT', - file.path, error) + OSjs.error(this.__label, + _('ERR_FILE_APP_OPEN'), + _('ERR_FILE_APP_OPEN_ALT_FMT', + file.path, error) ); return true; } return false; - } + }; - function onDone(result) { - self._setArgument('file', file); + const onDone = (result) => { + this._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) + const check = this.__metadata.mime || []; + if ( !FS.checkAcceptMime(file.mime, check) ) { + OSjs.error(this.__label, + _('ERR_FILE_APP_OPEN'), + _('ERR_FILE_APP_OPEN_FMT', file.path, file.mime) ); return false; } win._toggleLoading(true); - function CallbackVFS(error, result) { + function callbackVFS(error, result) { win._toggleLoading(false); if ( onError(error) ) { return; @@ -147,68 +140,63 @@ } if ( this.defaultOptions.readData ) { - VFS.read(file, CallbackVFS, {type: this.defaultOptions.rawData ? 'binary' : 'text'}); + VFS.read(file, {type: this.defaultOptions.rawData ? 'binary' : 'text'}, this) + .then((res) => callbackVFS(false, res)) + .catch((err) => callbackVFS(err)); } else { - VFS.url(file, CallbackVFS); + VFS.url(file) + .then((res) => callbackVFS(false, res)) + .catch((err) => callbackVFS(err)); } return true; - }; + } /** * Save given File * - * @function saveFile - * @memberof OSjs.Helpers.DefaultApplication# - * - * @param {OSjs.VFS.File} file File - * @param {Mixed} value File contents - * @param {OSjs.Core.Window} win Window reference + * @param {FileMetadata} file File + * @param {String|Object} value File contents + * @param {Window} win Window reference */ - DefaultApplication.prototype.saveFile = function(file, value, win) { - var self = this; + saveFile(file, value, win) { 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, error) - ); - return; - } - - self._setArgument('file', file); + VFS.write(file, value || '', null, this).then(() => { + this._setArgument('file', file); win.updateFile(file); - }, {}, this); - }; + return true; + }).catch((error) => { + OSjs.error(this.__label, + _('ERR_FILE_APP_SAVE'), + _('ERR_FILE_APP_SAVE_ALT_FMT', file.path, error) + ); + + }).finally(() => { + win._toggleLoading(false); + }); + } /** * Open Save dialog * - * @function saveDialog - * @memberof OSjs.Helpers.DefaultApplication# - * - * @param {OSjs.VFS.File} file File - * @param {OSjs.Core.Window} win Window reference - * @param {Boolean} saveAs SaveAs ? - * @param {CallbackDialog} cb Called after the user closed the dialog + * @param {FileMetadata} file File + * @param {Window} win Window reference + * @param {Boolean} saveAs SaveAs ? + * @param {CallbackDialog} cb Called after the user closed the dialog */ - DefaultApplication.prototype.saveDialog = function(file, win, saveAs, cb) { - var self = this; - var value = win.getFileData(); + saveDialog(file, win, saveAs, cb) { + const value = win.getFileData(); if ( !saveAs ) { this.saveFile(file, value, win); return; } - API.createDialog('File', { + DialogWindow.create('File', { file: file, filename: file ? file.filename : this.defaultOptions.filename, filetypes: this.defaultOptions.filetypes, @@ -216,70 +204,56 @@ extension: this.defaultOptions.extension, mime: this.defaultOptions.mime, type: 'save' - }, function(ev, button, result) { + }, (ev, button, result) => { if ( button === 'ok' ) { - self.saveFile(result, value, win); + this.saveFile(result, value, win); } if (typeof cb === 'function') { cb(ev, button, result); } }, {parent: win, modal: true}); - }; + } /** * Open Open dialog * - * @function openDialog - * @memberof OSjs.Helpers.DefaultApplication# - * - * @param {OSjs.VFS.File} [file] Current File - * @param {OSjs.Core.Window} [win] Window reference + * @param {FileMetadata} [file] Current File + * @param {Window} [win] Window reference */ - DefaultApplication.prototype.openDialog = function(file, win) { - var self = this; + openDialog(file, win) { - function openDialog() { - API.createDialog('File', { + const openDialog = () => { + DialogWindow.create('File', { file: file, - filter: self.__metadata.mime - }, function(ev, button, result) { + filter: this.__metadata.mime + }, (ev, button, result) => { if ( button === 'ok' && result ) { - self.openFile(new VFS.File(result), win); + this.openFile(new FileMetadata(result), win); } }, {parent: win, modal: true}); - } + }; - win.checkHasChanged(function(discard) { + win.checkHasChanged((discard) => { if ( discard ) { openDialog(); } }); - }; + } /** * Create a new file * - * @function newDialog - * @memberof OSjs.Helpers.DefaultApplication# - * - * @param {String} [path] Current path - * @param {OSjs.Core.Window} [win] Window reference + * @param {String} [path] Current path + * @param {Window} [win] Window reference */ - DefaultApplication.prototype.newDialog = function(path, win) { - var self = this; - win.checkHasChanged(function(discard) { + newDialog(path, win) { + win.checkHasChanged((discard) => { if ( discard ) { - self._setArgument('file', null); + this._setArgument('file', null); win.showFile(null, null); } }); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.DefaultApplication = DefaultApplication; + } -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.API, OSjs.GUI); +} diff --git a/src/client/javascript/helpers/event-handler.js b/src/client/javascript/helpers/event-handler.js index 7ca9e62b1f..695612ced4 100644 --- a/src/client/javascript/helpers/event-handler.js +++ b/src/client/javascript/helpers/event-handler.js @@ -28,27 +28,19 @@ * @licence Simplified BSD License */ -(function(Utils, API, GUI, Window) { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// +/** + * Event Handler Class + * + * @desc + * This class just holds a map of events that you can trigger. + */ +export default class EventHandler { /** - * Event Handler Class - * - * This class just holds a map of events that you can trigger. - * - * @summary Helper for handling events. - * * @param {String} name A name (identifier) * @param {Array} names List of initial event names - * - * @constructor - * @memberof OSjs.Helpers */ - function EventHandler(name, names) { + constructor(name, names) { this.name = name; this.events = {}; @@ -59,18 +51,15 @@ console.debug('EventHandler::constructor()', this.events); } - EventHandler.prototype.destroy = function() { + destroy() { this.events = {}; - }; + } /** * Register an event * * You can also give a RegExp pattern as a name to match multiple entries, * as well as a comma separated string. - * - * @function on - * @memberof OSjs.Helpers.EventHandler# * @throws {Error} On invalid callback * * @param {String} name Event name @@ -79,25 +68,24 @@ * * @return {Number} */ - EventHandler.prototype.on = function(name, cb, thisArg) { + on(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 = []; + const added = []; - function _register(n) { - if ( !(self.events[n] instanceof Array) ) { - self.events[n] = []; + const _register = (n) => { + if ( !(this.events[n] instanceof Array) ) { + this.events[n] = []; } - added.push(self.events[n].push(function(args) { + added.push(this.events[n].push((args) => { return cb.apply(thisArg, args); })); - } + }; if ( name instanceof RegExp ) { Object.keys(this.events).forEach(function(n) { @@ -112,19 +100,17 @@ } return added.length === 1 ? added[0] : added; - }; + } /** * Unregister an event * - * @function off - * @memberof OSjs.Helpers.EventHandler# * @throws {Error} On event name * * @param {String} name Event name * @param {Number} index Event index (as returned by on()) */ - EventHandler.prototype.off = function(name, index) { + off(name, index) { if ( !(this.events[name] instanceof Array) ) { throw new TypeError('Invalid event name'); } @@ -134,20 +120,17 @@ } else { this.events[name] = []; } - }; + } /** * Fire an event * - * @function emit - * @memberof OSjs.Helpers.EventHandler# - * * @param {String} name Event name * @param {Array} args List of arguments to send to .apply() * * @return {Boolean} If none of the handlers returned false */ - EventHandler.prototype.emit = function(name, args) { + emit(name, args) { args = args || []; if ( !(this.events[name] instanceof Array) ) { @@ -155,7 +138,7 @@ } return (this.events[name]).every(function(fn) { - var result; + let result; try { result = fn(args); } catch ( e ) { @@ -165,12 +148,6 @@ return typeof result === 'undefined' || result === true; }); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.EventHandler = EventHandler; + } +} -})(OSjs.Utils, OSjs.API, OSjs.GUI, OSjs.Core.Window); diff --git a/src/client/javascript/helpers/google-api.js b/src/client/javascript/helpers/google-api.js index c679f08467..39f0e0e06c 100644 --- a/src/client/javascript/helpers/google-api.js +++ b/src/client/javascript/helpers/google-api.js @@ -27,47 +27,41 @@ * @author Anders Evenrud * @licence Simplified BSD License */ +import MountManager from 'core/mount-manager'; +import ServiceNotificationIcon from 'helpers/service-notification-icon'; +import Preloader from 'utils/preloader'; +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; +import jsonp from 'then-jsonp'; -(function(Utils, API) { - 'use strict'; +const gapi = window.gapi = window.gapi || {}; - /** - * @namespace GoogleAPI - * @memberof OSjs.Helpers - */ - - var gapi = window.gapi = window.gapi || {}; +///////////////////////////////////////////////////////////////////////////// +// API +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// +let SingletonInstance = null; - var SingletonInstance = null; +/** + * The GoogleAPI wrapper class + * + *

+ * Generally you want to create an instance of this helper
+ * and when successfully created use `window.gapi`.
+ * 
+ * + * @desk Helper for communicating with Google API. + * + * @link https://developers.google.com/api-client-library/javascript/start/start-js + * @link https://developers.google.com/api-client-library/javascript/ + * @link https://console.developers.google.com/project + */ +class GoogleAPI { /** - * The GoogleAPI wrapper class - * - *

-   * Generally you want to create an instance of this helper
-   * and when successfully created use `window.gapi`.
-   *
-   * This is a private class and can only be aquired through
-   * OSjs.Helpers.GoogleAPI.createInsatance()
-   * 
- * - * @summary Helper for communicating with Google API. - * - * @constructor Class - * @memberof OSjs.Helpers.GoogleAPI - * @see OSjs.Helpers.GoogleAPI.createInsatance - * * @param {String} clientId Client ID (key) - * - * @link https://developers.google.com/api-client-library/javascript/start/start-js - * @link https://developers.google.com/api-client-library/javascript/ - * @link https://console.developers.google.com/project */ - function GoogleAPI(clientId) { + constructor(clientId) { this.clientId = clientId; this.accessToken = null; this.userId = null; @@ -85,64 +79,60 @@ /* * Destroy the class */ - GoogleAPI.prototype.destroy = function() { - }; + destroy() { + } /* * Initializes (preloads) the API */ - GoogleAPI.prototype.init = function(callback) { - var self = this; - + init(callback) { callback = callback || function() {}; if ( this.preloaded ) { callback(false, true); } else { - Utils.preload(this.preloads, function(total, failed) { - if ( !failed.length ) { - self.preloaded = true; + Preloader.preload(this.preloads).then((result) => { + if ( result.failed.length ) { + this.preloaded = true; } - callback(failed.join('\n')); - }); + callback(result.failed.join('\n')); + }).catch(callback); } - }; + } /* * Loads the API */ - GoogleAPI.prototype.load = function(load, scope, client, callback) { - var self = this; - - function auth(cb) { - self.authenticate(scope, function(error, result) { + load(load, scope, client, callback) { + const auth = (cb) => { + this.authenticate(scope, (error, result) => { if ( error ) { cb(error); } else { - if ( !self.authenticated ) { - cb(API._('GAPI_AUTH_FAILURE')); + if ( !this.authenticated ) { + cb(_('GAPI_AUTH_FAILURE')); return; } cb(false, result); } }); - } + }; - function loadAll(finished) { - var lload = []; - load.forEach(function(i) { - if ( self.loaded.indexOf(i) === -1 ) { + const loadAll = (finished) => { + const lload = []; + load.forEach((i) => { + if ( this.loaded.indexOf(i) === -1 ) { lload.push(i); } }); - var current = 0; - var total = lload.length; + let current = 0; + let total = lload.length; console.debug('GoogleAPI::load()', load, '=>', lload, scope); - function _load(iter, cb) { - var args = []; - var name = null; + const _load = (iter, cb) => { + let args = []; + let name = null; if ( iter instanceof Array ) { if ( iter.length > 0 && iter.length < 3 ) { @@ -154,11 +144,11 @@ name = iter; } - args.push(function() { - self.loaded.push(name); + args.push((a, b, c, d) => { + this.loaded.push(name); /* eslint no-invalid-this: "off" */ - cb.apply(this, arguments); + cb.call(this, a, b, c, d); }); if ( client ) { @@ -166,13 +156,13 @@ } else { gapi.load.apply(gapi, args); } - } + }; function _next() { if ( current >= total ) { finished(); } else { - _load(lload[current], function() { + _load(lload[current], () => { _next(); }); @@ -181,42 +171,39 @@ } _next(); - } + }; - this.init(function(error) { + this.init((error) => { if ( error ) { callback(error); return; } if ( !window.gapi || !gapi.load ) { - callback(API._('GAPI_LOAD_FAILURE')); + callback(_('GAPI_LOAD_FAILURE')); return; } - auth(function(error) { + auth((error) => { if ( error ) { callback(error); return; } - loadAll(function(error, result) { + loadAll((error, result) => { callback(error, result, SingletonInstance); }); }); }); - }; + } /** * Sign out of GoogleAPI * - * @function signOut - * @memberof OSjs.Helpers.GoogleAPI.Class# - * * @param {Function} cb Callback => fn(error, result) */ - GoogleAPI.prototype.signOut = function(cb) { + signOut(cb) { cb = cb || function() {}; console.info('GoogleAPI::signOut()'); @@ -230,26 +217,20 @@ this.authenticated = false; - var ring = API.getServiceNotificationIcon(); - if ( ring ) { - ring.remove('Google API'); - } + ServiceNotificationIcon.remove('Google API'); } - OSjs.Core.getMountManager().remove('GoogleDrive'); + MountManager.remove('GoogleDrive'); cb(false, true); - }; + } /** * Revoke Google permissions for this app * - * @function revoke - * @memberof OSjs.Helpers.GoogleAPI.Class# - * * @param {Function} callback Callback => fn(error, result) */ - GoogleAPI.prototype.revoke = function(callback) { + revoke(callback) { console.info('GoogleAPI::revoke()'); if ( !this.accessToken ) { @@ -257,179 +238,137 @@ return; } - 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); - } - }); - }; + const url = 'https://accounts.google.com/o/oauth2/revoke?token=' + this.accessToken; + jsonp('GET', url).then(() => callback(true)).catch(() => callback(false)); + } /* * Authenticates the user */ - GoogleAPI.prototype.authenticate = function(scope, callback) { + authenticate(scope, callback) { console.info('GoogleAPI::authenticate()'); callback = callback || function() {}; - var self = this; - - function getUserId(cb) { + const getUserId = (cb) => { cb = cb || function() {}; - gapi.client.load('oauth2', 'v2', function() { - gapi.client.oauth2.userinfo.get().execute(function(resp) { + gapi.client.load('oauth2', 'v2', () => { + gapi.client.oauth2.userinfo.get().execute((resp) => { console.info('GoogleAPI::authenticate() => getUserId()', resp); cb(resp.id); }); }); - } + }; - function login(immediate, cb) { + const login = (immediate, cb) => { console.info('GoogleAPI::authenticate() => login()', immediate); cb = cb || function() {}; gapi.auth.authorize({ - client_id: self.clientId, + client_id: this.clientId, scope: scope, - user_id: self.userId, + user_id: this.userId, immediate: immediate }, cb); - } + }; - function createRingNotification() { - var ring = API.getServiceNotificationIcon(); - if ( ring ) { - ring.remove('Google API'); + const createRingNotification = () => { + ServiceNotificationIcon.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(); - }); - } - }]); - } - } + ServiceNotificationIcon.add('Google API', [{ + title: _('GAPI_SIGN_OUT'), + onClick: () => { + this.signOut(); + } + }, { + title: _('GAPI_REVOKE'), + onClick: () => { + this.revoke(() => { + this.signOut(); + }); + } + }]); + }; - var handleAuthResult = function(authResult, immediate) { + const handleAuthResult = (authResult, immediate) => { console.info('GoogleAPI::authenticate() => handleAuthResult()', authResult); 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); + const msg = _('GAPI_AUTH_FAILURE_FMT', authResult.error, authResult.error_subtype); callback(msg); return; } } if ( authResult && !authResult.error ) { - getUserId(function(id) { - self.userId = id; + getUserId((id) => { + this.userId = id; if ( id ) { createRingNotification(); - self.authenticated = true; - self.accessToken = authResult.access_token || null; + this.authenticated = true; + this.accessToken = authResult.access_token || null; callback(false, true); } else { callback(false, false); } }); } else { - login(false, function(res) { + login(false, (res) => { handleAuthResult(res, false); }); } }; - gapi.load('auth:client', function(result) { + gapi.load('auth:client', (result) => { if ( result && result.error ) { - var msg = API._('GAPI_AUTH_FAILURE_FMT', result.error, result.error_subtype); + const msg = _('GAPI_AUTH_FAILURE_FMT', result.error, result.error_subtype); callback(msg); return; } - login(true, function(res) { + login(true, (res) => { handleAuthResult(res, true); }); }); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.GoogleAPI = OSjs.Helpers.GoogleAPI || {}; + } +} - /** - * Gets the currently running instance - * - * @function getInstance - * @memberof OSjs.Helpers.GoogleAPI - * - * @return {OSjs.Helpers.GoogleAPI.Class} Can also be null - */ - OSjs.Helpers.GoogleAPI.getInstance = function() { - return SingletonInstance; - }; +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// - /** - * Create an instance of GoogleAPI - * - * @example - * The 'load' Array can be filled with either strings, or arrays. ex: - * - ['drive-realtime', 'drive-share'] - * - [['calendar', 'v1'], 'drive-share'] - * - * @function createInstance - * @memberof OSjs.Helpers.GoogleAPI - * - * @param {Object} args Arguments - * @param {Array} args.load What functions/apis to load - * @param {Array} args.scope What scopes to load - * @param {boolean} [args.client=false] Load using gapi.client WILL BE REPLACED! - * @param {Function} callback Callback function => fn(error, instance) - */ - OSjs.Helpers.GoogleAPI.createInstance = function(args, callback) { - var load = args.load || []; - var scope = args.scope || []; - var client = args.client === true; +export function instance() { + return SingletonInstance; +} - function _run() { - SingletonInstance.load(load, scope, client, callback); - } +export function create(args, callback) { + const load = args.load || []; + const scope = args.scope || []; + const client = args.client === true; - if ( SingletonInstance ) { - _run(); - return; - } + function _run() { + SingletonInstance.load(load, scope, client, callback); + } - var clientId = null; - try { - clientId = API.getConfig('GoogleAPI.ClientId'); - } catch ( e ) { - console.warn('getGoogleAPI()', e, e.stack); - } + if ( SingletonInstance ) { + _run(); + return; + } - if ( !clientId ) { - callback(API._('GAPI_DISABLED')); - return; - } + let clientId = null; + try { + clientId = getConfig('GoogleAPI.ClientId'); + } catch ( e ) { + console.warn('getGoogleAPI()', e, e.stack); + } - SingletonInstance = new GoogleAPI(clientId); - _run(); - }; + if ( !clientId ) { + callback(_('GAPI_DISABLED')); + return; + } -})(OSjs.Utils, OSjs.API); + SingletonInstance = new GoogleAPI(clientId); + _run(); +} diff --git a/src/server/node/core/storage.js b/src/client/javascript/helpers/hooks.js similarity index 50% rename from src/server/node/core/storage.js rename to src/client/javascript/helpers/hooks.js index 353cd7b626..a682e0467b 100644 --- a/src/server/node/core/storage.js +++ b/src/client/javascript/helpers/hooks.js @@ -13,7 +13,7 @@ * 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 + * 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 @@ -27,66 +27,80 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -/*eslint strict:["error", "global"]*/ -'use strict'; - -const _settings = require('./settings.js'); -const _env = require('./env.js'); - -const _logger = require('./../lib/logger.js'); -const _utils = require('./../lib/utils.js'); +const _hooks = { + 'onInitialize': [], + 'onInited': [], + 'onSessionLoaded': [], + 'onShutdown': [], + 'onApplicationLaunch': [], + 'onApplicationLaunched': [], + 'onBlurMenu': [] +}; /** - * @namespace core.storage + * Get all hooks + * @param {String} name Hook name + * @return {Map} */ - -let MODULE; +export function getHooks(name) { + return _hooks[name]; +} /** - * Loads the Storage module + * Method for triggering a hook * - * @param {Object} opts Initial options - * - * @function load - * @memberof core.storage - * @return {Promise} + * @param {String} name Hook name + * @param {Array} args List of arguments + * @param {Object} thisarg 'this' ref */ -module.exports.load = function(opts) { - return new Promise((resolve, reject) => { - const config = _settings.get(); - const name = opts.STORAGE || (config.storage || 'demo'); - const ok = () => resolve(opts); - - _utils.loadModule(_env.get('MODULEDIR'), 'storage', name).then((path) => { - _logger.lognt('INFO', 'Loading:', _logger.colored('Storage', 'bold'), path.replace(_env.get('ROOTDIR'), '')); +export function triggerHook(name, args, thisarg) { + thisarg = thisarg || OSjs; + args = args || []; - try { - const a = require(path); - const c = _settings.get('modules.storage')[name] || {}; - const r = a.register(c); - MODULE = a; - - if ( r instanceof Promise ) { - r.then(ok).catch(reject); - } else { - ok(); + 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); } - } catch ( e ) { - _logger.lognt('WARN', _logger.colored('Warning:', 'yellow'), e); - console.warn(e.stack); - reject(e); + } else { + console.warn('No such Hook', name); } - }).catch(reject); - }); -}; + }); + } +} /** - * Gets the Storage module + * Method for adding a hook * - * @function get - * @memberof core.storage - * @return {Object} + * @param {String} name Hook name + * @param {Function} fn Callback => fn() + * + * @return {Number} The index of hook */ -module.exports.get = function() { - return MODULE; -}; +export function addHook(name, fn) { + if ( typeof _hooks[name] !== 'undefined' ) { + return _hooks[name].push(fn) - 1; + } + return -1; +} + +/** + * Method for removing a hook + * + * @param {String} name Hook name + * @param {Number} index Hook index + * + * @return {Boolean} + */ +export function removeHook(name, index) { + if ( typeof _hooks[name] !== 'undefined' ) { + if ( _hooks[name][index] ) { + _hooks[name][index] = null; + return true; + } + } + return false; +} diff --git a/src/client/javascript/helpers/iframe-application-window.js b/src/client/javascript/helpers/iframe-application-window.js new file mode 100644 index 0000000000..6e6ce2ac5e --- /dev/null +++ b/src/client/javascript/helpers/iframe-application-window.js @@ -0,0 +1,189 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +import Window from 'core/window'; + +let IFRAME_COUNT = 0; + +/** + * IFrame Application Window constructor + * + * @desc + *

+ * This class is a basic implementation of Window
+ * that uses Iframe as window content. It's usefull for creating
+ * applications that is not using OS.js API.
+ *
+ * You can use this in combination with 'IFrameApplication'
+ * 
+ * + * @link https://manual.os-js.org/packages/iframe/ + */ +export default class IFrameApplicationWindow extends Window { + + /** + * @param {String} name Window name + * @param {Object} opts Window options + * @param {String} opts.src The Iframe source + * @param {String} opts.icon The Icon relative/absolute path (./ for app dir) + * @param {String} opts.title The Window title + * @param {Application} app The Application reference + */ + constructor(name, opts, app) { + opts = Object.assign({}, { + src: 'about:blank', + focus: function() {}, + blur: function() {}, + icon: null, + title: 'IframeApplicationWindow', + width: 320, + height: 240, + allow_resize: false, + allow_restore: false, + allow_maximize: false + }, opts); + + super('IFrameApplicationWindow', opts, app); + + this._iwin = null; + this._frame = null; + } + + destroy() { + this.postMessage('Window::destroy'); + return super.destroy(...arguments); + } + + init(wmRef, app) { + const root = super.init(...arguments); + root.style.overflow = 'visible'; + + const id = 'IframeApplicationWindow' + IFRAME_COUNT.toString(); + const iframe = document.createElement('iframe'); + iframe.setAttribute('border', 0); + iframe.id = id; + iframe.className = 'IframeApplicationFrame'; + iframe.addEventListener('load', () => { + this._iwin = iframe.contentWindow; + this.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; + } + + _blur() { + if ( super._blur(...arguments) ) { + if ( this._iwin ) { + this._iwin.blur(); + } + if ( this._frame ) { + this._frame.blur(); + } + + this._opts.blur(this._frame, this._iwin); + return true; + } + return false; + } + + _focus() { + if ( super._focus(...arguments) ) { + if ( this._iwin ) { + this._iwin.focus(); + } + if ( this._frame ) { + this._frame.focus(); + } + this._opts.focus(this._frame, this._iwin); + return true; + } + return false; + } + + /** + * Post a message to IFrame Application + * + * @param {*} message The message + */ + postMessage(message) { + if ( this._iwin && this._app ) { + console.debug('IFrameApplicationWindow::postMessage()', message); + this._iwin.postMessage({ + message: message, + pid: this._app.__pid, + wid: this._wid + }, window.location.href); + } + } + + /** + * When Window receives a message from IFrame Application + * + * @param {*} message The message + * @param {Event} ev DOM Event + */ + onPostMessage(message, ev) { + console.debug('IFrameApplicationWindow::onPostMessage()', message); + } + + /** + * Set Iframe source + * + * @param {String} src Source + * @param {Element} iframe Iframe element + */ + setLocation(src, iframe) { + iframe = iframe || this._frame; + + const oldbefore = window.onbeforeunload; + window.onbeforeunload = null; + iframe.src = src; + window.onbeforeunload = oldbefore; + } + +} diff --git a/src/client/javascript/helpers/iframe-application.js b/src/client/javascript/helpers/iframe-application.js index 53aeb05959..2ce985f585 100644 --- a/src/client/javascript/helpers/iframe-application.js +++ b/src/client/javascript/helpers/iframe-application.js @@ -28,251 +28,75 @@ * @licence Simplified BSD License */ -(function(Application, Window, Utils, VFS, GUI) { - 'use strict'; +import IFrameApplicationWindow from 'helpers/iframe-application-window'; +import Application from 'core/application'; - var IFRAME_COUNT = 0; +///////////////////////////////////////////////////////////////////////////// +// IFrame Application Helper +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // Iframe Application Window Helper - ///////////////////////////////////////////////////////////////////////////// - - /** - * IFrame Application Window constructor - * - *

-   * This class is a basic implementation of OSjs.Core.Window
-   * that uses Iframe as window content. It's usefull for creating
-   * applications that is not using OS.js API.
-   *
-   * You can use this in combination with 'IFrameApplication'
-   * 
- * - * @summary Helper for making IFrame Applications. - * - * @param {String} name Window name - * @param {Object} opts Window options - * @param {String} opts.src The Iframe source - * @param {String} opts.icon The Icon relative/absolute path (./ for app dir) - * @param {String} opts.title The Window title - * @param {OSjs.Core.Application} app The Application reference - * - * @constructor - * @memberof OSjs.Helpers - * @see OSjs.Core.Window - * - * @link https://os-js.org/manual/package/iframe/ - */ - function IFrameApplicationWindow(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; - }; - - /** - * Post a message to IFrame Application - * - * @function postMessage - * @memberof OSjs.Helpers.IframeApplicationWindow# - * - * @param {Mixed} message The message - */ - IFrameApplicationWindow.prototype.postMessage = function(message) { - if ( this._iwin && this._app ) { - console.debug('IFrameApplicationWindow::postMessage()', message); - this._iwin.postMessage({ - message: message, - pid: this._app.__pid, - wid: this._wid - }, window.location.href); - } - }; - - /** - * When Window receives a message from IFrame Application - * - * @function onPostMessage - * @memberof OSjs.Helpers.IframeApplicationWindow# - * - * @param {Mixed} message The message - * @param {Event} ev DOM Event - */ - IFrameApplicationWindow.prototype.onPostMessage = function(message, ev) { - console.debug('IFrameApplicationWindow::onPostMessage()', message); - }; - - /** - * Set Iframe source - * - * @function setLocation - * @memberof OSjs.Helpers.IframeApplicationWindow# - * - * @param {String} src Source - * @param {Element} iframe Iframe element - */ - IFrameApplicationWindow.prototype.setLocation = function(src, iframe) { - iframe = iframe || this._frame; - - var oldbefore = window.onbeforeunload; - window.onbeforeunload = null; - iframe.src = src; - window.onbeforeunload = oldbefore; - }; - - ///////////////////////////////////////////////////////////////////////////// - // IFrame Application Helper - ///////////////////////////////////////////////////////////////////////////// +/** + * IFrame Application constructor + * + * @desc + *

+ * Usage: Just apply the correct options and this should work
+ * automatically.
+ *
+ * This just inits an empty application with a window that uses
+ * iframe for contents. Look at the IFrameApplicationWindow
+ * constructor for more options you can apply here.
+ * 
+ */ +export default class IFrameApplication extends Application { /** - * IFrame Application constructor - * - *

-   * Usage: Just apply the correct options and this should work
-   * automatically.
-   *
-   * This just inits an empty application with a window that uses
-   * iframe for contents. Look at the IFrameApplicationWindow
-   * constructor for more options you can apply here.
-   * 
+ * This is an Iframe Window * - * @summary Helper for making IFrame Applications. + * See `Window` for more options * * @param {String} name Process name * @param {Object} args Process arguments * @param {Object} metadata Application metadata * @param {Object} opts Application options - * @param {String} opts.icon Window Icon - * @param {String} opts.title Window Title - * - * @constructor - * @memberof OSjs.Helpers - * @see OSjs.Core.Application + * @param {Object} opts.src Iframe Source */ - function IFrameApplication(name, args, metadata, opts) { - Application.call(this, name, args, metadata); + constructor(name, args, metadata, opts) { + super(...arguments); - this.options = Utils.argumentDefaults(opts, { + this.options = Object.assign({}, { icon: '', title: 'IframeApplicationWindow' - }); + }, opts); this.options.src = this._getResource(this.options.src); } - IFrameApplication.prototype = Object.create(Application.prototype); + init(settings, metadata) { + super.init(...arguments); - 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); - }; + const name = this.__pname + 'Window'; + this._addWindow(new IFrameApplicationWindow(name, this.options, this)); + } /** * When Application receives a message from IFrame * - * @alias OSjs.Helpers.IframeApplicationWindow#onPostMessage + * @alias IFrameApplicationWindow#onPostMessage * - * @param {Mixed} message The message - * @param {Event} ev DOM Event + * @param {*} message The message + * @param {Event} ev DOM Event */ - IFrameApplication.prototype.onPostMessage = function(message, ev) { + onPostMessage(message, ev) { console.debug('IFrameApplication::onPostMessage()', message); - var self = this; - - function _response(err, res) { - self.postMessage({ + const _response = (err, res) => { + this.postMessage({ id: message.id, method: message.method, error: err, - result: Utils.cloneObject(res) + result: Object.assign({}, res) }); - } + }; if ( typeof message.id === 'number' && message.method ) { if ( this[message.method] ) { @@ -281,25 +105,18 @@ _response('No such method'); } } - }; + } /** - * @param {Mixed} message The message - * @alias OSjs.Helpers.IframeApplicationWindow#postMessage + * @param {*} message The message + * @alias IFrameApplicationWindow#postMessage */ - IFrameApplication.prototype.postMessage = function(message) { - var win = this._getMainWindow(); + postMessage(message) { + const win = this._getMainWindow(); if ( win ) { win.postMessage(message); } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.IFrameApplication = IFrameApplication; - OSjs.Helpers.IFrameApplicationWindow = IFrameApplicationWindow; + } -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.VFS, OSjs.GUI); +} diff --git a/src/build/cli.js b/src/client/javascript/helpers/loader.js similarity index 55% rename from src/build/cli.js rename to src/client/javascript/helpers/loader.js index 0b23b4896f..f73785f32a 100644 --- a/src/build/cli.js +++ b/src/client/javascript/helpers/loader.js @@ -27,57 +27,62 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -/*eslint strict:["error", "global"]*/ -'use strict'; +class Loader { -const _fs = require('fs'); -const _path = require('path'); -const _build = require('./index.js'); -const _utils = require('./utils.js'); -const _minimist = require('minimist'); + constructor() { + this.loaders = {}; + this.loaderGraze = {}; + this.$container = document.createElement('osjs-loaders'); + } -module.exports.run = function(args, done) { - args = _minimist(args); + /** + * Create (or show) loading indicator + * + * @param {String} name Name of notification (unique) + * @param {Object} opts Options + */ + create(name, opts) { + opts = opts || {}; + if ( !this.$container.parentNode ) { + document.body.appendChild(this.$container); + } - if ( process.argv.length < 3 || args.help ) { - console.log(_fs.readFileSync(_path.join(__dirname, 'help.txt'), 'utf-8')); - done(true); - return; - } + if ( this.loaders[name] ) { + return; + } - _build._init(); + const el = document.createElement('osjs-loading'); + el.title = opts.title || ''; + if ( opts.icon ) { + const img = document.createElement('img'); + img.src = opts.icon; + el.appendChild(img); + } + this.$container.appendChild(el); + + this.loaderGraze[name] = setTimeout(() => { + el.style.display = 'inline-block'; + }, 100); - const actions = args._.map((iter) => { - let action = iter.trim().split(':'); - let task = action[0]; - let arg = action[1]; + this.loaders[name] = el; + } - if ( task.substr(0, 1) === '_' || !_build[task] ) { - console.error('Invalid task', task); - return done(true); + /** + * Destroy (or hide) loading indicator + * + * @param {String} name Name of notification (unique) + */ + destroy(name) { + if ( !this.loaders[name] ) { + return; } - return [task, arg]; - }); + clearTimeout(this.loaderGraze[name]); - process.on('uncaughtException', (error) => { - console.error('An uncaught exception occured', error); - console.error(error.stack); - done(true); - }); + this.loaders[name].remove(); + delete this.loaders[name]; + delete this.loaderGraze[name]; + } - _utils.eachp(actions.map((action) => { - return function() { - return _build[action[0]]({ - option: function(k, d) { - return typeof args[k] === 'undefined' ? d : args[k]; - } - }, action[1]); - }; - })).then(() => { - done(); - }).catch((err) => { - console.error(err); - done(err); - }); -}; +} +export default (new Loader()); diff --git a/src/client/javascript/helpers/service-notification-icon.js b/src/client/javascript/helpers/service-notification-icon.js new file mode 100644 index 0000000000..ee557ec7b1 --- /dev/null +++ b/src/client/javascript/helpers/service-notification-icon.js @@ -0,0 +1,125 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +import Notification from 'gui/notification'; +import Theme from 'core/theme'; +import * as Menu from 'gui/menu'; +import {_} from 'core/locales'; + +/* + * Service Notification Icon Class + */ +class ServiceNotificationIcon { + + constructor() { + this.entries = {}; + this.size = 0; + this.notif = null; + } + + init() { + const show = (ev) => { + this.displayMenu(ev); + return false; + }; + + this.notif = Notification.createIcon('ServiceNotificationIcon', { + image: Theme.getIcon('status/dialog-password.png'), + onContextMenu: show, + onClick: show, + onInited: (el, img) => { + this._updateIcon(); + } + }); + + this._updateIcon(); + } + + /* + * Destroys the notification icon + */ + destroy() { + Notification.destroyIcon('ServiceNotificationIcon'); + + this.size = 0; + this.entries = {}; + this.notif = null; + } + + _updateIcon() { + if ( this.notif ) { + if ( this.notif.$container ) { + this.notif.$container.style.display = this.size ? 'inline-block' : 'none'; + } + this.notif.setTitle(_('SERVICENOTIFICATION_TOOLTIP', this.size.toString())); + } + } + + displayMenu(ev) { + const menu = []; + const entries = this.entries; + + Object.keys(entries).forEach((name) => { + menu.push({ + title: name, + menu: entries[name] + }); + }); + + Menu.create(menu, ev); + } + + /* + * Adds an entry + */ + add(name, menu) { + if ( !this.entries[name] ) { + this.entries[name] = menu; + + this.size++; + this._updateIcon(); + } + } + + /* + * Removes an entry + */ + remove(name) { + if ( this.entries[name] ) { + delete this.entries[name]; + this.size--; + this._updateIcon(); + } + } + +} + +export default (new ServiceNotificationIcon()); + diff --git a/src/client/javascript/helpers/settings-fragment.js b/src/client/javascript/helpers/settings-fragment.js index 6bc080185a..0b2b36c841 100644 --- a/src/client/javascript/helpers/settings-fragment.js +++ b/src/client/javascript/helpers/settings-fragment.js @@ -28,32 +28,33 @@ * @licence Simplified BSD License */ -(function(Utils) { - 'use strict'; +import {mergeObject} from 'utils/misc'; - ///////////////////////////////////////////////////////////////////////////// - // Settings Fragment. - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// Settings Fragment. +///////////////////////////////////////////////////////////////////////////// + +/** + * Settings Fragment Class + * + * @desc + *

+ * This is the object returned when manipulating with SettingsManager.
+ * 
+ * + * @throws {Error} If an invalid object was given + */ +export default class SettingsFragment { /** - * Settings Fragment Class - * - *

-   * This is the object returned when manipulating with SettingsManager.
-   * 
- * - * @summary This is the class returned from SettingsManager getters. - * @throws {Error} If an invalid object was given - * - * @param {Object} obj Settings tree - * @param {String} poolName Name of the pool - * - * @constructor - * @memberof OSjs.Helpers - * @see OSjs.Core.SettingsManager + * @param {Object} obj Settings tree + * @param {String} poolName Name of the pool + * @param {SettingsManager} sm SettigsManager instance */ - function SettingsFragment(obj, poolName) { + constructor(obj, poolName, sm) { + this._sm = sm; this._pool = poolName; + if ( obj.constructor !== {}.constructor ) { if ( !(obj instanceof Array) ) { throw new Error('SettingsFragment will not work unless you give it a object to manage.'); @@ -66,39 +67,33 @@ /** * Gets setting(s) by key * - * @function get - * @memberof OSjs.Helpers.SettingsFragment# + * @param {String} [key] Name of key + * @param {*} [defaultValue] Default value if result is undefined * - * @param {String} [key] Name of key - * @param {Mixed} [defaultValue] Default value if result is undefined - * - * @return {Mixed} Either an entry or entire tree + * @return {*} Either an entry or entire tree */ - SettingsFragment.prototype.get = function(key, defaultValue) { - var ret = key ? this._settings[key] : this._settings; + get(key, defaultValue) { + const ret = key ? this._settings[key] : this._settings; return (typeof ret === 'undefined') ? defaultValue : ret; - }; + } /** * Sets setting(s) by key/value * * If you set `key` to `null` you will write to the tree root. * - * @function set - * @memberof OSjs.Helpers.SettingsFragment# + * @param {String|Number} [key] The key + * @param {Object|*} value The value + * @param {Boolean|Function} save Saves the pool (either boolean or callback function) + * @param {Boolean} [triggerWatch=true] Trigger change event for watchers * - * @param {Mixed} key The key - * @param {Mixed} value The value - * @param {Mixed} save Saves the pool (either boolean or callback function) - * @param {Boolean} [triggerWatch=true] Trigger change event for watchers - * - * @return {OSjs.Helpers.SettingsFragment} Itself `this` + * @return {SettingsFragment} Itself `this` */ - SettingsFragment.prototype.set = function(key, value, save, triggerWatch) { + set(key, value, save, triggerWatch) { // Key here is actually the value // So you can update the whole object if you want. if ( key === null ) { - Utils.mergeObject(this._settings, value); + mergeObject(this._settings, value); } else { if ( (['number', 'string']).indexOf(typeof key) >= 0 ) { this._settings[key] = value; @@ -107,34 +102,31 @@ } } - if (save) { - OSjs.Core.getSettingsManager().save(this._pool, save); + if ( save ) { + this._sm.save(this._pool, save); } if ( typeof triggerWatch === 'undefined' || triggerWatch === true ) { - OSjs.Core.getSettingsManager().changed(this._pool); + this._sm.changed(this._pool); } return this; - }; + } /** * Saves the pool - * - * @function save - * @memberof OSjs.Helpers.SettingsFragment# - * @see OSjs.Core.SettingsManager#save + * @see SettingsManager#save * * @param {Function} [callback] Callback function * - * @return Boolean + * @return {Promise} */ - SettingsFragment.prototype.save = function(callback) { - return OSjs.Core.getSettingsManager().save(this._pool, callback); - }; + save(callback) { + return this._sm.save(this._pool, callback); + } - SettingsFragment.prototype.getChained = function() { - var nestedSetting = this._settings; + getChained() { + let nestedSetting = this._settings; arguments.every(function(key) { if (nestedSetting[key]) { nestedSetting = nestedSetting[key]; @@ -145,46 +137,35 @@ }); return nestedSetting; - }; + } /** * Merges given tree with current one * - * @function mergeDefaults - * @memberof OSjs.Helpers.SettingsFragment# - * * @param {Object} defaults The tree * - * @return {OSjs.Helpers.SettingsFragment} Itself `this` + * @return {SettingsFragment} Itself `this` */ - SettingsFragment.prototype.mergeDefaults = function(defaults) { - Utils.mergeObject(this._settings, defaults, {overwrite: false}); + mergeDefaults(defaults) { + mergeObject(this._settings, defaults, {overwrite: false}); return this; - }; + } /** * Creates a new SettingsFragment instance from given key - * - * @function instance - * @memberof OSjs.Helpers.SettingsFragment# * @throws {Error} If the given key does not exist * * @param {String} key Key name * - * @return {OSjs.Helpers.SettingsFragment} New instance + * @return {SettingsFragment} New instance */ - SettingsFragment.prototype.instance = function(key) { + instance(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); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// + return new SettingsFragment(this._settings[key], this._pool, this._sm); + } - OSjs.Helpers.SettingsFragment = SettingsFragment; +} -})(OSjs.Utils); diff --git a/src/client/javascript/helpers/window-behaviour.js b/src/client/javascript/helpers/window-behaviour.js new file mode 100644 index 0000000000..086d406a69 --- /dev/null +++ b/src/client/javascript/helpers/window-behaviour.js @@ -0,0 +1,387 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import * as Menu from 'gui/menu'; +import * as DOM from 'utils/dom'; +import * as Events from 'utils/events'; +import Theme from 'core/theme'; + +/* + * Holds information about current behaviour + */ +class BehaviourState { + constructor(wm, win, action, mousePosition) { + 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 + }; + + const theme = Object.assign({}, Theme.getStyleTheme(true, true)); + if ( !theme.style ) { + theme.style = {'window': {margin: 0, border: 0}}; + } + + this.theme = { + topMargin: theme.style.window.margin || 0, // FIXME + 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; + + const windowRects = []; + wm.getWindows().forEach((w) => { + if ( w && w._wid !== win._wid ) { + const pos = w._position; + const dim = w._dimension; + const rect = { + left: pos.x - this.theme.borderSize, + top: pos.y - this.theme.borderSize, + width: dim.w + (this.theme.borderSize * 2), + height: dim.h + (this.theme.borderSize * 2) + this.theme.topMargin + }; + + rect.right = rect.left + rect.width; + rect.bottom = (pos.y + dim.h) + this.theme.topMargin + this.theme.borderSize;//rect.top + rect.height; + + windowRects.push(rect); + } + }); + + this.snapRects = windowRects; + } + + getRect() { + const win = this.win; + + return { + left: win._position.x, + top: win._position.y, + width: win._dimension.w, + height: win._dimension.h + }; + } + + calculateDirection() { + const dir = DOM.$position(this.$handle); + const dirX = this.startX - dir.left; + const dirY = this.startY - dir.top; + const dirD = 20; + + const 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)) + }; + + let direction = 's'; + Object.keys(checks).forEach(function(k) { + if ( checks[k] ) { + direction = k; + } + }); + + this.direction = direction; + } +} + +/* + * Window Behavour Abstraction + */ +export function createWindowBehaviour(win, wm) { + let current = null; + let newRect = {}; + + /* + * Resizing action + */ + function onWindowResize(ev, mousePosition, dx, dy) { + if ( !current || !current.direction ) { + return false; + } + + let 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; + } + + /* + * Movement action + */ + function onWindowMove(ev, mousePosition, dx, dy) { + let newWidth = null; + let newHeight = null; + let newLeft = current.rectWindow.x + dx; + let newTop = current.rectWindow.y + dy; + + const borderSize = current.theme.borderSize; + const topMargin = current.theme.topMargin; + const cornerSnapSize = current.snapping.cornerSize; + const windowSnapSize = current.snapping.windowSize; + + if ( newTop < current.rectWorkspace.top ) { + newTop = current.rectWorkspace.top; + } + + let newRight = newLeft + current.rectWindow.w + (borderSize * 2); + let newBottom = newTop + current.rectWindow.h + topMargin + (borderSize); + + // 8-directional corner window snapping + 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; + } + } + + // Snapping to other windows + 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}; + } + + /* + * When mouse button is released + */ + 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; + } + + /* + * When mouse is moved + */ + function onMouseMove(ev, action, win, mousePosition) { + if ( !wm.getMouseLocked() || !action || !current ) { + return; + } + + ev.preventDefault(); + + let result; + + const dx = mousePosition.x - current.startX; + const 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; + } + + /* + * When mouse button is pressed + */ + function onMouseDown(ev, action, win, mousePosition) { + Menu.blur(); + ev.preventDefault(); + + if ( win._state.maximized ) { + return; + } + + current = new BehaviourState(wm, 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'); + + function _onMouseMove(ev, pos) { + if ( wm._mouselock ) { + onMouseMove(ev, action, win, pos); + } + } + function _onMouseUp(ev, pos) { + onMouseUp(ev, action, win, pos); + Events.$unbind(document, 'mousemove:movewindow'); + Events.$unbind(document, 'mouseup:movewindowstop'); + } + + Events.$bind(document, 'mousemove:movewindow', _onMouseMove, false); + Events.$bind(document, 'mouseup:movewindowstop', _onMouseUp, false); + } + + /* + * Register a window + */ + if ( win._properties.allow_move ) { + Events.$bind(win._$top, 'mousedown', (ev, pos) => { + onMouseDown(ev, 'move', win, pos); + }, true); + } + if ( win._properties.allow_resize ) { + Events.$bind(win._$resize, 'mousedown', (ev, pos) => { + onMouseDown(ev, 'resize', win, pos); + }); + } +} diff --git a/src/client/javascript/helpers/windows-live-api.js b/src/client/javascript/helpers/windows-live-api.js index 6d2398a4b6..bfbf08b138 100644 --- a/src/client/javascript/helpers/windows-live-api.js +++ b/src/client/javascript/helpers/windows-live-api.js @@ -28,50 +28,43 @@ * @licence Simplified BSD License */ -(function(Utils, API) { - 'use strict'; +import MountManager from 'core/mount-manager'; +import ServiceNotificationIcon from 'helpers/service-notification-icon'; +import Preloader from 'utils/preloader'; +import {_} from 'core/locales'; +import {getConfig} from 'core/config'; - /** - * @namespace OSjs.Helpers.WindowsLiveAPI - * @memberof OSjs.Helpers - */ +const redirectURI = window.location.href.replace(/\/$/, '') + '/windows-live-oauth.html'; - var redirectURI = window.location.href.replace(/\/$/, '') + '/vendor/wlOauthReceiver.html'; +///////////////////////////////////////////////////////////////////////////// +// API +///////////////////////////////////////////////////////////////////////////// - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// +let SingletonInstance = null; - var SingletonInstance = null; +/** + * The WindowsLiveAPI wrapper class + * + * @desc Helper for communicating with Windows Live API. + *

+ * Generally you want to create an instance of this helper
+ * and when successfully created use `window.WL`.
+ * 
+ * + * @link http://msdn.microsoft.com/en-us/library/hh826547.aspx + * @link http://msdn.microsoft.com/en-us/library/hh826538.aspx + * @link http://msdn.microsoft.com/en-us/library/hh550837.aspx + * @link http://msdn.microsoft.com/en-us/library/dn631844.aspx + * @link http://msdn.microsoft.com/en-us/library/dn631839.aspx + * @link http://msdn.microsoft.com/en-us/library/hh243643.aspx + * @link https://account.live.com/developers/applications/index + */ +class WindowsLiveAPI { /** - * The WindowsLiveAPI wrapper class - * - *

-   * This is a private class and can only be aquired through
-   * OSjs.Helpers.WindowsLiveAPI.createInsatance()
-   *
-   * Generally you want to create an instance of this helper
-   * and when successfully created use `window.WL`.
-   * 
- * - * @summary Helper for communicating with Windows Live API. - * - * @constructor Class - * @memberof OSjs.Helpers.WindowsLiveAPI - * @see OSjs.Helpers.WindowsLiveAPI.createInsatance - * * @param {String} clientId Client ID (key) - * - * @link http://msdn.microsoft.com/en-us/library/hh826547.aspx - * @link http://msdn.microsoft.com/en-us/library/hh826538.aspx - * @link http://msdn.microsoft.com/en-us/library/hh550837.aspx - * @link http://msdn.microsoft.com/en-us/library/dn631844.aspx - * @link http://msdn.microsoft.com/en-us/library/dn631839.aspx - * @link http://msdn.microsoft.com/en-us/library/hh243643.aspx - * @link https://account.live.com/developers/applications/index */ - function WindowsLiveAPI(clientId) { + constructor(clientId) { this.hasSession = false; this.clientId = clientId; this.loaded = false; @@ -87,95 +80,93 @@ /* * Destroy the class */ - WindowsLiveAPI.prototype.destroy = function() { - }; + destroy() { + } /* * Initializes (preloads) the API */ - WindowsLiveAPI.prototype.init = function(callback) { + init(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; + Preloader.preload(this.preloads).then((result) => { + if ( !result.failed.length ) { + this.loaded = true; } - callback(failed.join('\n')); - }); + callback(result.failed.join('\n')); + }).catch(() => callback()); } - }; + } /* * Loads the API */ - WindowsLiveAPI.prototype.load = function(scope, callback) { + load(scope, callback) { console.debug('WindowsLiveAPI::load()', scope); - var self = this; - var WL = window.WL || {}; + let WL = window.WL || {}; - function _login() { - var lastScope = (self.lastScope || []).sort(); - var currScope = (scope || []).sort(); + const _login = () => { + const lastScope = (this.lastScope || []).sort(); + const currScope = (scope || []).sort(); - if ( self.hasSession && (lastScope.toString() === currScope.toString()) ) { + if ( this.hasSession && (lastScope.toString() === currScope.toString()) ) { callback(false, true); return; } - self.login(scope, function(error, response) { + this.login(scope, (error, response) => { if ( error ) { callback(error); return; } - setTimeout(function() { + setTimeout(() => { callback(false, true); }, 10); }); - } + }; - this.init(function(error) { + this.init((error) => { if ( error ) { callback(error); return; } if ( !window.WL ) { - callback(API._('WLAPI_LOAD_FAILURE')); + callback(_('WLAPI_LOAD_FAILURE')); return; } WL = window.WL || {}; - if ( self.inited ) { + if ( this.inited ) { _login(); } else { - self.inited = true; - WL.Event.subscribe('auth.login', function() { - self.onLogin.apply(self, arguments); + this.inited = true; + WL.Event.subscribe('auth.login', (a, b, c, d) => { + this.onLogin(a, b, c, d); }); - WL.Event.subscribe('auth.logout', function() { - self.onLogout.apply(self, arguments); + WL.Event.subscribe('auth.logout', (a, b, c, d) => { + this.onLogout(a, b, c, d); }); - WL.Event.subscribe('wl.log', function() { - self.onLog.apply(self, arguments); + WL.Event.subscribe('wl.log', (a, b, c, d) => { + this.onLog(a, b, c, d); }); - WL.Event.subscribe('auth.sessionChange', function() { - self.onSessionChange.apply(self, arguments); + WL.Event.subscribe('auth.sessionChange', (a, b, c, d) => { + this.onSessionChange(a, b, c, d); }); WL.init({ - client_id: self.clientId, + client_id: this.clientId, display: 'popup', redirect_uri: redirectURI - }).then(function(result) { + }).then((result) => { console.debug('WindowsLiveAPI::load()', '=>', result); if ( result.session ) { - self.accessToken = result.session.access_token || null; + this.accessToken = result.session.access_token || null; } if ( result.status === 'connected' ) { @@ -183,44 +174,37 @@ } else if ( result.status === 'success' ) { _login(); } else { - callback(API._('WLAPI_INIT_FAILED_FMT', result.status.toString())); + callback(_('WLAPI_INIT_FAILED_FMT', result.status.toString())); } - }, function(result) { + }, (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'); - } - }; + _removeRing() { + ServiceNotificationIcon.remove('Windows Live API'); + } /** * Sign out of WindowsLiveAPI * - * @function logout - * @memberof OSjs.Helpers.WindowsLiveAPI.Class# - * * @param {Function} callback Callback => fn(error, result) */ - WindowsLiveAPI.prototype.logout = function(callback) { + logout(callback) { callback = callback || function() {}; - var self = this; - var WL = window.WL || {}; + const WL = window.WL || {}; if ( this.hasSession ) { callback(false, false); } WL.Event.unsubscribe('auth.logout'); - WL.Event.subscribe('auth.logout', function() { - self._removeRing(); + WL.Event.subscribe('auth.logout', () => { + this._removeRing(); WL.Event.unsubscribe('auth.logout'); callback(false, true); @@ -228,14 +212,14 @@ WL.logout(); - OSjs.Core.getMountManager().remove('OneDrive'); - }; + MountManager.remove('OneDrive'); + } /* * Authenticates the user */ - WindowsLiveAPI.prototype.login = function(scope, callback) { - var WL = window.WL || {}; + login(scope, callback) { + const WL = window.WL || {}; if ( this.hasSession ) { callback(false, true); @@ -245,123 +229,99 @@ WL.login({ scope: scope, redirect_uri: redirectURI - }).then(function(result) { + }).then((result) => { if ( result.status === 'connected' ) { callback(false, true); } else { - callback(API._('WLAPI_LOGIN_FAILED')); + callback(_('WLAPI_LOGIN_FAILED')); } - }, function(result) { - callback(API._('WLAPI_LOGIN_FAILED_FMT', result.error_description)); + }, (result) => { + callback(_('WLAPI_LOGIN_FAILED_FMT', result.error_description)); }); - }; + } /* * If the API session was changed */ - WindowsLiveAPI.prototype.onSessionChange = function() { + onSessionChange() { console.warn('WindowsLiveAPI::onSessionChange()', arguments); - var WL = window.WL || {}; - var session = WL.getSession(); + const WL = window.WL || {}; + const session = WL.getSession(); if ( session ) { this.hasSession = true; } else { this.hasSession = false; } - }; + } /* * When user logged in */ - WindowsLiveAPI.prototype.onLogin = function() { + onLogin() { 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(); - } - }]); - } - }; + ServiceNotificationIcon.add('Windows Live API', [{ + title: _('WLAPI_SIGN_OUT'), + onClick: () => { + this.logout(); + } + }]); + } /* * When user logs out */ - WindowsLiveAPI.prototype.onLogout = function() { + onLogout() { console.warn('WindowsLiveAPI::onLogout()', arguments); this.hasSession = false; this._removeRing(); - }; + } /* * When API sends a log message */ - WindowsLiveAPI.prototype.onLog = function() { + onLog() { console.debug('WindowsLiveAPI::onLog()', arguments); - }; + } - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// +} - OSjs.Helpers.WindowsLiveAPI = OSjs.Helpers.WindowsLiveAPI || {}; +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// - /** - * Gets the currently running instance - * - * @function getInstance - * @memberof OSjs.Helpers.WindowsLiveAPI - * - * @return {OSjs.Helpers.WindowsLiveAPI.Class} Can also be null - */ - OSjs.Helpers.WindowsLiveAPI.getInstance = function() { - return SingletonInstance; - }; +export function instance() { + return SingletonInstance; +} - /** - * Create an instance of WindowsLiveAPI - * - * @function createInstance - * @memberof OSjs.Helpers.WindowsLiveAPI - * - * @param {Object} args Arguments - * @param {Array} args.load What functions/apis to load - * @param {Function} callback Callback function => fn(error, instance) - */ - 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); - }); - } +export function create(args, callback) { + args = args || {}; - if ( SingletonInstance ) { - _run(); - return; - } + function _run() { + const scope = args.scope; + SingletonInstance.load(scope, (error) => { + callback(error ? error : false, SingletonInstance); + }); + } - var clientId = null; - try { - clientId = API.getConfig('WindowsLiveAPI.ClientId'); - } catch ( e ) { - console.warn('getWindowsLiveAPI()', e, e.stack); - } + if ( SingletonInstance ) { + _run(); + return; + } - if ( !clientId ) { - callback(API._('WLAPI_DISABLED')); - return; - } + let clientId = null; + try { + clientId = getConfig('WindowsLiveAPI.ClientId'); + } catch ( e ) { + console.warn('getWindowsLiveAPI()', e, e.stack); + } - SingletonInstance = new WindowsLiveAPI(clientId); - _run(); - }; + if ( !clientId ) { + callback(_('WLAPI_DISABLED')); + return; + } -})(OSjs.Utils, OSjs.API); + SingletonInstance = new WindowsLiveAPI(clientId); + _run(); +} diff --git a/src/client/javascript/helpers/zip-archiver.js b/src/client/javascript/helpers/zip-archiver.js deleted file mode 100644 index 5c5816a45d..0000000000 --- a/src/client/javascript/helpers/zip-archiver.js +++ /dev/null @@ -1,639 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -(function(Utils, API, VFS) { - 'use strict'; - - /** - * @namespace ZipArchiver - * @memberof OSjs.Helpers - */ - - 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) { - console.log('-->', 'openFile()'); - - VFS.download(file, function(error, data) { - if ( error ) { - console.warn('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 || []; - - console.log('-->', 'importFiles()', entries); - - 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; - } - - console.log('Importing', index, current); - - 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) { - console.log('-->', 'createZip()'); - - var writer = new zip.BlobWriter(); - zip.createWriter(writer, function(writer) { - done(false, writer); - }, function(error) { - done(error); - }); - } - - function saveZip(writer, file, ccb) { - console.log('-->', 'saveZip()'); - - 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}); - }); - } - - ///////////////////////////////////////////////////////////////////////////// - // API - ///////////////////////////////////////////////////////////////////////////// - - var SingletonInstance = null; - - /** - * The GoogleAPI wrapper class - * - *

-   * This is a private class and can only be aquired through
-   * OSjs.Helpers.ZipArchiver.createInsatance()
-   *
-   * Generally you want to create an instance of this helper
-   * and when successfully created use `window.zip` use the instance helpers.
-   * 
- * - * @summary Helper for handling ZIP files. - * - * @example - * OSjs.Helpers.ZipArchiver.createInstance({}, (err, instance) => {}); - * - * @param {Object} opts Options - * - * @constructor Class - * @memberof OSjs.Helpers.ZipArchiver - * @see OSjs.Helpers.ZipArchiver.createInsatance - */ - 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(); - }); - }; - - /** - * Lists contents of a ZIP file - * - * @function list - * @memberof OSjs.Helpers.ZipArchiver.Class# - * - * @param {OSjs.VFS.File} file File to extract - * @param {Function} cb Callback function => fn(error, entries) - */ - 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); - }); - }); - }; - - /** - * Create a new blank ZIP file - * - * @function create - * @memberof OSjs.Helpers.ZipArchiver.Class# - * - * @param {OSjs.VFS.File} file File to extract - * @param {Function} cb Callback function => fn(error) - * @param {OSjs.Core.Application} [appRef] Application reference - */ - 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}); - }); - }); - }; - - /** - * Add a entry to the ZIP file - * - * @function add - * @memberof OSjs.Helpers.ZipArchiver.Class# - * @TODO Adding directory does not actually add files inside dirs yet - * - * @param {OSjs.VFS.File} file Archive File - * @param {OSjs.VFS.File} add File to add - * @param {Object} args Arguments - * @param {String} [args.path=/] Root path to add to - * @param {Function} args.onprogress Callback on progress => fn(state[, args, ...]) - * @param {Function} args.oncomplete Callback on complete => fn(error, result) - */ - ZipArchiver.prototype.add = function(file, add, args) { - var cb = args.oncomplete || function() {}; - var pr = args.onprogress || function() {}; - var currentDir = args.path || '/'; - - console.group('ZipArchiver::add()'); - console.log('Archive', file); - console.log('Add', file); - - function finished(err, res) { - console.groupEnd(); - cb(err, res); - } - - function checkIfExists(entries, done) { - console.log('-->', 'checkIfExists()'); - - 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'); - - console.log('-->', 'addFile()', filename, type, add); - - filename = ((currentDir || '/').replace(/\/$/, '') + '/' + filename).replace(/^\//, ''); - - function _addBlob(blob) { - console.log('-->', 'addFile()', '-->', '_addBlob()'); - - writer.add(filename, new zip.BlobReader(blob), function() { - console.log('ADDED FILE', filename); - - saveZip(writer, file, done); - }, function(current, total) { - pr('compressing', current); - }); - } - - function _addFolder() { - console.log('-->', 'addFile()', '-->', '_addFolder()'); - writer.add(filename, null, function() { - console.log('ADDED FOLDER', filename); - - 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); - }); - } - } - } - - // Proceed! - 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); - }); - }); - }); - }); - }); - - }; - - /** - * Removes an entry from ZIP file - * - * @function remove - * @memberof OSjs.Helpers.ZipArchiver.Class# - * - * @param {OSjs.VFS.File} file Archive File - * @param {String} path Path - * @param {Function} cb Callback function => fn(err, result) - */ - ZipArchiver.prototype.remove = function(file, path, cb) { - - console.group('ZipArchiver::remove()'); - console.log('Archive', file); - console.log('Remove', path); - - function finished(err, res, writer) { - if ( err || !writer ) { - console.groupEnd(); - cb(err || API._('ZIP_NO_RESOURCE')); - return; - } - - saveZip(writer, file, function(eer, rees) { - console.groupEnd(); - 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]); - }); - }); - }; - - /** - * Extract a File to destination - * - * @function extract - * @memberof OSjs.Helpers.ZipArchiver.Class# - * - * @param {OSjs.VFS.File} file File to extract - * @param {String} destination Destination path - * @param {Object} args Arguments - * @param {Function} args.onprogress Callback on progress => fn(filename, currentIndex, totalIndex) - * @param {Function} args.oncomplete Callback on complete => fn(error, warnings, result) - * @param {OSjs.Core.Application} [args.app] Application reference - */ - ZipArchiver.prototype.extract = function(file, destination, args) { - args = args || {}; - - args.onprogress = args.onprogress || function(/*filename, current, total*/) {}; - args.oncomplete = args.oncomplete || function(/*error, warnings, result*/) {}; - - console.group('ZipArchiver::extract()'); - console.log('Archive', file); - console.log('Destination', destination); - - function finished(error, warnings, result) { - if ( !error ) { - API.message('vfs:update', destination, {source: args.app ? args.app.__pid : null}); - } - - console.groupEnd(); - args.oncomplete(error, warnings, result); - } - - var extracted = []; - var warnings = []; - var total = 0; - - function _extractList(list, destination) { - total = list.length; - console.debug('ZipArchiver::extract()', 'Extracting', total, 'item(s)'); - - 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); - } - } - - console.log('Extract', item, dest); - 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) { - console.log('....', 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() { - console.log('Extract finished', total, 'total', extracted.length, 'extracted', extracted); - console.log(warnings.length, 'warnings', warnings); - finished(false, warnings, true); - } - - function _next() { - if ( !list.length || index >= list.length ) { - _finished(); - return; - } - - _extract(list[index], function() { - index++; - _next(); - }); - } - - _next(); - } - - function _checkDirectory(destination, cb) { - console.debug('ZipArchiver::extract()', 'Checking destination'); - - 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'); - } - }); - }); - } - - console.debug('ZipArchiver::extract()', 'Downloading file...'); - - 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); - }); - }); - }); - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Helpers.ZipArchiver = OSjs.Helpers.ZipArchiver || {}; - - /** - * Gets the currently running instance - * - * @function getInstance - * @memberof OSjs.Helpers.ZipArchiver - * - * @return {OSjs.Helpers.ZipArchiver.Class} Can also be null - */ - OSjs.Helpers.ZipArchiver.getInstance = function() { - return SingletonInstance; - }; - - /** - * Create an instance of ZipArchiver - * - * @function createInstance - * @memberof OSjs.Helpers.ZipArchiver - * - * @param {Object} args Arguments - * @param {Function} callback Callback function => fn(error, instance) - */ - 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); diff --git a/src/client/javascript/locales/ar_DZ.js b/src/client/javascript/locales/ar_DZ.js index daab042320..2d716485a8 100644 --- a/src/client/javascript/locales/ar_DZ.js +++ b/src/client/javascript/locales/ar_DZ.js @@ -28,428 +28,424 @@ * @author Mohammed Seddik Laraba * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.ar_DZ = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'خطأ فتح الملف', - 'ERR_WM_NOT_RUNNING' : 'مسيير النوافذ ليس قيد التشغيل', - 'ERR_FILE_OPEN_FMT' : ' الملف \'**{0}**\' غير قابل للفتح من طرف النظام', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'لم يتمكن النظام من إيجاد تطبيق يدعم هذه الملفات \'{0}\' files', - 'ERR_APP_LAUNCH_FAILED' : 'خطأ في تشغيل التطبيق', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'حدث خطأ أثناء محاولة التشغيل: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'التطبيق \'{0}\' construct فشل: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'التطبيق \'{0}\' init() فشل: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'موارد التطبيق ناقصة لـ \'{0}\' أو لم تتمكن من التشغيل!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'التطبيق \'{0}\' preloading failed: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'The application \'{0}\' is already launched and allows only one instance!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'خطأ في تشغيل \'{0}\'. لا توجد تعاريف للتطبيق!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'خطأ في تشغيل \'{0}\'. متصفحك غير مدعوم: {1}', - - 'ERR_NO_WM_RUNNING' : 'لايوجد أي مسيير نوافذ قيد التشغيل', - 'ERR_CORE_INIT_FAILED' : 'Failed to initialize OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'حدث خطأ أثناء بداية تشغيل OS.js', - 'ERR_CORE_INIT_NO_WM' : 'لا يمكن تشغيل OS.js: لايوجد مسيير نوافذ!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'لايمكن تشغيل OS.js: فشل في تحميل مسير النوافذ: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'لايمكن تشغيل OS.js: فشل في تحميل الموارد...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript إشعار بخطأ', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'خطأ غير متوقع.', - - 'ERR_APP_API_ERROR' : 'خطأ في API التطبيق ', - 'ERR_APP_API_ERROR_DESC_FMT' : 'التطبيق {0} لم يستطيع أن يقوم بالعملية \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'نقص في لعناصر : {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'خطأ غير معروف', - - 'ERR_OPERATION_TIMEOUT' : 'نهاية الوقت المسموع للعملية', - 'ERR_OPERATION_TIMEOUT_FMT' : 'نهاية الوقت المسموح للعملية ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' متوقع \'{1}\' أن تكون \'{2}\', \'{3}\' معطى', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'لديك نافذة مسبقا بإسم \'{0}\'', - 'WINDOW_MINIMIZE' : 'تصغير', - 'WINDOW_MAXIMIZE' : 'تكبير', - 'WINDOW_RESTORE' : 'إستعادة', - 'WINDOW_CLOSE' : 'إغلاق', - 'WINDOW_ONTOP_ON' : 'فوق الجميع (تشغيل)', - 'WINDOW_ONTOP_OFF': 'فوق الجميع (تعطيل)', - - // Handler - 'TITLE_SIGN_OUT' : 'تسجيل الخروج', - 'TITLE_SIGNED_IN_AS_FMT' : 'متصل بإسم: {0}', - 'ERR_LOGIN_FMT' : 'خطأ تسجيل الدخول: {0}', - 'ERR_LOGIN_INVALID' : 'تسجيل دخول غير موجود', - - // SESSION - 'ERR_NO_SESSION': 'لا توجد أي حصة منشأة، هل تريد التجربة مرة أخرى ؟', - 'MSG_SESSION_WARNING' : 'هل تريد بالتأكيد الخروج من OS.js ؟ جميع التغيرات الغير محفوظة ستلغى !', - - // Service - 'BUGREPORT_MSG' : 'الرجاء إشعارنا إذا ضننت أن هذا خطأ،\n أضف شرح قصير حول كيفية حدوث الخطأ، وإن أمكن كيفية إعادة إستحداث الخطأ مرة أخرى', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'تسجيل دخول إلى خدمات خارجية: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'خطأ مميت', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR خطأ: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'تسجيل الخروج (خروج)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'خروج المستخدم \'{0}\'.\nهل تريد بالتأكيد إنهاء الحصة الجارية?', - - 'DIALOG_CLOSE' : 'إغلاق', - 'DIALOG_CANCEL': 'إلغاء', - 'DIALOG_APPLY' : 'تطبيق', - 'DIALOG_OK' : 'موافق', - - 'DIALOG_ALERT_TITLE' : 'نافذة التحذير', - - 'DIALOG_COLOR_TITLE' : 'نافذة الألوان', - 'DIALOG_COLOR_R' : 'أحمر: {0}', - 'DIALOG_COLOR_G' : 'أخضر: {0}', - 'DIALOG_COLOR_B' : 'أزرق: {0}', - 'DIALOG_COLOR_A' : 'ألفا: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'نافذة التأكيد', - - 'DIALOG_ERROR_MESSAGE' : 'رسالة', - 'DIALOG_ERROR_SUMMARY' : 'الحوصلة', - 'DIALOG_ERROR_TRACE' : 'إتباع', - 'DIALOG_ERROR_BUGREPORT' : 'إشعار بخطأ', - - 'DIALOG_FILE_SAVE' : 'حفظ', - 'DIALOG_FILE_OPEN' : 'فتح', - 'DIALOG_FILE_MKDIR' : 'مجلد جديد', - 'DIALOG_FILE_MKDIR_MSG' : 'إنشاء مجلد جديد في **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'هل تريد بالتأكيد تجاوز وإستبدال الملف \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'نوع المظهر', - 'DIALOG_FILE_MNU_LISTVIEW' : 'مظهر القائمة', - 'DIALOG_FILE_MNU_TREEVIEW' : 'مظهر الشجرة', - 'DIALOG_FILE_MNU_ICONVIEW' : 'مظهر الأيقونات', - 'DIALOG_FILE_ERROR' : 'خطأ نافذة الملفات', - 'DIALOG_FILE_ERROR_SCANDIR': 'فشل إظهار محتوي المجلد \'{0}\' بسبب حدوث خطأ', - 'DIALOG_FILE_ERROR_FIND': 'فشل البحث في المجلد \'{0}\' بسبب حدوث خطأ', - 'DIALOG_FILE_MISSING_FILENAME' : 'يجب إختيار ملف أو إدخال ملف جديد!', - 'DIALOG_FILE_MISSING_SELECTION': 'يجب إختيار ملف!', - - 'DIALOG_FILEINFO_TITLE' : 'معلومات الملف', - 'DIALOG_FILEINFO_LOADING' : 'تحميل معلومات الملف: {0}', - 'DIALOG_FILEINFO_ERROR' : 'نافذة معلومات الملف خطأ', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'فشل في تحديد معلومات الملف for **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'فشل في تحديد معلومات الملف for: {0}', - - 'DIALOG_INPUT_TITLE' : 'نافذة الإدخال', - - 'DIALOG_FILEPROGRESS_TITLE' : 'عملية على الملفات جارية', - 'DIALOG_FILEPROGRESS_LOADING' : 'تحميل...', - - 'DIALOG_UPLOAD_TITLE' : 'نافذة رفع الملفات', - 'DIALOG_UPLOAD_DESC' : 'رفم الملف إلى **{0}**.
حد الحجم: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'جاري الرفع \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'جاري رفع الملف...', - 'DIALOG_UPLOAD_FAILED' : 'رفع الملف', - 'DIALOG_UPLOAD_FAILED_MSG' : 'خطأ رفع الملف', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'أسباب غير معروفة...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'إلغي من طرف المستخدم...', - 'DIALOG_UPLOAD_TOO_BIG': 'ملف كبير جدا', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'ملف كبير جدا, تخطى {0}', - - 'DIALOG_FONT_TITLE' : 'نافذة الخطوط', - - 'DIALOG_APPCHOOSER_TITLE' : 'إختيار التطبيق', - 'DIALOG_APPCHOOSER_MSG' : 'إختار تطبيق لفتحه', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'يجب إختيار تطبيق', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'إستخدام كتطبيق إفتراضي دائم {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Module not configured or disabled', - 'GAPI_SIGN_OUT' : 'Sign out from Google API Services', - 'GAPI_REVOKE' : 'Revoke permissions and Sign Out', - 'GAPI_AUTH_FAILURE' : 'Google API Authentication failed or did not take place', - 'GAPI_AUTH_FAILURE_FMT' : 'Failed to authenticate: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Failed to load Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API module not configured or disabled', - 'WLAPI_SIGN_OUT' : 'Sign out from Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Failed to load Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Failed to log into Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Failed to log into Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'لا يمكن إنشاء IndexedDB دون إسم قاعدة معطيات', - 'IDB_NO_SUCH_ITEM' : 'عنصر غير موجود', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'خطأ مميت', - 'ERR_VFS_UNAVAILABLE' : 'غير متوفر', - 'ERR_VFS_FILE_ARGS' : 'ملف ينتظر على الأقل عنصر', - 'ERR_VFS_NUM_ARGS' : 'عدد العناصر غير كافي', - 'ERR_VFS_EXPECT_FILE' : 'متوقع ملف', - 'ERR_VFS_EXPECT_SRC_FILE' : 'متوقع مصدر الملف', - 'ERR_VFS_EXPECT_DST_FILE' : 'متوقع وجهة الملف', - 'ERR_VFS_FILE_EXISTS' : 'وجهة موجودة مسبقا', - 'ERR_VFS_TARGET_NOT_EXISTS': 'وجهة غير موجودة', - 'ERR_VFS_TRANSFER_FMT' : 'حدث خطأ أثناء التحويل من مساحات التخزين: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'لا يمكن رفع ملف من دون وجهة', - 'ERR_VFS_UPLOAD_NO_FILES' : 'لا يمكن رفع الملفات من دون تعيينها', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'خطأ رفع الملف: {0}', - 'ERR_VFS_UPLOAD_CANCELLED' : 'تك إلغاء رفع الملف', - 'ERR_VFS_DOWNLOAD_NO_FILE' : 'لا يمكن رفع مسار من دون مسار', - 'ERR_VFS_DOWNLOAD_FAILED' : 'حدث خطأ أثناء تحميل: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY' : 'الإجابة كانت فارغة', - - 'ERR_VFSMODULE_INVALID' : 'قسم VFS غير صحيح', - 'ERR_VFSMODULE_INVALID_FMT' : 'قسم VFS غير صحيح: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'قسم VFS طريقة', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'قسم VFS طريقة: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'نوع القسم VFS غير صحيح', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'نوع القسم VFS غير صحيح: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'إعدادات القسم VFS غير صحيحة', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'إعدادات القسم VFS إعدادات القسم: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'قسم VFS مركب مسبقا', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'قسم VFS \'{0}\' مركب مسبقا', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'قسم VFS غير مركب', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'قسم VFS \'{0}\' غير مركب', - 'ERR_VFSMODULE_EXCEPTION' : 'قسم VFS خطأ', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'قسم VFS خطأ: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'لا يوجد VFS {0}. خطأ في شاكلة المسار ?', - 'ERR_VFSMODULE_READONLY' : 'هذا VFS للقراءة فقط', - 'ERR_VFSMODULE_READONLY_FMT' : 'هذا VFS للقراءة فقط : {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'جاري تحميل الملف', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR خطأ', - 'ERR_VFSMODULE_ROOT_ID' : 'خطأ تحديد معرف root', - 'ERR_VFSMODULE_NOSUCH' : 'ملف غير موجود', - 'ERR_VFSMODULE_PARENT' : 'لا يوجد أب', - 'ERR_VFSMODULE_PARENT_FMT' : 'فشل البحث عن أب: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'فشل مسح المجلد', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'فشل مسح المجلد : {0}', - 'ERR_VFSMODULE_READ' : 'فشل قراءة الملف', - 'ERR_VFSMODULE_READ_FMT' : 'فشل قراءة الملف: {0}', - 'ERR_VFSMODULE_WRITE' : 'فشل الكتابة في الملف', - 'ERR_VFSMODULE_WRITE_FMT' : 'فشل الكتابة في الملف: {0}', - 'ERR_VFSMODULE_COPY' : 'فشل في النسخ', - 'ERR_VFSMODULE_COPY_FMT' : 'فشل في النسخ: {0}', - 'ERR_VFSMODULE_UNLINK' : 'فشل في حذف رابط الملف', - 'ERR_VFSMODULE_UNLINK_FMT' : 'فشل في حذف رابط الملف: {0}', - 'ERR_VFSMODULE_MOVE' : 'فشل في تحريك الملف', - 'ERR_VFSMODULE_MOVE_FMT' : 'فشل في تحريك الملف: {0}', - 'ERR_VFSMODULE_EXIST' : 'فشل في تحديد وجود الملف', - 'ERR_VFSMODULE_EXIST_FMT' : 'فشل في تحديد وجود الملف: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'فشل في تحديد معلومات الملف', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'فشل في تحديد معلومات الملف: {0}', - 'ERR_VFSMODULE_MKDIR' : 'فشل في إنشاء المجلد', - 'ERR_VFSMODULE_MKDIR_FMT' : 'فشل في إنشاء المجلد: {0}', - 'ERR_VFSMODULE_URL' : 'فشل في الحصول على رابط الملف', - 'ERR_VFSMODULE_URL_FMT' : 'فشل في الحصول على رابط الملف: {0}', - 'ERR_VFSMODULE_TRASH' : 'فشل في تحريك الملف إلى سلة المحذوفات', - 'ERR_VFSMODULE_TRASH_FMT' : 'فشل في تحريك الملف إلى سلة المحذوفات: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'فشل في تحريك الملف من سلة المحذوفات', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'فشل في تحريك الملف من سلة المحذوفات: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'فشل في تفريغ سلة المحذوفات', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'فشل في تفريغ سلة المحذوفات: {0}', - 'ERR_VFSMODULE_FIND' : 'فشل في البحث', - 'ERR_VFSMODULE_FIND_FMT' : 'فشل في البحث: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'فشل في الحصول على المساحة الفارغة', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'فشل في الحصول على المساحة الفارغة: {0}', - 'ERR_VFSMODULE_EXISTS' : 'فشل في التأكيد على الوجود', - 'ERR_VFSMODULE_EXISTS_FMT' : 'فشل في التأكيد على الوجود: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'أنت الآن مسجل في Dropbox API', - 'DROPBOX_SIGN_OUT' : 'خروج من Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'خطأ في تحديد المسار : لا يوجد أي عنصر', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'خطأ تحميل zip.js', - 'ZIP_VENDOR_FAIL' : 'zip.js غير موجود ?', - 'ZIP_NO_RESOURCE' : 'لا توجد أي موارد zip.', - 'ZIP_NO_PATH' : 'لم يعطى إي مسار', - - // - // SearchEngine - // - 'SEARCH_LOADING': 'جاري البحث...', - 'SEARCH_NO_RESULTS': 'لا توجد أي نتيجة', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'مجلد التثبيت موجود من قبل، من المستحيل المتابعة !', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'لا يمكن فتح الملف', - 'ERR_FILE_APP_OPEN_FMT' : 'الملف {0} غير قابل للفتح لأن التعريف {1} غير مدعوم', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'الملف {0} غير ممكن فتحه: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'الملف {0} غير ممكن حفظه: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} خطأ في التطبيق', - 'ERR_GENERIC_APP_ACTION_FMT': 'عدم التمكن من إنجاز العملية \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'خطأ غير معروف', - 'ERR_GENERIC_APP_REQUEST' : 'حدث خطأ أثناء إجراء العملية المطلوبة', - 'ERR_GENERIC_APP_FATAL_FMT' : 'خطأ مميت {0}', - 'MSG_GENERIC_APP_DISCARD' : 'إلغاء التغيرات ?', - 'MSG_FILE_CHANGED' : 'تم تغيير الملف، هل تريد التحديث', - 'MSG_APPLICATION_WARNING' : 'تحذير النطبيق', - 'MSG_MIME_OVERRIDE' : 'نوع الملف "{0}" غير مدعوم, إستخدم "{1}" في مكانه.', - - // - // General - // - - 'LBL_UNKNOWN' : 'غير معروف', - 'LBL_APPEARANCE' : 'مظهر', - 'LBL_USER' : 'مستخدم', - 'LBL_NAME' : 'إسم', - 'LBL_APPLY' : 'تطبيق', - 'LBL_FILENAME' : 'إسم الملف', - 'LBL_PATH' : 'مسار', - 'LBL_SIZE' : 'حجم', - 'LBL_TYPE' : 'نوع', - 'LBL_MIME' : 'التعريف', - 'LBL_LOADING' : 'جاري التحميل', - 'LBL_SETTINGS' : 'إعدادات', - 'LBL_ADD_FILE' : 'إضافة ملفات', - 'LBL_COMMENT' : 'تعليق', - 'LBL_ACCOUNT' : 'حساب', - 'LBL_CONNECT' : 'إتصال', - 'LBL_ONLINE' : 'متصل', - 'LBL_OFFLINE' : 'غير متصل', - 'LBL_AWAY' : 'بعيد', - 'LBL_BUSY' : 'مشغول', - 'LBL_CHAT' : 'دردشة', - 'LBL_HELP' : 'مساعدة', - 'LBL_ABOUT' : 'عن', - 'LBL_PANELS' : 'اللوحات', - 'LBL_LOCALES' : 'اللغة/المنطقة', - 'LBL_THEME' : 'القالب', - 'LBL_COLOR' : 'اللون', - 'LBL_PID' : 'رقم العملية', - 'LBL_KILL' : 'إنهاء', - 'LBL_ALIVE' : 'في الخدمة', - 'LBL_INDEX' : 'الرقم', - 'LBL_ADD' : 'إضافة', - 'LBL_FONT' : 'الخط', - 'LBL_YES' : 'نعم', - 'LBL_NO' : 'لا', - 'LBL_CANCEL' : 'إلغاء', - 'LBL_TOP' : 'أعلى', - 'LBL_LEFT' : 'اليسار', - 'LBL_RIGHT' : 'اليمين', - 'LBL_BOTTOM' : 'أسفل', - 'LBL_CENTER' : 'وسط', - 'LBL_FILE' : 'ملف', - 'LBL_NEW' : 'جديد', - 'LBL_OPEN' : 'فتح', - 'LBL_SAVE' : 'حفظ', - 'LBL_SAVEAS' : 'حفظ بإسم...', - 'LBL_CLOSE' : 'إغلاق', - 'LBL_MKDIR' : 'مجلد جديد', - 'LBL_UPLOAD' : 'رفع ملف', - 'LBL_VIEW' : 'إظهار', - 'LBL_EDIT' : 'تغيير', - 'LBL_RENAME' : 'إعادة تسمية', - 'LBL_DELETE' : 'حذف', - 'LBL_OPENWITH' : 'فتح بواسطة ...', - 'LBL_ICONVIEW' : 'إظهار كأيقونات', - 'LBL_TREEVIEW' : 'إظهار كشجرة', - 'LBL_LISTVIEW' : 'إظهار كقائمة', - 'LBL_REFRESH' : 'تحديث', - 'LBL_VIEWTYPE' : 'نوع المظهر', - 'LBL_BOLD' : 'غليظ', - 'LBL_ITALIC' : 'مائل', - 'LBL_UNDERLINE' : 'مسطر', - 'LBL_REGULAR' : 'عادي', - 'LBL_STRIKE' : 'مشطوب', - 'LBL_INDENT' : 'مساحة لأمام', - 'LBL_OUTDENT' : 'مساحة للخلف', - 'LBL_UNDO' : 'تراجع', - 'LBL_REDO' : 'إلى الأمام', - 'LBL_CUT' : 'قص', - 'LBL_UNLINK' : 'حذف الرابط', - 'LBL_COPY' : 'نسخ', - 'LBL_PASTE' : 'لصق', - 'LBL_INSERT' : 'إدراج', - 'LBL_IMAGE' : 'صورة', - 'LBL_LINK' : 'رابط', - 'LBL_DISCONNECT' : 'قطع الإتصال', - 'LBL_APPLICATIONS' : 'التطبيقات', - 'LBL_ADD_FOLDER' : 'إضافة مجلد', - 'LBL_INFORMATION' : 'معلومات', - 'LBL_TEXT_COLOR' : 'لون النص', - 'LBL_BACK_COLOR' : 'خلفية النص', - 'LBL_RESET_DEFAULT' : 'لإستعادة لإفتراضي', - 'LBL_DOWNLOAD_COMP' : 'تحميل إلى الكمبيوتر', - 'LBL_ORDERED_LIST' : 'ترتيب القائمة', - 'LBL_BACKGROUND_IMAGE' : 'صورة الخلفية', - 'LBL_BACKGROUND_COLOR' : 'لون الخلفية', - 'LBL_UNORDERED_LIST' : 'قائمة غير مرتبة', - 'LBL_STATUS' : 'الحالة', - 'LBL_READONLY' : 'قراءة-فقط', - 'LBL_CREATED' : 'تاريخ الإنشاء', - 'LBL_MODIFIED' : 'تاريخ التغيير', - 'LBL_SHOW_COLUMNS' : 'إظهار الأعمدة', - 'LBL_MOVE' : 'تحريك', - 'LBL_OPTIONS' : 'خيارات', - 'LBL_OK' : 'موافق', - 'LBL_DIRECTORY' : 'مجلد', - 'LBL_CREATE' : 'إنشاء', - 'LBL_BUGREPORT' : 'إشعار بخطأ', - 'LBL_INSTALL' : 'تثبيت', - 'LBL_UPDATE' : 'تحديث', - 'LBL_REMOVE' : 'إزالة', - 'LBL_SHOW_SIDEBAR' : 'إظهار الشريط الجانبي', - 'LBL_SHOW_NAVIGATION' : 'إظهار شريط الإنتقال', - 'LBL_SHOW_HIDDENFILES' : 'إظهار الملفات المخفية', - 'LBL_SHOW_FILEEXTENSIONS' : 'إظهار لواحق الملفات', - 'LBL_MOUNT': 'تركيب', - 'LBL_DESCRIPTION': 'الوصف', - 'LBL_USERNAME': 'المستخدم', - 'LBL_PASSWORD': 'كلمة المرور', - 'LBL_HOST': 'المستضيف', - 'LBL_NAMESPACE': 'إسم الساحة', - 'LBL_SEARCH': 'بحث', - 'LBL_Theme' : 'القالب', - 'LBL_SOUNDS' : 'أصوات', - 'LBL_ICONS' : 'أيقونات', - 'LBL_BACKGROUND' : 'خلفيات', - 'LBL_DESKTOP' : 'المكتب', - 'LBL_PANEL' : 'اللوحة', - 'LBL_POSITION' : 'الوصعية', - 'LBL_ONTOP' : 'في المقدمة', - 'LBL_ITEMS' : 'العناصر', - 'LBL_GENERAL' : 'عام', - 'LBL_DEBUG' : 'تصحيح', - 'LBL_AUTOHIDE' : 'إخفاء تلقائي', - 'LBL_OPACITY' : 'الشفافية', - 'LBL_PACKAGES' : 'الحزم', - 'LBL_GROUPS' : 'المجموعات', - 'LBL_VERSION' : 'الطبعة', - 'LBL_AUTHOR' : 'الكاتب', - 'LBL_HIDE' : 'إخفاء', - 'LBL_APPLICATION' : 'تطبيق', - 'LBL_SCOPE' : 'الزمرة' - }; - -})(); +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'خطأ فتح الملف', + 'ERR_WM_NOT_RUNNING' : 'مسيير النوافذ ليس قيد التشغيل', + 'ERR_FILE_OPEN_FMT' : ' الملف \'**{0}**\' غير قابل للفتح من طرف النظام', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'لم يتمكن النظام من إيجاد تطبيق يدعم هذه الملفات \'{0}\' files', + 'ERR_APP_LAUNCH_FAILED' : 'خطأ في تشغيل التطبيق', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'حدث خطأ أثناء محاولة التشغيل: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'التطبيق \'{0}\' construct فشل: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'التطبيق \'{0}\' init() فشل: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'موارد التطبيق ناقصة لـ \'{0}\' أو لم تتمكن من التشغيل!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'التطبيق \'{0}\' preloading failed: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'The application \'{0}\' is already launched and allows only one instance!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'خطأ في تشغيل \'{0}\'. لا توجد تعاريف للتطبيق!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'خطأ في تشغيل \'{0}\'. متصفحك غير مدعوم: {1}', + + 'ERR_NO_WM_RUNNING' : 'لايوجد أي مسيير نوافذ قيد التشغيل', + 'ERR_CORE_INIT_FAILED' : 'Failed to initialize OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'حدث خطأ أثناء بداية تشغيل OS.js', + 'ERR_CORE_INIT_NO_WM' : 'لا يمكن تشغيل OS.js: لايوجد مسيير نوافذ!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'لايمكن تشغيل OS.js: فشل في تحميل مسير النوافذ: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'لايمكن تشغيل OS.js: فشل في تحميل الموارد...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript إشعار بخطأ', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'خطأ غير متوقع.', + + 'ERR_APP_API_ERROR' : 'خطأ في API التطبيق ', + 'ERR_APP_API_ERROR_DESC_FMT' : 'التطبيق {0} لم يستطيع أن يقوم بالعملية \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'نقص في لعناصر : {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'خطأ غير معروف', + + 'ERR_OPERATION_TIMEOUT' : 'نهاية الوقت المسموع للعملية', + 'ERR_OPERATION_TIMEOUT_FMT' : 'نهاية الوقت المسموح للعملية ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' متوقع \'{1}\' أن تكون \'{2}\', \'{3}\' معطى', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'لديك نافذة مسبقا بإسم \'{0}\'', + 'WINDOW_MINIMIZE' : 'تصغير', + 'WINDOW_MAXIMIZE' : 'تكبير', + 'WINDOW_RESTORE' : 'إستعادة', + 'WINDOW_CLOSE' : 'إغلاق', + 'WINDOW_ONTOP_ON' : 'فوق الجميع (تشغيل)', + 'WINDOW_ONTOP_OFF': 'فوق الجميع (تعطيل)', + + // Handler + 'TITLE_SIGN_OUT' : 'تسجيل الخروج', + 'TITLE_SIGNED_IN_AS_FMT' : 'متصل بإسم: {0}', + 'ERR_LOGIN_FMT' : 'خطأ تسجيل الدخول: {0}', + 'ERR_LOGIN_INVALID' : 'تسجيل دخول غير موجود', + + // SESSION + 'ERR_NO_SESSION': 'لا توجد أي حصة منشأة، هل تريد التجربة مرة أخرى ؟', + 'MSG_SESSION_WARNING' : 'هل تريد بالتأكيد الخروج من OS.js ؟ جميع التغيرات الغير محفوظة ستلغى !', + + // Service + 'BUGREPORT_MSG' : 'الرجاء إشعارنا إذا ضننت أن هذا خطأ،\n أضف شرح قصير حول كيفية حدوث الخطأ، وإن أمكن كيفية إعادة إستحداث الخطأ مرة أخرى', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'تسجيل دخول إلى خدمات خارجية: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'خطأ مميت', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR خطأ: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'تسجيل الخروج (خروج)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'خروج المستخدم \'{0}\'.\nهل تريد بالتأكيد إنهاء الحصة الجارية?', + + 'DIALOG_CLOSE' : 'إغلاق', + 'DIALOG_CANCEL': 'إلغاء', + 'DIALOG_APPLY' : 'تطبيق', + 'DIALOG_OK' : 'موافق', + + 'DIALOG_ALERT_TITLE' : 'نافذة التحذير', + + 'DIALOG_COLOR_TITLE' : 'نافذة الألوان', + 'DIALOG_COLOR_R' : 'أحمر: {0}', + 'DIALOG_COLOR_G' : 'أخضر: {0}', + 'DIALOG_COLOR_B' : 'أزرق: {0}', + 'DIALOG_COLOR_A' : 'ألفا: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'نافذة التأكيد', + + 'DIALOG_ERROR_MESSAGE' : 'رسالة', + 'DIALOG_ERROR_SUMMARY' : 'الحوصلة', + 'DIALOG_ERROR_TRACE' : 'إتباع', + 'DIALOG_ERROR_BUGREPORT' : 'إشعار بخطأ', + + 'DIALOG_FILE_SAVE' : 'حفظ', + 'DIALOG_FILE_OPEN' : 'فتح', + 'DIALOG_FILE_MKDIR' : 'مجلد جديد', + 'DIALOG_FILE_MKDIR_MSG' : 'إنشاء مجلد جديد في **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'هل تريد بالتأكيد تجاوز وإستبدال الملف \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'نوع المظهر', + 'DIALOG_FILE_MNU_LISTVIEW' : 'مظهر القائمة', + 'DIALOG_FILE_MNU_TREEVIEW' : 'مظهر الشجرة', + 'DIALOG_FILE_MNU_ICONVIEW' : 'مظهر الأيقونات', + 'DIALOG_FILE_ERROR' : 'خطأ نافذة الملفات', + 'DIALOG_FILE_ERROR_SCANDIR': 'فشل إظهار محتوي المجلد \'{0}\' بسبب حدوث خطأ', + 'DIALOG_FILE_ERROR_FIND': 'فشل البحث في المجلد \'{0}\' بسبب حدوث خطأ', + 'DIALOG_FILE_MISSING_FILENAME' : 'يجب إختيار ملف أو إدخال ملف جديد!', + 'DIALOG_FILE_MISSING_SELECTION': 'يجب إختيار ملف!', + + 'DIALOG_FILEINFO_TITLE' : 'معلومات الملف', + 'DIALOG_FILEINFO_LOADING' : 'تحميل معلومات الملف: {0}', + 'DIALOG_FILEINFO_ERROR' : 'نافذة معلومات الملف خطأ', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'فشل في تحديد معلومات الملف for **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'فشل في تحديد معلومات الملف for: {0}', + + 'DIALOG_INPUT_TITLE' : 'نافذة الإدخال', + + 'DIALOG_FILEPROGRESS_TITLE' : 'عملية على الملفات جارية', + 'DIALOG_FILEPROGRESS_LOADING' : 'تحميل...', + + 'DIALOG_UPLOAD_TITLE' : 'نافذة رفع الملفات', + 'DIALOG_UPLOAD_DESC' : 'رفم الملف إلى **{0}**.
حد الحجم: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'جاري الرفع \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'جاري رفع الملف...', + 'DIALOG_UPLOAD_FAILED' : 'رفع الملف', + 'DIALOG_UPLOAD_FAILED_MSG' : 'خطأ رفع الملف', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'أسباب غير معروفة...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'إلغي من طرف المستخدم...', + 'DIALOG_UPLOAD_TOO_BIG': 'ملف كبير جدا', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'ملف كبير جدا, تخطى {0}', + + 'DIALOG_FONT_TITLE' : 'نافذة الخطوط', + + 'DIALOG_APPCHOOSER_TITLE' : 'إختيار التطبيق', + 'DIALOG_APPCHOOSER_MSG' : 'إختار تطبيق لفتحه', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'يجب إختيار تطبيق', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'إستخدام كتطبيق إفتراضي دائم {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Module not configured or disabled', + 'GAPI_SIGN_OUT' : 'Sign out from Google API Services', + 'GAPI_REVOKE' : 'Revoke permissions and Sign Out', + 'GAPI_AUTH_FAILURE' : 'Google API Authentication failed or did not take place', + 'GAPI_AUTH_FAILURE_FMT' : 'Failed to authenticate: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Failed to load Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API module not configured or disabled', + 'WLAPI_SIGN_OUT' : 'Sign out from Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Failed to load Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Failed to log into Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Failed to log into Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'لا يمكن إنشاء IndexedDB دون إسم قاعدة معطيات', + 'IDB_NO_SUCH_ITEM' : 'عنصر غير موجود', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'خطأ مميت', + 'ERR_VFS_UNAVAILABLE' : 'غير متوفر', + 'ERR_VFS_FILE_ARGS' : 'ملف ينتظر على الأقل عنصر', + 'ERR_VFS_NUM_ARGS' : 'عدد العناصر غير كافي', + 'ERR_VFS_EXPECT_FILE' : 'متوقع ملف', + 'ERR_VFS_EXPECT_SRC_FILE' : 'متوقع مصدر الملف', + 'ERR_VFS_EXPECT_DST_FILE' : 'متوقع وجهة الملف', + 'ERR_VFS_FILE_EXISTS' : 'وجهة موجودة مسبقا', + 'ERR_VFS_TARGET_NOT_EXISTS': 'وجهة غير موجودة', + 'ERR_VFS_TRANSFER_FMT' : 'حدث خطأ أثناء التحويل من مساحات التخزين: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'لا يمكن رفع ملف من دون وجهة', + 'ERR_VFS_UPLOAD_NO_FILES' : 'لا يمكن رفع الملفات من دون تعيينها', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'خطأ رفع الملف: {0}', + 'ERR_VFS_UPLOAD_CANCELLED' : 'تك إلغاء رفع الملف', + 'ERR_VFS_DOWNLOAD_NO_FILE' : 'لا يمكن رفع مسار من دون مسار', + 'ERR_VFS_DOWNLOAD_FAILED' : 'حدث خطأ أثناء تحميل: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY' : 'الإجابة كانت فارغة', + + 'ERR_VFSMODULE_INVALID' : 'قسم VFS غير صحيح', + 'ERR_VFSMODULE_INVALID_FMT' : 'قسم VFS غير صحيح: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'قسم VFS طريقة', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'قسم VFS طريقة: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'نوع القسم VFS غير صحيح', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'نوع القسم VFS غير صحيح: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'إعدادات القسم VFS غير صحيحة', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'إعدادات القسم VFS إعدادات القسم: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'قسم VFS مركب مسبقا', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'قسم VFS \'{0}\' مركب مسبقا', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'قسم VFS غير مركب', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'قسم VFS \'{0}\' غير مركب', + 'ERR_VFSMODULE_EXCEPTION' : 'قسم VFS خطأ', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'قسم VFS خطأ: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'لا يوجد VFS {0}. خطأ في شاكلة المسار ?', + 'ERR_VFSMODULE_READONLY' : 'هذا VFS للقراءة فقط', + 'ERR_VFSMODULE_READONLY_FMT' : 'هذا VFS للقراءة فقط : {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'جاري تحميل الملف', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR خطأ', + 'ERR_VFSMODULE_ROOT_ID' : 'خطأ تحديد معرف root', + 'ERR_VFSMODULE_NOSUCH' : 'ملف غير موجود', + 'ERR_VFSMODULE_PARENT' : 'لا يوجد أب', + 'ERR_VFSMODULE_PARENT_FMT' : 'فشل البحث عن أب: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'فشل مسح المجلد', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'فشل مسح المجلد : {0}', + 'ERR_VFSMODULE_READ' : 'فشل قراءة الملف', + 'ERR_VFSMODULE_READ_FMT' : 'فشل قراءة الملف: {0}', + 'ERR_VFSMODULE_WRITE' : 'فشل الكتابة في الملف', + 'ERR_VFSMODULE_WRITE_FMT' : 'فشل الكتابة في الملف: {0}', + 'ERR_VFSMODULE_COPY' : 'فشل في النسخ', + 'ERR_VFSMODULE_COPY_FMT' : 'فشل في النسخ: {0}', + 'ERR_VFSMODULE_UNLINK' : 'فشل في حذف رابط الملف', + 'ERR_VFSMODULE_UNLINK_FMT' : 'فشل في حذف رابط الملف: {0}', + 'ERR_VFSMODULE_MOVE' : 'فشل في تحريك الملف', + 'ERR_VFSMODULE_MOVE_FMT' : 'فشل في تحريك الملف: {0}', + 'ERR_VFSMODULE_EXIST' : 'فشل في تحديد وجود الملف', + 'ERR_VFSMODULE_EXIST_FMT' : 'فشل في تحديد وجود الملف: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'فشل في تحديد معلومات الملف', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'فشل في تحديد معلومات الملف: {0}', + 'ERR_VFSMODULE_MKDIR' : 'فشل في إنشاء المجلد', + 'ERR_VFSMODULE_MKDIR_FMT' : 'فشل في إنشاء المجلد: {0}', + 'ERR_VFSMODULE_URL' : 'فشل في الحصول على رابط الملف', + 'ERR_VFSMODULE_URL_FMT' : 'فشل في الحصول على رابط الملف: {0}', + 'ERR_VFSMODULE_TRASH' : 'فشل في تحريك الملف إلى سلة المحذوفات', + 'ERR_VFSMODULE_TRASH_FMT' : 'فشل في تحريك الملف إلى سلة المحذوفات: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'فشل في تحريك الملف من سلة المحذوفات', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'فشل في تحريك الملف من سلة المحذوفات: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'فشل في تفريغ سلة المحذوفات', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'فشل في تفريغ سلة المحذوفات: {0}', + 'ERR_VFSMODULE_FIND' : 'فشل في البحث', + 'ERR_VFSMODULE_FIND_FMT' : 'فشل في البحث: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'فشل في الحصول على المساحة الفارغة', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'فشل في الحصول على المساحة الفارغة: {0}', + 'ERR_VFSMODULE_EXISTS' : 'فشل في التأكيد على الوجود', + 'ERR_VFSMODULE_EXISTS_FMT' : 'فشل في التأكيد على الوجود: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'أنت الآن مسجل في Dropbox API', + 'DROPBOX_SIGN_OUT' : 'خروج من Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'خطأ في تحديد المسار : لا يوجد أي عنصر', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'خطأ تحميل zip.js', + 'ZIP_VENDOR_FAIL' : 'zip.js غير موجود ?', + 'ZIP_NO_RESOURCE' : 'لا توجد أي موارد zip.', + 'ZIP_NO_PATH' : 'لم يعطى إي مسار', + + // + // SearchEngine + // + 'SEARCH_LOADING': 'جاري البحث...', + 'SEARCH_NO_RESULTS': 'لا توجد أي نتيجة', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'مجلد التثبيت موجود من قبل، من المستحيل المتابعة !', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'لا يمكن فتح الملف', + 'ERR_FILE_APP_OPEN_FMT' : 'الملف {0} غير قابل للفتح لأن التعريف {1} غير مدعوم', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'الملف {0} غير ممكن فتحه: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'الملف {0} غير ممكن حفظه: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} خطأ في التطبيق', + 'ERR_GENERIC_APP_ACTION_FMT': 'عدم التمكن من إنجاز العملية \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'خطأ غير معروف', + 'ERR_GENERIC_APP_REQUEST' : 'حدث خطأ أثناء إجراء العملية المطلوبة', + 'ERR_GENERIC_APP_FATAL_FMT' : 'خطأ مميت {0}', + 'MSG_GENERIC_APP_DISCARD' : 'إلغاء التغيرات ?', + 'MSG_FILE_CHANGED' : 'تم تغيير الملف، هل تريد التحديث', + 'MSG_APPLICATION_WARNING' : 'تحذير النطبيق', + 'MSG_MIME_OVERRIDE' : 'نوع الملف "{0}" غير مدعوم, إستخدم "{1}" في مكانه.', + + // + // General + // + + 'LBL_UNKNOWN' : 'غير معروف', + 'LBL_APPEARANCE' : 'مظهر', + 'LBL_USER' : 'مستخدم', + 'LBL_NAME' : 'إسم', + 'LBL_APPLY' : 'تطبيق', + 'LBL_FILENAME' : 'إسم الملف', + 'LBL_PATH' : 'مسار', + 'LBL_SIZE' : 'حجم', + 'LBL_TYPE' : 'نوع', + 'LBL_MIME' : 'التعريف', + 'LBL_LOADING' : 'جاري التحميل', + 'LBL_SETTINGS' : 'إعدادات', + 'LBL_ADD_FILE' : 'إضافة ملفات', + 'LBL_COMMENT' : 'تعليق', + 'LBL_ACCOUNT' : 'حساب', + 'LBL_CONNECT' : 'إتصال', + 'LBL_ONLINE' : 'متصل', + 'LBL_OFFLINE' : 'غير متصل', + 'LBL_AWAY' : 'بعيد', + 'LBL_BUSY' : 'مشغول', + 'LBL_CHAT' : 'دردشة', + 'LBL_HELP' : 'مساعدة', + 'LBL_ABOUT' : 'عن', + 'LBL_PANELS' : 'اللوحات', + 'LBL_LOCALES' : 'اللغة/المنطقة', + 'LBL_THEME' : 'القالب', + 'LBL_COLOR' : 'اللون', + 'LBL_PID' : 'رقم العملية', + 'LBL_KILL' : 'إنهاء', + 'LBL_ALIVE' : 'في الخدمة', + 'LBL_INDEX' : 'الرقم', + 'LBL_ADD' : 'إضافة', + 'LBL_FONT' : 'الخط', + 'LBL_YES' : 'نعم', + 'LBL_NO' : 'لا', + 'LBL_CANCEL' : 'إلغاء', + 'LBL_TOP' : 'أعلى', + 'LBL_LEFT' : 'اليسار', + 'LBL_RIGHT' : 'اليمين', + 'LBL_BOTTOM' : 'أسفل', + 'LBL_CENTER' : 'وسط', + 'LBL_FILE' : 'ملف', + 'LBL_NEW' : 'جديد', + 'LBL_OPEN' : 'فتح', + 'LBL_SAVE' : 'حفظ', + 'LBL_SAVEAS' : 'حفظ بإسم...', + 'LBL_CLOSE' : 'إغلاق', + 'LBL_MKDIR' : 'مجلد جديد', + 'LBL_UPLOAD' : 'رفع ملف', + 'LBL_VIEW' : 'إظهار', + 'LBL_EDIT' : 'تغيير', + 'LBL_RENAME' : 'إعادة تسمية', + 'LBL_DELETE' : 'حذف', + 'LBL_OPENWITH' : 'فتح بواسطة ...', + 'LBL_ICONVIEW' : 'إظهار كأيقونات', + 'LBL_TREEVIEW' : 'إظهار كشجرة', + 'LBL_LISTVIEW' : 'إظهار كقائمة', + 'LBL_REFRESH' : 'تحديث', + 'LBL_VIEWTYPE' : 'نوع المظهر', + 'LBL_BOLD' : 'غليظ', + 'LBL_ITALIC' : 'مائل', + 'LBL_UNDERLINE' : 'مسطر', + 'LBL_REGULAR' : 'عادي', + 'LBL_STRIKE' : 'مشطوب', + 'LBL_INDENT' : 'مساحة لأمام', + 'LBL_OUTDENT' : 'مساحة للخلف', + 'LBL_UNDO' : 'تراجع', + 'LBL_REDO' : 'إلى الأمام', + 'LBL_CUT' : 'قص', + 'LBL_UNLINK' : 'حذف الرابط', + 'LBL_COPY' : 'نسخ', + 'LBL_PASTE' : 'لصق', + 'LBL_INSERT' : 'إدراج', + 'LBL_IMAGE' : 'صورة', + 'LBL_LINK' : 'رابط', + 'LBL_DISCONNECT' : 'قطع الإتصال', + 'LBL_APPLICATIONS' : 'التطبيقات', + 'LBL_ADD_FOLDER' : 'إضافة مجلد', + 'LBL_INFORMATION' : 'معلومات', + 'LBL_TEXT_COLOR' : 'لون النص', + 'LBL_BACK_COLOR' : 'خلفية النص', + 'LBL_RESET_DEFAULT' : 'لإستعادة لإفتراضي', + 'LBL_DOWNLOAD_COMP' : 'تحميل إلى الكمبيوتر', + 'LBL_ORDERED_LIST' : 'ترتيب القائمة', + 'LBL_BACKGROUND_IMAGE' : 'صورة الخلفية', + 'LBL_BACKGROUND_COLOR' : 'لون الخلفية', + 'LBL_UNORDERED_LIST' : 'قائمة غير مرتبة', + 'LBL_STATUS' : 'الحالة', + 'LBL_READONLY' : 'قراءة-فقط', + 'LBL_CREATED' : 'تاريخ الإنشاء', + 'LBL_MODIFIED' : 'تاريخ التغيير', + 'LBL_SHOW_COLUMNS' : 'إظهار الأعمدة', + 'LBL_MOVE' : 'تحريك', + 'LBL_OPTIONS' : 'خيارات', + 'LBL_OK' : 'موافق', + 'LBL_DIRECTORY' : 'مجلد', + 'LBL_CREATE' : 'إنشاء', + 'LBL_BUGREPORT' : 'إشعار بخطأ', + 'LBL_INSTALL' : 'تثبيت', + 'LBL_UPDATE' : 'تحديث', + 'LBL_REMOVE' : 'إزالة', + 'LBL_SHOW_SIDEBAR' : 'إظهار الشريط الجانبي', + 'LBL_SHOW_NAVIGATION' : 'إظهار شريط الإنتقال', + 'LBL_SHOW_HIDDENFILES' : 'إظهار الملفات المخفية', + 'LBL_SHOW_FILEEXTENSIONS' : 'إظهار لواحق الملفات', + 'LBL_MOUNT': 'تركيب', + 'LBL_DESCRIPTION': 'الوصف', + 'LBL_USERNAME': 'المستخدم', + 'LBL_PASSWORD': 'كلمة المرور', + 'LBL_HOST': 'المستضيف', + 'LBL_NAMESPACE': 'إسم الساحة', + 'LBL_SEARCH': 'بحث', + 'LBL_Theme' : 'القالب', + 'LBL_SOUNDS' : 'أصوات', + 'LBL_ICONS' : 'أيقونات', + 'LBL_BACKGROUND' : 'خلفيات', + 'LBL_DESKTOP' : 'المكتب', + 'LBL_PANEL' : 'اللوحة', + 'LBL_POSITION' : 'الوصعية', + 'LBL_ONTOP' : 'في المقدمة', + 'LBL_ITEMS' : 'العناصر', + 'LBL_GENERAL' : 'عام', + 'LBL_DEBUG' : 'تصحيح', + 'LBL_AUTOHIDE' : 'إخفاء تلقائي', + 'LBL_OPACITY' : 'الشفافية', + 'LBL_PACKAGES' : 'الحزم', + 'LBL_GROUPS' : 'المجموعات', + 'LBL_VERSION' : 'الطبعة', + 'LBL_AUTHOR' : 'الكاتب', + 'LBL_HIDE' : 'إخفاء', + 'LBL_APPLICATION' : 'تطبيق', + 'LBL_SCOPE' : 'الزمرة' +}; diff --git a/src/client/javascript/locales/bg_BG.js b/src/client/javascript/locales/bg_BG.js index e0335deed7..91f949d300 100644 --- a/src/client/javascript/locales/bg_BG.js +++ b/src/client/javascript/locales/bg_BG.js @@ -27,361 +27,357 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.bg_BG = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Ãðåøêà ïðè îòâàðÿíå íà ôàéë', - 'ERR_WM_NOT_RUNNING' : 'Ìåíèäæúðà íà ïðîçîðöè íå ðàáîòè ', - 'ERR_FILE_OPEN_FMT' : 'Ôàéëúò \'**{0}**\' íå ìîæå äà áúäå îòâîðåí', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Íÿìà íàìåðåíè ïðèëîæåíèÿ ñ ïîääðúæêà çà \'{0}\' ôàéëîâå', - 'ERR_APP_LAUNCH_FAILED' : 'Ïðèëîæåíèåòî íå ìîæà äà áúäå ñòàðòèðàíî', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Ïîëó÷è ñå ãðåøêà ïî âðåìå íà ñòàðòèðàíå: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Ïðèìîæåíèåòî \'{0}\' ïðîâàëåíî èçãðàæäàíå: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Ïðèëîæåíèåòî \'{0}\' init() ïðîâàëåíî: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Ëèïñâàùè ðåñóðñè çà ïðèëîæåíèåòî \'{0}\' èëè ñå ïðîâàëè ñòàðòèðàíåòî!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Ïðèëîæåíèåòî \'{0}\' ïðåäâàðèòåëíî ñòàðòèðàíå ïðîâàëåíî: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Ïðèëîæåíèåòî \'{0}\' å âå÷å ñòàðòèðàíî!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Ãðåøêà ïðè ñòàðòèðàíå \'{0}\'. íÿìà íàìåðåíè äàííè!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Ãðåøêà ïðè ñòàðòèðàíå \'{0}\'. íåïîääúðæàí áðàóçúð: {1}', - - 'ERR_NO_WM_RUNNING' : 'Íÿìà ðàáîòåù ìåíèäæúð íà ïðîçîðöè', - 'ERR_CORE_INIT_FAILED' : 'Ïðîâàëåíî èíèöèàëèçèðàíå íà OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Ãðåøêà ïðè èíèöèàëèçèðàíå íà OS.js', - 'ERR_CORE_INIT_NO_WM' : 'OS.js íå ìîæå äà ñå ñòàðòèðà: Íå å îïðåäåëåí ìåíèäæúð íà ïðîçîðöè!', - 'ERR_CORE_INIT_WM_FAILED_FMT': 'OS.js íå ìîæå äà ñå ñòàðòèðà: Ïðîâàëåíî îòâàðÿíå íà ìåíèäæúð íà ïðîçîðöè: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED': 'OS.js íå ìîæå äà ñå ñòàðòèðà: Ïðîâàëåíî çàðåæäàíå íà ðåñóðñèòå...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript èíôîðìàöèÿ íà ãðåøêà ', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Ïîÿâè ñå íåî÷êàâàíà ãðåøêà, âåðîÿòíî áúã.', - - 'ERR_APP_API_ERROR' : 'Ãðåøêà â API íà ïðèëîæåíèåòî', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Ïðèëîæåíèåòî {0} íå ìîæà äà èçïúëíè îïåðàöèÿòà \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Ëèïñâàù àðãóìåíò: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Íåïîçíàòà ãðåøêà', - - 'ERR_OPERATION_TIMEOUT' : 'Ïðåñðî÷åíî âðåìå íà îïåðàöèÿòà', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Ïðåñðî÷åíî âðåìå íà îïåðàöèÿòà ({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Âå÷å èìà íàèìåíîâàí ïðîçîðåö \'{0}\'', - 'WINDOW_MINIMIZE' : 'Ìèíèìèçèðàé', - 'WINDOW_MAXIMIZE' : 'Ìàêñèìèçèðàíå', - 'WINDOW_RESTORE' : 'Âúçîáíîâè', - 'WINDOW_CLOSE' : 'çàòâîðè', - 'WINDOW_ONTOP_ON' : 'íàé-îòãîðå (ðàçðåøåíî)', - 'WINDOW_ONTOP_OFF': 'íàé-îòãîðå (çàáðàíåíî)', - - // Handler - 'TITLE_SIGN_OUT' : 'Èçõîä', - 'TITLE_SIGNED_IN_AS_FMT' : 'Âëåçëè ñòå êàòî: {0}', - - // SESSION - 'MSG_SESSION_WARNING' : 'Ñèãóðíè ëè ñòå, ÷å èñêàòå íà èçëåçåòå îò OS.js? Âñè÷êè íå çàïàçåíè íàñòðîéêè è èíôîðìàöèÿ ùå áúäàò çàãóáåíè!', - - // Service - 'BUGREPORT_MSG' : 'Ìîëÿ äîêëàäâàéòå òîâà àêî ìèñëèòå, ÷å å áúã.\âêëþ÷åòå äåòàéëíî îïèñàíèå êàê ñå ïîëó÷è ãðåøêàòà è ñàìî àêî ìîæåòå; êàê ìîæå äà áúäå ïîïðàâåíà ', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Âëåçëè ñòå âúâ âúíøíè óñëóãè: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Ôàòàëíà ãðåøêà', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR ãðåøêà: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Èçëåç (Èçõîä)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Èçëèçàíå îò ïîòðåáèòåë \'{0}\'.\nÈñêàòå ëè äà çàïàçèòå òåêóùàòà ñåñèÿ?', - - 'DIALOG_CLOSE' : 'Çàòâîðè', - 'DIALOG_CANCEL': 'Îòêàæè', - 'DIALOG_APPLY' : 'Ïðèëîæè', - 'DIALOG_OK' : 'ÎÊ', - - 'DIALOG_ALERT_TITLE' : 'Äèàëîã çà èçâåñòèå', - - 'DIALOG_COLOR_TITLE' : 'Öâÿò íà äèàëîãà', - 'DIALOG_COLOR_R' : '×åðâåí: {0}', - 'DIALOG_COLOR_G' : 'Çåëåí: {0}', - 'DIALOG_COLOR_B' : 'Ñèí: {0}', - 'DIALOG_COLOR_A' : 'Àëôà: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Ïîòâúðäè äèàëîã', - - 'DIALOG_ERROR_MESSAGE' : 'Ñúîáùåíèå', - 'DIALOG_ERROR_SUMMARY' : 'Ñúäúðæàíèå', - 'DIALOG_ERROR_TRACE' : 'Òúðñè', - 'DIALOG_ERROR_BUGREPORT' : 'Äîêëàäâàé áúã', - - 'DIALOG_FILE_SAVE' : 'Çàïàçè', - 'DIALOG_FILE_OPEN' : 'Îòâîðè', - 'DIALOG_FILE_MKDIR' : 'Íîâà ïàïêà', - 'DIALOG_FILE_MKDIR_MSG' : 'Ñúçäàé íîâà äèðåêòîðèÿ â **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Ñèãóðíè ëè ñòå, ÷å èñêàòå äà ïðåçàïèøåòå ôàèëúò \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Òèï íà èçãëåä', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Ñïèñúê', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Äúðâî', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Èêîíè', - 'DIALOG_FILE_ERROR' : 'Ãðåøêà âúâ ôàéëîâ äèàëîã', - 'DIALOG_FILE_ERROR_SCANDIR': 'Ïðîâàëåíî ðàçãëåæäàíå íà äèðåêòîðèÿòà \'{0}\' ïîðàäè ãðåøêà', - 'DIALOG_FILE_MISSING_FILENAME' : 'Òðÿáâà äà èçáåðåòå ôàéë èëè äà âúâåäåòå èìå!', - 'DIALOG_FILE_MISSING_SELECTION': 'Òðÿáâà äà èçáåðåòå ôàéë!', - - 'DIALOG_FILEINFO_TITLE' : 'Èíôîðàìöèÿ çà ôàéëúò', - 'DIALOG_FILEINFO_LOADING' : 'Çàðåæäàíå íà èíôîðìàöèÿ çà: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Ãðåøêà â èíôîðìàöèÿ çà ôàéë', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Íå ìîæå äà áúäå íàìåðåíà èíôîðìàöèÿ çà ôàéëúò **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Íå ìîæå äà áúäå íàìåðåíà èíôîðìàöèÿ çà ôàéëúò: {0}', - - 'DIALOG_INPUT_TITLE' : 'Âõîäÿù äèàëîã', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Ïðîãðåñ íà îïåðàöèÿòà íà ôàéëúò', - 'DIALOG_FILEPROGRESS_LOADING' : 'Çàðåæäàíå...', - - 'DIALOG_UPLOAD_TITLE' : 'Äîáàâè äèàëîã', - 'DIALOG_UPLOAD_DESC' : 'Äîáàâè ôàéë êúì **{0}**.
Ìàêñèìàëåí ðàçìåð: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Äîáàâÿíå \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Äîáàâÿíå íà ôàèë...', - 'DIALOG_UPLOAD_FAILED' : 'Äîáàâÿíå ïðîâàëåíî', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Äîáàâÿíåòî å ïðîâàëåíî', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Íåîïðåäåëåíà ïðè÷èíà...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Îòêàçàíî îò ïîòðåáèòåë...', - 'DIALOG_UPLOAD_TOO_BIG': 'Ôàéëúò å ïðåêàëåíî ãîëÿì', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Ôàéëúò å ïðåêàëåíî ãîëÿì, íàäâèøàâà {0}', - - 'DIALOG_FONT_TITLE' : 'Øðèôò íà äèàëîã', - - 'DIALOG_APPCHOOSER_TITLE' : 'Èçáåðåòå ïðèëîæåíèå', - 'DIALOG_APPCHOOSER_MSG' : 'Èçáåðåòå ïðèëîæåíèå êîåòî äà ñå îòâîðè', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Òðÿáâà äà èçáåðåòå ïðèëîæåíèå', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Èçïîëçâàé êàòî ïðèëîæåíèå ïî ïîäðàçáèðàíå çà {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Ìîäóë íå å êîíôèãóðèðàí èëè å èçêëþ÷åí', - 'GAPI_SIGN_OUT' : 'Èçõîä îò Google API óñëóãè', - 'GAPI_REVOKE' : 'Îòòåãëÿíå íà ïðàâàòà è èçõîä', - 'GAPI_AUTH_FAILURE' : 'Google API óäîñòîâåðÿâàíå ïðîâàëåíî èëè íå å ïðîâåäåíî', - 'GAPI_AUTH_FAILURE_FMT' : 'Ãðåøêà ïðè óäîñòîâåðÿâàíå: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Ïðîâàëåíî ñòàðòèðàíå íà Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API ìîäóë íå å êîíôèãóðèðàí èëè å èçêëþ÷åí', - 'WLAPI_SIGN_OUT' : 'Èçõîä îò Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Ïðîâàëåíî ñòàðòèðàíå íà Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Ïðîâàëåíî âëèçàíå â Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Ïðîâàëåíî âëèçàíå â Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API îòãîâîðè {0} ñòàòóñ', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Íå ìîæå äà áúäå ñúçäàäåíà IndexedDB áåç èìå íà áàçà äàííè', - 'IDB_NO_SUCH_ITEM' : 'Íå ñúùåñòâóâàù îáåêò', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Ôàòàëíà ãðåøêà', - 'ERR_VFS_UNAVAILABLE' : 'Íå â íàëè÷íî', - 'ERR_VFS_FILE_ARGS' : 'Ôàéëúò î÷àêâà ïîíå åäèí àðãóìåíò', - 'ERR_VFS_NUM_ARGS' : 'Íÿìà äîñòàòú÷íî àðãóìåíòè', - 'ERR_VFS_EXPECT_FILE' : 'Î÷àêâà ôàéëîâ-îáåêò', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Î÷êâà èçòî÷íèê Ôàéëîâ-îáåêò', - 'ERR_VFS_EXPECT_DST_FILE' : 'Î÷àêâà äåñòèíàöèÿ Ôàéëîâ-îáåêò', - 'ERR_VFS_FILE_EXISTS' : 'Äåñòèíàöèÿòà âå÷å ñúùåñòâóâà', - 'ERR_VFS_TRANSFER_FMT' : 'Ïîÿâè ñå ãðåøêà äîêàòî ñå èçâúðøâàøå òðàíñôåð: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Íå ìîæå äà áúäå äîáàâåí ôàéë áåç äåâñòèíàöèÿ', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Íå ìîæå äà ñå äîáàâÿ áåç îïðåäåëÿíå íà ôàéëîâå', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Ïðîâàëåíî äîáàâÿíå íà ôàéëîâå: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Äîáàâÿíåòî íà ôàéëîâå áåøå ïðåêðàòåíî', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Íå ìîæå äà ñå èçòåãëè áåç óêàçàí ïúò ', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Ïîÿâè ñå ãðåøêà ïðè èçòåãëÿíå: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Îòãîâîðà áåøå ïðàçåí', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Èçòåãëÿíå íà ôàéë', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR ãðåøêà', - 'ERR_VFSMODULE_ROOT_ID' : 'Íå ìîæå äà áúäå íàìåðåíî ÈÄ íà root ïàïêàòà', - 'ERR_VFSMODULE_NOSUCH' : 'Ôàéëúò íå ñúùåñòâóâà', - 'ERR_VFSMODULE_PARENT' : 'Íÿìà íàìåðåí èçòî÷íèê', - 'ERR_VFSMODULE_PARENT_FMT' : 'Íå ìîæà äà áúäå íàìåðåí èçòî÷íêè: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Ïðîâàëåíî ñêàíèðàíå íà äèðåêòîðèÿ', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Ïðîâàëåíî ñêàíèðàíå íà äèðåêòîðèÿ: {0}', - 'ERR_VFSMODULE_READ' : 'Ïðîâàëåíî ïðî÷èòàíå íà ôàéëúò', - 'ERR_VFSMODULE_READ_FMT' : 'Ïðîâàëåíî ïðî÷èòàíå íà ôàéëúò: {0}', - 'ERR_VFSMODULE_WRITE' : 'Ïðîâàëåíî çàïèñâàíå íà ôàéëúò', - 'ERR_VFSMODULE_WRITE_FMT' : 'Ïðîâàëåíî çàïèñâàíå íà ôàéëúò: {0}', - 'ERR_VFSMODULE_COPY' : 'Ïðîâàëåíî êîïèðàíå', - 'ERR_VFSMODULE_COPY_FMT' : 'Ïðîâàëåíî êîïèðàíå: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Ïðîâàëåíî ðàçêà÷àíå íà ôàéëúò ', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Ïðîâàëåíî ðàçêà÷àíå íà ôàéëúò: {0}', - 'ERR_VFSMODULE_MOVE' : 'Ïðîâàëåíî ïðåìåñòâàíå íà ôàéëúò', - 'ERR_VFSMODULE_MOVE_FMT' : 'Ïðîâàëåíî ïðåìåñòâàíå íà ôàèëúò: {0}', - 'ERR_VFSMODULE_EXIST' : 'Ïðîâàëåíà ïðîæåðêà çà ñúùåñòâóâàíå íà ôàéëúò', - 'ERR_VFSMODULE_EXIST_FMT' : 'Ïðîâàëåíà ïðîæåðêà çà ñúùåñòâóâàíå íà ôàéëúò: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Ïðîâàëåíî ïîëó÷àâàíå íà èíôîðìàöèÿ çà ôàéëúò', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Ïðîâàëåíî ïîëó÷àâàíå íà èíôîðìàöèÿ çà ôàéëúò: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Ïðîâàëåíî ñúçäàâàíå íà äèðåêòîðèÿ', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Ïðîâàëåíî ñúçäàâàíå íà äèðåêòîðèÿ: {0}', - 'ERR_VFSMODULE_URL' : 'Ïðîâàëåíî ïîëó÷àâàíå íà URL çà ôàéëúò', - 'ERR_VFSMODULE_URL_FMT' : 'Ïðîâàëåíî ïîëó÷àâàíå íà URL çà ôàéëúò: {0}', - 'ERR_VFSMODULE_TRASH' : 'Ïðîâàëåíî èçòðèâàíå', - 'ERR_VFSMODULE_TRASH_FMT' : 'Ïðîâàëåíî èçòðèâàíå: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Ïðîâàëåíî èçêàðâàíå îò êîø÷åòî', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Ïðîâàëåíî èçêàðâàíå îò êîø÷åòî: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Ïðîâàëåíî èçïðàçâàíå íà êîø÷åòî', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Ïðîâàëåíî èçïðàçâàíå íà êîø÷åòî: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Âëåçëè ñòå â Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Èçõîä îò Dropbox API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Ïðîâàëåíî íàìèðàíå íà ïúò: Îáåêòà íå å íàìåðåí', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Äèðåêòîðèÿ çà èíñòàëèðàíå íà ïàêåòè âå÷å ñúùåñòâóâà. Íå ìîæå äà ïðîäúëæèòå!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Íå ìîæå äà áúäå îòâîðåí ôàéëúò', - 'ERR_FILE_APP_OPEN_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå îòîâîðåí {1} íå ñå ïîääúðæà', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå îòâîðåí: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå çàïàçåí: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} ãðåøêà â ïðèëîæåíèåòî', - 'ERR_GENERIC_APP_ACTION_FMT': 'Ïðîâàëåíî èçïúëíåíÿâàíå íà äåéñòâèå \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Íåïîçíàòà ãðåøêà', - 'ERR_GENERIC_APP_REQUEST' : 'Ïîëó÷è ñå ãðåøêà ïðè èçïúëíÿâàíå íà çàÿâêàòà', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Ôàòàëíà ãðåøêà: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Îòêàæè ïðîìåíèòå?', - 'MSG_FILE_CHANGED' : 'Ôàéëúò å ïðîìåíåí. ïðåçàðåäè?', - 'MSG_APPLICATION_WARNING' : 'Ïðåäóïðåæäåíèå', - 'MSG_MIME_OVERRIDE' : 'âèäà íà ôàéëà "{0}" íå ñå ïîääúðæà, èçïîëçâàéòå "{1}".', - - // - // General - // - - 'LBL_UNKNOWN' : 'Íåïîçíàò', - 'LBL_APPEARANCE' : 'Âúíøåí âèä', - 'LBL_USER' : 'Ïîòðåáèòåë', - 'LBL_NAME' : 'Èìå', - 'LBL_APPLY' : 'Ïðèëîæè', - 'LBL_FILENAME' : 'Èìå íà ôàéë', - 'LBL_PATH' : 'Ïúò', - 'LBL_SIZE' : 'Ðàçìåð', - 'LBL_TYPE' : 'Òèï', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Çàðåæäàíå', - 'LBL_SETTINGS' : 'Íàñòðîéêè', - 'LBL_ADD_FILE' : 'Äîáàâè ôàéë', - 'LBL_COMMENT' : 'Êîìåíòàð', - 'LBL_ACCOUNT' : 'Àêàóíò', - 'LBL_CONNECT' : 'Ñâúðæè ñå', - 'LBL_ONLINE' : 'Íà ëèíèÿ', - 'LBL_OFFLINE' : 'Èçâúí ëèíèÿ', - 'LBL_AWAY' : 'Îòñúñòâàù', - 'LBL_BUSY' : 'Çàåò', - 'LBL_CHAT' : '×àò', - 'LBL_HELP' : 'Ïîìîù', - 'LBL_ABOUT' : 'Èíôîðìàöèÿ', - 'LBL_PANELS' : 'Ïàíåëè', - 'LBL_LOCALES' : 'Ëîêàëèçàöèÿ', - 'LBL_THEME' : 'Òåìà', - 'LBL_COLOR' : 'Öâÿò', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Ïðåêðàòè', - 'LBL_ALIVE' : 'Âêëþ÷è', - 'LBL_INDEX' : 'Èíäåêñ', - 'LBL_ADD' : 'Äîáàâè', - 'LBL_FONT' : 'Øðèôò', - 'LBL_YES' : 'Äà', - 'LBL_NO' : 'Íå', - 'LBL_CANCEL' : 'Îòêàæè', - 'LBL_TOP' : 'Ãîðå', - 'LBL_LEFT' : 'Ëÿâî', - 'LBL_RIGHT' : 'Äÿñíî', - 'LBL_BOTTOM' : 'Äîëó', - 'LBL_CENTER' : 'Öåíòúð', - 'LBL_FILE' : 'Ôàéë', - 'LBL_NEW' : 'Íîâ', - 'LBL_OPEN' : 'Îòâîðè', - 'LBL_SAVE' : 'Çàïàçè', - 'LBL_SAVEAS' : 'Çàïàçè êàòî...', - 'LBL_CLOSE' : 'Çàòðâîðè', - 'LBL_MKDIR' : 'Ñúçäàé äèðåêòîðèÿ', - 'LBL_UPLOAD' : 'Äîáàâè', - 'LBL_VIEW' : 'Èçãëåä', - 'LBL_EDIT' : 'Ðåäàêòèðàé', - 'LBL_RENAME' : 'Ïðåèìåíóâàé', - 'LBL_DELETE' : 'Èçòðèè', - 'LBL_OPENWITH' : 'Îòâîðè ñ...', - 'LBL_ICONVIEW' : 'Èêîíè', - 'LBL_TREEVIEW' : 'Äúðâî', - 'LBL_LISTVIEW' : 'Ñïèñúê', - 'LBL_REFRESH' : 'Îïðåñíè', - 'LBL_VIEWTYPE' : 'Íà÷èí íà èçãëåä', - 'LBL_BOLD' : 'Ïîëó÷åð', - 'LBL_ITALIC' : 'Íàêëîíåí', - 'LBL_UNDERLINE' : 'Ïîä÷åðòàí', - 'LBL_REGULAR' : 'Îáèêíîâåí', - 'LBL_STRIKE' : 'Strike', - 'LBL_INDENT' : 'Èäåíòèôèêàöèÿ', - 'LBL_OUTDENT' : 'Ïðåñðî÷âàíå', - 'LBL_UNDO' : 'Ïððåìàõíè', - 'LBL_REDO' : 'Îòìåíè ïðåìàõâàíåòî', - 'LBL_CUT' : 'Èçðåæè', - 'LBL_UNLINK' : 'Îòêà÷è', - 'LBL_COPY' : 'Êîïèðàé', - 'LBL_PASTE' : 'Ïîñòàâè', - 'LBL_INSERT' : 'Äîáàâè', - 'LBL_IMAGE' : 'Èçîáðàæåíèå', - 'LBL_LINK' : 'Ëèíê', - 'LBL_DISCONNECT' : 'Èçëåç îò âðúçêà', - 'LBL_APPLICATIONS' : 'Ïðèëîæåíèÿ', - 'LBL_ADD_FOLDER' : 'Äîáàâè ïàïêà', - 'LBL_INFORMATION' : 'Èíôîðìàöèÿ', - 'LBL_TEXT_COLOR' : 'Öâÿò íà òåêñòà', - 'LBL_BACK_COLOR' : 'Öâÿò íà ôîíà', - 'LBL_RESET_DEFAULT' : 'Âúðíè ïî ïîäðàçáèðàíå', - 'LBL_DOWNLOAD_COMP' : 'Èçòåãëÿíå íà êîìïþòúðà', - 'LBL_ORDERED_LIST' : 'Ïîäðåäåí ñïèñúê', - 'LBL_BACKGROUND_IMAGE' : 'Èçîáðàæåíèÿ çà ôîí', - 'LBL_BACKGROUND_COLOR' : 'Öâÿò íà ôîí', - 'LBL_UNORDERED_LIST' : 'Íåïîäðåäåí ñïèñúê', - 'LBL_STATUS' : 'Ñàòóñ', - 'LBL_READONLY' : 'ñàìî çà ÷åòåíå', - 'LBL_CREATED' : 'Ñúçäàäåí', - 'LBL_MODIFIED' : 'Ìîäèôèöèðàí', - 'LBL_SHOW_COLUMNS' : 'Ïîêàæè êîëîíè', - 'LBL_MOVE' : 'Ïðåìåñòè', - 'LBL_OPTIONS' : 'Îïöèè', - 'LBL_OK' : 'ÎÊ', - 'LBL_DIRECTORY' : 'Äèðåêòîðèÿ', - 'LBL_CREATE' : 'Ñúçäàé', - 'LBL_BUGREPORT' : 'Áúã-ðåïîðò', - 'LBL_INSTALL' : 'Èíñòàëèðàé', - 'LBL_UPDATE' : 'Àêòóàëèçèðàé', - 'LBL_REMOVE' : 'Ïðåìàõíè', - 'LBL_SHOW_SIDEBAR' : 'покажи страничен бар', - 'LBL_BACKGROUND' : 'Фон', - 'LBL_DESKTOP' : 'Работен плот', - 'LBL_PANEL' : 'Панел', - 'LBL_POSITION' : 'Позиция', - 'LBL_ONTOP' : 'Най-отгоре', - 'LBL_ITEMS' : 'Обекти', - 'LBL_GENERAL': 'Основен' - }; - -})(); +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Ãðåøêà ïðè îòâàðÿíå íà ôàéë', + 'ERR_WM_NOT_RUNNING' : 'Ìåíèäæúðà íà ïðîçîðöè íå ðàáîòè ', + 'ERR_FILE_OPEN_FMT' : 'Ôàéëúò \'**{0}**\' íå ìîæå äà áúäå îòâîðåí', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Íÿìà íàìåðåíè ïðèëîæåíèÿ ñ ïîääðúæêà çà \'{0}\' ôàéëîâå', + 'ERR_APP_LAUNCH_FAILED' : 'Ïðèëîæåíèåòî íå ìîæà äà áúäå ñòàðòèðàíî', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Ïîëó÷è ñå ãðåøêà ïî âðåìå íà ñòàðòèðàíå: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Ïðèìîæåíèåòî \'{0}\' ïðîâàëåíî èçãðàæäàíå: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Ïðèëîæåíèåòî \'{0}\' init() ïðîâàëåíî: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Ëèïñâàùè ðåñóðñè çà ïðèëîæåíèåòî \'{0}\' èëè ñå ïðîâàëè ñòàðòèðàíåòî!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Ïðèëîæåíèåòî \'{0}\' ïðåäâàðèòåëíî ñòàðòèðàíå ïðîâàëåíî: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Ïðèëîæåíèåòî \'{0}\' å âå÷å ñòàðòèðàíî!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Ãðåøêà ïðè ñòàðòèðàíå \'{0}\'. íÿìà íàìåðåíè äàííè!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Ãðåøêà ïðè ñòàðòèðàíå \'{0}\'. íåïîääúðæàí áðàóçúð: {1}', + + 'ERR_NO_WM_RUNNING' : 'Íÿìà ðàáîòåù ìåíèäæúð íà ïðîçîðöè', + 'ERR_CORE_INIT_FAILED' : 'Ïðîâàëåíî èíèöèàëèçèðàíå íà OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Ãðåøêà ïðè èíèöèàëèçèðàíå íà OS.js', + 'ERR_CORE_INIT_NO_WM' : 'OS.js íå ìîæå äà ñå ñòàðòèðà: Íå å îïðåäåëåí ìåíèäæúð íà ïðîçîðöè!', + 'ERR_CORE_INIT_WM_FAILED_FMT': 'OS.js íå ìîæå äà ñå ñòàðòèðà: Ïðîâàëåíî îòâàðÿíå íà ìåíèäæúð íà ïðîçîðöè: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED': 'OS.js íå ìîæå äà ñå ñòàðòèðà: Ïðîâàëåíî çàðåæäàíå íà ðåñóðñèòå...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript èíôîðìàöèÿ íà ãðåøêà ', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Ïîÿâè ñå íåî÷êàâàíà ãðåøêà, âåðîÿòíî áúã.', + + 'ERR_APP_API_ERROR' : 'Ãðåøêà â API íà ïðèëîæåíèåòî', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Ïðèëîæåíèåòî {0} íå ìîæà äà èçïúëíè îïåðàöèÿòà \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Ëèïñâàù àðãóìåíò: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Íåïîçíàòà ãðåøêà', + + 'ERR_OPERATION_TIMEOUT' : 'Ïðåñðî÷åíî âðåìå íà îïåðàöèÿòà', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Ïðåñðî÷åíî âðåìå íà îïåðàöèÿòà ({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Âå÷å èìà íàèìåíîâàí ïðîçîðåö \'{0}\'', + 'WINDOW_MINIMIZE' : 'Ìèíèìèçèðàé', + 'WINDOW_MAXIMIZE' : 'Ìàêñèìèçèðàíå', + 'WINDOW_RESTORE' : 'Âúçîáíîâè', + 'WINDOW_CLOSE' : 'çàòâîðè', + 'WINDOW_ONTOP_ON' : 'íàé-îòãîðå (ðàçðåøåíî)', + 'WINDOW_ONTOP_OFF': 'íàé-îòãîðå (çàáðàíåíî)', + + // Handler + 'TITLE_SIGN_OUT' : 'Èçõîä', + 'TITLE_SIGNED_IN_AS_FMT' : 'Âëåçëè ñòå êàòî: {0}', + + // SESSION + 'MSG_SESSION_WARNING' : 'Ñèãóðíè ëè ñòå, ÷å èñêàòå íà èçëåçåòå îò OS.js? Âñè÷êè íå çàïàçåíè íàñòðîéêè è èíôîðìàöèÿ ùå áúäàò çàãóáåíè!', + + // Service + 'BUGREPORT_MSG' : 'Ìîëÿ äîêëàäâàéòå òîâà àêî ìèñëèòå, ÷å å áúã.\âêëþ÷åòå äåòàéëíî îïèñàíèå êàê ñå ïîëó÷è ãðåøêàòà è ñàìî àêî ìîæåòå; êàê ìîæå äà áúäå ïîïðàâåíà ', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Âëåçëè ñòå âúâ âúíøíè óñëóãè: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Ôàòàëíà ãðåøêà', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR ãðåøêà: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Èçëåç (Èçõîä)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Èçëèçàíå îò ïîòðåáèòåë \'{0}\'.\nÈñêàòå ëè äà çàïàçèòå òåêóùàòà ñåñèÿ?', + + 'DIALOG_CLOSE' : 'Çàòâîðè', + 'DIALOG_CANCEL': 'Îòêàæè', + 'DIALOG_APPLY' : 'Ïðèëîæè', + 'DIALOG_OK' : 'ÎÊ', + + 'DIALOG_ALERT_TITLE' : 'Äèàëîã çà èçâåñòèå', + + 'DIALOG_COLOR_TITLE' : 'Öâÿò íà äèàëîãà', + 'DIALOG_COLOR_R' : '×åðâåí: {0}', + 'DIALOG_COLOR_G' : 'Çåëåí: {0}', + 'DIALOG_COLOR_B' : 'Ñèí: {0}', + 'DIALOG_COLOR_A' : 'Àëôà: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Ïîòâúðäè äèàëîã', + + 'DIALOG_ERROR_MESSAGE' : 'Ñúîáùåíèå', + 'DIALOG_ERROR_SUMMARY' : 'Ñúäúðæàíèå', + 'DIALOG_ERROR_TRACE' : 'Òúðñè', + 'DIALOG_ERROR_BUGREPORT' : 'Äîêëàäâàé áúã', + + 'DIALOG_FILE_SAVE' : 'Çàïàçè', + 'DIALOG_FILE_OPEN' : 'Îòâîðè', + 'DIALOG_FILE_MKDIR' : 'Íîâà ïàïêà', + 'DIALOG_FILE_MKDIR_MSG' : 'Ñúçäàé íîâà äèðåêòîðèÿ â **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Ñèãóðíè ëè ñòå, ÷å èñêàòå äà ïðåçàïèøåòå ôàèëúò \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Òèï íà èçãëåä', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Ñïèñúê', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Äúðâî', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Èêîíè', + 'DIALOG_FILE_ERROR' : 'Ãðåøêà âúâ ôàéëîâ äèàëîã', + 'DIALOG_FILE_ERROR_SCANDIR': 'Ïðîâàëåíî ðàçãëåæäàíå íà äèðåêòîðèÿòà \'{0}\' ïîðàäè ãðåøêà', + 'DIALOG_FILE_MISSING_FILENAME' : 'Òðÿáâà äà èçáåðåòå ôàéë èëè äà âúâåäåòå èìå!', + 'DIALOG_FILE_MISSING_SELECTION': 'Òðÿáâà äà èçáåðåòå ôàéë!', + + 'DIALOG_FILEINFO_TITLE' : 'Èíôîðàìöèÿ çà ôàéëúò', + 'DIALOG_FILEINFO_LOADING' : 'Çàðåæäàíå íà èíôîðìàöèÿ çà: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Ãðåøêà â èíôîðìàöèÿ çà ôàéë', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Íå ìîæå äà áúäå íàìåðåíà èíôîðìàöèÿ çà ôàéëúò **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Íå ìîæå äà áúäå íàìåðåíà èíôîðìàöèÿ çà ôàéëúò: {0}', + + 'DIALOG_INPUT_TITLE' : 'Âõîäÿù äèàëîã', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Ïðîãðåñ íà îïåðàöèÿòà íà ôàéëúò', + 'DIALOG_FILEPROGRESS_LOADING' : 'Çàðåæäàíå...', + + 'DIALOG_UPLOAD_TITLE' : 'Äîáàâè äèàëîã', + 'DIALOG_UPLOAD_DESC' : 'Äîáàâè ôàéë êúì **{0}**.
Ìàêñèìàëåí ðàçìåð: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Äîáàâÿíå \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Äîáàâÿíå íà ôàèë...', + 'DIALOG_UPLOAD_FAILED' : 'Äîáàâÿíå ïðîâàëåíî', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Äîáàâÿíåòî å ïðîâàëåíî', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Íåîïðåäåëåíà ïðè÷èíà...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Îòêàçàíî îò ïîòðåáèòåë...', + 'DIALOG_UPLOAD_TOO_BIG': 'Ôàéëúò å ïðåêàëåíî ãîëÿì', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Ôàéëúò å ïðåêàëåíî ãîëÿì, íàäâèøàâà {0}', + + 'DIALOG_FONT_TITLE' : 'Øðèôò íà äèàëîã', + + 'DIALOG_APPCHOOSER_TITLE' : 'Èçáåðåòå ïðèëîæåíèå', + 'DIALOG_APPCHOOSER_MSG' : 'Èçáåðåòå ïðèëîæåíèå êîåòî äà ñå îòâîðè', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Òðÿáâà äà èçáåðåòå ïðèëîæåíèå', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Èçïîëçâàé êàòî ïðèëîæåíèå ïî ïîäðàçáèðàíå çà {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Ìîäóë íå å êîíôèãóðèðàí èëè å èçêëþ÷åí', + 'GAPI_SIGN_OUT' : 'Èçõîä îò Google API óñëóãè', + 'GAPI_REVOKE' : 'Îòòåãëÿíå íà ïðàâàòà è èçõîä', + 'GAPI_AUTH_FAILURE' : 'Google API óäîñòîâåðÿâàíå ïðîâàëåíî èëè íå å ïðîâåäåíî', + 'GAPI_AUTH_FAILURE_FMT' : 'Ãðåøêà ïðè óäîñòîâåðÿâàíå: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Ïðîâàëåíî ñòàðòèðàíå íà Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API ìîäóë íå å êîíôèãóðèðàí èëè å èçêëþ÷åí', + 'WLAPI_SIGN_OUT' : 'Èçõîä îò Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Ïðîâàëåíî ñòàðòèðàíå íà Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Ïðîâàëåíî âëèçàíå â Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Ïðîâàëåíî âëèçàíå â Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API îòãîâîðè {0} ñòàòóñ', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Íå ìîæå äà áúäå ñúçäàäåíà IndexedDB áåç èìå íà áàçà äàííè', + 'IDB_NO_SUCH_ITEM' : 'Íå ñúùåñòâóâàù îáåêò', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Ôàòàëíà ãðåøêà', + 'ERR_VFS_UNAVAILABLE' : 'Íå â íàëè÷íî', + 'ERR_VFS_FILE_ARGS' : 'Ôàéëúò î÷àêâà ïîíå åäèí àðãóìåíò', + 'ERR_VFS_NUM_ARGS' : 'Íÿìà äîñòàòú÷íî àðãóìåíòè', + 'ERR_VFS_EXPECT_FILE' : 'Î÷àêâà ôàéëîâ-îáåêò', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Î÷êâà èçòî÷íèê Ôàéëîâ-îáåêò', + 'ERR_VFS_EXPECT_DST_FILE' : 'Î÷àêâà äåñòèíàöèÿ Ôàéëîâ-îáåêò', + 'ERR_VFS_FILE_EXISTS' : 'Äåñòèíàöèÿòà âå÷å ñúùåñòâóâà', + 'ERR_VFS_TRANSFER_FMT' : 'Ïîÿâè ñå ãðåøêà äîêàòî ñå èçâúðøâàøå òðàíñôåð: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Íå ìîæå äà áúäå äîáàâåí ôàéë áåç äåâñòèíàöèÿ', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Íå ìîæå äà ñå äîáàâÿ áåç îïðåäåëÿíå íà ôàéëîâå', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Ïðîâàëåíî äîáàâÿíå íà ôàéëîâå: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Äîáàâÿíåòî íà ôàéëîâå áåøå ïðåêðàòåíî', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Íå ìîæå äà ñå èçòåãëè áåç óêàçàí ïúò ', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Ïîÿâè ñå ãðåøêà ïðè èçòåãëÿíå: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Îòãîâîðà áåøå ïðàçåí', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Èçòåãëÿíå íà ôàéë', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR ãðåøêà', + 'ERR_VFSMODULE_ROOT_ID' : 'Íå ìîæå äà áúäå íàìåðåíî ÈÄ íà root ïàïêàòà', + 'ERR_VFSMODULE_NOSUCH' : 'Ôàéëúò íå ñúùåñòâóâà', + 'ERR_VFSMODULE_PARENT' : 'Íÿìà íàìåðåí èçòî÷íèê', + 'ERR_VFSMODULE_PARENT_FMT' : 'Íå ìîæà äà áúäå íàìåðåí èçòî÷íêè: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Ïðîâàëåíî ñêàíèðàíå íà äèðåêòîðèÿ', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Ïðîâàëåíî ñêàíèðàíå íà äèðåêòîðèÿ: {0}', + 'ERR_VFSMODULE_READ' : 'Ïðîâàëåíî ïðî÷èòàíå íà ôàéëúò', + 'ERR_VFSMODULE_READ_FMT' : 'Ïðîâàëåíî ïðî÷èòàíå íà ôàéëúò: {0}', + 'ERR_VFSMODULE_WRITE' : 'Ïðîâàëåíî çàïèñâàíå íà ôàéëúò', + 'ERR_VFSMODULE_WRITE_FMT' : 'Ïðîâàëåíî çàïèñâàíå íà ôàéëúò: {0}', + 'ERR_VFSMODULE_COPY' : 'Ïðîâàëåíî êîïèðàíå', + 'ERR_VFSMODULE_COPY_FMT' : 'Ïðîâàëåíî êîïèðàíå: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Ïðîâàëåíî ðàçêà÷àíå íà ôàéëúò ', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Ïðîâàëåíî ðàçêà÷àíå íà ôàéëúò: {0}', + 'ERR_VFSMODULE_MOVE' : 'Ïðîâàëåíî ïðåìåñòâàíå íà ôàéëúò', + 'ERR_VFSMODULE_MOVE_FMT' : 'Ïðîâàëåíî ïðåìåñòâàíå íà ôàèëúò: {0}', + 'ERR_VFSMODULE_EXIST' : 'Ïðîâàëåíà ïðîæåðêà çà ñúùåñòâóâàíå íà ôàéëúò', + 'ERR_VFSMODULE_EXIST_FMT' : 'Ïðîâàëåíà ïðîæåðêà çà ñúùåñòâóâàíå íà ôàéëúò: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Ïðîâàëåíî ïîëó÷àâàíå íà èíôîðìàöèÿ çà ôàéëúò', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Ïðîâàëåíî ïîëó÷àâàíå íà èíôîðìàöèÿ çà ôàéëúò: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Ïðîâàëåíî ñúçäàâàíå íà äèðåêòîðèÿ', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Ïðîâàëåíî ñúçäàâàíå íà äèðåêòîðèÿ: {0}', + 'ERR_VFSMODULE_URL' : 'Ïðîâàëåíî ïîëó÷àâàíå íà URL çà ôàéëúò', + 'ERR_VFSMODULE_URL_FMT' : 'Ïðîâàëåíî ïîëó÷àâàíå íà URL çà ôàéëúò: {0}', + 'ERR_VFSMODULE_TRASH' : 'Ïðîâàëåíî èçòðèâàíå', + 'ERR_VFSMODULE_TRASH_FMT' : 'Ïðîâàëåíî èçòðèâàíå: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Ïðîâàëåíî èçêàðâàíå îò êîø÷åòî', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Ïðîâàëåíî èçêàðâàíå îò êîø÷åòî: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Ïðîâàëåíî èçïðàçâàíå íà êîø÷åòî', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Ïðîâàëåíî èçïðàçâàíå íà êîø÷åòî: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Âëåçëè ñòå â Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Èçõîä îò Dropbox API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Ïðîâàëåíî íàìèðàíå íà ïúò: Îáåêòà íå å íàìåðåí', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Äèðåêòîðèÿ çà èíñòàëèðàíå íà ïàêåòè âå÷å ñúùåñòâóâà. Íå ìîæå äà ïðîäúëæèòå!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Íå ìîæå äà áúäå îòâîðåí ôàéëúò', + 'ERR_FILE_APP_OPEN_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå îòîâîðåí {1} íå ñå ïîääúðæà', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå îòâîðåí: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Ôàéëúò {0} íå ìîæå äà áúäå çàïàçåí: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} ãðåøêà â ïðèëîæåíèåòî', + 'ERR_GENERIC_APP_ACTION_FMT': 'Ïðîâàëåíî èçïúëíåíÿâàíå íà äåéñòâèå \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Íåïîçíàòà ãðåøêà', + 'ERR_GENERIC_APP_REQUEST' : 'Ïîëó÷è ñå ãðåøêà ïðè èçïúëíÿâàíå íà çàÿâêàòà', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Ôàòàëíà ãðåøêà: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Îòêàæè ïðîìåíèòå?', + 'MSG_FILE_CHANGED' : 'Ôàéëúò å ïðîìåíåí. ïðåçàðåäè?', + 'MSG_APPLICATION_WARNING' : 'Ïðåäóïðåæäåíèå', + 'MSG_MIME_OVERRIDE' : 'âèäà íà ôàéëà "{0}" íå ñå ïîääúðæà, èçïîëçâàéòå "{1}".', + + // + // General + // + + 'LBL_UNKNOWN' : 'Íåïîçíàò', + 'LBL_APPEARANCE' : 'Âúíøåí âèä', + 'LBL_USER' : 'Ïîòðåáèòåë', + 'LBL_NAME' : 'Èìå', + 'LBL_APPLY' : 'Ïðèëîæè', + 'LBL_FILENAME' : 'Èìå íà ôàéë', + 'LBL_PATH' : 'Ïúò', + 'LBL_SIZE' : 'Ðàçìåð', + 'LBL_TYPE' : 'Òèï', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Çàðåæäàíå', + 'LBL_SETTINGS' : 'Íàñòðîéêè', + 'LBL_ADD_FILE' : 'Äîáàâè ôàéë', + 'LBL_COMMENT' : 'Êîìåíòàð', + 'LBL_ACCOUNT' : 'Àêàóíò', + 'LBL_CONNECT' : 'Ñâúðæè ñå', + 'LBL_ONLINE' : 'Íà ëèíèÿ', + 'LBL_OFFLINE' : 'Èçâúí ëèíèÿ', + 'LBL_AWAY' : 'Îòñúñòâàù', + 'LBL_BUSY' : 'Çàåò', + 'LBL_CHAT' : '×àò', + 'LBL_HELP' : 'Ïîìîù', + 'LBL_ABOUT' : 'Èíôîðìàöèÿ', + 'LBL_PANELS' : 'Ïàíåëè', + 'LBL_LOCALES' : 'Ëîêàëèçàöèÿ', + 'LBL_THEME' : 'Òåìà', + 'LBL_COLOR' : 'Öâÿò', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Ïðåêðàòè', + 'LBL_ALIVE' : 'Âêëþ÷è', + 'LBL_INDEX' : 'Èíäåêñ', + 'LBL_ADD' : 'Äîáàâè', + 'LBL_FONT' : 'Øðèôò', + 'LBL_YES' : 'Äà', + 'LBL_NO' : 'Íå', + 'LBL_CANCEL' : 'Îòêàæè', + 'LBL_TOP' : 'Ãîðå', + 'LBL_LEFT' : 'Ëÿâî', + 'LBL_RIGHT' : 'Äÿñíî', + 'LBL_BOTTOM' : 'Äîëó', + 'LBL_CENTER' : 'Öåíòúð', + 'LBL_FILE' : 'Ôàéë', + 'LBL_NEW' : 'Íîâ', + 'LBL_OPEN' : 'Îòâîðè', + 'LBL_SAVE' : 'Çàïàçè', + 'LBL_SAVEAS' : 'Çàïàçè êàòî...', + 'LBL_CLOSE' : 'Çàòðâîðè', + 'LBL_MKDIR' : 'Ñúçäàé äèðåêòîðèÿ', + 'LBL_UPLOAD' : 'Äîáàâè', + 'LBL_VIEW' : 'Èçãëåä', + 'LBL_EDIT' : 'Ðåäàêòèðàé', + 'LBL_RENAME' : 'Ïðåèìåíóâàé', + 'LBL_DELETE' : 'Èçòðèè', + 'LBL_OPENWITH' : 'Îòâîðè ñ...', + 'LBL_ICONVIEW' : 'Èêîíè', + 'LBL_TREEVIEW' : 'Äúðâî', + 'LBL_LISTVIEW' : 'Ñïèñúê', + 'LBL_REFRESH' : 'Îïðåñíè', + 'LBL_VIEWTYPE' : 'Íà÷èí íà èçãëåä', + 'LBL_BOLD' : 'Ïîëó÷åð', + 'LBL_ITALIC' : 'Íàêëîíåí', + 'LBL_UNDERLINE' : 'Ïîä÷åðòàí', + 'LBL_REGULAR' : 'Îáèêíîâåí', + 'LBL_STRIKE' : 'Strike', + 'LBL_INDENT' : 'Èäåíòèôèêàöèÿ', + 'LBL_OUTDENT' : 'Ïðåñðî÷âàíå', + 'LBL_UNDO' : 'Ïððåìàõíè', + 'LBL_REDO' : 'Îòìåíè ïðåìàõâàíåòî', + 'LBL_CUT' : 'Èçðåæè', + 'LBL_UNLINK' : 'Îòêà÷è', + 'LBL_COPY' : 'Êîïèðàé', + 'LBL_PASTE' : 'Ïîñòàâè', + 'LBL_INSERT' : 'Äîáàâè', + 'LBL_IMAGE' : 'Èçîáðàæåíèå', + 'LBL_LINK' : 'Ëèíê', + 'LBL_DISCONNECT' : 'Èçëåç îò âðúçêà', + 'LBL_APPLICATIONS' : 'Ïðèëîæåíèÿ', + 'LBL_ADD_FOLDER' : 'Äîáàâè ïàïêà', + 'LBL_INFORMATION' : 'Èíôîðìàöèÿ', + 'LBL_TEXT_COLOR' : 'Öâÿò íà òåêñòà', + 'LBL_BACK_COLOR' : 'Öâÿò íà ôîíà', + 'LBL_RESET_DEFAULT' : 'Âúðíè ïî ïîäðàçáèðàíå', + 'LBL_DOWNLOAD_COMP' : 'Èçòåãëÿíå íà êîìïþòúðà', + 'LBL_ORDERED_LIST' : 'Ïîäðåäåí ñïèñúê', + 'LBL_BACKGROUND_IMAGE' : 'Èçîáðàæåíèÿ çà ôîí', + 'LBL_BACKGROUND_COLOR' : 'Öâÿò íà ôîí', + 'LBL_UNORDERED_LIST' : 'Íåïîäðåäåí ñïèñúê', + 'LBL_STATUS' : 'Ñàòóñ', + 'LBL_READONLY' : 'ñàìî çà ÷åòåíå', + 'LBL_CREATED' : 'Ñúçäàäåí', + 'LBL_MODIFIED' : 'Ìîäèôèöèðàí', + 'LBL_SHOW_COLUMNS' : 'Ïîêàæè êîëîíè', + 'LBL_MOVE' : 'Ïðåìåñòè', + 'LBL_OPTIONS' : 'Îïöèè', + 'LBL_OK' : 'ÎÊ', + 'LBL_DIRECTORY' : 'Äèðåêòîðèÿ', + 'LBL_CREATE' : 'Ñúçäàé', + 'LBL_BUGREPORT' : 'Áúã-ðåïîðò', + 'LBL_INSTALL' : 'Èíñòàëèðàé', + 'LBL_UPDATE' : 'Àêòóàëèçèðàé', + 'LBL_REMOVE' : 'Ïðåìàõíè', + 'LBL_SHOW_SIDEBAR' : 'покажи страничен бар', + 'LBL_BACKGROUND' : 'Фон', + 'LBL_DESKTOP' : 'Работен плот', + 'LBL_PANEL' : 'Панел', + 'LBL_POSITION' : 'Позиция', + 'LBL_ONTOP' : 'Най-отгоре', + 'LBL_ITEMS' : 'Обекти', + 'LBL_GENERAL': 'Основен' +}; diff --git a/src/client/javascript/locales/de_DE.js b/src/client/javascript/locales/de_DE.js index 1a5920cdf3..115277d7e4 100644 --- a/src/client/javascript/locales/de_DE.js +++ b/src/client/javascript/locales/de_DE.js @@ -27,258 +27,254 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; +/*eslint key-spacing: "off"*/ - OSjs.Locales.de_DE = { - 'ERR_FILE_OPEN' : 'Fehler beim Öffnen der Datei', - 'ERR_WM_NOT_RUNNING': 'Fenster-Manager wird nicht ausgeführt', - 'ERR_FILE_OPEN_FMT' : 'Die Datei \'**{0}**\' kann nicht geöffnet werden', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Keine Anwendung gefunden, die den Datentyp \'{0}\' unterstützt', - 'ERR_APP_LAUNCH_FAILED' : 'Fehler beim Starten der Anwendung', - 'ERR_APP_LAUNCH_FAILED_FMT': 'Ein Fehler ist aufgetreten, während des Versuchs \'{0}\' zu starten', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Anwendung \'{0}\' construct gescheitert: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Anwendung \'{0}\' init() gescheitert: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Anwendungsressourcen fehlen oder wurden nicht geladen für: {0}', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Anwendung \'{0}\' preloading gescheitert: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Anwendung \'{0}\' ist bereits gestartet und erlaubt nur eine Instanz', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '\'{0}\' konnte nicht gestartet werden. Anwendungsmanifest nicht gefunden!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Uw browser ondersteunt geen: {1}', +module.exports = { + 'ERR_FILE_OPEN' : 'Fehler beim Öffnen der Datei', + 'ERR_WM_NOT_RUNNING': 'Fenster-Manager wird nicht ausgeführt', + 'ERR_FILE_OPEN_FMT' : 'Die Datei \'**{0}**\' kann nicht geöffnet werden', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Keine Anwendung gefunden, die den Datentyp \'{0}\' unterstützt', + 'ERR_APP_LAUNCH_FAILED' : 'Fehler beim Starten der Anwendung', + 'ERR_APP_LAUNCH_FAILED_FMT': 'Ein Fehler ist aufgetreten, während des Versuchs \'{0}\' zu starten', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Anwendung \'{0}\' construct gescheitert: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Anwendung \'{0}\' init() gescheitert: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Anwendungsressourcen fehlen oder wurden nicht geladen für: {0}', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Anwendung \'{0}\' preloading gescheitert: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Anwendung \'{0}\' ist bereits gestartet und erlaubt nur eine Instanz', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '\'{0}\' konnte nicht gestartet werden. Anwendungsmanifest nicht gefunden!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Uw browser ondersteunt geen: {1}', - 'ERR_NO_WM_RUNNING' : 'Es wird kein Fenster-Manager ausgeführt', - 'ERR_CORE_INIT_FAILED' : 'OS.js konnte nicht initialisiert werden', - 'ERR_CORE_INIT_FAILED_DESC' : 'Während der Initialisirung von OS.js ist ein Fehler aufgetreten', - 'ERR_CORE_INIT_NO_WM' : 'OS.js konnte nicht gestartet werden: Fenster-Manager nicht festgelegt!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js konnte nicht gestartet werden: Fenster-Manager konnte nicht gestartet werden: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED': 'OS.js konnte nicht gestartet werden: Resourssen konnten nicht vorab geladen werden...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Fehlerbericht', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Ein unerwarteter Fehler ist aufgetreten, möglicherweise ein Bug', + 'ERR_NO_WM_RUNNING' : 'Es wird kein Fenster-Manager ausgeführt', + 'ERR_CORE_INIT_FAILED' : 'OS.js konnte nicht initialisiert werden', + 'ERR_CORE_INIT_FAILED_DESC' : 'Während der Initialisirung von OS.js ist ein Fehler aufgetreten', + 'ERR_CORE_INIT_NO_WM' : 'OS.js konnte nicht gestartet werden: Fenster-Manager nicht festgelegt!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js konnte nicht gestartet werden: Fenster-Manager konnte nicht gestartet werden: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED': 'OS.js konnte nicht gestartet werden: Resourssen konnten nicht vorab geladen werden...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Fehlerbericht', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Ein unerwarteter Fehler ist aufgetreten, möglicherweise ein Bug', - 'ERR_APP_API_ERROR' : 'Anwendungs API Fehler', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Anwendung {0} konnte Aktion nicht ausführen \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Fehlendes Argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Unbekannter Fehler', + 'ERR_APP_API_ERROR' : 'Anwendungs API Fehler', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Anwendung {0} konnte Aktion nicht ausführen \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Fehlendes Argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Unbekannter Fehler', - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Sie haben bereits ein Fenster namens \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimieren', - 'WINDOW_MAXIMIZE' : 'Maximieren', - 'WINDOW_RESTORE' : 'Wiederherstellen', - 'WINDOW_CLOSE' : 'Schließen', - 'WINDOW_ONTOP_ON' : 'Im Vordergrund - Aktivieren', - 'WINDOW_ONTOP_OFF': 'Im Vordergrund - Deaktivieren', + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Sie haben bereits ein Fenster namens \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimieren', + 'WINDOW_MAXIMIZE' : 'Maximieren', + 'WINDOW_RESTORE' : 'Wiederherstellen', + 'WINDOW_CLOSE' : 'Schließen', + 'WINDOW_ONTOP_ON' : 'Im Vordergrund - Aktivieren', + 'WINDOW_ONTOP_OFF': 'Im Vordergrund - Deaktivieren', - // Handler - 'TITLE_SIGN_OUT' : 'Abmelden', - 'TITLE_SIGNED_IN_AS_FMT' : 'Angemeldet als: {0}', + // Handler + 'TITLE_SIGN_OUT' : 'Abmelden', + 'TITLE_SIGNED_IN_AS_FMT' : 'Angemeldet als: {0}', - // Dialogs - 'DIALOG_LOGOUT_TITLE' : 'Abmelden (Exit)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Benutzer wird abgemeldet \'{0}\'.\nWollen Sie die aktuelle Sitzung speichern?', + // Dialogs + 'DIALOG_LOGOUT_TITLE' : 'Abmelden (Exit)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Benutzer wird abgemeldet \'{0}\'.\nWollen Sie die aktuelle Sitzung speichern?', - 'DIALOG_CLOSE' : 'Schließen', - 'DIALOG_CANCEL': 'Abbrechen', - 'DIALOG_APPLY' : 'Übernehmen', - 'DIALOG_OK' : 'OK', + 'DIALOG_CLOSE' : 'Schließen', + 'DIALOG_CANCEL': 'Abbrechen', + 'DIALOG_APPLY' : 'Übernehmen', + 'DIALOG_OK' : 'OK', - 'DIALOG_ALERT_TITLE' : 'Warnungsdialog', + 'DIALOG_ALERT_TITLE' : 'Warnungsdialog', - 'DIALOG_COLOR_TITLE' : 'Farb-Dialog', - 'DIALOG_COLOR_R' : 'Rot: {0}', - 'DIALOG_COLOR_G' : 'Grün: {0}', - 'DIALOG_COLOR_B' : 'Blau: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', + 'DIALOG_COLOR_TITLE' : 'Farb-Dialog', + 'DIALOG_COLOR_R' : 'Rot: {0}', + 'DIALOG_COLOR_G' : 'Grün: {0}', + 'DIALOG_COLOR_B' : 'Blau: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', - 'DIALOG_CONFIRM_TITLE' : 'Bestätigungsdialog', + 'DIALOG_CONFIRM_TITLE' : 'Bestätigungsdialog', - 'DIALOG_ERROR_MESSAGE' : 'Meldung', - 'DIALOG_ERROR_SUMMARY' : 'Zusammenfassung', - 'DIALOG_ERROR_TRACE' : 'Trace', - 'DIALOG_ERROR_BUGREPORT' : 'Fehlerbericht', + 'DIALOG_ERROR_MESSAGE' : 'Meldung', + 'DIALOG_ERROR_SUMMARY' : 'Zusammenfassung', + 'DIALOG_ERROR_TRACE' : 'Trace', + 'DIALOG_ERROR_BUGREPORT' : 'Fehlerbericht', - 'DIALOG_FILE_SAVE' : 'Speichern', - 'DIALOG_FILE_OPEN' : 'Öffnen', - 'DIALOG_FILE_MKDIR' : 'Verzeichnis erstellen', - 'DIALOG_FILE_MKDIR_MSG' : 'Erstelle ein neues Verzeichnis in **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Sind Sie sicher, dass Sie die Datei \'{0}\' überschreiben wollen?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Ansichtstyp', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Baum', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Symbole', - 'DIALOG_FILE_ERROR' : 'Datei-Dialog Fehler', - 'DIALOG_FILE_ERROR_SCANDIR': 'Verzeichnis \'{0}\' konnte nicht geöffnet werden', - 'DIALOG_FILE_MISSING_FILENAME' : 'Sie müssen eine Datei auswählen oder geben Sie einen neuen Dateinamen an!', - 'DIALOG_FILE_MISSING_SELECTION': 'Sie müssen eine Datei auswählen!', + 'DIALOG_FILE_SAVE' : 'Speichern', + 'DIALOG_FILE_OPEN' : 'Öffnen', + 'DIALOG_FILE_MKDIR' : 'Verzeichnis erstellen', + 'DIALOG_FILE_MKDIR_MSG' : 'Erstelle ein neues Verzeichnis in **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Sind Sie sicher, dass Sie die Datei \'{0}\' überschreiben wollen?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Ansichtstyp', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Baum', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Symbole', + 'DIALOG_FILE_ERROR' : 'Datei-Dialog Fehler', + 'DIALOG_FILE_ERROR_SCANDIR': 'Verzeichnis \'{0}\' konnte nicht geöffnet werden', + 'DIALOG_FILE_MISSING_FILENAME' : 'Sie müssen eine Datei auswählen oder geben Sie einen neuen Dateinamen an!', + 'DIALOG_FILE_MISSING_SELECTION': 'Sie müssen eine Datei auswählen!', - 'DIALOG_FILEINFO_TITLE' : 'Dateiinformationen', - 'DIALOG_FILEINFO_LOADING' : 'Laster fil-informasjon for: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Dateiinformationen Dialog Fehler', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Fehler beim bekommen von Dateiinformationen für **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Fehler beim bekommen von Dateiinformationen für: {0}', + 'DIALOG_FILEINFO_TITLE' : 'Dateiinformationen', + 'DIALOG_FILEINFO_LOADING' : 'Laster fil-informasjon for: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Dateiinformationen Dialog Fehler', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Fehler beim bekommen von Dateiinformationen für **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Fehler beim bekommen von Dateiinformationen für: {0}', - 'DIALOG_INPUT_TITLE' : 'Eingabedialog', + 'DIALOG_INPUT_TITLE' : 'Eingabedialog', - 'DIALOG_FILEPROGRESS_TITLE' : 'Fortschritt', - 'DIALOG_FILEPROGRESS_LOADING' : 'Lade...', + 'DIALOG_FILEPROGRESS_TITLE' : 'Fortschritt', + 'DIALOG_FILEPROGRESS_LOADING' : 'Lade...', - 'DIALOG_UPLOAD_TITLE' : 'Upload-Dialog', - 'DIALOG_UPLOAD_DESC' : 'Upload nach **{0}**.
Maximale Größe: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Hochladen von \'{0}\' ({1} {2}) von {3}', - 'DIALOG_UPLOAD_MSG' : 'Datei-Upload...', - 'DIALOG_UPLOAD_FAILED' : 'Upload fehlgeschlagen', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Der Upload ist fehlgeschlagen', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Unbekannter Grund...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Abbruch durch Benutzer...', + 'DIALOG_UPLOAD_TITLE' : 'Upload-Dialog', + 'DIALOG_UPLOAD_DESC' : 'Upload nach **{0}**.
Maximale Größe: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Hochladen von \'{0}\' ({1} {2}) von {3}', + 'DIALOG_UPLOAD_MSG' : 'Datei-Upload...', + 'DIALOG_UPLOAD_FAILED' : 'Upload fehlgeschlagen', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Der Upload ist fehlgeschlagen', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Unbekannter Grund...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Abbruch durch Benutzer...', - 'DIALOG_FONT_TITLE' : 'Schriftarten-Dialog', + 'DIALOG_FONT_TITLE' : 'Schriftarten-Dialog', - 'DIALOG_APPCHOOSER_TITLE' : 'Wählen Sie eine Anwendung', - 'DIALOG_APPCHOOSER_MSG' : 'Wählen Sie eine Anwendung zum Öffnen', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Sie müssen eine Anwendung auswählen', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Als Standartanwendung für {0} verwenden', + 'DIALOG_APPCHOOSER_TITLE' : 'Wählen Sie eine Anwendung', + 'DIALOG_APPCHOOSER_MSG' : 'Wählen Sie eine Anwendung zum Öffnen', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Sie müssen eine Anwendung auswählen', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Als Standartanwendung für {0} verwenden', - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Modul ist nicht konfiguriert oder aktiviert', - 'GAPI_NOTIFICATION_TITLE' : 'Sie sind bei Google API angemeldet', - 'GAPI_SIGN_OUT' : 'Von Google API Dienst abmelden', - 'GAPI_REVOKE' : 'Berechtigungen wiederrufen und abmelden', - 'GAPI_AUTH_FAILURE' : 'Google API Authentifizierung ist fehlgeschlagen oder fand nicht statt', - 'GAPI_AUTH_FAILURE_FMT' : 'Fehler beim Authentifizieren: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Konnte Google API nicht laden', + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Modul ist nicht konfiguriert oder aktiviert', + 'GAPI_NOTIFICATION_TITLE' : 'Sie sind bei Google API angemeldet', + 'GAPI_SIGN_OUT' : 'Von Google API Dienst abmelden', + 'GAPI_REVOKE' : 'Berechtigungen wiederrufen und abmelden', + 'GAPI_AUTH_FAILURE' : 'Google API Authentifizierung ist fehlgeschlagen oder fand nicht statt', + 'GAPI_AUTH_FAILURE_FMT' : 'Fehler beim Authentifizieren: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Konnte Google API nicht laden', - // IndexedDB - 'IDB_MISSING_DBNAME' : 'IndexedDB kann nicht ohne Datenbankname erstellt werden', - 'IDB_NO_SUCH_ITEM' : 'Keine Elemente', + // IndexedDB + 'IDB_MISSING_DBNAME' : 'IndexedDB kann nicht ohne Datenbankname erstellt werden', + 'IDB_NO_SUCH_ITEM' : 'Keine Elemente', - // VFS - 'ERR_VFS_FATAL' : 'Schwerwiegender Fehler', - 'ERR_VFS_FILE_ARGS' : 'Datei erwartet mindestens ein Argument', - 'ERR_VFS_NUM_ARGS' : 'Nicht genug Argumente', - 'ERR_VFS_EXPECT_FILE' : 'Erwartet ein Datei-Objekt', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Erwartet einen Quelldatei-Objekt', - 'ERR_VFS_EXPECT_DST_FILE' : 'Erwartet ein Zieldatei-Objekt', - 'ERR_VFS_FILE_EXISTS' : 'Ziel existiert bereits', - 'ERR_VFS_TRANSFER_FMT' : 'Während des übertragen zwischen Speicher ist ein Fehler aufgetreten: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Eine Datei ohne Ziel kann nicht hochgeladen werden', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Ohne Dateien zu definieren kann nicht hochgeladen werden', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Datei-Upload fehlgeschlagen: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Datei-Upload wurde abgebrochen', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kann keinen Pfad ohne angegebenen Pfad herunterladen', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Während des Downloads ist ein Fehler aufgetreten: {0}', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Datei herunterladen', + // VFS + 'ERR_VFS_FATAL' : 'Schwerwiegender Fehler', + 'ERR_VFS_FILE_ARGS' : 'Datei erwartet mindestens ein Argument', + 'ERR_VFS_NUM_ARGS' : 'Nicht genug Argumente', + 'ERR_VFS_EXPECT_FILE' : 'Erwartet ein Datei-Objekt', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Erwartet einen Quelldatei-Objekt', + 'ERR_VFS_EXPECT_DST_FILE' : 'Erwartet ein Zieldatei-Objekt', + 'ERR_VFS_FILE_EXISTS' : 'Ziel existiert bereits', + 'ERR_VFS_TRANSFER_FMT' : 'Während des übertragen zwischen Speicher ist ein Fehler aufgetreten: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Eine Datei ohne Ziel kann nicht hochgeladen werden', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Ohne Dateien zu definieren kann nicht hochgeladen werden', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Datei-Upload fehlgeschlagen: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Datei-Upload wurde abgebrochen', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kann keinen Pfad ohne angegebenen Pfad herunterladen', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Während des Downloads ist ein Fehler aufgetreten: {0}', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Datei herunterladen', - // DefaultApplication - 'ERR_FILE_APP_OPEN' : 'Datei kann nicht geöffnet werden', - 'ERR_FILE_APP_OPEN_FMT' : 'Die Datei {0} kann nicht geöffnet werden, da der Dateityp (MIME) {1} nicht unterstützt wird', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Die Datei {0} konnte nicht geöffnet werden: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Die Datei {0} konnte nicht gespeichert werden: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Anwendungsfehler', - 'ERR_GENERIC_APP_ACTION_FMT': 'Konnte Aktion nicht durchführen: \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Unbekannter Fehler', - 'ERR_GENERIC_APP_REQUEST' : 'Während Ihres Requests ist ein Fehler aufgetreten', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Schwerwiegender Fehler: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Aktuelles Dokument verwerfen?', - 'MSG_FILE_CHANGED' : 'Die Datei wurde geändert. Neuladen?', - 'MSG_APPLICATION_WARNING' : 'Anwendungswarnung', - 'MSG_MIME_OVERRIDE' : 'Der Dateityp "{0}" wird nicht unterstützt, benutzen Sie "{1}" stattdessen.', + // DefaultApplication + 'ERR_FILE_APP_OPEN' : 'Datei kann nicht geöffnet werden', + 'ERR_FILE_APP_OPEN_FMT' : 'Die Datei {0} kann nicht geöffnet werden, da der Dateityp (MIME) {1} nicht unterstützt wird', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Die Datei {0} konnte nicht geöffnet werden: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Die Datei {0} konnte nicht gespeichert werden: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Anwendungsfehler', + 'ERR_GENERIC_APP_ACTION_FMT': 'Konnte Aktion nicht durchführen: \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Unbekannter Fehler', + 'ERR_GENERIC_APP_REQUEST' : 'Während Ihres Requests ist ein Fehler aufgetreten', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Schwerwiegender Fehler: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Aktuelles Dokument verwerfen?', + 'MSG_FILE_CHANGED' : 'Die Datei wurde geändert. Neuladen?', + 'MSG_APPLICATION_WARNING' : 'Anwendungswarnung', + 'MSG_MIME_OVERRIDE' : 'Der Dateityp "{0}" wird nicht unterstützt, benutzen Sie "{1}" stattdessen.', - // General - 'LBL_UNKNOWN' : 'Unbekannt', - 'LBL_APPEARANCE' : 'Aussehen', - 'LBL_USER' : 'Benutzer', - 'LBL_NAME' : 'Name', - 'LBL_APPLY' : 'Übernehmen', - 'LBL_FILENAME' : 'Dateiname', - 'LBL_PATH' : 'Pfad', - 'LBL_SIZE' : 'Größe', - 'LBL_TYPE' : 'Type', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Lade', - 'LBL_SETTINGS' : 'Einstellungen', - 'LBL_ADD_FILE' : 'Datei hinzufügen', - 'LBL_COMMENT' : 'Kommentar', - 'LBL_ACCOUNT' : 'Konto', - 'LBL_CONNECT' : 'Verbinden', - 'LBL_ONLINE' : 'Online', - 'LBL_OFFLINE' : 'Offline', - 'LBL_AWAY' : 'Abwesend', - 'LBL_BUSY' : 'Beschäftigt', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Hilfe', - 'LBL_ABOUT' : 'Über', - 'LBL_PANELS' : 'Panel', - 'LBL_LOCALES' : 'Lokalisierung', - 'LBL_THEME' : 'Design', - 'LBL_COLOR' : 'Farbe', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Beenden (Kill)', - 'LBL_ALIVE' : 'Aktiv', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Hinzufügen', - 'LBL_FONT' : 'Schriftart', - 'LBL_YES' : 'Ja', - 'LBL_NO' : 'Nein', - 'LBL_CANCEL' : 'Abbrechen', - 'LBL_TOP' : 'Oben', - 'LBL_LEFT' : 'Links', - 'LBL_RIGHT' : 'Right', - 'LBL_BOTTOM' : 'Unten', - 'LBL_CENTER' : 'Zentriert', - 'LBL_FILE' : 'Datei', - 'LBL_NEW' : 'Neu', - 'LBL_OPEN' : 'Öffnen', - 'LBL_SAVE' : 'Speichern', - 'LBL_SAVEAS' : 'Speichern unter...', - 'LBL_CLOSE' : 'Schließen', - 'LBL_MKDIR' : 'Verzeichnis erstellen', - 'LBL_UPLOAD' : 'Hochladen', - 'LBL_VIEW' : 'Ansicht', - 'LBL_EDIT' : 'Bearbeiten', - 'LBL_RENAME' : 'Umbenennen', - 'LBL_DELETE' : 'Löschen', - 'LBL_OPENWITH' : 'Öffnen mit...', - 'LBL_ICONVIEW' : 'Symbole', - 'LBL_TREEVIEW' : 'Baum', - 'LBL_LISTVIEW' : 'Liste', - 'LBL_REFRESH' : 'Aktualisieren', - 'LBL_VIEWTYPE' : 'Ansichtstyp', - 'LBL_BOLD' : 'Fett', - 'LBL_ITALIC' : 'Kursiv', - 'LBL_UNDERLINE' : 'Unterstrichen', - 'LBL_REGULAR' : 'Regelmäßig', - 'LBL_STRIKE' : 'Gjennomstrek', - 'LBL_INDENT' : 'Einzug', - 'LBL_OUTDENT' : 'Negativeinzug', - 'LBL_UNDO' : 'Rückgängig', - 'LBL_REDO' : 'Vorwärts', - 'LBL_CUT' : 'Ausschneiden', - 'LBL_UNLINK' : 'Verknüpfung entfernen', - 'LBL_COPY' : 'Kopieren', - 'LBL_PASTE' : 'Einfügen', - 'LBL_INSERT' : 'Einfügen', - 'LBL_IMAGE' : 'Bild', - 'LBL_LINK' : 'Verknüpfung', - 'LBL_DISCONNECT' : 'Disconnect', - 'LBL_APPLICATIONS' : 'Anwendung', - 'LBL_ADD_FOLDER' : 'Verzeichnis hinzufügen', - 'LBL_INFORMATION' : 'Information', - 'LBL_TEXT_COLOR' : 'Textfarbe', - 'LBL_BACK_COLOR' : 'Hintergrundfarbe', - 'LBL_RESET_DEFAULT' : 'Werkseinstellungen wiederherstellen', - 'LBL_DOWNLOAD_COMP' : 'Auf PC herunterladen', - 'LBL_ORDERED_LIST' : 'Sortierte Liste', - 'LBL_BACKGROUND_IMAGE' : 'Hintergrundbild', - 'LBL_BACKGROUND_COLOR' : 'Hintergrundfarbe', - 'LBL_UNORDERED_LIST' : 'Unsortierte Liste', - 'LBL_SHOW_SIDEBAR' : 'Seitenleiste anzeigen', - 'LBL_BACKGROUND' : 'Hintergrund', - 'LBL_DESKTOP' : 'Arbeitsoberflächen', - 'LBL_PANEL' : 'Panel', - 'LBL_POSITION' : 'Position', - 'LBL_ONTOP' : 'Vordergrund', - 'LBL_ITEMS' : 'Items', - 'LBL_GENERAL': 'General' - }; - -})(); + // General + 'LBL_UNKNOWN' : 'Unbekannt', + 'LBL_APPEARANCE' : 'Aussehen', + 'LBL_USER' : 'Benutzer', + 'LBL_NAME' : 'Name', + 'LBL_APPLY' : 'Übernehmen', + 'LBL_FILENAME' : 'Dateiname', + 'LBL_PATH' : 'Pfad', + 'LBL_SIZE' : 'Größe', + 'LBL_TYPE' : 'Type', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Lade', + 'LBL_SETTINGS' : 'Einstellungen', + 'LBL_ADD_FILE' : 'Datei hinzufügen', + 'LBL_COMMENT' : 'Kommentar', + 'LBL_ACCOUNT' : 'Konto', + 'LBL_CONNECT' : 'Verbinden', + 'LBL_ONLINE' : 'Online', + 'LBL_OFFLINE' : 'Offline', + 'LBL_AWAY' : 'Abwesend', + 'LBL_BUSY' : 'Beschäftigt', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Hilfe', + 'LBL_ABOUT' : 'Über', + 'LBL_PANELS' : 'Panel', + 'LBL_LOCALES' : 'Lokalisierung', + 'LBL_THEME' : 'Design', + 'LBL_COLOR' : 'Farbe', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Beenden (Kill)', + 'LBL_ALIVE' : 'Aktiv', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Hinzufügen', + 'LBL_FONT' : 'Schriftart', + 'LBL_YES' : 'Ja', + 'LBL_NO' : 'Nein', + 'LBL_CANCEL' : 'Abbrechen', + 'LBL_TOP' : 'Oben', + 'LBL_LEFT' : 'Links', + 'LBL_RIGHT' : 'Right', + 'LBL_BOTTOM' : 'Unten', + 'LBL_CENTER' : 'Zentriert', + 'LBL_FILE' : 'Datei', + 'LBL_NEW' : 'Neu', + 'LBL_OPEN' : 'Öffnen', + 'LBL_SAVE' : 'Speichern', + 'LBL_SAVEAS' : 'Speichern unter...', + 'LBL_CLOSE' : 'Schließen', + 'LBL_MKDIR' : 'Verzeichnis erstellen', + 'LBL_UPLOAD' : 'Hochladen', + 'LBL_VIEW' : 'Ansicht', + 'LBL_EDIT' : 'Bearbeiten', + 'LBL_RENAME' : 'Umbenennen', + 'LBL_DELETE' : 'Löschen', + 'LBL_OPENWITH' : 'Öffnen mit...', + 'LBL_ICONVIEW' : 'Symbole', + 'LBL_TREEVIEW' : 'Baum', + 'LBL_LISTVIEW' : 'Liste', + 'LBL_REFRESH' : 'Aktualisieren', + 'LBL_VIEWTYPE' : 'Ansichtstyp', + 'LBL_BOLD' : 'Fett', + 'LBL_ITALIC' : 'Kursiv', + 'LBL_UNDERLINE' : 'Unterstrichen', + 'LBL_REGULAR' : 'Regelmäßig', + 'LBL_STRIKE' : 'Gjennomstrek', + 'LBL_INDENT' : 'Einzug', + 'LBL_OUTDENT' : 'Negativeinzug', + 'LBL_UNDO' : 'Rückgängig', + 'LBL_REDO' : 'Vorwärts', + 'LBL_CUT' : 'Ausschneiden', + 'LBL_UNLINK' : 'Verknüpfung entfernen', + 'LBL_COPY' : 'Kopieren', + 'LBL_PASTE' : 'Einfügen', + 'LBL_INSERT' : 'Einfügen', + 'LBL_IMAGE' : 'Bild', + 'LBL_LINK' : 'Verknüpfung', + 'LBL_DISCONNECT' : 'Disconnect', + 'LBL_APPLICATIONS' : 'Anwendung', + 'LBL_ADD_FOLDER' : 'Verzeichnis hinzufügen', + 'LBL_INFORMATION' : 'Information', + 'LBL_TEXT_COLOR' : 'Textfarbe', + 'LBL_BACK_COLOR' : 'Hintergrundfarbe', + 'LBL_RESET_DEFAULT' : 'Werkseinstellungen wiederherstellen', + 'LBL_DOWNLOAD_COMP' : 'Auf PC herunterladen', + 'LBL_ORDERED_LIST' : 'Sortierte Liste', + 'LBL_BACKGROUND_IMAGE' : 'Hintergrundbild', + 'LBL_BACKGROUND_COLOR' : 'Hintergrundfarbe', + 'LBL_UNORDERED_LIST' : 'Unsortierte Liste', + 'LBL_SHOW_SIDEBAR' : 'Seitenleiste anzeigen', + 'LBL_BACKGROUND' : 'Hintergrund', + 'LBL_DESKTOP' : 'Arbeitsoberflächen', + 'LBL_PANEL' : 'Panel', + 'LBL_POSITION' : 'Position', + 'LBL_ONTOP' : 'Vordergrund', + 'LBL_ITEMS' : 'Items', + 'LBL_GENERAL': 'General' +}; diff --git a/src/client/javascript/locales/en_EN.js b/src/client/javascript/locales/en_EN.js index 6cd288766a..f5422e5304 100644 --- a/src/client/javascript/locales/en_EN.js +++ b/src/client/javascript/locales/en_EN.js @@ -27,467 +27,466 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.en_EN = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Error opening file', - 'ERR_WM_NOT_RUNNING' : 'Window manager is not running', - 'ERR_FILE_OPEN_FMT' : 'The file \'**{0}**\' could not be opened', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Could not find any Applications with support for \'{0}\' files', - 'ERR_APP_LAUNCH_FAILED' : 'Failed to launch Application', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'An error occured while trying to launch: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Application \'{0}\' construct failed: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Application \'{0}\' init() failed: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Application resources missing for \'{0}\' or it failed to load!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Application \'{0}\' preloading failed: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'The application \'{0}\' is already launched and allows only one instance!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Failed to launch \'{0}\'. Application manifest data not found!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Failed to launch \'{0}\'. Your browser does not support: {1}', - - 'ERR_NO_WM_RUNNING' : 'No window manager is running', - 'ERR_CORE_INIT_FAILED' : 'Failed to initialize OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'An error occured while initializing OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Cannot launch OS.js: No window manager defined!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Cannot launch OS.js: Failed to launch Window Manager: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Cannot launch OS.js: Failed to preload resources...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Error Report', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'An unexpected error occured, maybe a bug.', - - 'ERR_APP_API_ERROR' : 'Application API error', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Application {0} failed to perform operation \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Missing argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Unknown error', - - 'ERR_OPERATION_TIMEOUT' : 'Operation Timeout', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Timeout ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' expects \'{1}\' to be a \'{2}\', \'{3}\' given', - 'ERR_INVALID_LOCATION': 'Invalid location', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'You already have a Window named \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimize', - 'WINDOW_MAXIMIZE' : 'Maximize', - 'WINDOW_RESTORE' : 'Restore', - 'WINDOW_CLOSE' : 'Close', - 'WINDOW_ONTOP_ON' : 'Ontop (Enable)', - 'WINDOW_ONTOP_OFF': 'Ontop (Disable)', - - // Handler - 'TITLE_SIGN_OUT' : 'Sign out', - 'TITLE_SIGNED_IN_AS_FMT' : 'Signed in as: {0}', - 'ERR_LOGIN_FMT' : 'Login error: {0}', - 'ERR_LOGIN_INVALID' : 'Invalid login', - - // SESSION - 'ERR_NO_SESSION': 'No session was created by the server. Do you want to retry login?', - 'MSG_SESSION_WARNING' : 'Are you sure you want to quit OS.js? All unsaved settings and application data will be lost!', - - // Service - 'BUGREPORT_MSG' : 'Please report this if you think this is a bug.\nInclude a brief description on how the error occured, and if you can; how to replicate it', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Logged into external services: {0}', - 'CONNECTION_LOST': 'Connection to the server was lost. Reconnecting...', - 'CONNECTION_RESTORED': 'Connection to the server was restored', - 'CONNECTION_RESTORE_FAILED': 'Failed to re-establish connection. Trying again.', - 'CONNECTION_ERROR': 'Connection error', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Fatal Error', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Error: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Log out (Exit)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Logging out user \'{0}\'.\nDo you want to save current session?', - - 'DIALOG_CLOSE' : 'Close', - 'DIALOG_CANCEL': 'Cancel', - 'DIALOG_APPLY' : 'Apply', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Alert Dialog', - - 'DIALOG_COLOR_TITLE' : 'Color Dialog', - 'DIALOG_COLOR_R' : 'Red: {0}', - 'DIALOG_COLOR_G' : 'Green: {0}', - 'DIALOG_COLOR_B' : 'Blue: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Confirm Dialog', - - 'DIALOG_ERROR_TITLE' : 'Error', - 'DIALOG_ERROR_MESSAGE' : 'Message', - 'DIALOG_ERROR_SUMMARY' : 'Summary', - 'DIALOG_ERROR_TRACE' : 'Trace', - 'DIALOG_ERROR_BUGREPORT' : 'Report Bug', - - 'DIALOG_FILE_SAVE' : 'Save', - 'DIALOG_FILE_OPEN' : 'Open', - 'DIALOG_FILE_MKDIR' : 'New Folder', - 'DIALOG_FILE_MKDIR_MSG' : 'Create a new directory in **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Are you sure you want to overwrite the file \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'View type', - 'DIALOG_FILE_MNU_LISTVIEW' : 'List View', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Tree View', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Icon View', - 'DIALOG_FILE_ERROR' : 'FileDialog Error', - 'DIALOG_FILE_ERROR_SCANDIR': 'Failed listing directory \'{0}\' because an error occured', - 'DIALOG_FILE_ERROR_FIND': 'Failed searching directory \'{0}\' because an error occured', - 'DIALOG_FILE_MISSING_FILENAME' : 'You need to select a file or enter new filename!', - 'DIALOG_FILE_MISSING_SELECTION': 'You need to select a file!', - - 'DIALOG_FILEINFO_TITLE' : 'File Information', - 'DIALOG_FILEINFO_LOADING' : 'Loading file information for: {0}', - 'DIALOG_FILEINFO_ERROR' : 'FileInformationDialog Error', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Failed to get file information for **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Failed to get file information for: {0}', - - 'DIALOG_INPUT_TITLE' : 'Input Dialog', - - 'DIALOG_FILEPROGRESS_TITLE' : 'File Operation Progress', - 'DIALOG_FILEPROGRESS_LOADING' : 'Loading...', - - 'DIALOG_UPLOAD_TITLE' : 'Upload Dialog', - 'DIALOG_UPLOAD_DESC' : 'Upload file to **{0}**.
Maximum size: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Uploading \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Uploading file...', - 'DIALOG_UPLOAD_FAILED' : 'Upload failed', - 'DIALOG_UPLOAD_FAILED_MSG' : 'The upload has failed', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Reason unknown...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelled by user...', - 'DIALOG_UPLOAD_TOO_BIG': 'File is too big', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'File is too big, exceeds {0}', - - 'DIALOG_FONT_TITLE' : 'Font Dialog', - - 'DIALOG_APPCHOOSER_TITLE' : 'Choose Application', - 'DIALOG_APPCHOOSER_MSG' : 'Choose an application to open', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'You need to select an application', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Use as default application for {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Module not configured or disabled', - 'GAPI_SIGN_OUT' : 'Sign out from Google API Services', - 'GAPI_REVOKE' : 'Revoke permissions and Sign Out', - 'GAPI_AUTH_FAILURE' : 'Google API Authentication failed or did not take place', - 'GAPI_AUTH_FAILURE_FMT' : 'Failed to authenticate: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Failed to load Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API module not configured or disabled', - 'WLAPI_SIGN_OUT' : 'Sign out from Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Failed to load Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Failed to log into Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Failed to log into Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Cannot create IndexedDB without Database Name', - 'IDB_NO_SUCH_ITEM' : 'No such item', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Fatal Error', - 'ERR_VFS_UNAVAILABLE' : 'Not available', - 'ERR_VFS_FILE_ARGS' : 'File expects at least one argument', - 'ERR_VFS_NUM_ARGS' : 'Not enough arguments', - 'ERR_VFS_EXPECT_FILE' : 'Expects a file-object', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Expects a source file-object', - 'ERR_VFS_EXPECT_DST_FILE' : 'Expects a destination file-object', - 'ERR_VFS_FILE_EXISTS' : 'Destination already exists', - 'ERR_VFS_TARGET_NOT_EXISTS': 'Target does not exist', - 'ERR_VFS_TRANSFER_FMT' : 'An error occured while transfering between storage: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Cannot upload a file without a destination', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Cannot upload without any files defined', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'File upload failed: {0}', - 'ERR_VFS_UPLOAD_CANCELLED' : 'File upload was cancelled', - 'ERR_VFS_DOWNLOAD_NO_FILE' : 'Cannot download a path without a path', - 'ERR_VFS_DOWNLOAD_FAILED' : 'An error occured while downloading: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY' : 'Response was empty', - 'ERR_VFS_NO_MIME_DETECT' : 'No mime type detected', - - 'ERR_VFSMODULE_INVALID' : 'Invalid VFS Module', - 'ERR_VFSMODULE_INVALID_FMT' : 'Invalid VFS Module: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Invalid VFS Method', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Invalid VFS Method: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Invalid VFS Module type', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Invalid VFS Module type: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Invalid VFS Module configuration', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Invalid VFS Module configuration: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Module already mounted', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Module \'{0}\' already mounted', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Module not mounted', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Module \'{0}\' not mounted', - 'ERR_VFSMODULE_EXCEPTION' : 'VFS Module Exception', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Module Exception: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'No VFS Module matches {0}. Wrong path or format ?', - 'ERR_VFSMODULE_READONLY' : 'This VFS Module is read-only', - 'ERR_VFSMODULE_READONLY_FMT' : 'This VFS Module is read-only: {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Downloading file', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Error', - 'ERR_VFSMODULE_ROOT_ID' : 'Failed to find root folder id', - 'ERR_VFSMODULE_NOSUCH' : 'File does not exist', - 'ERR_VFSMODULE_PARENT' : 'No such parent', - 'ERR_VFSMODULE_PARENT_FMT' : 'Failed to look up parent: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Failed to scan directory', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Failed to scan directory: {0}', - 'ERR_VFSMODULE_READ' : 'Failed to read file', - 'ERR_VFSMODULE_READ_FMT' : 'Failed to read file: {0}', - 'ERR_VFSMODULE_WRITE' : 'Failed to write file', - 'ERR_VFSMODULE_WRITE_FMT' : 'Failed to write file: {0}', - 'ERR_VFSMODULE_COPY' : 'Failed to copy', - 'ERR_VFSMODULE_COPY_FMT' : 'Failed to copy: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Failed to unlink file', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Failed to unlink file: {0}', - 'ERR_VFSMODULE_MOVE' : 'Failed to move file', - 'ERR_VFSMODULE_MOVE_FMT' : 'Failed to move file: {0}', - 'ERR_VFSMODULE_EXIST' : 'Failed to check file existence', - 'ERR_VFSMODULE_EXIST_FMT' : 'Failed to check file existence: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Failed to get file information', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Failed to get file information: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Failed to create directory', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Failed to create directory: {0}', - 'ERR_VFSMODULE_MKFILE' : 'Failed to create file', - 'ERR_VFSMODULE_MKFILE_FMT' : 'Failed to create file: {0}', - 'ERR_VFSMODULE_URL' : 'Failed to get URL for file', - 'ERR_VFSMODULE_URL_FMT' : 'Failed to get URL for file: {0}', - 'ERR_VFSMODULE_TRASH' : 'Failed to move file to trash', - 'ERR_VFSMODULE_TRASH_FMT' : 'Failed to move file to trash: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Failed to move file out of trash', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Failed to move file out of trash: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Failed to empty trash', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Failed to empty trash: {0}', - 'ERR_VFSMODULE_FIND' : 'Failed to search', - 'ERR_VFSMODULE_FIND_FMT' : 'Failed to search: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'Failed to get free space', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'Failed to get free space: {0}', - 'ERR_VFSMODULE_EXISTS' : 'Failed to check if exists', - 'ERR_VFSMODULE_EXISTS_FMT' : 'Failed to check if exists: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'You are signed in to Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Sign out from Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Failed to resolve path: item not found', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'Failed to load zip.js', - 'ZIP_VENDOR_FAIL' : 'zip.js library was not found. Did it load properly?', - 'ZIP_NO_RESOURCE' : 'No zip resource was given', - 'ZIP_NO_PATH' : 'No path given', - - // - // SearchEngine - // - 'SEARCH_LOADING': 'Searching...', - 'SEARCH_NO_RESULTS': 'No results found', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Package installation directory already exists. Cannot continue!', - 'ERR_PACKAGE_MANIFEST': 'Failed to load package manifest', - 'ERR_PACKAGE_ENUM_FAILED': 'Failed to get package list. Make sure you\'re not using "Private Mode" as this might case problems.', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Cannot open file', - 'ERR_FILE_APP_OPEN_FMT' : 'The file {0} could not be opened because the mime {1} is not supported', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'The file {0} could not be opened: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'The file {0} could not be saved: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Application Error', - 'ERR_GENERIC_APP_ACTION_FMT': 'Failed to perform action \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Unknown Error', - 'ERR_GENERIC_APP_REQUEST' : 'An error occured while handling your request', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatal Error: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Discard changes?', - 'MSG_FILE_CHANGED' : 'The file has changed. Reload?', - 'MSG_APPLICATION_WARNING' : 'Application Warning', - 'MSG_MIME_OVERRIDE' : 'The filetype "{0}" is not supported, using "{1}" instead.', - - 'ERR_OPEN_LOCATION' : 'Failed to open location', - 'ERR_OPEN_LOCATION_FMT' : 'Failed to open location: {0}', - - // - // General - // - - 'LBL_UNKNOWN' : 'Unknown', - 'LBL_APPEARANCE' : 'Appearance', - 'LBL_USER' : 'User', - 'LBL_NAME' : 'Name', - 'LBL_APPLY' : 'Apply', - 'LBL_FILENAME' : 'Filename', - 'LBL_PATH' : 'Path', - 'LBL_SIZE' : 'Size', - 'LBL_TYPE' : 'Type', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Loading', - 'LBL_SETTINGS' : 'Settings', - 'LBL_ADD_FILE' : 'Add file', - 'LBL_COMMENT' : 'Comment', - 'LBL_ACCOUNT' : 'Account', - 'LBL_CONNECT' : 'Connect', - 'LBL_ONLINE' : 'Online', - 'LBL_OFFLINE' : 'Offline', - 'LBL_AWAY' : 'Away', - 'LBL_BUSY' : 'Busy', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Help', - 'LBL_ABOUT' : 'About', - 'LBL_PANELS' : 'Panels', - 'LBL_LOCALES' : 'Locales', - 'LBL_THEME' : 'Theme', - 'LBL_COLOR' : 'Color', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Kill', - 'LBL_ALIVE' : 'Alive', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Add', - 'LBL_FONT' : 'Font', - 'LBL_YES' : 'Yes', - 'LBL_NO' : 'No', - 'LBL_CANCEL' : 'Cancel', - 'LBL_TOP' : 'Top', - 'LBL_LEFT' : 'Left', - 'LBL_RIGHT' : 'Right', - 'LBL_BOTTOM' : 'Bottom', - 'LBL_CENTER' : 'Center', - 'LBL_FILE' : 'File', - 'LBL_NEW' : 'New', - 'LBL_OPEN' : 'Open', - 'LBL_SAVE' : 'Save', - 'LBL_SAVEAS' : 'Save as...', - 'LBL_CLOSE' : 'Close', - 'LBL_MKDIR' : 'Create directory', - 'LBL_UPLOAD' : 'Upload', - 'LBL_VIEW' : 'View', - 'LBL_EDIT' : 'Edit', - 'LBL_RENAME' : 'Rename', - 'LBL_DELETE' : 'Delete', - 'LBL_OPENWITH' : 'Open With ...', - 'LBL_ICONVIEW' : 'Icon View', - 'LBL_TREEVIEW' : 'Tree View', - 'LBL_LISTVIEW' : 'List View', - 'LBL_REFRESH' : 'Refresh', - 'LBL_VIEWTYPE' : 'View type', - 'LBL_BOLD' : 'Bold', - 'LBL_ITALIC' : 'Italic', - 'LBL_UNDERLINE' : 'Underline', - 'LBL_REGULAR' : 'Regular', - 'LBL_STRIKE' : 'Strike', - 'LBL_INDENT' : 'Indent', - 'LBL_OUTDENT' : 'Outdate', - 'LBL_UNDO' : 'Undo', - 'LBL_REDO' : 'Redo', - 'LBL_CUT' : 'Cut', - 'LBL_UNLINK' : 'Unlink', - 'LBL_COPY' : 'Copy', - 'LBL_PASTE' : 'Paste', - 'LBL_INSERT' : 'Insert', - 'LBL_IMAGE' : 'Image', - 'LBL_LINK' : 'Link', - 'LBL_DISCONNECT' : 'Disconnect', - 'LBL_APPLICATIONS' : 'Applications', - 'LBL_ADD_FOLDER' : 'Add folder', - 'LBL_INFORMATION' : 'Information', - 'LBL_TEXT_COLOR' : 'Text Color', - 'LBL_BACK_COLOR' : 'Back Color', - 'LBL_RESET_DEFAULT' : 'Reset to defaults', - 'LBL_DOWNLOAD_COMP' : 'Download to computer', - 'LBL_ORDERED_LIST' : 'Ordered List', - 'LBL_BACKGROUND_IMAGE' : 'Background Image', - 'LBL_BACKGROUND_COLOR' : 'Background Color', - 'LBL_UNORDERED_LIST' : 'Unordered List', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Read-Only', - 'LBL_CREATED' : 'Created', - 'LBL_MODIFIED' : 'Modified', - 'LBL_SHOW_COLUMNS' : 'Show Columns', - 'LBL_MOVE' : 'Move', - 'LBL_OPTIONS' : 'Options', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Directory', - 'LBL_CREATE' : 'Create', - 'LBL_BUGREPORT' : 'Bugreport', - 'LBL_INSTALL' : 'Install', - 'LBL_UPDATE' : 'Update', - 'LBL_REMOVE' : 'Remove', - 'LBL_SHOW_SIDEBAR' : 'Show sidebar', - 'LBL_SHOW_NAVIGATION' : 'Show navigation', - 'LBL_SHOW_HIDDENFILES' : 'Show hidden files', - 'LBL_SHOW_FILEEXTENSIONS' : 'Show file extensions', - 'LBL_MOUNT': 'Mount', - 'LBL_DESCRIPTION': 'Description', - 'LBL_USERNAME': 'Username', - 'LBL_PASSWORD': 'Password', - 'LBL_HOST': 'Host', - 'LBL_NAMESPACE': 'Namespace', - 'LBL_SEARCH': 'Search', - 'LBL_BACK': 'Back', - 'LBL_ICONS': 'Icons', - 'LBL_ICON': 'Icon', - 'LBL_UNINSTALL': 'Uninstall', - 'LBL_REGENERATE': 'Regenerate', - 'LBL_DESKTOP': 'Desktop', - 'LBL_WINDOWMANAGER': 'Window Manager', - 'LBL_HOTKEY': 'Hotkey', - 'LBL_HOTKEYS': 'Hotkeys', - 'LBL_MOUNTS': 'Mounts', - 'LBL_ID': 'ID', - 'LBL_APPLICATION': 'Application', - 'LBL_SCOPE': 'Scope', - 'LBL_HIDE': 'Hide', - 'LBL_REPOSITORY': 'Repository', - 'LBL_VERSION': 'Version', - 'LBL_AUTHOR': 'Author', - 'LBL_GROUPS': 'Groups', - 'LBL_AUTOHIDE': 'Autohide', - 'LBL_PERSONAL': 'Personal', - 'LBL_SYSTEM': 'System', - 'LBL_STARTING': 'Starting', - 'LBL_SOUNDS': 'Sounds', - 'LBL_STORE': 'Store', - 'LBL_LOCALE': 'Locale', - 'LBL_PACKAGE': 'Package', - 'LBL_PACKAGES': 'Packages', - 'LBL_INPUT': 'Input', - 'LBL_MISC': 'Misc', - 'LBL_OTHER': 'Other', - 'LBL_USERS': 'Users', - 'LBL_FONTS': 'Fonts', - 'LBL_OPEN_LOCATION': 'Open Location', - 'LBL_HOME': 'Home', - 'LBL_WIDGET': 'Widget', - 'LBL_WIDGETS': 'Widgets', - 'LBL_LOCK': 'Lock', - 'LBL_UNLOCK': 'Unlock', - 'LBL_WARNING': 'Warning', - 'LBL_INFO': 'Info', - 'LBL_POSITION': 'Position', - 'LBL_OPACITY': 'Opactiy', - 'LBL_ITEMS': 'Items', - 'LBL_ONTOP': 'On top', - 'LBL_BACKGROUND': 'Background' - }; - -})(); +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Error opening file', + 'ERR_WM_NOT_RUNNING' : 'Window manager is not running', + 'ERR_FILE_OPEN_FMT' : 'The file \'**{0}**\' could not be opened', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Could not find any Applications with support for \'{0}\' files', + 'ERR_APP_LAUNCH_FAILED' : 'Failed to launch Application', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'An error occured while trying to launch: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Application \'{0}\' construct failed: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Application \'{0}\' init() failed: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Application resources missing for \'{0}\' or it failed to load!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Application \'{0}\' preloading failed: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'The application \'{0}\' is already launched and allows only one instance!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Failed to launch \'{0}\'. Application manifest data not found!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Failed to launch \'{0}\'. Your browser does not support: {1}', + + 'ERR_NO_WM_RUNNING' : 'No window manager is running', + 'ERR_CORE_INIT_FAILED' : 'Failed to initialize OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'An error occured while initializing OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Cannot launch OS.js: No window manager defined!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Cannot launch OS.js: Failed to launch Window Manager: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Cannot launch OS.js: Failed to preload resources...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Error Report', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'An unexpected error occured, maybe a bug.', + + 'ERR_APP_API_ERROR' : 'Application API error', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Application {0} failed to perform operation \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Missing argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Unknown error', + + 'ERR_OPERATION_TIMEOUT' : 'Operation Timeout', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Timeout ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' expects \'{1}\' to be a \'{2}\', \'{3}\' given', + 'ERR_INVALID_LOCATION': 'Invalid location', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'You already have a Window named \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimize', + 'WINDOW_MAXIMIZE' : 'Maximize', + 'WINDOW_RESTORE' : 'Restore', + 'WINDOW_CLOSE' : 'Close', + 'WINDOW_ONTOP_ON' : 'Ontop (Enable)', + 'WINDOW_ONTOP_OFF': 'Ontop (Disable)', + + // Handler + 'TITLE_SIGN_OUT' : 'Sign out', + 'TITLE_SIGNED_IN_AS_FMT' : 'Signed in as: {0}', + 'ERR_LOGIN_FMT' : 'Login error: {0}', + 'ERR_LOGIN_INVALID' : 'Invalid login', + + // SESSION + 'ERR_NO_SESSION': 'No session was created by the server. Do you want to retry login?', + 'MSG_SESSION_WARNING' : 'Are you sure you want to quit OS.js? All unsaved settings and application data will be lost!', + + // Service + 'BUGREPORT_MSG' : 'Please report this if you think this is a bug.\nInclude a brief description on how the error occured, and if you can; how to replicate it', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Logged into external services: {0}', + 'CONNECTION_LOST': 'Connection to the server was lost. Reconnecting...', + 'CONNECTION_RESTORED': 'Connection to the server was restored', + 'CONNECTION_RESTORE_FAILED': 'Failed to re-establish connection. Trying again.', + 'CONNECTION_ERROR': 'Connection error', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Fatal Error', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Error: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Log out (Exit)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Logging out user \'{0}\'.\nDo you want to save current session?', + + 'DIALOG_CLOSE' : 'Close', + 'DIALOG_CANCEL': 'Cancel', + 'DIALOG_APPLY' : 'Apply', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Alert Dialog', + + 'DIALOG_COLOR_TITLE' : 'Color Dialog', + 'DIALOG_COLOR_R' : 'Red: {0}', + 'DIALOG_COLOR_G' : 'Green: {0}', + 'DIALOG_COLOR_B' : 'Blue: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Confirm Dialog', + + 'DIALOG_ERROR_TITLE' : 'Error', + 'DIALOG_ERROR_MESSAGE' : 'Message', + 'DIALOG_ERROR_SUMMARY' : 'Summary', + 'DIALOG_ERROR_TRACE' : 'Trace', + 'DIALOG_ERROR_BUGREPORT' : 'Report Bug', + + 'DIALOG_FILE_SAVE' : 'Save', + 'DIALOG_FILE_OPEN' : 'Open', + 'DIALOG_FILE_MKDIR' : 'New Folder', + 'DIALOG_FILE_MKDIR_MSG' : 'Create a new directory in **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Are you sure you want to overwrite the file \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'View type', + 'DIALOG_FILE_MNU_LISTVIEW' : 'List View', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Tree View', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Icon View', + 'DIALOG_FILE_ERROR' : 'FileDialog Error', + 'DIALOG_FILE_ERROR_SCANDIR': 'Failed listing directory \'{0}\' because an error occured', + 'DIALOG_FILE_ERROR_FIND': 'Failed searching directory \'{0}\' because an error occured', + 'DIALOG_FILE_MISSING_FILENAME' : 'You need to select a file or enter new filename!', + 'DIALOG_FILE_MISSING_SELECTION': 'You need to select a file!', + + 'DIALOG_FILEINFO_TITLE' : 'File Information', + 'DIALOG_FILEINFO_LOADING' : 'Loading file information for: {0}', + 'DIALOG_FILEINFO_ERROR' : 'FileInformationDialog Error', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Failed to get file information for **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Failed to get file information for: {0}', + + 'DIALOG_INPUT_TITLE' : 'Input Dialog', + + 'DIALOG_FILEPROGRESS_TITLE' : 'File Operation Progress', + 'DIALOG_FILEPROGRESS_LOADING' : 'Loading...', + + 'DIALOG_UPLOAD_TITLE' : 'Upload Dialog', + 'DIALOG_UPLOAD_DESC' : 'Upload file to **{0}**.
Maximum size: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Uploading \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Uploading file...', + 'DIALOG_UPLOAD_FAILED' : 'Upload failed', + 'DIALOG_UPLOAD_FAILED_MSG' : 'The upload has failed', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Reason unknown...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelled by user...', + 'DIALOG_UPLOAD_TOO_BIG': 'File is too big', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'File is too big, exceeds {0}', + + 'DIALOG_FONT_TITLE' : 'Font Dialog', + + 'DIALOG_APPCHOOSER_TITLE' : 'Choose Application', + 'DIALOG_APPCHOOSER_MSG' : 'Choose an application to open', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'You need to select an application', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Use as default application for {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Module not configured or disabled', + 'GAPI_SIGN_OUT' : 'Sign out from Google API Services', + 'GAPI_REVOKE' : 'Revoke permissions and Sign Out', + 'GAPI_AUTH_FAILURE' : 'Google API Authentication failed or did not take place', + 'GAPI_AUTH_FAILURE_FMT' : 'Failed to authenticate: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Failed to load Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API module not configured or disabled', + 'WLAPI_SIGN_OUT' : 'Sign out from Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Failed to load Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Failed to log into Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Failed to log into Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Cannot create IndexedDB without Database Name', + 'IDB_NO_SUCH_ITEM' : 'No such item', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Fatal Error', + 'ERR_VFS_UNAVAILABLE' : 'Not available', + 'ERR_VFS_FILE_ARGS' : 'File expects at least one argument', + 'ERR_VFS_NUM_ARGS' : 'Not enough arguments', + 'ERR_VFS_EXPECT_FILE' : 'Expects a file-object', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Expects a source file-object', + 'ERR_VFS_EXPECT_DST_FILE' : 'Expects a destination file-object', + 'ERR_VFS_FILE_EXISTS' : 'Destination already exists', + 'ERR_VFS_TARGET_NOT_EXISTS': 'Target does not exist', + 'ERR_VFS_TRANSFER_FMT' : 'An error occured while transfering between storage: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Cannot upload a file without a destination', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Cannot upload without any files defined', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'File upload failed: {0}', + 'ERR_VFS_UPLOAD_CANCELLED' : 'File upload was cancelled', + 'ERR_VFS_DOWNLOAD_NO_FILE' : 'Cannot download a path without a path', + 'ERR_VFS_DOWNLOAD_FAILED' : 'An error occured while downloading: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY' : 'Response was empty', + 'ERR_VFS_NO_MIME_DETECT' : 'No mime type detected', + + 'ERR_VFSMODULE_INVALID' : 'Invalid VFS Module', + 'ERR_VFSMODULE_INVALID_FMT' : 'Invalid VFS Module: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Invalid VFS Method', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Invalid VFS Method: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Invalid VFS Module type', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Invalid VFS Module type: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Invalid VFS Module configuration', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Invalid VFS Module configuration: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Module already mounted', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Module \'{0}\' already mounted', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Module not mounted', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Module \'{0}\' not mounted', + 'ERR_VFSMODULE_EXCEPTION' : 'VFS Module Exception', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Module Exception: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'No VFS Module matches {0}. Wrong path or format ?', + 'ERR_VFSMODULE_READONLY' : 'This VFS Module is read-only', + 'ERR_VFSMODULE_READONLY_FMT' : 'This VFS Module is read-only: {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Downloading file', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Error', + 'ERR_VFSMODULE_ROOT_ID' : 'Failed to find root folder id', + 'ERR_VFSMODULE_NOSUCH' : 'File does not exist', + 'ERR_VFSMODULE_PARENT' : 'No such parent', + 'ERR_VFSMODULE_PARENT_FMT' : 'Failed to look up parent: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Failed to scan directory', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Failed to scan directory: {0}', + 'ERR_VFSMODULE_READ' : 'Failed to read file', + 'ERR_VFSMODULE_READ_FMT' : 'Failed to read file: {0}', + 'ERR_VFSMODULE_WRITE' : 'Failed to write file', + 'ERR_VFSMODULE_WRITE_FMT' : 'Failed to write file: {0}', + 'ERR_VFSMODULE_COPY' : 'Failed to copy', + 'ERR_VFSMODULE_COPY_FMT' : 'Failed to copy: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Failed to unlink file', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Failed to unlink file: {0}', + 'ERR_VFSMODULE_MOVE' : 'Failed to move file', + 'ERR_VFSMODULE_MOVE_FMT' : 'Failed to move file: {0}', + 'ERR_VFSMODULE_EXIST' : 'Failed to check file existence', + 'ERR_VFSMODULE_EXIST_FMT' : 'Failed to check file existence: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Failed to get file information', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Failed to get file information: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Failed to create directory', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Failed to create directory: {0}', + 'ERR_VFSMODULE_MKFILE' : 'Failed to create file', + 'ERR_VFSMODULE_MKFILE_FMT' : 'Failed to create file: {0}', + 'ERR_VFSMODULE_URL' : 'Failed to get URL for file', + 'ERR_VFSMODULE_URL_FMT' : 'Failed to get URL for file: {0}', + 'ERR_VFSMODULE_TRASH' : 'Failed to move file to trash', + 'ERR_VFSMODULE_TRASH_FMT' : 'Failed to move file to trash: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Failed to move file out of trash', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Failed to move file out of trash: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Failed to empty trash', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Failed to empty trash: {0}', + 'ERR_VFSMODULE_FIND' : 'Failed to search', + 'ERR_VFSMODULE_FIND_FMT' : 'Failed to search: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'Failed to get free space', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'Failed to get free space: {0}', + 'ERR_VFSMODULE_EXISTS' : 'Failed to check if exists', + 'ERR_VFSMODULE_EXISTS_FMT' : 'Failed to check if exists: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'You are signed in to Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Sign out from Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Failed to resolve path: item not found', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'Failed to load zip.js', + 'ZIP_VENDOR_FAIL' : 'zip.js library was not found. Did it load properly?', + 'ZIP_NO_RESOURCE' : 'No zip resource was given', + 'ZIP_NO_PATH' : 'No path given', + + // + // SearchEngine + // + 'SEARCH_LOADING': 'Searching...', + 'SEARCH_NO_RESULTS': 'No results found', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Package installation directory already exists. Cannot continue!', + 'ERR_PACKAGE_MANIFEST': 'Failed to load package manifest', + 'ERR_PACKAGE_ENUM_FAILED': 'Failed to get package list. Make sure you\'re not using "Private Mode" as this might case problems.', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Cannot open file', + 'ERR_FILE_APP_OPEN_FMT' : 'The file {0} could not be opened because the mime {1} is not supported', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'The file {0} could not be opened: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'The file {0} could not be saved: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Application Error', + 'ERR_GENERIC_APP_ACTION_FMT': 'Failed to perform action \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Unknown Error', + 'ERR_GENERIC_APP_REQUEST' : 'An error occured while handling your request', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatal Error: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Discard changes?', + 'MSG_FILE_CHANGED' : 'The file has changed. Reload?', + 'MSG_APPLICATION_WARNING' : 'Application Warning', + 'MSG_MIME_OVERRIDE' : 'The filetype "{0}" is not supported, using "{1}" instead.', + + 'ERR_OPEN_LOCATION' : 'Failed to open location', + 'ERR_OPEN_LOCATION_FMT' : 'Failed to open location: {0}', + + // + // General + // + + 'LBL_UNKNOWN' : 'Unknown', + 'LBL_APPEARANCE' : 'Appearance', + 'LBL_USER' : 'User', + 'LBL_NAME' : 'Name', + 'LBL_APPLY' : 'Apply', + 'LBL_FILENAME' : 'Filename', + 'LBL_PATH' : 'Path', + 'LBL_SIZE' : 'Size', + 'LBL_TYPE' : 'Type', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Loading', + 'LBL_SETTINGS' : 'Settings', + 'LBL_ADD_FILE' : 'Add file', + 'LBL_COMMENT' : 'Comment', + 'LBL_ACCOUNT' : 'Account', + 'LBL_CONNECT' : 'Connect', + 'LBL_ONLINE' : 'Online', + 'LBL_OFFLINE' : 'Offline', + 'LBL_AWAY' : 'Away', + 'LBL_BUSY' : 'Busy', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Help', + 'LBL_ABOUT' : 'About', + 'LBL_PANELS' : 'Panels', + 'LBL_LOCALES' : 'Locales', + 'LBL_THEME' : 'Theme', + 'LBL_COLOR' : 'Color', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Kill', + 'LBL_ALIVE' : 'Alive', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Add', + 'LBL_FONT' : 'Font', + 'LBL_YES' : 'Yes', + 'LBL_NO' : 'No', + 'LBL_CANCEL' : 'Cancel', + 'LBL_TOP' : 'Top', + 'LBL_LEFT' : 'Left', + 'LBL_RIGHT' : 'Right', + 'LBL_BOTTOM' : 'Bottom', + 'LBL_CENTER' : 'Center', + 'LBL_FILE' : 'File', + 'LBL_NEW' : 'New', + 'LBL_OPEN' : 'Open', + 'LBL_SAVE' : 'Save', + 'LBL_SAVEAS' : 'Save as...', + 'LBL_CLOSE' : 'Close', + 'LBL_MKDIR' : 'Create directory', + 'LBL_UPLOAD' : 'Upload', + 'LBL_VIEW' : 'View', + 'LBL_EDIT' : 'Edit', + 'LBL_RENAME' : 'Rename', + 'LBL_DELETE' : 'Delete', + 'LBL_OPENWITH' : 'Open With ...', + 'LBL_ICONVIEW' : 'Icon View', + 'LBL_TREEVIEW' : 'Tree View', + 'LBL_LISTVIEW' : 'List View', + 'LBL_REFRESH' : 'Refresh', + 'LBL_VIEWTYPE' : 'View type', + 'LBL_BOLD' : 'Bold', + 'LBL_ITALIC' : 'Italic', + 'LBL_UNDERLINE' : 'Underline', + 'LBL_REGULAR' : 'Regular', + 'LBL_STRIKE' : 'Strike', + 'LBL_INDENT' : 'Indent', + 'LBL_OUTDENT' : 'Outdate', + 'LBL_UNDO' : 'Undo', + 'LBL_REDO' : 'Redo', + 'LBL_CUT' : 'Cut', + 'LBL_UNLINK' : 'Unlink', + 'LBL_COPY' : 'Copy', + 'LBL_PASTE' : 'Paste', + 'LBL_INSERT' : 'Insert', + 'LBL_IMAGE' : 'Image', + 'LBL_LINK' : 'Link', + 'LBL_DISCONNECT' : 'Disconnect', + 'LBL_APPLICATIONS' : 'Applications', + 'LBL_ADD_FOLDER' : 'Add folder', + 'LBL_INFORMATION' : 'Information', + 'LBL_TEXT_COLOR' : 'Text Color', + 'LBL_BACK_COLOR' : 'Back Color', + 'LBL_RESET_DEFAULT' : 'Reset to defaults', + 'LBL_DOWNLOAD_COMP' : 'Download to computer', + 'LBL_ORDERED_LIST' : 'Ordered List', + 'LBL_BACKGROUND_IMAGE' : 'Background Image', + 'LBL_BACKGROUND_COLOR' : 'Background Color', + 'LBL_UNORDERED_LIST' : 'Unordered List', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Read-Only', + 'LBL_CREATED' : 'Created', + 'LBL_MODIFIED' : 'Modified', + 'LBL_SHOW_COLUMNS' : 'Show Columns', + 'LBL_MOVE' : 'Move', + 'LBL_OPTIONS' : 'Options', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Directory', + 'LBL_CREATE' : 'Create', + 'LBL_BUGREPORT' : 'Bugreport', + 'LBL_INSTALL' : 'Install', + 'LBL_UPDATE' : 'Update', + 'LBL_REMOVE' : 'Remove', + 'LBL_SHOW_SIDEBAR' : 'Show sidebar', + 'LBL_SHOW_NAVIGATION' : 'Show navigation', + 'LBL_SHOW_HIDDENFILES' : 'Show hidden files', + 'LBL_SHOW_FILEEXTENSIONS' : 'Show file extensions', + 'LBL_MOUNT': 'Mount', + 'LBL_DESCRIPTION': 'Description', + 'LBL_USERNAME': 'Username', + 'LBL_PASSWORD': 'Password', + 'LBL_HOST': 'Host', + 'LBL_NAMESPACE': 'Namespace', + 'LBL_SEARCH': 'Search', + 'LBL_BACK': 'Back', + 'LBL_ICONS': 'Icons', + 'LBL_ICON': 'Icon', + 'LBL_UNINSTALL': 'Uninstall', + 'LBL_REGENERATE': 'Regenerate', + 'LBL_DESKTOP': 'Desktop', + 'LBL_WINDOWMANAGER': 'Window Manager', + 'LBL_HOTKEY': 'Hotkey', + 'LBL_HOTKEYS': 'Hotkeys', + 'LBL_MOUNTS': 'Mounts', + 'LBL_ID': 'ID', + 'LBL_APPLICATION': 'Application', + 'LBL_SCOPE': 'Scope', + 'LBL_HIDE': 'Hide', + 'LBL_REPOSITORY': 'Repository', + 'LBL_VERSION': 'Version', + 'LBL_AUTHOR': 'Author', + 'LBL_GROUPS': 'Groups', + 'LBL_AUTOHIDE': 'Autohide', + 'LBL_PERSONAL': 'Personal', + 'LBL_SYSTEM': 'System', + 'LBL_STARTING': 'Starting', + 'LBL_SOUNDS': 'Sounds', + 'LBL_STORE': 'Store', + 'LBL_LOCALE': 'Locale', + 'LBL_PACKAGE': 'Package', + 'LBL_PACKAGES': 'Packages', + 'LBL_INPUT': 'Input', + 'LBL_MISC': 'Misc', + 'LBL_OTHER': 'Other', + 'LBL_USERS': 'Users', + 'LBL_FONTS': 'Fonts', + 'LBL_OPEN_LOCATION': 'Open Location', + 'LBL_HOME': 'Home', + 'LBL_WIDGET': 'Widget', + 'LBL_WIDGETS': 'Widgets', + 'LBL_LOCK': 'Lock', + 'LBL_UNLOCK': 'Unlock', + 'LBL_WARNING': 'Warning', + 'LBL_INFO': 'Info', + 'LBL_POSITION': 'Position', + 'LBL_OPACITY': 'Opactiy', + 'LBL_ITEMS': 'Items', + 'LBL_ONTOP': 'On top', + 'LBL_BACKGROUND': 'Background', + 'LBL_QUIT': 'Quit', + 'LBL_EXIT': 'Exit', + 'LBL_WINDOWS': 'Windows' +}; diff --git a/src/client/javascript/locales/es_ES.js b/src/client/javascript/locales/es_ES.js index d15976c7c6..131a2fc017 100644 --- a/src/client/javascript/locales/es_ES.js +++ b/src/client/javascript/locales/es_ES.js @@ -27,346 +27,343 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.es_ES = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Error abriendo archivo', - 'ERR_WM_NOT_RUNNING' : 'El gestor de ventanas no está en ejecución', - 'ERR_FILE_OPEN_FMT' : 'No se pudo abrir el fichero \'**{0}**\'', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'No se pudo encontrar ninguna aplicación asociada a los archivos \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Error abriendo aplicación', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Se produjo un error intentando ejecutar: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Error construyendo la aplicación \'{0}\': {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Error en init() de la applicación \'{0}\': {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : '¡La aplicación \'{0}\' no pudo obtener los recursos necesarios, o falló al cargarse!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Error en la precarga de la application \'{0}\': \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '¡La aplicación \'{0}\' ya está ejecutándose y sólo permite una instancia!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '¡Error al abrir \'{0}\'. No se encontraron los datos del manifiesto de la aplicación!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '¡Error al abrir \'{0}\'. Tu explorador no da soporte: {1}', - - 'ERR_NO_WM_RUNNING' : 'Ningún gestor de ventanas en ejecución', - 'ERR_CORE_INIT_FAILED' : 'Error inicializando OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Se produjo un error inicializando OS.js', - 'ERR_CORE_INIT_NO_WM' : 'No se puede lanzar OS.js: ¡No se definió ningún gestor de ventanas!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'No se puede lanzar OS.js: se fallo al lanzar el gestor de ventanas: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'No se puede lanzar OS.js: se falló precargando recursos...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Informe de errores de JavaScript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Error inesperado, puede que sea un bug.', - - 'ERR_APP_API_ERROR' : 'Error del API de la aplicación', - 'ERR_APP_API_ERROR_DESC_FMT' : 'La aplicación {0} no pudo realizar la operación \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Falta un argumento: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Error desconocido', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Ya tienes una ventana llamada \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimizar', - 'WINDOW_MAXIMIZE' : 'Maximizar', - 'WINDOW_RESTORE' : 'Restaurar', - 'WINDOW_CLOSE' : 'Cerrar', - 'WINDOW_ONTOP_ON' : 'En primer plano (Activar)', - 'WINDOW_ONTOP_OFF': 'En primer plano (Desactivar)', - - // Handler - 'TITLE_SIGN_OUT' : 'Sesión finalizada', - 'TITLE_SIGNED_IN_AS_FMT' : 'Sesión iniciada como: {0}', - - // SESSION - 'MSG_SESSION_WARNING' : '¿Estás seguro de que quieres salir de OS.js? Se perderán todas las configuraciones y datos que no se hayan guardado', - - // Service - 'BUGREPORT_MSG' : 'Por favor, informa de esto si piensas que es un bug.\nIncluye una breve descripción sobre cómo se produjo el probleñam y si es posible, cómo reproducirlo. Gracias', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Se accedió a servicios externos: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Error fatal', - 'ERR_UTILS_XHR_FMT' : 'Error AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Finalizar sesión (Salir)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Usuario \'{0}\' desconectando.\n¿Quieres guardar la sesión en curso?', - - 'DIALOG_CLOSE' : 'Cerrar', - 'DIALOG_CANCEL': 'Cancelar', - 'DIALOG_APPLY' : 'Aplicar', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Diálogo de alerta', - - 'DIALOG_COLOR_TITLE' : 'Diálogo de color', - 'DIALOG_COLOR_R' : 'Rojo: {0}', - 'DIALOG_COLOR_G' : 'Verde: {0}', - 'DIALOG_COLOR_B' : 'Azul: {0}', - 'DIALOG_COLOR_A' : 'Alfa: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Diálogo de confirmación', - - 'DIALOG_ERROR_MESSAGE' : 'Mensaje', - 'DIALOG_ERROR_SUMMARY' : 'Resumen', - 'DIALOG_ERROR_TRACE' : 'Traza', - 'DIALOG_ERROR_BUGREPORT' : 'Informe de errores', - - 'DIALOG_FILE_SAVE' : 'Guardar', - 'DIALOG_FILE_OPEN' : 'Abrir', - 'DIALOG_FILE_MKDIR' : 'Nueva carpeta', - 'DIALOG_FILE_MKDIR_MSG' : 'Crear una nueva carpeta en **{0}**', - 'DIALOG_FILE_OVERWRITE' : '¿Seguro que quieres sobreescribir el fichero \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Tipo de vista', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Vista de lista', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Vista de árbol', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Vista de icono', - 'DIALOG_FILE_ERROR' : 'Error en el diálogo de fichero', - 'DIALOG_FILE_ERROR_SCANDIR': 'Error listando el directorio \'{0}\' porque ocurrió un error', - 'DIALOG_FILE_MISSING_FILENAME' : '¡Tienes que seleccionar un archivo o introducir un nombre de archivo nuevo!', - 'DIALOG_FILE_MISSING_SELECTION': '¡Tienes que seleccionar un archivo!', - - 'DIALOG_FILEINFO_TITLE' : 'Información de fichero', - 'DIALOG_FILEINFO_LOADING' : 'Cargando la información del fichero: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Error del diálogo de información de fichero', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'No se pudo obtener la información del fichero **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'No se pudo obtener la información del fichero: {0}', - - 'DIALOG_INPUT_TITLE' : 'Diálogo de entrada', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Operación de archivo en progreso', - 'DIALOG_FILEPROGRESS_LOADING' : 'Cargando...', - - 'DIALOG_UPLOAD_TITLE' : 'Diálogo de subida', - 'DIALOG_UPLOAD_DESC' : 'Subir archivo a **{0}**.
Tamaño máximo: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Subiendo \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Subiendo archivo...', - 'DIALOG_UPLOAD_FAILED' : 'Fallo en la subida', - 'DIALOG_UPLOAD_FAILED_MSG' : 'La subida ha fallado', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Razón desconocida...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelado por el usuario...', - 'DIALOG_UPLOAD_TOO_BIG': 'El archivo es demasiado grande', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'El archivo es demasiado grande, excede los {0}', - - 'DIALOG_FONT_TITLE' : 'Diálogo de tipografía', - - 'DIALOG_APPCHOOSER_TITLE' : 'Elegir aplicación', - 'DIALOG_APPCHOOSER_MSG' : 'Elegir la aplicación a abrir', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Necesitas seleccionar una aplicación', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usar como la aplicación por defecto para {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'El módulo GoogleAPI no está configurado o está desactivado', - 'GAPI_SIGN_OUT' : 'Desconectar de los servicios Google API', - 'GAPI_REVOKE' : 'Revocar permisos y desconectar', - 'GAPI_AUTH_FAILURE' : 'La autenticación en Google API falló, o no llegó a efectuarse', - 'GAPI_AUTH_FAILURE_FMT' : 'No se pudo autenticar: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'No se pudo cargar Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'El módulo Windows Live API no está configurado o está desactivado', - 'WLAPI_SIGN_OUT' : 'Desconectar de los servicios Windows Live API', - 'WLAPI_LOAD_FAILURE' : 'No se pudo cargar Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'No se pudo acceder a Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'No se pudo acceder a Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API devolvió el estado {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'No se pudo crear IndexedDB sin un nombre de base de datos', - 'IDB_NO_SUCH_ITEM' : 'No existe ese elemento', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Error fatal', - 'ERR_VFS_UNAVAILABLE' : 'No disponible', - 'ERR_VFS_FILE_ARGS' : 'El archivo espera al menos un argumento', - 'ERR_VFS_NUM_ARGS' : 'Argumentos insuficientes', - 'ERR_VFS_EXPECT_FILE' : 'Se espera un objeto-fichero', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Se espera un origen objeto-fichero', - 'ERR_VFS_EXPECT_DST_FILE' : 'Se espera un destino objeto-fichero', - 'ERR_VFS_FILE_EXISTS' : 'El destino ya existe', - 'ERR_VFS_TRANSFER_FMT' : 'Se produjo un error al transferir entre almacenamientos: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'No se puede subir un fichero sin un destino', - 'ERR_VFS_UPLOAD_NO_FILES' : 'No se puede efectuar la subida si no hay archivos definidos', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Fallo en la subida: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Se canceló la subida del fichero', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'No se puede descargar una ruta sin una ruta', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Se produjo un error en la descarga: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'La respuesta estaba vacía', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Descargando fichero', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Error XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'No se pudo encontrar el identificador del directorio raíz', - 'ERR_VFSMODULE_NOSUCH' : 'El archivo no existe', - 'ERR_VFSMODULE_PARENT' : 'No existe el padre', - 'ERR_VFSMODULE_PARENT_FMT' : 'No se pudo localizar el padre: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'No se pudo analizar el directorio', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'No se pudo analizar el directorio: {0}', - 'ERR_VFSMODULE_READ' : 'No se pudo leer el fichero', - 'ERR_VFSMODULE_READ_FMT' : 'No se pudo leer el fichero: {0}', - 'ERR_VFSMODULE_WRITE' : 'No se pudo escribir el fichero', - 'ERR_VFSMODULE_WRITE_FMT' : 'No se pudo escribir el fichero: {0}', - 'ERR_VFSMODULE_COPY' : 'No se pudo copiar', - 'ERR_VFSMODULE_COPY_FMT' : 'No se pudo copiar: {0}', - 'ERR_VFSMODULE_UNLINK' : 'No se pudo desenlazar el fichero', - 'ERR_VFSMODULE_UNLINK_FMT' : 'No se pudo desenlazar el fichero: {0}', - 'ERR_VFSMODULE_MOVE' : 'No se pudo mover el fichero', - 'ERR_VFSMODULE_MOVE_FMT' : 'No se pudo mover el fichero: {0}', - 'ERR_VFSMODULE_EXIST' : 'No se pudo comprobar la existencia del fichero', - 'ERR_VFSMODULE_EXIST_FMT' : 'No se pudo comprobar la existencia del fichero: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'No se pudo obtener la infomación del archivo', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'No se pudo obtener la infomación del archivo: {0}', - 'ERR_VFSMODULE_MKDIR' : 'No se pudo crear el directorio', - 'ERR_VFSMODULE_MKDIR_FMT' : 'No se pudo crear el directorio: {0}', - 'ERR_VFSMODULE_URL' : 'No se pudo obtener la URL del archivo', - 'ERR_VFSMODULE_URL_FMT' : 'No se pudo obtener la URL del archivo: {0}', - 'ERR_VFSMODULE_TRASH' : 'No se pudo enviar el archivo a la papelera', - 'ERR_VFSMODULE_TRASH_FMT' : 'No se pudo enviar el archivo a la papelera: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'No se pudo recuperar el archivo de la papelera', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'No se pudo recuperar el archivo de la papelera: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'No se pudo vaciar la papelera', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'No se pudo vaciar la papelera: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Estás identificado en el API de dropbox', - 'DROPBOX_SIGN_OUT' : 'Desconectar de los servicios Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'No se pudo resolver la ruta: no se encontró el elemento', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'No se puede abrir el archivo', - 'ERR_FILE_APP_OPEN_FMT' : 'El archivo {0} no pudo abrirse porque no hay soporte para el tipo MIME {1}', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'No pudo abrirse el archivo {0}: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'No pudo guardarse el archivo {0}: {1}', - 'ERR_GENERIC_APP_FMT' : 'Error en la aplicación {0}', - 'ERR_GENERIC_APP_ACTION_FMT': 'No se pudo efectuar la acción \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Error desconocido', - 'ERR_GENERIC_APP_REQUEST' : 'Se produjo un error manipulando la solicitud', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Error fatal: {0}', - 'MSG_GENERIC_APP_DISCARD' : '¿Descartar cambios?', - 'MSG_FILE_CHANGED' : 'El archivo ha cambiado. ¿Recargar?', - 'MSG_APPLICATION_WARNING' : 'Advertencia de aplicación', - 'MSG_MIME_OVERRIDE' : 'El tipo de fichero "{0}" no está soportado, se usará "{1}" en su lugar.', - - // - // General - // - - 'LBL_UNKNOWN' : 'Desconocido', - 'LBL_APPEARANCE' : 'Aspecto', - 'LBL_USER' : 'Usuario', - 'LBL_NAME' : 'Nombre', - 'LBL_APPLY' : 'Aplicar', - 'LBL_FILENAME' : 'Nombre de archivo', - 'LBL_PATH' : 'Ruta', - 'LBL_SIZE' : 'Tamaño', - 'LBL_TYPE' : 'Tipo', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Cargando', - 'LBL_SETTINGS' : 'Configuración', - 'LBL_ADD_FILE' : 'Añadir fichero', - 'LBL_COMMENT' : 'Comentario', - 'LBL_ACCOUNT' : 'Cuenta', - 'LBL_CONNECT' : 'Conectar', - 'LBL_ONLINE' : 'Conectado', - 'LBL_OFFLINE' : 'Desconectado', - 'LBL_AWAY' : 'No disponible', - 'LBL_BUSY' : 'Ocupado', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Ayuda', - 'LBL_ABOUT' : 'A propósito de', - 'LBL_PANELS' : 'Paneles', - 'LBL_LOCALES' : 'Internacionalización', - 'LBL_THEME' : 'Tema', - 'LBL_COLOR' : 'Color', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Kill', - 'LBL_ALIVE' : 'Alive', - 'LBL_INDEX' : 'Índice', - 'LBL_ADD' : 'Añadir', - 'LBL_FONT' : 'Tipografía', - 'LBL_YES' : 'Si', - 'LBL_NO' : 'No', - 'LBL_CANCEL' : 'Cancelar', - 'LBL_TOP' : 'Arriba', - 'LBL_LEFT' : 'Izquierda', - 'LBL_RIGHT' : 'Derecha', - 'LBL_BOTTOM' : 'Abajo', - 'LBL_CENTER' : 'Centro', - 'LBL_FILE' : 'Fichero', - 'LBL_NEW' : 'Nuevo', - 'LBL_OPEN' : 'Abrir', - 'LBL_SAVE' : 'Guardar', - 'LBL_SAVEAS' : 'Guardar cómo...', - 'LBL_CLOSE' : 'Cerrar', - 'LBL_MKDIR' : 'Crear directorio', - 'LBL_UPLOAD' : 'Subir', - 'LBL_VIEW' : 'Vista', - 'LBL_EDIT' : 'Editar', - 'LBL_RENAME' : 'Renombrar', - 'LBL_DELETE' : 'Eliminar', - 'LBL_OPENWITH' : 'Abrir con...', - 'LBL_ICONVIEW' : 'Vista de iconos', - 'LBL_TREEVIEW' : 'Vista de árbol', - 'LBL_LISTVIEW' : 'Vista de lista', - 'LBL_REFRESH' : 'Recargar', - 'LBL_VIEWTYPE' : 'Ver tipo', - 'LBL_BOLD' : 'Negrita', - 'LBL_ITALIC' : 'Cursiva', - 'LBL_UNDERLINE' : 'Subrayado', - 'LBL_REGULAR' : 'Regular', - 'LBL_STRIKE' : 'Barra', - 'LBL_INDENT' : 'Indentar', - 'LBL_OUTDENT' : 'Obsoleto', - 'LBL_UNDO' : 'Deshacer', - 'LBL_REDO' : 'Rehacer', - 'LBL_CUT' : 'Cortar', - 'LBL_UNLINK' : 'Desenlazar', - 'LBL_COPY' : 'Copiar', - 'LBL_PASTE' : 'Pegar', - 'LBL_INSERT' : 'Insertar', - 'LBL_IMAGE' : 'Imágen', - 'LBL_LINK' : 'Enlace', - 'LBL_DISCONNECT' : 'Desconectar', - 'LBL_APPLICATIONS' : 'Aplicaciones', - 'LBL_ADD_FOLDER' : 'Añadir carpeta', - 'LBL_INFORMATION' : 'Información', - 'LBL_TEXT_COLOR' : 'Color de texto', - 'LBL_BACK_COLOR' : 'Color de fondo', - 'LBL_RESET_DEFAULT' : 'Restablecer los valores por defecto', - 'LBL_DOWNLOAD_COMP' : 'Descargar en el ordenador', - 'LBL_ORDERED_LIST' : 'Lista ordenada', - 'LBL_BACKGROUND_IMAGE' : 'Imagen de fondo', - 'LBL_BACKGROUND_COLOR' : 'Color de fondo', - 'LBL_UNORDERED_LIST' : 'Lista no ordenada', - 'LBL_STATUS' : 'Estado', - 'LBL_READONLY' : 'Sólo lectura', - 'LBL_CREATED' : 'Creado', - 'LBL_MODIFIED' : 'Modificado', - 'LBL_SHOW_COLUMNS' : 'Mostrar columnas', - 'LBL_MOVE' : 'Mover', - 'LBL_OPTIONS' : 'Opciones', - 'LBL_OK' : 'OK', - 'LBL_Background' : 'Fondo', - 'LBL_DESKTOP' : 'Escritorio', - 'LBL_PANEL' : 'Panel', - 'LBL_POSITION' : 'Posición', - 'LBL_ONTOP' : 'Primer plano', - 'LBL_ITEMS' : 'Elementos', - 'LBL_GENERAL': 'General', - 'LBL_BACKGROUND' : 'Pozadie' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Error abriendo archivo', + 'ERR_WM_NOT_RUNNING' : 'El gestor de ventanas no está en ejecución', + 'ERR_FILE_OPEN_FMT' : 'No se pudo abrir el fichero \'**{0}**\'', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'No se pudo encontrar ninguna aplicación asociada a los archivos \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Error abriendo aplicación', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Se produjo un error intentando ejecutar: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Error construyendo la aplicación \'{0}\': {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Error en init() de la applicación \'{0}\': {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : '¡La aplicación \'{0}\' no pudo obtener los recursos necesarios, o falló al cargarse!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Error en la precarga de la application \'{0}\': \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '¡La aplicación \'{0}\' ya está ejecutándose y sólo permite una instancia!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '¡Error al abrir \'{0}\'. No se encontraron los datos del manifiesto de la aplicación!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '¡Error al abrir \'{0}\'. Tu explorador no da soporte: {1}', + + 'ERR_NO_WM_RUNNING' : 'Ningún gestor de ventanas en ejecución', + 'ERR_CORE_INIT_FAILED' : 'Error inicializando OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Se produjo un error inicializando OS.js', + 'ERR_CORE_INIT_NO_WM' : 'No se puede lanzar OS.js: ¡No se definió ningún gestor de ventanas!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'No se puede lanzar OS.js: se fallo al lanzar el gestor de ventanas: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'No se puede lanzar OS.js: se falló precargando recursos...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Informe de errores de JavaScript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Error inesperado, puede que sea un bug.', + + 'ERR_APP_API_ERROR' : 'Error del API de la aplicación', + 'ERR_APP_API_ERROR_DESC_FMT' : 'La aplicación {0} no pudo realizar la operación \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Falta un argumento: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Error desconocido', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Ya tienes una ventana llamada \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimizar', + 'WINDOW_MAXIMIZE' : 'Maximizar', + 'WINDOW_RESTORE' : 'Restaurar', + 'WINDOW_CLOSE' : 'Cerrar', + 'WINDOW_ONTOP_ON' : 'En primer plano (Activar)', + 'WINDOW_ONTOP_OFF': 'En primer plano (Desactivar)', + + // Handler + 'TITLE_SIGN_OUT' : 'Sesión finalizada', + 'TITLE_SIGNED_IN_AS_FMT' : 'Sesión iniciada como: {0}', + + // SESSION + 'MSG_SESSION_WARNING' : '¿Estás seguro de que quieres salir de OS.js? Se perderán todas las configuraciones y datos que no se hayan guardado', + + // Service + 'BUGREPORT_MSG' : 'Por favor, informa de esto si piensas que es un bug.\nIncluye una breve descripción sobre cómo se produjo el probleñam y si es posible, cómo reproducirlo. Gracias', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Se accedió a servicios externos: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Error fatal', + 'ERR_UTILS_XHR_FMT' : 'Error AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Finalizar sesión (Salir)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Usuario \'{0}\' desconectando.\n¿Quieres guardar la sesión en curso?', + + 'DIALOG_CLOSE' : 'Cerrar', + 'DIALOG_CANCEL': 'Cancelar', + 'DIALOG_APPLY' : 'Aplicar', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Diálogo de alerta', + + 'DIALOG_COLOR_TITLE' : 'Diálogo de color', + 'DIALOG_COLOR_R' : 'Rojo: {0}', + 'DIALOG_COLOR_G' : 'Verde: {0}', + 'DIALOG_COLOR_B' : 'Azul: {0}', + 'DIALOG_COLOR_A' : 'Alfa: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Diálogo de confirmación', + + 'DIALOG_ERROR_MESSAGE' : 'Mensaje', + 'DIALOG_ERROR_SUMMARY' : 'Resumen', + 'DIALOG_ERROR_TRACE' : 'Traza', + 'DIALOG_ERROR_BUGREPORT' : 'Informe de errores', + + 'DIALOG_FILE_SAVE' : 'Guardar', + 'DIALOG_FILE_OPEN' : 'Abrir', + 'DIALOG_FILE_MKDIR' : 'Nueva carpeta', + 'DIALOG_FILE_MKDIR_MSG' : 'Crear una nueva carpeta en **{0}**', + 'DIALOG_FILE_OVERWRITE' : '¿Seguro que quieres sobreescribir el fichero \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Tipo de vista', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Vista de lista', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Vista de árbol', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Vista de icono', + 'DIALOG_FILE_ERROR' : 'Error en el diálogo de fichero', + 'DIALOG_FILE_ERROR_SCANDIR': 'Error listando el directorio \'{0}\' porque ocurrió un error', + 'DIALOG_FILE_MISSING_FILENAME' : '¡Tienes que seleccionar un archivo o introducir un nombre de archivo nuevo!', + 'DIALOG_FILE_MISSING_SELECTION': '¡Tienes que seleccionar un archivo!', + + 'DIALOG_FILEINFO_TITLE' : 'Información de fichero', + 'DIALOG_FILEINFO_LOADING' : 'Cargando la información del fichero: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Error del diálogo de información de fichero', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'No se pudo obtener la información del fichero **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'No se pudo obtener la información del fichero: {0}', + + 'DIALOG_INPUT_TITLE' : 'Diálogo de entrada', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Operación de archivo en progreso', + 'DIALOG_FILEPROGRESS_LOADING' : 'Cargando...', + + 'DIALOG_UPLOAD_TITLE' : 'Diálogo de subida', + 'DIALOG_UPLOAD_DESC' : 'Subir archivo a **{0}**.
Tamaño máximo: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Subiendo \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Subiendo archivo...', + 'DIALOG_UPLOAD_FAILED' : 'Fallo en la subida', + 'DIALOG_UPLOAD_FAILED_MSG' : 'La subida ha fallado', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Razón desconocida...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelado por el usuario...', + 'DIALOG_UPLOAD_TOO_BIG': 'El archivo es demasiado grande', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'El archivo es demasiado grande, excede los {0}', + + 'DIALOG_FONT_TITLE' : 'Diálogo de tipografía', + + 'DIALOG_APPCHOOSER_TITLE' : 'Elegir aplicación', + 'DIALOG_APPCHOOSER_MSG' : 'Elegir la aplicación a abrir', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Necesitas seleccionar una aplicación', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usar como la aplicación por defecto para {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'El módulo GoogleAPI no está configurado o está desactivado', + 'GAPI_SIGN_OUT' : 'Desconectar de los servicios Google API', + 'GAPI_REVOKE' : 'Revocar permisos y desconectar', + 'GAPI_AUTH_FAILURE' : 'La autenticación en Google API falló, o no llegó a efectuarse', + 'GAPI_AUTH_FAILURE_FMT' : 'No se pudo autenticar: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'No se pudo cargar Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'El módulo Windows Live API no está configurado o está desactivado', + 'WLAPI_SIGN_OUT' : 'Desconectar de los servicios Windows Live API', + 'WLAPI_LOAD_FAILURE' : 'No se pudo cargar Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'No se pudo acceder a Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'No se pudo acceder a Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API devolvió el estado {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'No se pudo crear IndexedDB sin un nombre de base de datos', + 'IDB_NO_SUCH_ITEM' : 'No existe ese elemento', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Error fatal', + 'ERR_VFS_UNAVAILABLE' : 'No disponible', + 'ERR_VFS_FILE_ARGS' : 'El archivo espera al menos un argumento', + 'ERR_VFS_NUM_ARGS' : 'Argumentos insuficientes', + 'ERR_VFS_EXPECT_FILE' : 'Se espera un objeto-fichero', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Se espera un origen objeto-fichero', + 'ERR_VFS_EXPECT_DST_FILE' : 'Se espera un destino objeto-fichero', + 'ERR_VFS_FILE_EXISTS' : 'El destino ya existe', + 'ERR_VFS_TRANSFER_FMT' : 'Se produjo un error al transferir entre almacenamientos: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'No se puede subir un fichero sin un destino', + 'ERR_VFS_UPLOAD_NO_FILES' : 'No se puede efectuar la subida si no hay archivos definidos', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Fallo en la subida: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Se canceló la subida del fichero', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'No se puede descargar una ruta sin una ruta', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Se produjo un error en la descarga: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'La respuesta estaba vacía', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Descargando fichero', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Error XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'No se pudo encontrar el identificador del directorio raíz', + 'ERR_VFSMODULE_NOSUCH' : 'El archivo no existe', + 'ERR_VFSMODULE_PARENT' : 'No existe el padre', + 'ERR_VFSMODULE_PARENT_FMT' : 'No se pudo localizar el padre: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'No se pudo analizar el directorio', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'No se pudo analizar el directorio: {0}', + 'ERR_VFSMODULE_READ' : 'No se pudo leer el fichero', + 'ERR_VFSMODULE_READ_FMT' : 'No se pudo leer el fichero: {0}', + 'ERR_VFSMODULE_WRITE' : 'No se pudo escribir el fichero', + 'ERR_VFSMODULE_WRITE_FMT' : 'No se pudo escribir el fichero: {0}', + 'ERR_VFSMODULE_COPY' : 'No se pudo copiar', + 'ERR_VFSMODULE_COPY_FMT' : 'No se pudo copiar: {0}', + 'ERR_VFSMODULE_UNLINK' : 'No se pudo desenlazar el fichero', + 'ERR_VFSMODULE_UNLINK_FMT' : 'No se pudo desenlazar el fichero: {0}', + 'ERR_VFSMODULE_MOVE' : 'No se pudo mover el fichero', + 'ERR_VFSMODULE_MOVE_FMT' : 'No se pudo mover el fichero: {0}', + 'ERR_VFSMODULE_EXIST' : 'No se pudo comprobar la existencia del fichero', + 'ERR_VFSMODULE_EXIST_FMT' : 'No se pudo comprobar la existencia del fichero: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'No se pudo obtener la infomación del archivo', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'No se pudo obtener la infomación del archivo: {0}', + 'ERR_VFSMODULE_MKDIR' : 'No se pudo crear el directorio', + 'ERR_VFSMODULE_MKDIR_FMT' : 'No se pudo crear el directorio: {0}', + 'ERR_VFSMODULE_URL' : 'No se pudo obtener la URL del archivo', + 'ERR_VFSMODULE_URL_FMT' : 'No se pudo obtener la URL del archivo: {0}', + 'ERR_VFSMODULE_TRASH' : 'No se pudo enviar el archivo a la papelera', + 'ERR_VFSMODULE_TRASH_FMT' : 'No se pudo enviar el archivo a la papelera: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'No se pudo recuperar el archivo de la papelera', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'No se pudo recuperar el archivo de la papelera: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'No se pudo vaciar la papelera', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'No se pudo vaciar la papelera: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Estás identificado en el API de dropbox', + 'DROPBOX_SIGN_OUT' : 'Desconectar de los servicios Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'No se pudo resolver la ruta: no se encontró el elemento', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'No se puede abrir el archivo', + 'ERR_FILE_APP_OPEN_FMT' : 'El archivo {0} no pudo abrirse porque no hay soporte para el tipo MIME {1}', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'No pudo abrirse el archivo {0}: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'No pudo guardarse el archivo {0}: {1}', + 'ERR_GENERIC_APP_FMT' : 'Error en la aplicación {0}', + 'ERR_GENERIC_APP_ACTION_FMT': 'No se pudo efectuar la acción \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Error desconocido', + 'ERR_GENERIC_APP_REQUEST' : 'Se produjo un error manipulando la solicitud', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Error fatal: {0}', + 'MSG_GENERIC_APP_DISCARD' : '¿Descartar cambios?', + 'MSG_FILE_CHANGED' : 'El archivo ha cambiado. ¿Recargar?', + 'MSG_APPLICATION_WARNING' : 'Advertencia de aplicación', + 'MSG_MIME_OVERRIDE' : 'El tipo de fichero "{0}" no está soportado, se usará "{1}" en su lugar.', + + // + // General + // + + 'LBL_UNKNOWN' : 'Desconocido', + 'LBL_APPEARANCE' : 'Aspecto', + 'LBL_USER' : 'Usuario', + 'LBL_NAME' : 'Nombre', + 'LBL_APPLY' : 'Aplicar', + 'LBL_FILENAME' : 'Nombre de archivo', + 'LBL_PATH' : 'Ruta', + 'LBL_SIZE' : 'Tamaño', + 'LBL_TYPE' : 'Tipo', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Cargando', + 'LBL_SETTINGS' : 'Configuración', + 'LBL_ADD_FILE' : 'Añadir fichero', + 'LBL_COMMENT' : 'Comentario', + 'LBL_ACCOUNT' : 'Cuenta', + 'LBL_CONNECT' : 'Conectar', + 'LBL_ONLINE' : 'Conectado', + 'LBL_OFFLINE' : 'Desconectado', + 'LBL_AWAY' : 'No disponible', + 'LBL_BUSY' : 'Ocupado', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Ayuda', + 'LBL_ABOUT' : 'A propósito de', + 'LBL_PANELS' : 'Paneles', + 'LBL_LOCALES' : 'Internacionalización', + 'LBL_THEME' : 'Tema', + 'LBL_COLOR' : 'Color', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Kill', + 'LBL_ALIVE' : 'Alive', + 'LBL_INDEX' : 'Índice', + 'LBL_ADD' : 'Añadir', + 'LBL_FONT' : 'Tipografía', + 'LBL_YES' : 'Si', + 'LBL_NO' : 'No', + 'LBL_CANCEL' : 'Cancelar', + 'LBL_TOP' : 'Arriba', + 'LBL_LEFT' : 'Izquierda', + 'LBL_RIGHT' : 'Derecha', + 'LBL_BOTTOM' : 'Abajo', + 'LBL_CENTER' : 'Centro', + 'LBL_FILE' : 'Fichero', + 'LBL_NEW' : 'Nuevo', + 'LBL_OPEN' : 'Abrir', + 'LBL_SAVE' : 'Guardar', + 'LBL_SAVEAS' : 'Guardar cómo...', + 'LBL_CLOSE' : 'Cerrar', + 'LBL_MKDIR' : 'Crear directorio', + 'LBL_UPLOAD' : 'Subir', + 'LBL_VIEW' : 'Vista', + 'LBL_EDIT' : 'Editar', + 'LBL_RENAME' : 'Renombrar', + 'LBL_DELETE' : 'Eliminar', + 'LBL_OPENWITH' : 'Abrir con...', + 'LBL_ICONVIEW' : 'Vista de iconos', + 'LBL_TREEVIEW' : 'Vista de árbol', + 'LBL_LISTVIEW' : 'Vista de lista', + 'LBL_REFRESH' : 'Recargar', + 'LBL_VIEWTYPE' : 'Ver tipo', + 'LBL_BOLD' : 'Negrita', + 'LBL_ITALIC' : 'Cursiva', + 'LBL_UNDERLINE' : 'Subrayado', + 'LBL_REGULAR' : 'Regular', + 'LBL_STRIKE' : 'Barra', + 'LBL_INDENT' : 'Indentar', + 'LBL_OUTDENT' : 'Obsoleto', + 'LBL_UNDO' : 'Deshacer', + 'LBL_REDO' : 'Rehacer', + 'LBL_CUT' : 'Cortar', + 'LBL_UNLINK' : 'Desenlazar', + 'LBL_COPY' : 'Copiar', + 'LBL_PASTE' : 'Pegar', + 'LBL_INSERT' : 'Insertar', + 'LBL_IMAGE' : 'Imágen', + 'LBL_LINK' : 'Enlace', + 'LBL_DISCONNECT' : 'Desconectar', + 'LBL_APPLICATIONS' : 'Aplicaciones', + 'LBL_ADD_FOLDER' : 'Añadir carpeta', + 'LBL_INFORMATION' : 'Información', + 'LBL_TEXT_COLOR' : 'Color de texto', + 'LBL_BACK_COLOR' : 'Color de fondo', + 'LBL_RESET_DEFAULT' : 'Restablecer los valores por defecto', + 'LBL_DOWNLOAD_COMP' : 'Descargar en el ordenador', + 'LBL_ORDERED_LIST' : 'Lista ordenada', + 'LBL_BACKGROUND_IMAGE' : 'Imagen de fondo', + 'LBL_BACKGROUND_COLOR' : 'Color de fondo', + 'LBL_UNORDERED_LIST' : 'Lista no ordenada', + 'LBL_STATUS' : 'Estado', + 'LBL_READONLY' : 'Sólo lectura', + 'LBL_CREATED' : 'Creado', + 'LBL_MODIFIED' : 'Modificado', + 'LBL_SHOW_COLUMNS' : 'Mostrar columnas', + 'LBL_MOVE' : 'Mover', + 'LBL_OPTIONS' : 'Opciones', + 'LBL_OK' : 'OK', + 'LBL_Background' : 'Fondo', + 'LBL_DESKTOP' : 'Escritorio', + 'LBL_PANEL' : 'Panel', + 'LBL_POSITION' : 'Posición', + 'LBL_ONTOP' : 'Primer plano', + 'LBL_ITEMS' : 'Elementos', + 'LBL_GENERAL': 'General', + 'LBL_BACKGROUND' : 'Pozadie' +}; diff --git a/src/client/javascript/locales/fa_FA.js b/src/client/javascript/locales/fa_FA.js index af9f68cdba..063d938201 100644 --- a/src/client/javascript/locales/fa_FA.js +++ b/src/client/javascript/locales/fa_FA.js @@ -27,381 +27,377 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.fa_FA = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'خطا در باز کردن فايل', - 'ERR_WM_NOT_RUNNING' : 'مديريت پنجره ها اجرا نشده است', - 'ERR_FILE_OPEN_FMT' : 'فايل \'**{0}**\' رانمي توان باز کرد', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'برنامه اي که از \'{0}\' فايل پشتيباني کند پيدا نشد', - 'ERR_APP_LAUNCH_FAILED' : 'اجراي برنامه موفق نبود', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'وقوع خطادر زمان اجراي برنامه: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'برنامه \'{0}\' خطا در سازنده: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'برنامه \'{0}\' init() با خطا مواجه شد: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'نبودن منابع براي برنامه \'{0}\' يا اجرا کردن نا موفق!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'برنامه \'{0}\'قبل بارگزاري با خطا مواجه شد: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'برنامه \'{0}\' قبلا اجرا شده و فقط ميتواند يک نمونه از آن اجرا شود!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'مشکل در اجرا \'{0}\'. اطلاعات فايل مانيفست پيدا نشد!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'مشکل در اجرا \'{0}\'. مرورگر شما از اين نسخه پشتيباني نميکند: {1}', - - 'ERR_NO_WM_RUNNING' : 'مديريت پنجره ها در حال اجرا نيست', - 'ERR_CORE_INIT_FAILED' : 'اجراي OS.js با مشکل مواجه شد', - 'ERR_CORE_INIT_FAILED_DESC' : 'بروز يک مشکل در زمان اجراي OS.js', - 'ERR_CORE_INIT_NO_WM' : 'ناتوان در اجراي OS.js: مديريت پنجره مشخص نشده!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'ناتوان در اجراي OS.js: با مشکل مواجه شدن مديريت پنجره : {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'ناتوان در اجراي OS.js: خطا در بارگزاري اوليه منابع ...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'گزارش خطا جاواسکريپت', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'يک خطاي غيره منتظره رخ داد, ممکن است يک باگ باشد.', - - 'ERR_APP_API_ERROR' : 'خظاي API برنامه', - 'ERR_APP_API_ERROR_DESC_FMT' : 'برنامه {0} با خطا مواجه شدن اجراي عمليات \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'کمبود آرگامنت: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'خطاي ناشناخته', - - 'ERR_OPERATION_TIMEOUT' : 'به اتمام رسيدن عمليات', - 'ERR_OPERATION_TIMEOUT_FMT' : 'به اتمام رسيدن عمليات ({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'شما قبلا يک پنجره با نام \'{0}\'', - 'WINDOW_MINIMIZE' : 'تمام صفحه', - 'WINDOW_MAXIMIZE' : 'کوچک شدن صفحه', - 'WINDOW_RESTORE' : 'بازيابي', - 'WINDOW_CLOSE' : 'بستن', - 'WINDOW_ONTOP_ON' : 'برروي همه (فعال)', - 'WINDOW_ONTOP_OFF': 'برري همه(غيرفعال)', - - // Handler - 'TITLE_SIGN_OUT' : 'خروج', - 'TITLE_SIGNED_IN_AS_FMT' : 'وارد شده با نام : {0}', - 'ERR_LOGIN_FMT' : 'خطاي ورود: {0}', - 'ERR_LOGIN_INVALID' : 'نا معتبر بودن ورود', - - // SESSION - 'MSG_SESSION_WARNING' : 'آيا شما مطمئن به خارح شدن از برنامه هستيد? تماميه اطلاعات ذخيره نشد پنجره ها از بين خواهند رفت!', - - // Service - 'BUGREPORT_MSG' : 'درصورتي که تصورميکنيد اين يک باگ است گزارش دهيد.\nشامل توضيح کوتاهي که چگونه اين اتفاق افتاد, و اگر شما توانستد برطرف کنيد نحوه آن را اطلاع دهيد', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'وارد شدن به سرويس هاي خارجي: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'خطاي مخرب', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR خطاي: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'خروج از برنامه', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'خروج کاربر \'{0}\'.\nآيا نميخواهيد جلسه جاري حفظ شود?', - - 'DIALOG_CLOSE' : 'بستن', - 'DIALOG_CANCEL': 'انصراف', - 'DIALOG_APPLY' : 'اعمال', - 'DIALOG_OK' : 'تاييد', - - 'DIALOG_ALERT_TITLE' : 'ديالوگ هشدار', - - 'DIALOG_COLOR_TITLE' : 'ديالوگ رنگ', - 'DIALOG_COLOR_R' : 'قرمز: {0}', - 'DIALOG_COLOR_G' : 'سبز: {0}', - 'DIALOG_COLOR_B' : 'آبي: {0}', - 'DIALOG_COLOR_A' : 'آلفا: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'ديالوگ تاييد', - - 'DIALOG_ERROR_MESSAGE' : 'پيام', - 'DIALOG_ERROR_SUMMARY' : 'خلاصه', - 'DIALOG_ERROR_TRACE' : 'پيگيري', - 'DIALOG_ERROR_BUGREPORT' : 'گزارش باگ', - - 'DIALOG_FILE_SAVE' : 'ذخيره', - 'DIALOG_FILE_OPEN' : 'بازکردن', - 'DIALOG_FILE_MKDIR' : 'پوشه جديد', - 'DIALOG_FILE_MKDIR_MSG' : 'ساخت پوشه در مسير **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'داشتن حصول اطمينان از رونوشت فايل \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'نوع نمايش', - 'DIALOG_FILE_MNU_LISTVIEW' : 'نمايش ليست', - 'DIALOG_FILE_MNU_TREEVIEW' : 'نمايش درختي', - 'DIALOG_FILE_MNU_ICONVIEW' : 'نمايش آيکون', - 'DIALOG_FILE_ERROR' : 'خطاي ديالوگ فايل', - 'DIALOG_FILE_ERROR_SCANDIR': 'خطا در ليست کردن مسير \'{0}\' به دليل رخ دادن يک خطا', - 'DIALOG_FILE_MISSING_FILENAME' : 'شما ميبايست يک فايل انتخاب کنيد يا يک نام فايل جديد وارد کنيد!', - 'DIALOG_FILE_MISSING_SELECTION': 'شما مي بايست يک فايل انتخاب کنيد!', - - 'DIALOG_FILEINFO_TITLE' : 'اطلاعات فايل', - 'DIALOG_FILEINFO_LOADING' : 'بارکزاري اطلاعات فايل براي: {0}', - 'DIALOG_FILEINFO_ERROR' : 'خطاي ديالوک انتقال فايل', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'مشکل در گرفتن اطلاعات فايل براي **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'مشکل در گرفتن اطلاعات فايل براي: {0}', - - 'DIALOG_INPUT_TITLE' : 'ديالوگ ورودي', - - 'DIALOG_FILEPROGRESS_TITLE' : 'پروسه عمليات فايل', - 'DIALOG_FILEPROGRESS_LOADING' : 'بارگزاري...', - - 'DIALOG_UPLOAD_TITLE' : 'ديالوگ ارسال فايل', - 'DIALOG_UPLOAD_DESC' : 'ارسال فايل به **{0}**.
بيشترين اندازه: {1} بايت', - 'DIALOG_UPLOAD_MSG_FMT' : 'بارگزاري', - 'DIALOG_UPLOAD_MSG' : 'درحال ارسال فايل...', - 'DIALOG_UPLOAD_FAILED' : 'ارسال فايل با خطا مواجه شد', - 'DIALOG_UPLOAD_FAILED_MSG' : 'ارسال فايل با خطا مواجه شده است', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'دليل ناشناخته...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'انصراف به وسيله کاربر...', - 'DIALOG_UPLOAD_TOO_BIG': 'فايل بيش ازاندازه بزرگ است', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'فايل بيش از اندازه بزرک است, سقف {0}', - - 'DIALOG_FONT_TITLE' : 'ديالوگ فونت', - - 'DIALOG_APPCHOOSER_TITLE' : 'انتخاب برنامه', - 'DIALOG_APPCHOOSER_MSG' : 'انتخاب يک برنامه براي باز شدن', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'شما ميبايست يک برنامه انتخاب کنيد', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'استفاده به عنوان پيش فرض براي {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : ' ماژول GoogleAPI پيکربندي نشده يا غير فعال ميباشد', - 'GAPI_SIGN_OUT' : 'خارج شدن از API هاي سرويس هاي گوگل', - 'GAPI_REVOKE' : 'رد مجوز هاو خروج از برنامه', - 'GAPI_AUTH_FAILURE' : 'Google API تشخيض هويت با مشکل واجه شد و يا اتفاق نيافتاد', - 'GAPI_AUTH_FAILURE_FMT' : 'با مشکل مواجه شدن تشخيص هويت: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'مشکل با بارگزاري Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'ماژول هاي Windows Live API پيکربندي نشده و يا غير فعال مي باشد', - 'WLAPI_SIGN_OUT' : 'خروج از Window Live API', - 'WLAPI_LOAD_FAILURE' : 'مشکل در بارگزاري Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'مشکل در ثبت لاگ در Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'مشکل ثبت لاگ در Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API ارجاع {0} وضعيت', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'قادر به ايجاد IndexDB بدون نام پايگاه داده ها نمي باشيم', - 'IDB_NO_SUCH_ITEM' : 'آيتم اين چنين نميباد', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'خطاي بحراني', - 'ERR_VFS_UNAVAILABLE' : 'موجود نمي باشد', - 'ERR_VFS_FILE_ARGS' : 'فايل حدااقل يک آرگامنت مي خواهد', - 'ERR_VFS_NUM_ARGS' : 'آرگامنت ها کافي نيست', - 'ERR_VFS_EXPECT_FILE' : 'انتظار يک شي فايلي', - 'ERR_VFS_EXPECT_SRC_FILE' : 'انتظار يک شي فايلي منبع', - 'ERR_VFS_EXPECT_DST_FILE' : 'انتظار شي فايلي مقصد', - 'ERR_VFS_FILE_EXISTS' : 'مقصد قبلا وجود دارد', - 'ERR_VFS_TRANSFER_FMT' : 'بروز مشکل در زمان انتقال بين ذخيره کننده ها: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'بدون اطلاعات مقصد قادر به ارسال فايل نمي باشد', - 'ERR_VFS_UPLOAD_NO_FILES' : 'بدن مشخص کردن فايل امکان پذير نمي باشد', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'ارسال فايل به مشکل برخورد کرد: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'ارسال فايل لغو شد', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'دانلود فايل بدون انتخاب فايل امکان پذير نميباشد', - 'ERR_VFS_DOWNLOAD_FAILED' : 'بروز مشکل در حين دانلود فايل : {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'پاسخ تهي ميباشد', - - 'ERR_VFSMODULE_INVALID' : 'ماژول VFS نا م عتبر ميباشد', - 'ERR_VFSMODULE_INVALID_FMT' : ' ماژول VFS نامعتبر ميباشد : {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'متد VُّّFS نامعتبر مي باشد', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'متد VُّّFS نامعتبر مي باشد: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'نوع ماژول VFS نامعتبر ميباشد', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'نوع ماژول VFS نامعتبر ميباشد: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'پيکربندي ماژول VFS نامعتبر مي باشد', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'پيکربندي ماژول VFS نامعتبر مي باشد: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'ماژول VFS قبلا الصاق شده است', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'ماژول VFS \'{0}\' قابلا الصاق شده ', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'ماژول VFS الصاق نشده', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'ماؤول VFS \'{0}\' الصاق نشده است', - 'ERR_VFSMODULE_EXCEPTION' : 'بروز خطا در ماژول VFS', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'بروز خطا در ماژول VFS : {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'در حال دانلود فايل', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR خطاي', - 'ERR_VFSMODULE_ROOT_ID' : 'پيدا کردن شناسه پوشه روت با خطا مواجه شد', - 'ERR_VFSMODULE_NOSUCH' : 'فايل موحود نيست', - 'ERR_VFSMODULE_PARENT' : 'والدين اين چنين وجود ندارد', - 'ERR_VFSMODULE_PARENT_FMT' : 'جستجوي والدين با خطا مواجه شد: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'اسکن دايرکتوري باخطا موجه شد', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'اسکن دايرکتوري باخطا موجه شد: {0}', - 'ERR_VFSMODULE_READ' : 'خواندن فايل با خطا مواجه شد', - 'ERR_VFSMODULE_READ_FMT' : 'خواندن فايل با خطا مواجه شد: {0}', - 'ERR_VFSMODULE_WRITE' : 'نوشتن فايل با خطا مواجه شد', - 'ERR_VFSMODULE_WRITE_FMT' : 'نوشتن فايل با خطا موجه شد: {0}', - 'ERR_VFSMODULE_COPY' : 'کپي با خطا مواجه شد', - 'ERR_VFSMODULE_COPY_FMT' : 'کپي با خطا مواجه شد: {0}', - 'ERR_VFSMODULE_UNLINK' : 'قطع اتصال با خطا مواجه شد', - 'ERR_VFSMODULE_UNLINK_FMT' : 'قطع ارتباط با شکست مواجه شد: {0}', - 'ERR_VFSMODULE_MOVE' : 'جابه جايي فايل با شکست مواجه شد', - 'ERR_VFSMODULE_MOVE_FMT' : 'جابه جايي فايل با شکست مواجه شد: {0}', - 'ERR_VFSMODULE_EXIST' : 'برسي موجود بودن فايل با مشکل مواجه شد', - 'ERR_VFSMODULE_EXIST_FMT' : 'برسي موجود بودن فايل با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_MKDIR' : 'ساخت دايرکتوري با مشکل مواجه شد', - 'ERR_VFSMODULE_MKDIR_FMT' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_URL' : 'به دست آوردن URL فايل با مشکل مواجه شد', - 'ERR_VFSMODULE_URL_FMT' : 'به دست آوردن URL فايل با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_TRASH' : 'انتقال فايل به سطل زباله با مشکل مواجه شد', - 'ERR_VFSMODULE_TRASH_FMT' : 'انتقال فايل به سطل زباله با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'بازيافت فايل با مشکل مواجه شد', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'بازيافت فايل با مشکل مواجه شد: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'تخليه سطل زباله با مشکل مواجه شد', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'تخليه سطل زباله با مشکل مواجه شد: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'شما به وسيله DroBox API ثبت ورود کرده ايد', - 'DROPBOX_SIGN_OUT' : 'خروج از سرويس هاي Google API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'آيتم پيدا نشد: حل و فصل مسير با مشکل مواجه شد', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'بار گزاري zip.js با مشکل مواجه شد', - 'ZIP_VENDOR_FAIL' : 'کتابخانه zip.js پيدا نشد : آيا شما موارد متعلق به آن را بارگزاري کرده ايد ?', - 'ZIP_NO_RESOURCE' : 'هيچ يک از منابع zip داده نشده است', - 'ZIP_NO_PATH' : 'مسيري داده نشده است', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'ميسر نصب بسته قبلا وجود دارد. قادر به ادامه نميباشيم!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'باز کردن فايل امکان پذير نيست', - 'ERR_FILE_APP_OPEN_FMT' : 'فايل {0} قابل باز کردن نمي باشد به دليل اينکه نوع {1} پشنيباي نميشود', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'فايل {0} را نمي توان باز کرد: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'فايل {0} قادر ذخيره کردن نمي باشد: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} خطاي برنامه', - 'ERR_GENERIC_APP_ACTION_FMT': 'مشکل در اجراي فرآيند \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'خطاي ناشناخته', - 'ERR_GENERIC_APP_REQUEST' : 'درحال اجراي درخواست شما يک خطا اتفاق افتاد', - 'ERR_GENERIC_APP_FATAL_FMT' : 'خطاي مخرب: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'لغو تغييرات?', - 'MSG_FILE_CHANGED' : 'فايل تغيير کرده است.آيا دوباره بازگزاري شود؟', - 'MSG_APPLICATION_WARNING' : 'هشدار برنامه', - 'MSG_MIME_OVERRIDE' : 'نوع فايل "{0}" پشتيباني نميشود, ولي از نوع "{1}" استفاده شود.', - - // - // General - // - - 'LBL_UNKNOWN' : 'ناشناخته', - 'LBL_APPEARANCE' : 'ظاهر', - 'LBL_USER' : 'کاربر', - 'LBL_NAME' : 'نام', - 'LBL_APPLY' : 'اعمال', - 'LBL_FILENAME' : 'نام فايل', - 'LBL_PATH' : 'مسير', - 'LBL_SIZE' : 'حجم', - 'LBL_TYPE' : 'نوع', - 'LBL_MIME' : 'نوع', - 'LBL_LOADING' : 'درحال بارگزاري', - 'LBL_SETTINGS' : 'تنظيمات', - 'LBL_ADD_FILE' : 'اضافه کردن فايل', - 'LBL_COMMENT' : 'نظر', - 'LBL_ACCOUNT' : 'حساب', - 'LBL_CONNECT' : 'متصل', - 'LBL_ONLINE' : 'روي خط', - 'LBL_OFFLINE' : 'چراغ خاموش', - 'LBL_AWAY' : 'دور', - 'LBL_BUSY' : 'مشغول', - 'LBL_CHAT' : 'چت', - 'LBL_HELP' : 'کمک', - 'LBL_ABOUT' : 'درباره', - 'LBL_PANELS' : 'پنل ها', - 'LBL_LOCALES' : 'موقعيت ها', - 'LBL_THEME' : 'شمايل', - 'LBL_COLOR' : 'رنگ', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'کشتن', - 'LBL_ALIVE' : 'زنده', - 'LBL_INDEX' : 'ايندکس', - 'LBL_ADD' : 'اضافه', - 'LBL_FONT' : 'فونت', - 'LBL_YES' : 'بله', - 'LBL_NO' : 'نه', - 'LBL_CANCEL' : 'انصراف', - 'LBL_TOP' : 'روي', - 'LBL_LEFT' : 'چپ', - 'LBL_RIGHT' : 'راست', - 'LBL_BOTTOM' : 'پايين', - 'LBL_CENTER' : 'مرکز', - 'LBL_FILE' : 'فايل', - 'LBL_NEW' : 'جديد', - 'LBL_OPEN' : 'بازکردن', - 'LBL_SAVE' : 'ذخيره کردن', - 'LBL_SAVEAS' : 'ذخيره کردن به صورت...', - 'LBL_CLOSE' : 'بستن', - 'LBL_MKDIR' : 'ايجاد مسير', - 'LBL_UPLOAD' : 'ارسال', - 'LBL_VIEW' : 'نمايش', - 'LBL_EDIT' : 'ويرايش', - 'LBL_RENAME' : 'تغيير نام', - 'LBL_DELETE' : 'حذف', - 'LBL_OPENWITH' : 'بازکردن با ...', - 'LBL_ICONVIEW' : 'نمايش آيکون', - 'LBL_TREEVIEW' : 'نمايش درختي', - 'LBL_LISTVIEW' : 'نمايش ليست', - 'LBL_REFRESH' : 'تازه کردن', - 'LBL_VIEWTYPE' : 'نمايش نوع', - 'LBL_BOLD' : 'درشت', - 'LBL_ITALIC' : 'ايتاليک', - 'LBL_UNDERLINE' : 'زير خط', - 'LBL_REGULAR' : 'قاعده', - 'LBL_STRIKE' : 'Strike', - 'LBL_INDENT' : 'مقصود', - 'LBL_OUTDENT' : 'خارج از تاريخ', - 'LBL_UNDO' : 'برعکس ', - 'LBL_REDO' : 'دوباره کار', - 'LBL_CUT' : 'قطع کردن', - 'LBL_UNLINK' : 'برخلاف', - 'LBL_COPY' : 'کپي', - 'LBL_PASTE' : 'در اين محل', - 'LBL_INSERT' : 'درج', - 'LBL_IMAGE' : 'تصوير', - 'LBL_LINK' : 'اتصال', - 'LBL_DISCONNECT' : 'قطع ارتباط', - 'LBL_APPLICATIONS' : 'برنامه ها', - 'LBL_ADD_FOLDER' : 'اضاقه کردن پوشه', - 'LBL_INFORMATION' : 'اطلاعات', - 'LBL_TEXT_COLOR' : 'رنگ متن', - 'LBL_BACK_COLOR' : 'رنگ سياه', - 'LBL_RESET_DEFAULT' : 'برگردان به تنظيمات اوليه', - 'LBL_DOWNLOAD_COMP' : 'دانلود به کامپيوتر', - 'LBL_ORDERED_LIST' : 'ليست مرتب شده', - 'LBL_BACKGROUND_IMAGE' : 'تصوير پس زمينه', - 'LBL_BACKGROUND_COLOR' : 'رنگ پس زمينه', - 'LBL_UNORDERED_LIST' : 'ليست مرتب نشده', - 'LBL_STATUS' : 'وضعيت ها', - 'LBL_READONLY' : 'فقط خواندني', - 'LBL_CREATED' : 'ايجاد شده', - 'LBL_MODIFIED' : 'تغيير داده شده', - 'LBL_SHOW_COLUMNS' : 'نمايش ستون ها', - 'LBL_MOVE' : 'حرکت', - 'LBL_OPTIONS' : 'انتخاب', - 'LBL_OK' : 'تاييد', - 'LBL_DIRECTORY' : 'دايرکتوري', - 'LBL_CREATE' : 'ايجاد کردن', - 'LBL_BUGREPORT' : 'گزارش مشکل', - 'LBL_INSTALL' : 'نصب', - 'LBL_UPDATE' : 'به روز رساني', - 'LBL_REMOVE' : 'برداشتن', - 'LBL_SHOW_SIDEBAR' : 'نمايش نوار لغزنده', - 'LBL_SHOW_NAVIGATION' : 'نمايش ناوبري', - 'LBL_SHOW_HIDDENFILES' : 'نمايش فايل هاي مخفي', - 'LBL_SHOW_FILEEXTENSIONS' : 'نمايش پسوند فايل' - }; - -})(); +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'خطا در باز کردن فايل', + 'ERR_WM_NOT_RUNNING' : 'مديريت پنجره ها اجرا نشده است', + 'ERR_FILE_OPEN_FMT' : 'فايل \'**{0}**\' رانمي توان باز کرد', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'برنامه اي که از \'{0}\' فايل پشتيباني کند پيدا نشد', + 'ERR_APP_LAUNCH_FAILED' : 'اجراي برنامه موفق نبود', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'وقوع خطادر زمان اجراي برنامه: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'برنامه \'{0}\' خطا در سازنده: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'برنامه \'{0}\' init() با خطا مواجه شد: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'نبودن منابع براي برنامه \'{0}\' يا اجرا کردن نا موفق!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'برنامه \'{0}\'قبل بارگزاري با خطا مواجه شد: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'برنامه \'{0}\' قبلا اجرا شده و فقط ميتواند يک نمونه از آن اجرا شود!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'مشکل در اجرا \'{0}\'. اطلاعات فايل مانيفست پيدا نشد!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'مشکل در اجرا \'{0}\'. مرورگر شما از اين نسخه پشتيباني نميکند: {1}', + + 'ERR_NO_WM_RUNNING' : 'مديريت پنجره ها در حال اجرا نيست', + 'ERR_CORE_INIT_FAILED' : 'اجراي OS.js با مشکل مواجه شد', + 'ERR_CORE_INIT_FAILED_DESC' : 'بروز يک مشکل در زمان اجراي OS.js', + 'ERR_CORE_INIT_NO_WM' : 'ناتوان در اجراي OS.js: مديريت پنجره مشخص نشده!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'ناتوان در اجراي OS.js: با مشکل مواجه شدن مديريت پنجره : {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'ناتوان در اجراي OS.js: خطا در بارگزاري اوليه منابع ...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'گزارش خطا جاواسکريپت', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'يک خطاي غيره منتظره رخ داد, ممکن است يک باگ باشد.', + + 'ERR_APP_API_ERROR' : 'خظاي API برنامه', + 'ERR_APP_API_ERROR_DESC_FMT' : 'برنامه {0} با خطا مواجه شدن اجراي عمليات \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'کمبود آرگامنت: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'خطاي ناشناخته', + + 'ERR_OPERATION_TIMEOUT' : 'به اتمام رسيدن عمليات', + 'ERR_OPERATION_TIMEOUT_FMT' : 'به اتمام رسيدن عمليات ({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'شما قبلا يک پنجره با نام \'{0}\'', + 'WINDOW_MINIMIZE' : 'تمام صفحه', + 'WINDOW_MAXIMIZE' : 'کوچک شدن صفحه', + 'WINDOW_RESTORE' : 'بازيابي', + 'WINDOW_CLOSE' : 'بستن', + 'WINDOW_ONTOP_ON' : 'برروي همه (فعال)', + 'WINDOW_ONTOP_OFF': 'برري همه(غيرفعال)', + + // Handler + 'TITLE_SIGN_OUT' : 'خروج', + 'TITLE_SIGNED_IN_AS_FMT' : 'وارد شده با نام : {0}', + 'ERR_LOGIN_FMT' : 'خطاي ورود: {0}', + 'ERR_LOGIN_INVALID' : 'نا معتبر بودن ورود', + + // SESSION + 'MSG_SESSION_WARNING' : 'آيا شما مطمئن به خارح شدن از برنامه هستيد? تماميه اطلاعات ذخيره نشد پنجره ها از بين خواهند رفت!', + + // Service + 'BUGREPORT_MSG' : 'درصورتي که تصورميکنيد اين يک باگ است گزارش دهيد.\nشامل توضيح کوتاهي که چگونه اين اتفاق افتاد, و اگر شما توانستد برطرف کنيد نحوه آن را اطلاع دهيد', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'وارد شدن به سرويس هاي خارجي: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'خطاي مخرب', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR خطاي: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'خروج از برنامه', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'خروج کاربر \'{0}\'.\nآيا نميخواهيد جلسه جاري حفظ شود?', + + 'DIALOG_CLOSE' : 'بستن', + 'DIALOG_CANCEL': 'انصراف', + 'DIALOG_APPLY' : 'اعمال', + 'DIALOG_OK' : 'تاييد', + + 'DIALOG_ALERT_TITLE' : 'ديالوگ هشدار', + + 'DIALOG_COLOR_TITLE' : 'ديالوگ رنگ', + 'DIALOG_COLOR_R' : 'قرمز: {0}', + 'DIALOG_COLOR_G' : 'سبز: {0}', + 'DIALOG_COLOR_B' : 'آبي: {0}', + 'DIALOG_COLOR_A' : 'آلفا: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'ديالوگ تاييد', + + 'DIALOG_ERROR_MESSAGE' : 'پيام', + 'DIALOG_ERROR_SUMMARY' : 'خلاصه', + 'DIALOG_ERROR_TRACE' : 'پيگيري', + 'DIALOG_ERROR_BUGREPORT' : 'گزارش باگ', + + 'DIALOG_FILE_SAVE' : 'ذخيره', + 'DIALOG_FILE_OPEN' : 'بازکردن', + 'DIALOG_FILE_MKDIR' : 'پوشه جديد', + 'DIALOG_FILE_MKDIR_MSG' : 'ساخت پوشه در مسير **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'داشتن حصول اطمينان از رونوشت فايل \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'نوع نمايش', + 'DIALOG_FILE_MNU_LISTVIEW' : 'نمايش ليست', + 'DIALOG_FILE_MNU_TREEVIEW' : 'نمايش درختي', + 'DIALOG_FILE_MNU_ICONVIEW' : 'نمايش آيکون', + 'DIALOG_FILE_ERROR' : 'خطاي ديالوگ فايل', + 'DIALOG_FILE_ERROR_SCANDIR': 'خطا در ليست کردن مسير \'{0}\' به دليل رخ دادن يک خطا', + 'DIALOG_FILE_MISSING_FILENAME' : 'شما ميبايست يک فايل انتخاب کنيد يا يک نام فايل جديد وارد کنيد!', + 'DIALOG_FILE_MISSING_SELECTION': 'شما مي بايست يک فايل انتخاب کنيد!', + + 'DIALOG_FILEINFO_TITLE' : 'اطلاعات فايل', + 'DIALOG_FILEINFO_LOADING' : 'بارکزاري اطلاعات فايل براي: {0}', + 'DIALOG_FILEINFO_ERROR' : 'خطاي ديالوک انتقال فايل', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'مشکل در گرفتن اطلاعات فايل براي **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'مشکل در گرفتن اطلاعات فايل براي: {0}', + + 'DIALOG_INPUT_TITLE' : 'ديالوگ ورودي', + + 'DIALOG_FILEPROGRESS_TITLE' : 'پروسه عمليات فايل', + 'DIALOG_FILEPROGRESS_LOADING' : 'بارگزاري...', + + 'DIALOG_UPLOAD_TITLE' : 'ديالوگ ارسال فايل', + 'DIALOG_UPLOAD_DESC' : 'ارسال فايل به **{0}**.
بيشترين اندازه: {1} بايت', + 'DIALOG_UPLOAD_MSG_FMT' : 'بارگزاري', + 'DIALOG_UPLOAD_MSG' : 'درحال ارسال فايل...', + 'DIALOG_UPLOAD_FAILED' : 'ارسال فايل با خطا مواجه شد', + 'DIALOG_UPLOAD_FAILED_MSG' : 'ارسال فايل با خطا مواجه شده است', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'دليل ناشناخته...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'انصراف به وسيله کاربر...', + 'DIALOG_UPLOAD_TOO_BIG': 'فايل بيش ازاندازه بزرگ است', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'فايل بيش از اندازه بزرک است, سقف {0}', + + 'DIALOG_FONT_TITLE' : 'ديالوگ فونت', + + 'DIALOG_APPCHOOSER_TITLE' : 'انتخاب برنامه', + 'DIALOG_APPCHOOSER_MSG' : 'انتخاب يک برنامه براي باز شدن', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'شما ميبايست يک برنامه انتخاب کنيد', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'استفاده به عنوان پيش فرض براي {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : ' ماژول GoogleAPI پيکربندي نشده يا غير فعال ميباشد', + 'GAPI_SIGN_OUT' : 'خارج شدن از API هاي سرويس هاي گوگل', + 'GAPI_REVOKE' : 'رد مجوز هاو خروج از برنامه', + 'GAPI_AUTH_FAILURE' : 'Google API تشخيض هويت با مشکل واجه شد و يا اتفاق نيافتاد', + 'GAPI_AUTH_FAILURE_FMT' : 'با مشکل مواجه شدن تشخيص هويت: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'مشکل با بارگزاري Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'ماژول هاي Windows Live API پيکربندي نشده و يا غير فعال مي باشد', + 'WLAPI_SIGN_OUT' : 'خروج از Window Live API', + 'WLAPI_LOAD_FAILURE' : 'مشکل در بارگزاري Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'مشکل در ثبت لاگ در Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'مشکل ثبت لاگ در Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API ارجاع {0} وضعيت', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'قادر به ايجاد IndexDB بدون نام پايگاه داده ها نمي باشيم', + 'IDB_NO_SUCH_ITEM' : 'آيتم اين چنين نميباد', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'خطاي بحراني', + 'ERR_VFS_UNAVAILABLE' : 'موجود نمي باشد', + 'ERR_VFS_FILE_ARGS' : 'فايل حدااقل يک آرگامنت مي خواهد', + 'ERR_VFS_NUM_ARGS' : 'آرگامنت ها کافي نيست', + 'ERR_VFS_EXPECT_FILE' : 'انتظار يک شي فايلي', + 'ERR_VFS_EXPECT_SRC_FILE' : 'انتظار يک شي فايلي منبع', + 'ERR_VFS_EXPECT_DST_FILE' : 'انتظار شي فايلي مقصد', + 'ERR_VFS_FILE_EXISTS' : 'مقصد قبلا وجود دارد', + 'ERR_VFS_TRANSFER_FMT' : 'بروز مشکل در زمان انتقال بين ذخيره کننده ها: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'بدون اطلاعات مقصد قادر به ارسال فايل نمي باشد', + 'ERR_VFS_UPLOAD_NO_FILES' : 'بدن مشخص کردن فايل امکان پذير نمي باشد', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'ارسال فايل به مشکل برخورد کرد: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'ارسال فايل لغو شد', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'دانلود فايل بدون انتخاب فايل امکان پذير نميباشد', + 'ERR_VFS_DOWNLOAD_FAILED' : 'بروز مشکل در حين دانلود فايل : {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'پاسخ تهي ميباشد', + + 'ERR_VFSMODULE_INVALID' : 'ماژول VFS نا م عتبر ميباشد', + 'ERR_VFSMODULE_INVALID_FMT' : ' ماژول VFS نامعتبر ميباشد : {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'متد VُّّFS نامعتبر مي باشد', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'متد VُّّFS نامعتبر مي باشد: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'نوع ماژول VFS نامعتبر ميباشد', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'نوع ماژول VFS نامعتبر ميباشد: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'پيکربندي ماژول VFS نامعتبر مي باشد', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'پيکربندي ماژول VFS نامعتبر مي باشد: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'ماژول VFS قبلا الصاق شده است', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'ماژول VFS \'{0}\' قابلا الصاق شده ', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'ماژول VFS الصاق نشده', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'ماؤول VFS \'{0}\' الصاق نشده است', + 'ERR_VFSMODULE_EXCEPTION' : 'بروز خطا در ماژول VFS', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'بروز خطا در ماژول VFS : {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'در حال دانلود فايل', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR خطاي', + 'ERR_VFSMODULE_ROOT_ID' : 'پيدا کردن شناسه پوشه روت با خطا مواجه شد', + 'ERR_VFSMODULE_NOSUCH' : 'فايل موحود نيست', + 'ERR_VFSMODULE_PARENT' : 'والدين اين چنين وجود ندارد', + 'ERR_VFSMODULE_PARENT_FMT' : 'جستجوي والدين با خطا مواجه شد: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'اسکن دايرکتوري باخطا موجه شد', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'اسکن دايرکتوري باخطا موجه شد: {0}', + 'ERR_VFSMODULE_READ' : 'خواندن فايل با خطا مواجه شد', + 'ERR_VFSMODULE_READ_FMT' : 'خواندن فايل با خطا مواجه شد: {0}', + 'ERR_VFSMODULE_WRITE' : 'نوشتن فايل با خطا مواجه شد', + 'ERR_VFSMODULE_WRITE_FMT' : 'نوشتن فايل با خطا موجه شد: {0}', + 'ERR_VFSMODULE_COPY' : 'کپي با خطا مواجه شد', + 'ERR_VFSMODULE_COPY_FMT' : 'کپي با خطا مواجه شد: {0}', + 'ERR_VFSMODULE_UNLINK' : 'قطع اتصال با خطا مواجه شد', + 'ERR_VFSMODULE_UNLINK_FMT' : 'قطع ارتباط با شکست مواجه شد: {0}', + 'ERR_VFSMODULE_MOVE' : 'جابه جايي فايل با شکست مواجه شد', + 'ERR_VFSMODULE_MOVE_FMT' : 'جابه جايي فايل با شکست مواجه شد: {0}', + 'ERR_VFSMODULE_EXIST' : 'برسي موجود بودن فايل با مشکل مواجه شد', + 'ERR_VFSMODULE_EXIST_FMT' : 'برسي موجود بودن فايل با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_MKDIR' : 'ساخت دايرکتوري با مشکل مواجه شد', + 'ERR_VFSMODULE_MKDIR_FMT' : 'به دست آرودن اطلاعات فايل با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_URL' : 'به دست آوردن URL فايل با مشکل مواجه شد', + 'ERR_VFSMODULE_URL_FMT' : 'به دست آوردن URL فايل با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_TRASH' : 'انتقال فايل به سطل زباله با مشکل مواجه شد', + 'ERR_VFSMODULE_TRASH_FMT' : 'انتقال فايل به سطل زباله با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'بازيافت فايل با مشکل مواجه شد', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'بازيافت فايل با مشکل مواجه شد: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'تخليه سطل زباله با مشکل مواجه شد', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'تخليه سطل زباله با مشکل مواجه شد: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'شما به وسيله DroBox API ثبت ورود کرده ايد', + 'DROPBOX_SIGN_OUT' : 'خروج از سرويس هاي Google API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'آيتم پيدا نشد: حل و فصل مسير با مشکل مواجه شد', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'بار گزاري zip.js با مشکل مواجه شد', + 'ZIP_VENDOR_FAIL' : 'کتابخانه zip.js پيدا نشد : آيا شما موارد متعلق به آن را بارگزاري کرده ايد ?', + 'ZIP_NO_RESOURCE' : 'هيچ يک از منابع zip داده نشده است', + 'ZIP_NO_PATH' : 'مسيري داده نشده است', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'ميسر نصب بسته قبلا وجود دارد. قادر به ادامه نميباشيم!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'باز کردن فايل امکان پذير نيست', + 'ERR_FILE_APP_OPEN_FMT' : 'فايل {0} قابل باز کردن نمي باشد به دليل اينکه نوع {1} پشنيباي نميشود', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'فايل {0} را نمي توان باز کرد: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'فايل {0} قادر ذخيره کردن نمي باشد: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} خطاي برنامه', + 'ERR_GENERIC_APP_ACTION_FMT': 'مشکل در اجراي فرآيند \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'خطاي ناشناخته', + 'ERR_GENERIC_APP_REQUEST' : 'درحال اجراي درخواست شما يک خطا اتفاق افتاد', + 'ERR_GENERIC_APP_FATAL_FMT' : 'خطاي مخرب: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'لغو تغييرات?', + 'MSG_FILE_CHANGED' : 'فايل تغيير کرده است.آيا دوباره بازگزاري شود؟', + 'MSG_APPLICATION_WARNING' : 'هشدار برنامه', + 'MSG_MIME_OVERRIDE' : 'نوع فايل "{0}" پشتيباني نميشود, ولي از نوع "{1}" استفاده شود.', + + // + // General + // + + 'LBL_UNKNOWN' : 'ناشناخته', + 'LBL_APPEARANCE' : 'ظاهر', + 'LBL_USER' : 'کاربر', + 'LBL_NAME' : 'نام', + 'LBL_APPLY' : 'اعمال', + 'LBL_FILENAME' : 'نام فايل', + 'LBL_PATH' : 'مسير', + 'LBL_SIZE' : 'حجم', + 'LBL_TYPE' : 'نوع', + 'LBL_MIME' : 'نوع', + 'LBL_LOADING' : 'درحال بارگزاري', + 'LBL_SETTINGS' : 'تنظيمات', + 'LBL_ADD_FILE' : 'اضافه کردن فايل', + 'LBL_COMMENT' : 'نظر', + 'LBL_ACCOUNT' : 'حساب', + 'LBL_CONNECT' : 'متصل', + 'LBL_ONLINE' : 'روي خط', + 'LBL_OFFLINE' : 'چراغ خاموش', + 'LBL_AWAY' : 'دور', + 'LBL_BUSY' : 'مشغول', + 'LBL_CHAT' : 'چت', + 'LBL_HELP' : 'کمک', + 'LBL_ABOUT' : 'درباره', + 'LBL_PANELS' : 'پنل ها', + 'LBL_LOCALES' : 'موقعيت ها', + 'LBL_THEME' : 'شمايل', + 'LBL_COLOR' : 'رنگ', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'کشتن', + 'LBL_ALIVE' : 'زنده', + 'LBL_INDEX' : 'ايندکس', + 'LBL_ADD' : 'اضافه', + 'LBL_FONT' : 'فونت', + 'LBL_YES' : 'بله', + 'LBL_NO' : 'نه', + 'LBL_CANCEL' : 'انصراف', + 'LBL_TOP' : 'روي', + 'LBL_LEFT' : 'چپ', + 'LBL_RIGHT' : 'راست', + 'LBL_BOTTOM' : 'پايين', + 'LBL_CENTER' : 'مرکز', + 'LBL_FILE' : 'فايل', + 'LBL_NEW' : 'جديد', + 'LBL_OPEN' : 'بازکردن', + 'LBL_SAVE' : 'ذخيره کردن', + 'LBL_SAVEAS' : 'ذخيره کردن به صورت...', + 'LBL_CLOSE' : 'بستن', + 'LBL_MKDIR' : 'ايجاد مسير', + 'LBL_UPLOAD' : 'ارسال', + 'LBL_VIEW' : 'نمايش', + 'LBL_EDIT' : 'ويرايش', + 'LBL_RENAME' : 'تغيير نام', + 'LBL_DELETE' : 'حذف', + 'LBL_OPENWITH' : 'بازکردن با ...', + 'LBL_ICONVIEW' : 'نمايش آيکون', + 'LBL_TREEVIEW' : 'نمايش درختي', + 'LBL_LISTVIEW' : 'نمايش ليست', + 'LBL_REFRESH' : 'تازه کردن', + 'LBL_VIEWTYPE' : 'نمايش نوع', + 'LBL_BOLD' : 'درشت', + 'LBL_ITALIC' : 'ايتاليک', + 'LBL_UNDERLINE' : 'زير خط', + 'LBL_REGULAR' : 'قاعده', + 'LBL_STRIKE' : 'Strike', + 'LBL_INDENT' : 'مقصود', + 'LBL_OUTDENT' : 'خارج از تاريخ', + 'LBL_UNDO' : 'برعکس ', + 'LBL_REDO' : 'دوباره کار', + 'LBL_CUT' : 'قطع کردن', + 'LBL_UNLINK' : 'برخلاف', + 'LBL_COPY' : 'کپي', + 'LBL_PASTE' : 'در اين محل', + 'LBL_INSERT' : 'درج', + 'LBL_IMAGE' : 'تصوير', + 'LBL_LINK' : 'اتصال', + 'LBL_DISCONNECT' : 'قطع ارتباط', + 'LBL_APPLICATIONS' : 'برنامه ها', + 'LBL_ADD_FOLDER' : 'اضاقه کردن پوشه', + 'LBL_INFORMATION' : 'اطلاعات', + 'LBL_TEXT_COLOR' : 'رنگ متن', + 'LBL_BACK_COLOR' : 'رنگ سياه', + 'LBL_RESET_DEFAULT' : 'برگردان به تنظيمات اوليه', + 'LBL_DOWNLOAD_COMP' : 'دانلود به کامپيوتر', + 'LBL_ORDERED_LIST' : 'ليست مرتب شده', + 'LBL_BACKGROUND_IMAGE' : 'تصوير پس زمينه', + 'LBL_BACKGROUND_COLOR' : 'رنگ پس زمينه', + 'LBL_UNORDERED_LIST' : 'ليست مرتب نشده', + 'LBL_STATUS' : 'وضعيت ها', + 'LBL_READONLY' : 'فقط خواندني', + 'LBL_CREATED' : 'ايجاد شده', + 'LBL_MODIFIED' : 'تغيير داده شده', + 'LBL_SHOW_COLUMNS' : 'نمايش ستون ها', + 'LBL_MOVE' : 'حرکت', + 'LBL_OPTIONS' : 'انتخاب', + 'LBL_OK' : 'تاييد', + 'LBL_DIRECTORY' : 'دايرکتوري', + 'LBL_CREATE' : 'ايجاد کردن', + 'LBL_BUGREPORT' : 'گزارش مشکل', + 'LBL_INSTALL' : 'نصب', + 'LBL_UPDATE' : 'به روز رساني', + 'LBL_REMOVE' : 'برداشتن', + 'LBL_SHOW_SIDEBAR' : 'نمايش نوار لغزنده', + 'LBL_SHOW_NAVIGATION' : 'نمايش ناوبري', + 'LBL_SHOW_HIDDENFILES' : 'نمايش فايل هاي مخفي', + 'LBL_SHOW_FILEEXTENSIONS' : 'نمايش پسوند فايل' +}; diff --git a/src/client/javascript/locales/fr_FR.js b/src/client/javascript/locales/fr_FR.js index 2d8a12a916..12e5edd1d6 100644 --- a/src/client/javascript/locales/fr_FR.js +++ b/src/client/javascript/locales/fr_FR.js @@ -30,464 +30,461 @@ * @author James * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.fr_FR = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Erreur lors de l\'ouverture du fichier', - 'ERR_WM_NOT_RUNNING' : 'Le gestionnaire de fenêtre n\'est pas en cours d\'execution', - 'ERR_FILE_OPEN_FMT' : 'Le fichier \'**{0}**\' n\'a pas pu être ouvert', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Impossible de trouver une application supportant les fichiers \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Impossible de lancer l\'application', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Une erreur est survenue lors du lancement de : {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Application \'{0}\' construct failed: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Application \'{0}\' init() failed: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Application resources missing for \'{0}\' or it failed to load!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Application \'{0}\' preloading failed: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'L\'application \'{0}\' est déjà lancée et n\'autorise qu\'une seule instance !', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Impossible de lancer \'{0}\'. Le manifeste de l\'application n\'a pas été trouvé !', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Impossible de lancer \'{0}\'. Votre navigateur ne supporte pas : {1}', - - 'ERR_NO_WM_RUNNING' : 'Le gestionnaire de fenêtres n\'est pas lancé', - 'ERR_CORE_INIT_FAILED' : 'Impossible d\'initialiser OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Une erreur est survenue lors de l\'initialisation de OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Impossible de lancer OS.js: aucun gestionnaire de fenêtres défini !', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Impossible de lancer OS.js: erreur lors du lancement du gestionnaire de fenêtres : {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Impossible de lancer OS.js: impossible de précharger les ressources...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Rapport d\'erreur Javascript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Une erreur inconnue est survenue, peut-être un bug.', - - 'ERR_APP_API_ERROR' : 'Erreur de l\'API de l\'application', - 'ERR_APP_API_ERROR_DESC_FMT' : 'L\'pplication {0} n\'a pas pu exécuter l\'opération \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Argument manquant: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Erreur inconnue', - - 'ERR_OPERATION_TIMEOUT' : 'Operation Expirée', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Expirée ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' attends \'{1}\' d\'être \'{2}\', \'{3}\' fournie', - 'ERR_INVALID_LOCATION': 'Location invalide', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Une autre fenêtre porte déjà le nom \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimiser', - 'WINDOW_MAXIMIZE' : 'Maximiser', - 'WINDOW_RESTORE' : 'Restaurer', - 'WINDOW_CLOSE' : 'Fermer', - 'WINDOW_ONTOP_ON' : 'Au-dessus (activer)', - 'WINDOW_ONTOP_OFF': 'Au-dessous (désactiver)', - - // Handler - 'TITLE_SIGN_OUT' : 'Déconnexion', - 'TITLE_SIGNED_IN_AS_FMT' : 'Connecté en tant que: {0}', - 'ERR_LOGIN_FMT' : 'Erreur d\'identification : {0}', - 'ERR_LOGIN_INVALID' : 'Identifiant invalide', - - // SESSION - 'ERR_NO_SESSION': 'Aucune session n\'a été crée par le serveur. Voulez-vous réessayer de vous connecter?', - 'MSG_SESSION_WARNING' : 'Êtes-vous sûr de vouloir quitter OS.js? Tous vos paramètres et vos données seront perdues!', - - // Service - 'BUGREPORT_MSG' : 'Veuillez reporter ceci si vous pensez qu\'il s\'agit d\'un bug. \n Inclure une brève description de la façon dont l\'erreur s\'est produite, et si vous le pouvez; Comment le répliquer', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Connexion à des services externes: {0}', - 'CONNECTION_LOST': 'La connexion au serveur a été perdue. Reconnexion ...', - 'CONNECTION_RESTORED': 'La connexion au serveur a été restaurée', - 'CONNECTION_RESTORE_FAILED': 'Impossible de rétablir la connexion. Essayer à nouveau.', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Erreur Fatale', - 'ERR_UTILS_XHR_FMT' : 'Erreure AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Déconnexion (quitter)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Déconnexion de l\'utilisateur \'{0}\'.\nVoulez-vous enregistrer votre session courante ?', - - 'DIALOG_CLOSE' : 'Fermer', - 'DIALOG_CANCEL': 'Annuler', - 'DIALOG_APPLY' : 'Appliquer', - 'DIALOG_OK' : 'Valider', - - 'DIALOG_ALERT_TITLE' : 'Fenêtre d\'alerte', - - 'DIALOG_COLOR_TITLE' : 'Fenêtre des couleur', - 'DIALOG_COLOR_R' : 'Rouge: {0}', - 'DIALOG_COLOR_G' : 'Vert: {0}', - 'DIALOG_COLOR_B' : 'Bleu: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Fenêtre de confirmation', - - 'DIALOG_ERROR_TITLE' : 'Erreur', - 'DIALOG_ERROR_MESSAGE' : 'Message', - 'DIALOG_ERROR_SUMMARY' : 'Résumé', - 'DIALOG_ERROR_TRACE' : 'Trace', - 'DIALOG_ERROR_BUGREPORT' : 'Rapport de bug', - - 'DIALOG_FILE_SAVE' : 'Enregistrer', - 'DIALOG_FILE_OPEN' : 'Ouvrir', - 'DIALOG_FILE_MKDIR' : 'Nouveau dossier', - 'DIALOG_FILE_MKDIR_MSG' : 'Créer un nouveau dossier dans **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Êtes-vous sûr de vouloir écraser le fichier \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Type de vue', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Vue en liste', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Vue en arborescence', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Vue en icônes', - 'DIALOG_FILE_ERROR' : 'Erreur FileDialog', - 'DIALOG_FILE_ERROR_SCANDIR': 'Impossible de lister le contenu du dossier \'{0}\' car une erreur est survenue', - 'DIALOG_FILE_ERROR_FIND': 'Impossible de recherche dans le répertoire \'{0}\' car une erreur s\'est produite', - 'DIALOG_FILE_MISSING_FILENAME' : 'Vous devez sélectionner un fichier ou entrer un nouveau nom de fichier !', - 'DIALOG_FILE_MISSING_SELECTION': 'Vous devez sélectionner un fichier!', - - 'DIALOG_FILEINFO_TITLE' : 'Informations sur le fichier', - 'DIALOG_FILEINFO_LOADING' : 'Chargement des informations sur le fichier: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Erreur FileInformationDialog', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Impossible de récupérer les informations sur : **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Impossible de récupérer les informations sur : {0}', - - 'DIALOG_INPUT_TITLE' : 'Fenêtre de saisie', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Progression des opérations sur les fichiers', - 'DIALOG_FILEPROGRESS_LOADING' : 'Chargement...', - - 'DIALOG_UPLOAD_TITLE' : 'Fenêtre d\'envoi de fichier', - 'DIALOG_UPLOAD_DESC' : 'Envoyer un fichier vers **{0}**.\nTaille maximum: {1} octets', - 'DIALOG_UPLOAD_MSG_FMT' : 'Envoi de \'{0}\' ({1} {2}) vers {3}', - 'DIALOG_UPLOAD_MSG' : 'Envoi du fichier...', - 'DIALOG_UPLOAD_FAILED' : 'L\'envoi a échoué!', - 'DIALOG_UPLOAD_FAILED_MSG' : 'L\'envoi a échoué', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Raison inconnue...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Annulé pas l\'utilisateur...', - 'DIALOG_UPLOAD_TOO_BIG': 'Le fichier est trop gros', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Le fichier est trop gros, sa taille éxcède {0}', - - 'DIALOG_FONT_TITLE' : 'Fenêtre de police', - - 'DIALOG_APPCHOOSER_TITLE' : 'Choisir une application', - 'DIALOG_APPCHOOSER_MSG' : 'Choisir une application pour ouvrir', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Vous devez sélectionner une application', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Utiliser comme application par défaut pour {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'Module Google API non configuré ou désactivé', - 'GAPI_SIGN_OUT' : 'Déconnexion de l\'API Google', - 'GAPI_REVOKE' : 'Révoquer les permissions et déconnecter', - 'GAPI_AUTH_FAILURE' : 'L\'authentification Google API a échouer ou ne s\'est pas déroulée', - 'GAPI_AUTH_FAILURE_FMT' : 'Impossible d\'authentifier: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Impossible de charger l\'API Google', - - // Windows Live API - 'WLAPI_DISABLED' : 'Module Live API non configuré ou désactivé', - 'WLAPI_SIGN_OUT' : 'Déconnexion de l\'API Live', - 'WLAPI_LOAD_FAILURE' : 'Impossible de charger Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Impossible de s\'authentifier dans Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Impossible de s\'authentifier dans Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API a retourné le status {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Impossible de créer une base IndexedDB sans nom de base', - 'IDB_NO_SUCH_ITEM' : 'Aucun item correspondant', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Erreur fatale', - 'ERR_VFS_UNAVAILABLE' : 'Non disponible', - 'ERR_VFS_FILE_ARGS' : 'Le fichier attend au moins un argument', - 'ERR_VFS_NUM_ARGS' : 'Pas assez d\'arguments', - 'ERR_VFS_EXPECT_FILE' : 'Un objet "fichier" est attendu', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Un objet "fichier source" est attendu', - 'ERR_VFS_EXPECT_DST_FILE' : 'Un objet "fichier destination" est attendu', - 'ERR_VFS_FILE_EXISTS' : 'Le fichier destination existe déjà', - 'ERR_VFS_TARGET_NOT_EXISTS': 'La cible n\'existe pas', - 'ERR_VFS_TRANSFER_FMT' : 'Une erreur est survenu lors du transfert entre espaces de stockage : {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Impossible d\'envoyer un fichier sans destination', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Impossible d\'envoyer un fichier sans aucun fichier défini', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Impossible d\'envoyer le fichier: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'L\'envoi du fichier a été annulé', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Impossible de télécharger un chemin sans chemin', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Une erreur est survenue lors du téléchargement: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'La réponse est vide', - 'ERR_VFS_NO_MIME_DETECT' : 'Aucun type de mime détecté', - - 'ERR_VFSMODULE_INVALID' : 'Module VFS invalide', - 'ERR_VFSMODULE_INVALID_FMT' : 'Module VFS invalide: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Méthode VFS invalide', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Méthode VFS invalide: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Type de module VFS invalide', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Type de module VFS invalide: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Configuration VFS Module ', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Configuration VFS Module non valide : {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Module VFS déjà monté', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Module VFS \'{0}\' déjà monté', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'Module VFS non monté', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Module VFS \'{0}\' non monté', - 'ERR_VFSMODULE_EXCEPTION' : 'Exception du module VFS', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Exception du module VFS: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Aucun Module VFS ne correspond {0}. Mauvais chemin ou Mauvais formats ?', - 'ERR_VFSMODULE_READONLY' : 'Ce module VFS est en lecture seule', - 'ERR_VFSMODULE_READONLY_FMT' : 'Ce module VFS est en lecture seule: {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Téléchargement du fichier', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Erreur XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'Impossible de trouver l\'id du répertoire racine', - 'ERR_VFSMODULE_NOSUCH' : 'Le fichier n\'existe pas', - 'ERR_VFSMODULE_PARENT' : 'Pas de parent', - 'ERR_VFSMODULE_PARENT_FMT' : 'Impossible de trouver un parent: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Impossible de scanner le répertoire', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Impossible de scanner le répertoire: {0}', - 'ERR_VFSMODULE_READ' : 'Impossible de lire le fichier', - 'ERR_VFSMODULE_READ_FMT' : 'Impossible de lire le fichier: {0}', - 'ERR_VFSMODULE_WRITE' : 'Impossible d\'écrire dans le fichier', - 'ERR_VFSMODULE_WRITE_FMT' : 'Impossible d\'écrire dans le fichier: {0}', - 'ERR_VFSMODULE_COPY' : 'Impossible de copier', - 'ERR_VFSMODULE_COPY_FMT' : 'Impossible de copier: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Impossible de détacher le fichier', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Impossible de détacher le fichier: {0}', - 'ERR_VFSMODULE_MOVE' : 'Impossible de déplacer le fichier', - 'ERR_VFSMODULE_MOVE_FMT' : 'Impossible de déplacer le fichier: {0}', - 'ERR_VFSMODULE_EXIST' : 'Impossible de vérifier l\'existance du fichier', - 'ERR_VFSMODULE_EXIST_FMT' : 'Impossible de vérifier l\'existance du fichier: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Impossible de récuperer les informations du fichier', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Impossible de récuperer les informations du fichier: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Impossible de créer un répertoire', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Impossible de créer un répertoire: {0}', - 'ERR_VFSMODULE_MKFILE' : 'Impossible de créer le fichier', - 'ERR_VFSMODULE_MKFILE_FMT' : 'Impossible de créer le fichier: {0}', - 'ERR_VFSMODULE_URL' : 'Impossible de récuperer l\'URL du fichier', - 'ERR_VFSMODULE_URL_FMT' : 'Impossible de récuperer l\'URL du fichier: {0}', - 'ERR_VFSMODULE_TRASH' : 'Impossible de déplacer le fichier dans la corbeille', - 'ERR_VFSMODULE_TRASH_FMT' : 'Impossible de déplacer le fichier dans la corbeille: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Impossible de sortir le fichier de la corbeille', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Impossible de sortir le fichier de la corbeille: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Impossible de vider la corbeille', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Impossible de vider la corbeille: {0}', - 'ERR_VFSMODULE_FIND' : 'Impossible de chercher', - 'ERR_VFSMODULE_FIND_FMT' : 'Impossible de chercher: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'Impossible d\'obtenir de l\'espace libre', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'Impossible d\'obtenir de l\'espace libre: {0}', - 'ERR_VFSMODULE_EXISTS' : 'Impossible de Vérifier s\'il existe', - 'ERR_VFSMODULE_EXISTS_FMT' : 'Impossible de Vérifier s\'il existe: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Vous êtes connectés dans l\'API Dropbox', - 'DROPBOX_SIGN_OUT' : 'Déconnexion des services Google API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Impossible de résoudre le chemin: objet non trouvé', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'LE chargement de zip.js a échoué', - 'ZIP_VENDOR_FAIL' : 'La bibliothèque zip.js n\'a pas été trouvée. A-t-elle été chargée correctement?', - 'ZIP_NO_RESOURCE' : 'Aucune archive zip n\'a été fournie', - 'ZIP_NO_PATH' : 'Aucun chemin fourni', - - // - // SearchEngine - // - 'SEARCH_LOADING': 'Recherche...', - 'SEARCH_NO_RESULTS': 'Aucun resulta trouver', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Le répertoire d\'installation des paquêts existe déjà. L\'opération est interrompue!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Impossible d\'ouvrir le fichier', - 'ERR_FILE_APP_OPEN_FMT' : 'Le fichier {0} n\'a pas pu être ouvert car le type mime {1} m\'est pas supporté', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Le fichier {0} n\'a pas pu être ouvert: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Le fichier {0} n\'a pas pu être enregistré: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Erreur de l\'application', - 'ERR_GENERIC_APP_ACTION_FMT': 'Impossible d\'effectuer l\'action \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Erreur inconnue', - 'ERR_GENERIC_APP_REQUEST' : 'Une erreur est survenue lors du traitement de votre requête', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Erreur fatale : {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Abandonner les modifications ?', - 'MSG_FILE_CHANGED' : 'Le fichier a été modifié. Le recharger ?', - 'MSG_APPLICATION_WARNING' : 'Avertissement de l\'application', - 'MSG_MIME_OVERRIDE' : 'Le type de fichier "{0}" n\'est pas supporté, utilisation de "{1}" à la place.', - - 'ERR_OPEN_LOCATION' : 'Échec de l\'ouverture de l\'emplacement', - 'ERR_OPEN_LOCATION_FMT' : 'Échec de l\'ouverture de l\'emplacement: {0}', - - // - // General - // - - 'LBL_UNKNOWN' : 'Inconnu', - 'LBL_APPEARANCE' : 'Appearance', - 'LBL_USER' : 'Utilisateur', - 'LBL_NAME' : 'Nom', - 'LBL_APPLY' : 'Appliquer', - 'LBL_FILENAME' : 'Nom de fichier', - 'LBL_PATH' : 'Chemin', - 'LBL_SIZE' : 'Taille', - 'LBL_TYPE' : 'Type', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Chargement', - 'LBL_SETTINGS' : 'Paramètres', - 'LBL_ADD_FILE' : 'Ajouter un fichier', - 'LBL_COMMENT' : 'Commentaire', - 'LBL_ACCOUNT' : 'Compte', - 'LBL_CONNECT' : 'Connexion', - 'LBL_ONLINE' : 'En ligne', - 'LBL_OFFLINE' : 'Hors ligne', - 'LBL_AWAY' : 'Absent', - 'LBL_BUSY' : 'Occupé', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Aide', - 'LBL_ABOUT' : 'À propos', - 'LBL_PANELS' : 'Dock', - 'LBL_LOCALES' : 'Langues', - 'LBL_THEME' : 'Thème', - 'LBL_COLOR' : 'Couleur', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Fin de tâche', - 'LBL_ALIVE' : 'Vivant', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Ajouter', - 'LBL_FONT' : 'Police', - 'LBL_YES' : 'Oui', - 'LBL_NO' : 'Non', - 'LBL_CANCEL' : 'Annuler', - 'LBL_TOP' : 'Haut', - 'LBL_LEFT' : 'Gauche', - 'LBL_RIGHT' : 'Droite', - 'LBL_BOTTOM' : 'Bas', - 'LBL_CENTER' : 'Centre', - 'LBL_FILE' : 'Fichier', - 'LBL_NEW' : 'Nouveau', - 'LBL_OPEN' : 'Ouvrir', - 'LBL_SAVE' : 'Enregistrer', - 'LBL_SAVEAS' : 'Enregistrer sous...', - 'LBL_CLOSE' : 'Fermer', - 'LBL_MKDIR' : 'Créer un dossier', - 'LBL_UPLOAD' : 'Envoyer un fichier', - 'LBL_VIEW' : 'Vue', - 'LBL_EDIT' : 'Édition', - 'LBL_RENAME' : 'Renommer', - 'LBL_DELETE' : 'Supprimer', - 'LBL_OPENWITH' : 'Ouvrir avec...', - 'LBL_ICONVIEW' : 'Vue en icônes', - 'LBL_TREEVIEW' : 'Vue en arborescence', - 'LBL_LISTVIEW' : 'Vue en liste', - 'LBL_REFRESH' : 'Rafraîchir', - 'LBL_VIEWTYPE' : 'Type de vue', - 'LBL_BOLD' : 'Gras', - 'LBL_ITALIC' : 'Italique', - 'LBL_UNDERLINE' : 'Souligné', - 'LBL_REGULAR' : 'Régulier', - 'LBL_STRIKE' : 'Barré', - 'LBL_INDENT' : 'Indentation', - 'LBL_OUTDENT' : 'Dépassé', - 'LBL_UNDO' : 'Annuler', - 'LBL_REDO' : 'Refaire', - 'LBL_CUT' : 'Couper', - 'LBL_UNLINK' : 'Supprimer le lien', - 'LBL_COPY' : 'Copier', - 'LBL_PASTE' : 'Coller', - 'LBL_INSERT' : 'Insérer', - 'LBL_IMAGE' : 'Image', - 'LBL_LINK' : 'Lien', - 'LBL_DISCONNECT' : 'Déconnexion', - 'LBL_APPLICATIONS' : 'Applications', - 'LBL_ADD_FOLDER' : 'Ajouter un dossier', - 'LBL_INFORMATION' : 'Information', - 'LBL_TEXT_COLOR' : 'Couleur du texte', - 'LBL_BACK_COLOR' : 'Couleur de fond', - 'LBL_RESET_DEFAULT' : 'Rétablir par défaut', - 'LBL_DOWNLOAD_COMP' : 'Télécharger sur l\'ordinateur', - 'LBL_ORDERED_LIST' : 'Liste ordonnée', - 'LBL_BACKGROUND_IMAGE' : 'Image d\'arrière-plan', - 'LBL_BACKGROUND_COLOR' : 'Couleur d\'arrière-plan', - 'LBL_UNORDERED_LIST' : 'Liste désordonnée', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Lecture seule', - 'LBL_CREATED' : 'Crée', - 'LBL_MODIFIED' : 'Modifié', - 'LBL_SHOW_COLUMNS' : 'Montrer les colonnes', - 'LBL_MOVE' : 'Déplacer', - 'LBL_OPTIONS' : 'Options', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Repertoire', - 'LBL_CREATE' : 'Créer', - 'LBL_BUGREPORT' : 'Report de bug', - 'LBL_INSTALL' : 'Installer', - 'LBL_UPDATE' : 'Mettre à jour', - 'LBL_REMOVE' : 'Enlever', - 'LBL_SHOW_SIDEBAR' : 'Afficher la barre de côté', - 'LBL_SHOW_NAVIGATION' : 'Afficher la navigation', - 'LBL_SHOW_HIDDENFILES' : 'Afficher les fichiers cachés', - 'LBL_SHOW_FILEEXTENSIONS' : 'Afficher les extensions de fichier', - 'LBL_MOUNT': 'Monter', - 'LBL_DESCRIPTION': 'Description', - 'LBL_USERNAME': 'Nom d\'utilisateur', - 'LBL_PASSWORD': 'Mot de passe', - 'LBL_HOST': 'Hôte', - 'LBL_NAMESPACE': 'Espace de nom', - 'LBL_SEARCH': 'Recherche', - 'LBL_BACK': 'Retour', - 'LBL_ICONS' : 'Icônes', - 'LBL_ICON': 'Icône', - 'LBL_UNINSTALL': 'Désinstaller', - 'LBL_REGENERATE': 'Régénérer', - 'LBL_DESKTOP' : 'Bureau', - 'LBL_WINDOWMANAGER' : 'Gestionnaire de fenêtre', - 'LBL_HOTKEY': ' Raccourci clavier', - 'LBL_HOTKEYS': ' raccourcis clavier', - 'LBL_MOUNTS': 'Supports', - 'LBL_ID': 'ID', - 'LBL_APPLICATION' : 'Application', - 'LBL_SCOPE' : 'portée', - 'LBL_HIDE' : 'Cacher', - 'LBL_REPOSITORY': 'Dépôt', - 'LBL_VERSION' : 'Version', - 'LBL_AUTHOR' : 'Auteur', - 'LBL_GROUPS' : 'Groupes', - 'LBL_AUTOHIDE' : 'Masquer automatiquement', - 'LBL_PERSONAL': 'Personnel', - 'LBL_SYSTEM': 'Système', - 'LBL_STARTING': 'Démarage', - 'LBL_SOUNDS': 'Son', - 'LBL_STORE' : 'Centre d\'application', - 'LBL_LOCALE': 'Langue', - 'LBL_PACKAGE' : 'Paquet', - 'LBL_PACKAGES' : 'Paquets', - 'LBL_INPUT' : 'Clavier', - 'LBL_MISC': 'Divers', - 'LBL_OTHER': 'Autre', - 'LBL_USERS' : 'Gestion des utilisateurs', - 'LBL_FONTS': 'Polices', - 'LBL_OPEN_LOCATION': 'Ouvrir l\'emplacement ', - 'LBL_HOME': 'Accueil', - 'LBL_WIDGET': 'Widget', - 'LBL_WIDGETS': 'Widgets', - 'LBL_LOCK': 'Verrouiller', - 'LBL_UNLOCK': 'Déverrouiller', - 'LBL_WARNING': 'Attention', - 'LBL_INFO': 'Info', - 'LBL_POSITION' : 'Position', - 'LBL_OPACITY' : 'Opacité', - 'LBL_ITEMS' : 'Objets', - 'LBL_ONTOP' : 'Premier plan', - 'LBL_BACKGROUND' : 'Fond d\'écran' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Erreur lors de l\'ouverture du fichier', + 'ERR_WM_NOT_RUNNING' : 'Le gestionnaire de fenêtre n\'est pas en cours d\'execution', + 'ERR_FILE_OPEN_FMT' : 'Le fichier \'**{0}**\' n\'a pas pu être ouvert', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Impossible de trouver une application supportant les fichiers \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Impossible de lancer l\'application', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Une erreur est survenue lors du lancement de : {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Application \'{0}\' construct failed: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Application \'{0}\' init() failed: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Application resources missing for \'{0}\' or it failed to load!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Application \'{0}\' preloading failed: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'L\'application \'{0}\' est déjà lancée et n\'autorise qu\'une seule instance !', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Impossible de lancer \'{0}\'. Le manifeste de l\'application n\'a pas été trouvé !', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Impossible de lancer \'{0}\'. Votre navigateur ne supporte pas : {1}', + + 'ERR_NO_WM_RUNNING' : 'Le gestionnaire de fenêtres n\'est pas lancé', + 'ERR_CORE_INIT_FAILED' : 'Impossible d\'initialiser OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Une erreur est survenue lors de l\'initialisation de OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Impossible de lancer OS.js: aucun gestionnaire de fenêtres défini !', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Impossible de lancer OS.js: erreur lors du lancement du gestionnaire de fenêtres : {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Impossible de lancer OS.js: impossible de précharger les ressources...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Rapport d\'erreur Javascript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Une erreur inconnue est survenue, peut-être un bug.', + + 'ERR_APP_API_ERROR' : 'Erreur de l\'API de l\'application', + 'ERR_APP_API_ERROR_DESC_FMT' : 'L\'pplication {0} n\'a pas pu exécuter l\'opération \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Argument manquant: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Erreur inconnue', + + 'ERR_OPERATION_TIMEOUT' : 'Operation Expirée', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Expirée ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' attends \'{1}\' d\'être \'{2}\', \'{3}\' fournie', + 'ERR_INVALID_LOCATION': 'Location invalide', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Une autre fenêtre porte déjà le nom \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimiser', + 'WINDOW_MAXIMIZE' : 'Maximiser', + 'WINDOW_RESTORE' : 'Restaurer', + 'WINDOW_CLOSE' : 'Fermer', + 'WINDOW_ONTOP_ON' : 'Au-dessus (activer)', + 'WINDOW_ONTOP_OFF': 'Au-dessous (désactiver)', + + // Handler + 'TITLE_SIGN_OUT' : 'Déconnexion', + 'TITLE_SIGNED_IN_AS_FMT' : 'Connecté en tant que: {0}', + 'ERR_LOGIN_FMT' : 'Erreur d\'identification : {0}', + 'ERR_LOGIN_INVALID' : 'Identifiant invalide', + + // SESSION + 'ERR_NO_SESSION': 'Aucune session n\'a été crée par le serveur. Voulez-vous réessayer de vous connecter?', + 'MSG_SESSION_WARNING' : 'Êtes-vous sûr de vouloir quitter OS.js? Tous vos paramètres et vos données seront perdues!', + + // Service + 'BUGREPORT_MSG' : 'Veuillez reporter ceci si vous pensez qu\'il s\'agit d\'un bug. \n Inclure une brève description de la façon dont l\'erreur s\'est produite, et si vous le pouvez; Comment le répliquer', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Connexion à des services externes: {0}', + 'CONNECTION_LOST': 'La connexion au serveur a été perdue. Reconnexion ...', + 'CONNECTION_RESTORED': 'La connexion au serveur a été restaurée', + 'CONNECTION_RESTORE_FAILED': 'Impossible de rétablir la connexion. Essayer à nouveau.', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Erreur Fatale', + 'ERR_UTILS_XHR_FMT' : 'Erreure AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Déconnexion (quitter)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Déconnexion de l\'utilisateur \'{0}\'.\nVoulez-vous enregistrer votre session courante ?', + + 'DIALOG_CLOSE' : 'Fermer', + 'DIALOG_CANCEL': 'Annuler', + 'DIALOG_APPLY' : 'Appliquer', + 'DIALOG_OK' : 'Valider', + + 'DIALOG_ALERT_TITLE' : 'Fenêtre d\'alerte', + + 'DIALOG_COLOR_TITLE' : 'Fenêtre des couleur', + 'DIALOG_COLOR_R' : 'Rouge: {0}', + 'DIALOG_COLOR_G' : 'Vert: {0}', + 'DIALOG_COLOR_B' : 'Bleu: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Fenêtre de confirmation', + + 'DIALOG_ERROR_TITLE' : 'Erreur', + 'DIALOG_ERROR_MESSAGE' : 'Message', + 'DIALOG_ERROR_SUMMARY' : 'Résumé', + 'DIALOG_ERROR_TRACE' : 'Trace', + 'DIALOG_ERROR_BUGREPORT' : 'Rapport de bug', + + 'DIALOG_FILE_SAVE' : 'Enregistrer', + 'DIALOG_FILE_OPEN' : 'Ouvrir', + 'DIALOG_FILE_MKDIR' : 'Nouveau dossier', + 'DIALOG_FILE_MKDIR_MSG' : 'Créer un nouveau dossier dans **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Êtes-vous sûr de vouloir écraser le fichier \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Type de vue', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Vue en liste', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Vue en arborescence', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Vue en icônes', + 'DIALOG_FILE_ERROR' : 'Erreur FileDialog', + 'DIALOG_FILE_ERROR_SCANDIR': 'Impossible de lister le contenu du dossier \'{0}\' car une erreur est survenue', + 'DIALOG_FILE_ERROR_FIND': 'Impossible de recherche dans le répertoire \'{0}\' car une erreur s\'est produite', + 'DIALOG_FILE_MISSING_FILENAME' : 'Vous devez sélectionner un fichier ou entrer un nouveau nom de fichier !', + 'DIALOG_FILE_MISSING_SELECTION': 'Vous devez sélectionner un fichier!', + + 'DIALOG_FILEINFO_TITLE' : 'Informations sur le fichier', + 'DIALOG_FILEINFO_LOADING' : 'Chargement des informations sur le fichier: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Erreur FileInformationDialog', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Impossible de récupérer les informations sur : **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Impossible de récupérer les informations sur : {0}', + + 'DIALOG_INPUT_TITLE' : 'Fenêtre de saisie', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Progression des opérations sur les fichiers', + 'DIALOG_FILEPROGRESS_LOADING' : 'Chargement...', + + 'DIALOG_UPLOAD_TITLE' : 'Fenêtre d\'envoi de fichier', + 'DIALOG_UPLOAD_DESC' : 'Envoyer un fichier vers **{0}**.\nTaille maximum: {1} octets', + 'DIALOG_UPLOAD_MSG_FMT' : 'Envoi de \'{0}\' ({1} {2}) vers {3}', + 'DIALOG_UPLOAD_MSG' : 'Envoi du fichier...', + 'DIALOG_UPLOAD_FAILED' : 'L\'envoi a échoué!', + 'DIALOG_UPLOAD_FAILED_MSG' : 'L\'envoi a échoué', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Raison inconnue...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Annulé pas l\'utilisateur...', + 'DIALOG_UPLOAD_TOO_BIG': 'Le fichier est trop gros', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Le fichier est trop gros, sa taille éxcède {0}', + + 'DIALOG_FONT_TITLE' : 'Fenêtre de police', + + 'DIALOG_APPCHOOSER_TITLE' : 'Choisir une application', + 'DIALOG_APPCHOOSER_MSG' : 'Choisir une application pour ouvrir', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Vous devez sélectionner une application', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Utiliser comme application par défaut pour {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'Module Google API non configuré ou désactivé', + 'GAPI_SIGN_OUT' : 'Déconnexion de l\'API Google', + 'GAPI_REVOKE' : 'Révoquer les permissions et déconnecter', + 'GAPI_AUTH_FAILURE' : 'L\'authentification Google API a échouer ou ne s\'est pas déroulée', + 'GAPI_AUTH_FAILURE_FMT' : 'Impossible d\'authentifier: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Impossible de charger l\'API Google', + + // Windows Live API + 'WLAPI_DISABLED' : 'Module Live API non configuré ou désactivé', + 'WLAPI_SIGN_OUT' : 'Déconnexion de l\'API Live', + 'WLAPI_LOAD_FAILURE' : 'Impossible de charger Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Impossible de s\'authentifier dans Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Impossible de s\'authentifier dans Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API a retourné le status {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Impossible de créer une base IndexedDB sans nom de base', + 'IDB_NO_SUCH_ITEM' : 'Aucun item correspondant', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Erreur fatale', + 'ERR_VFS_UNAVAILABLE' : 'Non disponible', + 'ERR_VFS_FILE_ARGS' : 'Le fichier attend au moins un argument', + 'ERR_VFS_NUM_ARGS' : 'Pas assez d\'arguments', + 'ERR_VFS_EXPECT_FILE' : 'Un objet "fichier" est attendu', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Un objet "fichier source" est attendu', + 'ERR_VFS_EXPECT_DST_FILE' : 'Un objet "fichier destination" est attendu', + 'ERR_VFS_FILE_EXISTS' : 'Le fichier destination existe déjà', + 'ERR_VFS_TARGET_NOT_EXISTS': 'La cible n\'existe pas', + 'ERR_VFS_TRANSFER_FMT' : 'Une erreur est survenu lors du transfert entre espaces de stockage : {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Impossible d\'envoyer un fichier sans destination', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Impossible d\'envoyer un fichier sans aucun fichier défini', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Impossible d\'envoyer le fichier: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'L\'envoi du fichier a été annulé', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Impossible de télécharger un chemin sans chemin', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Une erreur est survenue lors du téléchargement: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'La réponse est vide', + 'ERR_VFS_NO_MIME_DETECT' : 'Aucun type de mime détecté', + + 'ERR_VFSMODULE_INVALID' : 'Module VFS invalide', + 'ERR_VFSMODULE_INVALID_FMT' : 'Module VFS invalide: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Méthode VFS invalide', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Méthode VFS invalide: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Type de module VFS invalide', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Type de module VFS invalide: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Configuration VFS Module ', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Configuration VFS Module non valide : {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Module VFS déjà monté', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Module VFS \'{0}\' déjà monté', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'Module VFS non monté', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Module VFS \'{0}\' non monté', + 'ERR_VFSMODULE_EXCEPTION' : 'Exception du module VFS', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Exception du module VFS: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Aucun Module VFS ne correspond {0}. Mauvais chemin ou Mauvais formats ?', + 'ERR_VFSMODULE_READONLY' : 'Ce module VFS est en lecture seule', + 'ERR_VFSMODULE_READONLY_FMT' : 'Ce module VFS est en lecture seule: {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Téléchargement du fichier', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Erreur XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'Impossible de trouver l\'id du répertoire racine', + 'ERR_VFSMODULE_NOSUCH' : 'Le fichier n\'existe pas', + 'ERR_VFSMODULE_PARENT' : 'Pas de parent', + 'ERR_VFSMODULE_PARENT_FMT' : 'Impossible de trouver un parent: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Impossible de scanner le répertoire', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Impossible de scanner le répertoire: {0}', + 'ERR_VFSMODULE_READ' : 'Impossible de lire le fichier', + 'ERR_VFSMODULE_READ_FMT' : 'Impossible de lire le fichier: {0}', + 'ERR_VFSMODULE_WRITE' : 'Impossible d\'écrire dans le fichier', + 'ERR_VFSMODULE_WRITE_FMT' : 'Impossible d\'écrire dans le fichier: {0}', + 'ERR_VFSMODULE_COPY' : 'Impossible de copier', + 'ERR_VFSMODULE_COPY_FMT' : 'Impossible de copier: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Impossible de détacher le fichier', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Impossible de détacher le fichier: {0}', + 'ERR_VFSMODULE_MOVE' : 'Impossible de déplacer le fichier', + 'ERR_VFSMODULE_MOVE_FMT' : 'Impossible de déplacer le fichier: {0}', + 'ERR_VFSMODULE_EXIST' : 'Impossible de vérifier l\'existance du fichier', + 'ERR_VFSMODULE_EXIST_FMT' : 'Impossible de vérifier l\'existance du fichier: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Impossible de récuperer les informations du fichier', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Impossible de récuperer les informations du fichier: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Impossible de créer un répertoire', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Impossible de créer un répertoire: {0}', + 'ERR_VFSMODULE_MKFILE' : 'Impossible de créer le fichier', + 'ERR_VFSMODULE_MKFILE_FMT' : 'Impossible de créer le fichier: {0}', + 'ERR_VFSMODULE_URL' : 'Impossible de récuperer l\'URL du fichier', + 'ERR_VFSMODULE_URL_FMT' : 'Impossible de récuperer l\'URL du fichier: {0}', + 'ERR_VFSMODULE_TRASH' : 'Impossible de déplacer le fichier dans la corbeille', + 'ERR_VFSMODULE_TRASH_FMT' : 'Impossible de déplacer le fichier dans la corbeille: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Impossible de sortir le fichier de la corbeille', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Impossible de sortir le fichier de la corbeille: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Impossible de vider la corbeille', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Impossible de vider la corbeille: {0}', + 'ERR_VFSMODULE_FIND' : 'Impossible de chercher', + 'ERR_VFSMODULE_FIND_FMT' : 'Impossible de chercher: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'Impossible d\'obtenir de l\'espace libre', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'Impossible d\'obtenir de l\'espace libre: {0}', + 'ERR_VFSMODULE_EXISTS' : 'Impossible de Vérifier s\'il existe', + 'ERR_VFSMODULE_EXISTS_FMT' : 'Impossible de Vérifier s\'il existe: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Vous êtes connectés dans l\'API Dropbox', + 'DROPBOX_SIGN_OUT' : 'Déconnexion des services Google API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Impossible de résoudre le chemin: objet non trouvé', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'LE chargement de zip.js a échoué', + 'ZIP_VENDOR_FAIL' : 'La bibliothèque zip.js n\'a pas été trouvée. A-t-elle été chargée correctement?', + 'ZIP_NO_RESOURCE' : 'Aucune archive zip n\'a été fournie', + 'ZIP_NO_PATH' : 'Aucun chemin fourni', + + // + // SearchEngine + // + 'SEARCH_LOADING': 'Recherche...', + 'SEARCH_NO_RESULTS': 'Aucun resulta trouver', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Le répertoire d\'installation des paquêts existe déjà. L\'opération est interrompue!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Impossible d\'ouvrir le fichier', + 'ERR_FILE_APP_OPEN_FMT' : 'Le fichier {0} n\'a pas pu être ouvert car le type mime {1} m\'est pas supporté', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Le fichier {0} n\'a pas pu être ouvert: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Le fichier {0} n\'a pas pu être enregistré: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Erreur de l\'application', + 'ERR_GENERIC_APP_ACTION_FMT': 'Impossible d\'effectuer l\'action \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Erreur inconnue', + 'ERR_GENERIC_APP_REQUEST' : 'Une erreur est survenue lors du traitement de votre requête', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Erreur fatale : {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Abandonner les modifications ?', + 'MSG_FILE_CHANGED' : 'Le fichier a été modifié. Le recharger ?', + 'MSG_APPLICATION_WARNING' : 'Avertissement de l\'application', + 'MSG_MIME_OVERRIDE' : 'Le type de fichier "{0}" n\'est pas supporté, utilisation de "{1}" à la place.', + + 'ERR_OPEN_LOCATION' : 'Échec de l\'ouverture de l\'emplacement', + 'ERR_OPEN_LOCATION_FMT' : 'Échec de l\'ouverture de l\'emplacement: {0}', + + // + // General + // + + 'LBL_UNKNOWN' : 'Inconnu', + 'LBL_APPEARANCE' : 'Appearance', + 'LBL_USER' : 'Utilisateur', + 'LBL_NAME' : 'Nom', + 'LBL_APPLY' : 'Appliquer', + 'LBL_FILENAME' : 'Nom de fichier', + 'LBL_PATH' : 'Chemin', + 'LBL_SIZE' : 'Taille', + 'LBL_TYPE' : 'Type', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Chargement', + 'LBL_SETTINGS' : 'Paramètres', + 'LBL_ADD_FILE' : 'Ajouter un fichier', + 'LBL_COMMENT' : 'Commentaire', + 'LBL_ACCOUNT' : 'Compte', + 'LBL_CONNECT' : 'Connexion', + 'LBL_ONLINE' : 'En ligne', + 'LBL_OFFLINE' : 'Hors ligne', + 'LBL_AWAY' : 'Absent', + 'LBL_BUSY' : 'Occupé', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Aide', + 'LBL_ABOUT' : 'À propos', + 'LBL_PANELS' : 'Dock', + 'LBL_LOCALES' : 'Langues', + 'LBL_THEME' : 'Thème', + 'LBL_COLOR' : 'Couleur', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Fin de tâche', + 'LBL_ALIVE' : 'Vivant', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Ajouter', + 'LBL_FONT' : 'Police', + 'LBL_YES' : 'Oui', + 'LBL_NO' : 'Non', + 'LBL_CANCEL' : 'Annuler', + 'LBL_TOP' : 'Haut', + 'LBL_LEFT' : 'Gauche', + 'LBL_RIGHT' : 'Droite', + 'LBL_BOTTOM' : 'Bas', + 'LBL_CENTER' : 'Centre', + 'LBL_FILE' : 'Fichier', + 'LBL_NEW' : 'Nouveau', + 'LBL_OPEN' : 'Ouvrir', + 'LBL_SAVE' : 'Enregistrer', + 'LBL_SAVEAS' : 'Enregistrer sous...', + 'LBL_CLOSE' : 'Fermer', + 'LBL_MKDIR' : 'Créer un dossier', + 'LBL_UPLOAD' : 'Envoyer un fichier', + 'LBL_VIEW' : 'Vue', + 'LBL_EDIT' : 'Édition', + 'LBL_RENAME' : 'Renommer', + 'LBL_DELETE' : 'Supprimer', + 'LBL_OPENWITH' : 'Ouvrir avec...', + 'LBL_ICONVIEW' : 'Vue en icônes', + 'LBL_TREEVIEW' : 'Vue en arborescence', + 'LBL_LISTVIEW' : 'Vue en liste', + 'LBL_REFRESH' : 'Rafraîchir', + 'LBL_VIEWTYPE' : 'Type de vue', + 'LBL_BOLD' : 'Gras', + 'LBL_ITALIC' : 'Italique', + 'LBL_UNDERLINE' : 'Souligné', + 'LBL_REGULAR' : 'Régulier', + 'LBL_STRIKE' : 'Barré', + 'LBL_INDENT' : 'Indentation', + 'LBL_OUTDENT' : 'Dépassé', + 'LBL_UNDO' : 'Annuler', + 'LBL_REDO' : 'Refaire', + 'LBL_CUT' : 'Couper', + 'LBL_UNLINK' : 'Supprimer le lien', + 'LBL_COPY' : 'Copier', + 'LBL_PASTE' : 'Coller', + 'LBL_INSERT' : 'Insérer', + 'LBL_IMAGE' : 'Image', + 'LBL_LINK' : 'Lien', + 'LBL_DISCONNECT' : 'Déconnexion', + 'LBL_APPLICATIONS' : 'Applications', + 'LBL_ADD_FOLDER' : 'Ajouter un dossier', + 'LBL_INFORMATION' : 'Information', + 'LBL_TEXT_COLOR' : 'Couleur du texte', + 'LBL_BACK_COLOR' : 'Couleur de fond', + 'LBL_RESET_DEFAULT' : 'Rétablir par défaut', + 'LBL_DOWNLOAD_COMP' : 'Télécharger sur l\'ordinateur', + 'LBL_ORDERED_LIST' : 'Liste ordonnée', + 'LBL_BACKGROUND_IMAGE' : 'Image d\'arrière-plan', + 'LBL_BACKGROUND_COLOR' : 'Couleur d\'arrière-plan', + 'LBL_UNORDERED_LIST' : 'Liste désordonnée', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Lecture seule', + 'LBL_CREATED' : 'Crée', + 'LBL_MODIFIED' : 'Modifié', + 'LBL_SHOW_COLUMNS' : 'Montrer les colonnes', + 'LBL_MOVE' : 'Déplacer', + 'LBL_OPTIONS' : 'Options', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Repertoire', + 'LBL_CREATE' : 'Créer', + 'LBL_BUGREPORT' : 'Report de bug', + 'LBL_INSTALL' : 'Installer', + 'LBL_UPDATE' : 'Mettre à jour', + 'LBL_REMOVE' : 'Enlever', + 'LBL_SHOW_SIDEBAR' : 'Afficher la barre de côté', + 'LBL_SHOW_NAVIGATION' : 'Afficher la navigation', + 'LBL_SHOW_HIDDENFILES' : 'Afficher les fichiers cachés', + 'LBL_SHOW_FILEEXTENSIONS' : 'Afficher les extensions de fichier', + 'LBL_MOUNT': 'Monter', + 'LBL_DESCRIPTION': 'Description', + 'LBL_USERNAME': 'Nom d\'utilisateur', + 'LBL_PASSWORD': 'Mot de passe', + 'LBL_HOST': 'Hôte', + 'LBL_NAMESPACE': 'Espace de nom', + 'LBL_SEARCH': 'Recherche', + 'LBL_BACK': 'Retour', + 'LBL_ICONS' : 'Icônes', + 'LBL_ICON': 'Icône', + 'LBL_UNINSTALL': 'Désinstaller', + 'LBL_REGENERATE': 'Régénérer', + 'LBL_DESKTOP' : 'Bureau', + 'LBL_WINDOWMANAGER' : 'Gestionnaire de fenêtre', + 'LBL_HOTKEY': ' Raccourci clavier', + 'LBL_HOTKEYS': ' raccourcis clavier', + 'LBL_MOUNTS': 'Supports', + 'LBL_ID': 'ID', + 'LBL_APPLICATION' : 'Application', + 'LBL_SCOPE' : 'portée', + 'LBL_HIDE' : 'Cacher', + 'LBL_REPOSITORY': 'Dépôt', + 'LBL_VERSION' : 'Version', + 'LBL_AUTHOR' : 'Auteur', + 'LBL_GROUPS' : 'Groupes', + 'LBL_AUTOHIDE' : 'Masquer automatiquement', + 'LBL_PERSONAL': 'Personnel', + 'LBL_SYSTEM': 'Système', + 'LBL_STARTING': 'Démarage', + 'LBL_SOUNDS': 'Son', + 'LBL_STORE' : 'Centre d\'application', + 'LBL_LOCALE': 'Langue', + 'LBL_PACKAGE' : 'Paquet', + 'LBL_PACKAGES' : 'Paquets', + 'LBL_INPUT' : 'Clavier', + 'LBL_MISC': 'Divers', + 'LBL_OTHER': 'Autre', + 'LBL_USERS' : 'Gestion des utilisateurs', + 'LBL_FONTS': 'Polices', + 'LBL_OPEN_LOCATION': 'Ouvrir l\'emplacement ', + 'LBL_HOME': 'Accueil', + 'LBL_WIDGET': 'Widget', + 'LBL_WIDGETS': 'Widgets', + 'LBL_LOCK': 'Verrouiller', + 'LBL_UNLOCK': 'Déverrouiller', + 'LBL_WARNING': 'Attention', + 'LBL_INFO': 'Info', + 'LBL_POSITION' : 'Position', + 'LBL_OPACITY' : 'Opacité', + 'LBL_ITEMS' : 'Objets', + 'LBL_ONTOP' : 'Premier plan', + 'LBL_BACKGROUND' : 'Fond d\'écran' +}; diff --git a/src/client/javascript/locales/it_IT.js b/src/client/javascript/locales/it_IT.js index 5c24a3bb4d..9275607e4a 100644 --- a/src/client/javascript/locales/it_IT.js +++ b/src/client/javascript/locales/it_IT.js @@ -27,460 +27,457 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.it_IT = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Errore durante l\'apertura del file', - 'ERR_WM_NOT_RUNNING' : 'Windows manager non in esecuzione', - 'ERR_FILE_OPEN_FMT' : 'Il file \'**{0}**\' non può essere aperto', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Nessuna applicazione che supporta il tipo di file \'{0}\' è stata trovata', - 'ERR_APP_LAUNCH_FAILED' : 'Avvio Applicazione fallito', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Si è verificato un errore durante l\'avvio di : {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Applicazione \'{0}\' construct failed: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Applicazione \'{0}\', init() fallito: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Applicazione resources missing for \'{0}\' or it failed to load!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Applicazione \'{0}\' preloading failed: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'L\' Applicazione \'{0}\' è già stata lanciata, ed è permessa una sola istanza!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Avvio di \'{0}\' fallito. Manifesto dell\'applicazione non trovato', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Avvio di \'{0}\' fallito. il tuo browser non supporta: {1}', - - 'ERR_NO_WM_RUNNING' : 'Nessun window manager in esecuzione', - 'ERR_CORE_INIT_FAILED' : 'Inizializzazione OS.js fallita', - 'ERR_CORE_INIT_FAILED_DESC' : 'Si è verificato un errore nella Inizializzazione di OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Impossibile avviare OS.js: Nessun window manager settato!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Impossibile avviare OS.js: Fallito avvio del window manager: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Impossibile avviare OS.js: Precaricamento risorse fallito...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Error Report', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Si è verificato un errore inaspettato, forse un bug.', - - 'ERR_APP_API_ERROR' : 'Application API error', - 'ERR_APP_API_ERROR_DESC_FMT' : 'L\'Applicazione {0} ha fallito nell\'eseguire l\'operazine \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Argomento mancante: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Errore sconosciuto', - - 'ERR_OPERATION_TIMEOUT' : 'Operation Timeout', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Timeout ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' prevede \'{1}\' di tipo \'{2}\', \'{3}\' ricevuto', - 'ERR_INVALID_LOCATION' : 'Percorso non valido', - - 'ERR_OPEN_LOCATION' : 'Fallito aprire percorso', - 'ERR_OPEN_LOCATION_FMT' : 'Fallito aprire il percorso: {0}', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Hai già dato un nome alla finestra \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimizza', - 'WINDOW_MAXIMIZE' : 'Massimizza', - 'WINDOW_RESTORE' : 'Ripristina', - 'WINDOW_CLOSE' : 'Chiudi', - 'WINDOW_ONTOP_ON' : 'Primopiano (Abilita)', - 'WINDOW_ONTOP_OFF': 'Primopiano (Disabilita)', - - // Handler - 'TITLE_SIGN_OUT' : 'Disconnetti', - 'TITLE_SIGNED_IN_AS_FMT' : 'Connesso come: {0}', - 'ERR_LOGIN_FMT' : 'Errore di accesso: {0}', - 'ERR_LOGIN_INVALID' : 'Accesso non corretto', - - // SESSION - 'ERR_NO_SESSION': 'Nessuna sessione create dal server. Vuoi riprovare l\'autenticazione?', - 'MSG_SESSION_WARNING' : 'Sei sicuro di voler chiudere OS.js? Ogni settaggio ed ogni dato non salvato andrà perduto!', - - // Service - 'BUGREPORT_MSG' : 'Per piacere, fai un report se pensi che questo sia un bug. \nIncludi una breve descrizione di come l\'errore si è verificato, se possibile come replicarlo.', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Connesso al servizio esterno: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Errore Fatale!', - 'ERR_UTILS_XHR_FMT' : 'Errore AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Disconetti (Esci)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Disconnessione utente \'{0}\'.\nVuoi salvare la sessinoe corrente?', - - 'DIALOG_CLOSE' : 'Chiudi', - 'DIALOG_CANCEL': 'Cancella', - 'DIALOG_APPLY' : 'Applica', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Attenzione!', - - 'DIALOG_COLOR_TITLE' : 'Scegli colori', - 'DIALOG_COLOR_R' : 'Rosso: {0}', - 'DIALOG_COLOR_G' : 'Verde: {0}', - 'DIALOG_COLOR_B' : 'Blue: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Conferma scelta', - - 'DIALOG_ERROR_MESSAGE' : 'Messaggio', - 'DIALOG_ERROR_SUMMARY' : 'Sommario', - 'DIALOG_ERROR_TRACE' : 'Stack dell\'errore', - 'DIALOG_ERROR_BUGREPORT' : 'Segnala Bug', - - 'DIALOG_FILE_SAVE' : 'Salva', - 'DIALOG_FILE_OPEN' : 'Open', - 'DIALOG_FILE_MKDIR' : 'Nuova Cartella', - 'DIALOG_FILE_MKDIR_MSG' : 'Crea una nuova cartella in **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Sei sicuro di voler sovrascrivere il file \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Mostra tipo', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Visualizzazione a lista', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Visualizzazione ad albero', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Visualizzazione ad icone', - 'DIALOG_FILE_ERROR' : 'FileDialog Errore', - 'DIALOG_FILE_ERROR_SCANDIR': 'Indicizzazione della cartella \'{0}\' fallito, perchè si è verificato un errore!', - 'DIALOG_FILE_ERROR_FIND': 'Ricerca cartella \'{0}\' fallita perchè si è verificato un errore!', - 'DIALOG_FILE_MISSING_FILENAME' : 'Devi selezionare un file o fornire un nuovo nome!', - 'DIALOG_FILE_MISSING_SELECTION': 'Devi selezionare un file!', - - 'DIALOG_FILEINFO_TITLE' : 'Informazioni file', - 'DIALOG_FILEINFO_LOADING' : 'Caricamento informazioni file: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Errore FileInformationDialog', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Recupero informazioni fallito **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Recupero infomazioni file fallito: {0}', - - 'DIALOG_INPUT_TITLE' : 'Richiesta di inserimento', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Operazione file in corso', - 'DIALOG_FILEPROGRESS_LOADING' : 'Caricamento...', - - 'DIALOG_UPLOAD_TITLE' : 'Caricamento', - 'DIALOG_UPLOAD_DESC' : 'Carimento del filo a **{0}**.
Dimensione massima: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Caricamento \'{0}\' ({1} {2}) a {3}', - 'DIALOG_UPLOAD_MSG' : 'Caricamento file...', - 'DIALOG_UPLOAD_FAILED' : 'Caricamento fallito', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Il caricamentoè fallito', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Ragione sconociuta...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancellato dall\'utente...', - 'DIALOG_UPLOAD_TOO_BIG': 'Dimensione file troppo grande', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Dimensione del file troppo grande, in eccesso {0}', - - 'DIALOG_FONT_TITLE' : 'Scelta Font', - - 'DIALOG_APPCHOOSER_TITLE' : 'Scegli Applicazione', - 'DIALOG_APPCHOOSER_MSG' : 'Scegli un applicazione da aprire', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Devi selezionare un applicazione', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usa l\'applicazione predefinita per {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'Modulo GoogleAPI non configurato o disabilitato', - 'GAPI_SIGN_OUT' : 'Disconnettiti da Google API Services', - 'GAPI_REVOKE' : 'Revoca i permessi e disconnetti', - 'GAPI_AUTH_FAILURE' : 'L\'Autenticazione alla Google API fallito o non avvenuto', - 'GAPI_AUTH_FAILURE_FMT' : 'Autenticazione fallita: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Caricamento Google API fallito', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API module non configurato o disabilitato', - 'WLAPI_SIGN_OUT' : 'Disconnetti da Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Caricamento Windows Live API fallito', - 'WLAPI_LOGIN_FAILED' : 'Connessione a Windows Live API fallita', - 'WLAPI_LOGIN_FAILED_FMT' : 'Connessione a Windows Live API fallito: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Impossibile creare IndexedDB senza un nome database', - 'IDB_NO_SUCH_ITEM' : 'Nessun elemento', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Errore fatale', - 'ERR_VFS_UNAVAILABLE' : 'No disponibile', - 'ERR_VFS_FILE_ARGS' : 'Il file richiede almeno un argumento', - 'ERR_VFS_NUM_ARGS' : 'Non abbastanza argomenti', - 'ERR_VFS_EXPECT_FILE' : 'File-object previsto', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Sorgente file-object prevista', - 'ERR_VFS_EXPECT_DST_FILE' : 'Destinazion file-object prevista', - 'ERR_VFS_FILE_EXISTS' : 'Destinazione già esistente', - 'ERR_VFS_TARGET_NOT_EXISTS': 'La destinazione non esiste', - 'ERR_VFS_TRANSFER_FMT' : 'Un errore si è verificato durante il trasferimento tra le memorie: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Impossibile caricare un file senza una destinazione', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Impossibile caricare senza definire un file', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Carimento file fallito: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Caricamento file cancellato', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Impossibile scaricare una destinazione senza una destinazione', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Si è verificato un errore durante il download: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'La risposta era vuota', - - 'ERR_VFSMODULE_INVALID' : 'Modulo VFS Invalido', - 'ERR_VFSMODULE_INVALID_FMT' : 'Modulo VFS Invalido: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Metodo VFS Invalido', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Metodo VFS Invalido: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Modulo VFS tipo non valido', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Modulo VFS tipo non valido: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Modulo VFS configurazione non valida', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Modulo VFS configurazione non valida: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Modulo VFS già montato', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Modulo VFS \'{0}\' già montato', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'Modulo VFS non montato', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Modulo VFS \'{0}\' non montato', - 'ERR_VFSMODULE_EXCEPTION' : 'Modulo VFS Eccezione', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Modulo VFS Eccezione: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Nessun modulo VFS associato con {0}. Desinazione o formato sbagliato?', - 'ERR_VFSMODULE_READONLY' : 'Questo modulo VFS è di sola lettura', - 'ERR_VFSMODULE_READONLY_FMT' : 'Questo modulo VFS è di sola lettura: {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Download file', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Errore XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'ID cartella root non trovato', - 'ERR_VFSMODULE_NOSUCH' : 'Il file non esiste', - 'ERR_VFSMODULE_PARENT' : 'Nessun parente', - 'ERR_VFSMODULE_PARENT_FMT' : 'Cartella parente non trovata: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Scansione cartella fallito', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Scansione cartella fallito: {0}', - 'ERR_VFSMODULE_READ' : 'Lettura file fallito', - 'ERR_VFSMODULE_READ_FMT' : 'Lettura file fallito: {0}', - 'ERR_VFSMODULE_WRITE' : 'Scrittura file fallita', - 'ERR_VFSMODULE_WRITE_FMT' : 'Scrittura file fallita: {0}', - 'ERR_VFSMODULE_COPY' : 'Copiatura fallita', - 'ERR_VFSMODULE_COPY_FMT' : 'Copiatura fallita: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Unlink file fallito', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Unlink file fallito: {0}', - 'ERR_VFSMODULE_MOVE' : 'Spostamento file fallito', - 'ERR_VFSMODULE_MOVE_FMT' : 'Spostamento file fallito: {0}', - 'ERR_VFSMODULE_EXIST' : 'Verifica esistenza file fallita', - 'ERR_VFSMODULE_EXIST_FMT' : 'Verifica esistenza file fallita: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Recupero informazioni file fallito', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Recupero informazioni file fallito: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Creazione cartella fallito', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Creazione cartella fallito: {0}', - 'ERR_VFSMODULE_MKFILE' : 'Creazione file fallita', - 'ERR_VFSMODULE_MKFILE_FMT' : 'Creazione file fallita: {0}', - 'ERR_VFSMODULE_URL' : 'Recupero URL file fallito', - 'ERR_VFSMODULE_URL_FMT' : 'Recupero URL file fallito: {0}', - 'ERR_VFSMODULE_TRASH' : 'Spostamento file nel cestino fallito', - 'ERR_VFSMODULE_TRASH_FMT' : 'Spostamento file nel cestino fallito: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Spostamento del file fuori dal cestino fallito', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Spostamento del file fuori dal cestino fallito: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Svuotamento cestino fallito', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Svuotamento cestino fallito: {0}', - 'ERR_VFSMODULE_FIND' : 'Ricerca fallita', - 'ERR_VFSMODULE_FIND_FMT' : 'Ricerca fallita: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'Allocamento spazio libero fallito', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'Allocamento spazio libero fallito: {0}', - 'ERR_VFSMODULE_EXISTS' : 'Verifica esistenza fallito', - 'ERR_VFSMODULE_EXISTS_FMT' : 'Verifica esistenza fallito: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Sei connesso a Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Disconnetti Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Risoluzione percorso fallita: elemento non trovato', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'Caricamento zip.js fallito', - 'ZIP_VENDOR_FAIL' : 'Libreria zip.js non trovata. L\'hai caricata correttamente?', - 'ZIP_NO_RESOURCE' : 'Nessuna risorsa zip fornita', - 'ZIP_NO_PATH' : 'Nessun percorso fornito', - - // - // SearchEngine - // - 'SEARCH_LOADING': 'Ricerca in corso...', - 'SEARCH_NO_RESULTS': 'Nessun risultato trovato', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Percorso installazione pacchetto gia esistente. Impossibile continuare!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Impossibile aprire il file', - 'ERR_FILE_APP_OPEN_FMT' : 'Impossibile aprire il file {0} perchè il mime {1} non è supportato', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Impossibile aprire il file {0}: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Impossibile salvare il file {0}: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Application Error', - 'ERR_GENERIC_APP_ACTION_FMT': 'Esecuzione azione fallito \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Errore sconosciuto', - 'ERR_GENERIC_APP_REQUEST' : 'Si è verificato un errore durante la risoluzione della richiesta', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Errore fatale: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Scarta cambiamenti?', - 'MSG_FILE_CHANGED' : 'Il file è stato cambiato. Ricaricarlo?', - 'MSG_APPLICATION_WARNING' : 'Avviso applicazione', - 'MSG_MIME_OVERRIDE' : 'tipo del file "{0}" non supportato, si userà "{1}" al suo posto.', - - // - // General - // - - 'LBL_UNKNOWN' : 'Sconosciuto', - 'LBL_APPEARANCE' : 'Aspetto', - 'LBL_USER' : 'Utente', - 'LBL_NAME' : 'Nome', - 'LBL_APPLY' : 'Applica', - 'LBL_FILENAME' : 'Nome file', - 'LBL_PATH' : 'Percorso', - 'LBL_SIZE' : 'Dimensione', - 'LBL_TYPE' : 'Tipo', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Caricamento', - 'LBL_SETTINGS' : 'Settaggi', - 'LBL_ADD_FILE' : 'Aggiungi file', - 'LBL_COMMENT' : 'Commenta', - 'LBL_ACCOUNT' : 'Account', - 'LBL_CONNECT' : 'Connetti', - 'LBL_ONLINE' : 'Online', - 'LBL_OFFLINE' : 'Offline', - 'LBL_AWAY' : 'Non presente', - 'LBL_BUSY' : 'Occupato', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Aiuto', - 'LBL_ABOUT' : 'Riguardo a', - 'LBL_PANELS' : 'Pannelli', - 'LBL_LOCALES' : 'Localizzazioni', - 'LBL_THEME' : 'Tema', - 'LBL_COLOR' : 'Colore', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Terminal (kill)', - 'LBL_ALIVE' : 'Mantieni (Alive)', - 'LBL_INDEX' : 'Indice', - 'LBL_ADD' : 'Aggiungi', - 'LBL_FONT' : 'Font', - 'LBL_YES' : 'Si', - 'LBL_NO' : 'No', - 'LBL_CANCEL' : 'Cancella', - 'LBL_TOP' : 'Sopra', - 'LBL_LEFT' : 'Sinistra', - 'LBL_RIGHT' : 'Destra', - 'LBL_BOTTOM' : 'Sotto', - 'LBL_CENTER' : 'Centro', - 'LBL_FILE' : 'File', - 'LBL_NEW' : 'Nuovo', - 'LBL_OPEN' : 'Apri', - 'LBL_SAVE' : 'Salva', - 'LBL_SAVEAS' : 'Salva come...', - 'LBL_CLOSE' : 'Chiudi', - 'LBL_MKDIR' : 'Crea cartella', - 'LBL_UPLOAD' : 'Carica', - 'LBL_VIEW' : 'Visualizza', - 'LBL_EDIT' : 'Modifica', - 'LBL_RENAME' : 'Rinomina', - 'LBL_DELETE' : 'Cancella', - 'LBL_OPENWITH' : 'Apri con...', - 'LBL_ICONVIEW' : 'Visualizzazione ad Icone', - 'LBL_TREEVIEW' : 'Visualizzazione ad Albero', - 'LBL_LISTVIEW' : 'Visualizzazione ad Lista', - 'LBL_REFRESH' : 'Aggiorna', - 'LBL_VIEWTYPE' : 'Visualizza tipo', - 'LBL_BOLD' : 'Grassetto', - 'LBL_ITALIC' : 'Corsivo', - 'LBL_UNDERLINE' : 'Sottolineato', - 'LBL_REGULAR' : 'Regolare', - 'LBL_STRIKE' : 'Strike', - 'LBL_INDENT' : 'Indenta', - 'LBL_OUTDENT' : 'Unindenta', - 'LBL_UNDO' : 'Torna indietro', - 'LBL_REDO' : 'Vai avanti', - 'LBL_CUT' : 'Taglia', - 'LBL_UNLINK' : 'Rimuovi link', - 'LBL_COPY' : 'Copia', - 'LBL_PASTE' : 'Incolla', - 'LBL_INSERT' : 'Inserisci', - 'LBL_IMAGE' : 'Immaggine', - 'LBL_LINK' : 'Link', - 'LBL_DISCONNECT' : 'Disconnetti', - 'LBL_APPLICATIONS' : 'Applicazioni', - 'LBL_ADD_FOLDER' : 'Aggiungi cartella', - 'LBL_INFORMATION' : 'Informazione', - 'LBL_TEXT_COLOR' : 'Colore testo', - 'LBL_BACK_COLOR' : 'Colore in secondo piano', - 'LBL_RESET_DEFAULT' : 'Resetta ai valori predefiniti', - 'LBL_DOWNLOAD_COMP' : 'Scarica sul computer', - 'LBL_ORDERED_LIST' : 'Lista ordinata', - 'LBL_BACKGROUND_IMAGE' : 'Immagine di sfondo', - 'LBL_BACKGROUND_COLOR' : 'Colore di sfondo', - 'LBL_UNORDERED_LIST' : 'Lista non ordinata', - 'LBL_STATUS' : 'Stato', - 'LBL_READONLY' : 'Di sola lettura', - 'LBL_CREATED' : 'Creato', - 'LBL_MODIFIED' : 'Modificato', - 'LBL_SHOW_COLUMNS' : 'Mostra colonne', - 'LBL_MOVE' : 'Muovi', - 'LBL_OPTIONS' : 'Opzioni', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Cartella', - 'LBL_CREATE' : 'Crea', - 'LBL_BUGREPORT' : 'Segnalazione bug', - 'LBL_INSTALL' : 'Installa', - 'LBL_UPDATE' : 'Aggiorna', - 'LBL_REMOVE' : 'Rimuovi', - 'LBL_SHOW_SIDEBAR' : 'Mostra barra laterale', - 'LBL_SHOW_NAVIGATION' : 'Mostra navigazione', - 'LBL_SHOW_HIDDENFILES' : 'Mostra file nascosti', - 'LBL_SHOW_FILEEXTENSIONS' : 'Mostra le estenzioni dei file', - 'LBL_MOUNT': 'Monta', - 'LBL_DESCRIPTION': 'Descrizione', - 'LBL_USERNAME': 'Nome utente', - 'LBL_PASSWORD': 'Password', - 'LBL_HOST': 'Host', - 'LBL_NAMESPACE': 'Namespace', - 'LBL_SEARCH': 'Ricerca', - 'LBL_SOUNDS' : 'Suoni', - 'LBL_ICONS' : 'Icone', - 'LBL_ICON' : 'Icona', - 'LBL_BACKGROUND' : 'Sfondo', - 'LBL_DESKTOP' : 'Scrivania', - 'LBL_PANEL' : 'Panello', - 'LBL_POSITION' : 'Posizione', - 'LBL_ONTOP' : 'In primo piano', - 'LBL_ITEMS' : 'Elementi', - 'LBL_GENERAL' : 'Generale', - 'LBL_DEBUG' : 'Risoluzione errori', - 'LBL_AUTOHIDE' : 'Nascondi automaticamente', - 'LBL_OPACITY' : 'Opacità', - 'LBL_PACKAGES' : 'Pacchetti', - 'LBL_PACKAGE' : 'Pacchetto', - 'LBL_GROUPS' : 'Gruppi', - 'LBL_VERSION' : 'Versione', - 'LBL_AUTHOR' : 'Autore', - 'LBL_HIDE' : 'Nascondi', - 'LBL_BACK': 'Indietro', - 'LBL_UNINSTALL': 'Disinstalla', - 'LBL_REGENERATE': 'Rigenera', - 'LBL_WINDOWMANAGER': 'Gestore Finestre Desktop', - 'LBL_HOTKEY': 'Tasto rapido', - 'LBL_HOTKEYS': 'Tasti rapidi', - 'LBL_MOUNTS': 'Monta', - 'LBL_ID': 'ID', - 'LBL_APPLICATION': 'Applicazione', - 'LBL_SCOPE': 'Scope', - 'LBL_REPOSITORY': 'Repository', - 'LBL_PERSONAL': 'Personale', - 'LBL_SYSTEM': 'Sistema', - 'LBL_STARTING': 'Avvio', - 'LBL_STORE': 'Store', - 'LBL_LOCALE': 'Lingue', - 'LBL_INPUT': 'Input', - 'LBL_MISC': 'Vari', - 'LBL_OTHER': 'Altro', - 'LBL_USERS': 'Utenti', - 'LBL_FONTS': 'Fonts', - 'LBL_OPEN_LOCATION': 'Apri percorso', - 'LBL_HOME': 'Cartella Home', - 'LBL_WIDGET': 'Widget', - 'LBL_WIDGETS': 'Widgets', - 'LBL_LOCK': 'Bloccare', - 'LBL_UNLOCK': 'Sbloccare' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Errore durante l\'apertura del file', + 'ERR_WM_NOT_RUNNING' : 'Windows manager non in esecuzione', + 'ERR_FILE_OPEN_FMT' : 'Il file \'**{0}**\' non può essere aperto', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Nessuna applicazione che supporta il tipo di file \'{0}\' è stata trovata', + 'ERR_APP_LAUNCH_FAILED' : 'Avvio Applicazione fallito', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Si è verificato un errore durante l\'avvio di : {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Applicazione \'{0}\' construct failed: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Applicazione \'{0}\', init() fallito: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Applicazione resources missing for \'{0}\' or it failed to load!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Applicazione \'{0}\' preloading failed: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'L\' Applicazione \'{0}\' è già stata lanciata, ed è permessa una sola istanza!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Avvio di \'{0}\' fallito. Manifesto dell\'applicazione non trovato', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Avvio di \'{0}\' fallito. il tuo browser non supporta: {1}', + + 'ERR_NO_WM_RUNNING' : 'Nessun window manager in esecuzione', + 'ERR_CORE_INIT_FAILED' : 'Inizializzazione OS.js fallita', + 'ERR_CORE_INIT_FAILED_DESC' : 'Si è verificato un errore nella Inizializzazione di OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Impossibile avviare OS.js: Nessun window manager settato!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Impossibile avviare OS.js: Fallito avvio del window manager: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Impossibile avviare OS.js: Precaricamento risorse fallito...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Error Report', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Si è verificato un errore inaspettato, forse un bug.', + + 'ERR_APP_API_ERROR' : 'Application API error', + 'ERR_APP_API_ERROR_DESC_FMT' : 'L\'Applicazione {0} ha fallito nell\'eseguire l\'operazine \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Argomento mancante: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Errore sconosciuto', + + 'ERR_OPERATION_TIMEOUT' : 'Operation Timeout', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Operation Timeout ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' prevede \'{1}\' di tipo \'{2}\', \'{3}\' ricevuto', + 'ERR_INVALID_LOCATION' : 'Percorso non valido', + + 'ERR_OPEN_LOCATION' : 'Fallito aprire percorso', + 'ERR_OPEN_LOCATION_FMT' : 'Fallito aprire il percorso: {0}', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Hai già dato un nome alla finestra \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimizza', + 'WINDOW_MAXIMIZE' : 'Massimizza', + 'WINDOW_RESTORE' : 'Ripristina', + 'WINDOW_CLOSE' : 'Chiudi', + 'WINDOW_ONTOP_ON' : 'Primopiano (Abilita)', + 'WINDOW_ONTOP_OFF': 'Primopiano (Disabilita)', + + // Handler + 'TITLE_SIGN_OUT' : 'Disconnetti', + 'TITLE_SIGNED_IN_AS_FMT' : 'Connesso come: {0}', + 'ERR_LOGIN_FMT' : 'Errore di accesso: {0}', + 'ERR_LOGIN_INVALID' : 'Accesso non corretto', + + // SESSION + 'ERR_NO_SESSION': 'Nessuna sessione create dal server. Vuoi riprovare l\'autenticazione?', + 'MSG_SESSION_WARNING' : 'Sei sicuro di voler chiudere OS.js? Ogni settaggio ed ogni dato non salvato andrà perduto!', + + // Service + 'BUGREPORT_MSG' : 'Per piacere, fai un report se pensi che questo sia un bug. \nIncludi una breve descrizione di come l\'errore si è verificato, se possibile come replicarlo.', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Connesso al servizio esterno: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Errore Fatale!', + 'ERR_UTILS_XHR_FMT' : 'Errore AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Disconetti (Esci)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Disconnessione utente \'{0}\'.\nVuoi salvare la sessinoe corrente?', + + 'DIALOG_CLOSE' : 'Chiudi', + 'DIALOG_CANCEL': 'Cancella', + 'DIALOG_APPLY' : 'Applica', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Attenzione!', + + 'DIALOG_COLOR_TITLE' : 'Scegli colori', + 'DIALOG_COLOR_R' : 'Rosso: {0}', + 'DIALOG_COLOR_G' : 'Verde: {0}', + 'DIALOG_COLOR_B' : 'Blue: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Conferma scelta', + + 'DIALOG_ERROR_MESSAGE' : 'Messaggio', + 'DIALOG_ERROR_SUMMARY' : 'Sommario', + 'DIALOG_ERROR_TRACE' : 'Stack dell\'errore', + 'DIALOG_ERROR_BUGREPORT' : 'Segnala Bug', + + 'DIALOG_FILE_SAVE' : 'Salva', + 'DIALOG_FILE_OPEN' : 'Open', + 'DIALOG_FILE_MKDIR' : 'Nuova Cartella', + 'DIALOG_FILE_MKDIR_MSG' : 'Crea una nuova cartella in **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Sei sicuro di voler sovrascrivere il file \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Mostra tipo', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Visualizzazione a lista', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Visualizzazione ad albero', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Visualizzazione ad icone', + 'DIALOG_FILE_ERROR' : 'FileDialog Errore', + 'DIALOG_FILE_ERROR_SCANDIR': 'Indicizzazione della cartella \'{0}\' fallito, perchè si è verificato un errore!', + 'DIALOG_FILE_ERROR_FIND': 'Ricerca cartella \'{0}\' fallita perchè si è verificato un errore!', + 'DIALOG_FILE_MISSING_FILENAME' : 'Devi selezionare un file o fornire un nuovo nome!', + 'DIALOG_FILE_MISSING_SELECTION': 'Devi selezionare un file!', + + 'DIALOG_FILEINFO_TITLE' : 'Informazioni file', + 'DIALOG_FILEINFO_LOADING' : 'Caricamento informazioni file: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Errore FileInformationDialog', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Recupero informazioni fallito **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Recupero infomazioni file fallito: {0}', + + 'DIALOG_INPUT_TITLE' : 'Richiesta di inserimento', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Operazione file in corso', + 'DIALOG_FILEPROGRESS_LOADING' : 'Caricamento...', + + 'DIALOG_UPLOAD_TITLE' : 'Caricamento', + 'DIALOG_UPLOAD_DESC' : 'Carimento del filo a **{0}**.
Dimensione massima: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Caricamento \'{0}\' ({1} {2}) a {3}', + 'DIALOG_UPLOAD_MSG' : 'Caricamento file...', + 'DIALOG_UPLOAD_FAILED' : 'Caricamento fallito', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Il caricamentoè fallito', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Ragione sconociuta...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancellato dall\'utente...', + 'DIALOG_UPLOAD_TOO_BIG': 'Dimensione file troppo grande', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Dimensione del file troppo grande, in eccesso {0}', + + 'DIALOG_FONT_TITLE' : 'Scelta Font', + + 'DIALOG_APPCHOOSER_TITLE' : 'Scegli Applicazione', + 'DIALOG_APPCHOOSER_MSG' : 'Scegli un applicazione da aprire', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Devi selezionare un applicazione', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usa l\'applicazione predefinita per {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'Modulo GoogleAPI non configurato o disabilitato', + 'GAPI_SIGN_OUT' : 'Disconnettiti da Google API Services', + 'GAPI_REVOKE' : 'Revoca i permessi e disconnetti', + 'GAPI_AUTH_FAILURE' : 'L\'Autenticazione alla Google API fallito o non avvenuto', + 'GAPI_AUTH_FAILURE_FMT' : 'Autenticazione fallita: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Caricamento Google API fallito', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API module non configurato o disabilitato', + 'WLAPI_SIGN_OUT' : 'Disconnetti da Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Caricamento Windows Live API fallito', + 'WLAPI_LOGIN_FAILED' : 'Connessione a Windows Live API fallita', + 'WLAPI_LOGIN_FAILED_FMT' : 'Connessione a Windows Live API fallito: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returned {0} status', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Impossibile creare IndexedDB senza un nome database', + 'IDB_NO_SUCH_ITEM' : 'Nessun elemento', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Errore fatale', + 'ERR_VFS_UNAVAILABLE' : 'No disponibile', + 'ERR_VFS_FILE_ARGS' : 'Il file richiede almeno un argumento', + 'ERR_VFS_NUM_ARGS' : 'Non abbastanza argomenti', + 'ERR_VFS_EXPECT_FILE' : 'File-object previsto', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Sorgente file-object prevista', + 'ERR_VFS_EXPECT_DST_FILE' : 'Destinazion file-object prevista', + 'ERR_VFS_FILE_EXISTS' : 'Destinazione già esistente', + 'ERR_VFS_TARGET_NOT_EXISTS': 'La destinazione non esiste', + 'ERR_VFS_TRANSFER_FMT' : 'Un errore si è verificato durante il trasferimento tra le memorie: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Impossibile caricare un file senza una destinazione', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Impossibile caricare senza definire un file', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Carimento file fallito: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Caricamento file cancellato', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Impossibile scaricare una destinazione senza una destinazione', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Si è verificato un errore durante il download: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'La risposta era vuota', + + 'ERR_VFSMODULE_INVALID' : 'Modulo VFS Invalido', + 'ERR_VFSMODULE_INVALID_FMT' : 'Modulo VFS Invalido: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Metodo VFS Invalido', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Metodo VFS Invalido: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Modulo VFS tipo non valido', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Modulo VFS tipo non valido: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Modulo VFS configurazione non valida', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Modulo VFS configurazione non valida: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Modulo VFS già montato', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Modulo VFS \'{0}\' già montato', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'Modulo VFS non montato', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Modulo VFS \'{0}\' non montato', + 'ERR_VFSMODULE_EXCEPTION' : 'Modulo VFS Eccezione', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Modulo VFS Eccezione: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Nessun modulo VFS associato con {0}. Desinazione o formato sbagliato?', + 'ERR_VFSMODULE_READONLY' : 'Questo modulo VFS è di sola lettura', + 'ERR_VFSMODULE_READONLY_FMT' : 'Questo modulo VFS è di sola lettura: {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Download file', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Errore XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'ID cartella root non trovato', + 'ERR_VFSMODULE_NOSUCH' : 'Il file non esiste', + 'ERR_VFSMODULE_PARENT' : 'Nessun parente', + 'ERR_VFSMODULE_PARENT_FMT' : 'Cartella parente non trovata: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Scansione cartella fallito', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Scansione cartella fallito: {0}', + 'ERR_VFSMODULE_READ' : 'Lettura file fallito', + 'ERR_VFSMODULE_READ_FMT' : 'Lettura file fallito: {0}', + 'ERR_VFSMODULE_WRITE' : 'Scrittura file fallita', + 'ERR_VFSMODULE_WRITE_FMT' : 'Scrittura file fallita: {0}', + 'ERR_VFSMODULE_COPY' : 'Copiatura fallita', + 'ERR_VFSMODULE_COPY_FMT' : 'Copiatura fallita: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Unlink file fallito', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Unlink file fallito: {0}', + 'ERR_VFSMODULE_MOVE' : 'Spostamento file fallito', + 'ERR_VFSMODULE_MOVE_FMT' : 'Spostamento file fallito: {0}', + 'ERR_VFSMODULE_EXIST' : 'Verifica esistenza file fallita', + 'ERR_VFSMODULE_EXIST_FMT' : 'Verifica esistenza file fallita: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Recupero informazioni file fallito', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Recupero informazioni file fallito: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Creazione cartella fallito', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Creazione cartella fallito: {0}', + 'ERR_VFSMODULE_MKFILE' : 'Creazione file fallita', + 'ERR_VFSMODULE_MKFILE_FMT' : 'Creazione file fallita: {0}', + 'ERR_VFSMODULE_URL' : 'Recupero URL file fallito', + 'ERR_VFSMODULE_URL_FMT' : 'Recupero URL file fallito: {0}', + 'ERR_VFSMODULE_TRASH' : 'Spostamento file nel cestino fallito', + 'ERR_VFSMODULE_TRASH_FMT' : 'Spostamento file nel cestino fallito: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Spostamento del file fuori dal cestino fallito', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Spostamento del file fuori dal cestino fallito: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Svuotamento cestino fallito', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Svuotamento cestino fallito: {0}', + 'ERR_VFSMODULE_FIND' : 'Ricerca fallita', + 'ERR_VFSMODULE_FIND_FMT' : 'Ricerca fallita: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'Allocamento spazio libero fallito', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'Allocamento spazio libero fallito: {0}', + 'ERR_VFSMODULE_EXISTS' : 'Verifica esistenza fallito', + 'ERR_VFSMODULE_EXISTS_FMT' : 'Verifica esistenza fallito: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Sei connesso a Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Disconnetti Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Risoluzione percorso fallita: elemento non trovato', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'Caricamento zip.js fallito', + 'ZIP_VENDOR_FAIL' : 'Libreria zip.js non trovata. L\'hai caricata correttamente?', + 'ZIP_NO_RESOURCE' : 'Nessuna risorsa zip fornita', + 'ZIP_NO_PATH' : 'Nessun percorso fornito', + + // + // SearchEngine + // + 'SEARCH_LOADING': 'Ricerca in corso...', + 'SEARCH_NO_RESULTS': 'Nessun risultato trovato', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Percorso installazione pacchetto gia esistente. Impossibile continuare!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Impossibile aprire il file', + 'ERR_FILE_APP_OPEN_FMT' : 'Impossibile aprire il file {0} perchè il mime {1} non è supportato', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Impossibile aprire il file {0}: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Impossibile salvare il file {0}: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Application Error', + 'ERR_GENERIC_APP_ACTION_FMT': 'Esecuzione azione fallito \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Errore sconosciuto', + 'ERR_GENERIC_APP_REQUEST' : 'Si è verificato un errore durante la risoluzione della richiesta', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Errore fatale: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Scarta cambiamenti?', + 'MSG_FILE_CHANGED' : 'Il file è stato cambiato. Ricaricarlo?', + 'MSG_APPLICATION_WARNING' : 'Avviso applicazione', + 'MSG_MIME_OVERRIDE' : 'tipo del file "{0}" non supportato, si userà "{1}" al suo posto.', + + // + // General + // + + 'LBL_UNKNOWN' : 'Sconosciuto', + 'LBL_APPEARANCE' : 'Aspetto', + 'LBL_USER' : 'Utente', + 'LBL_NAME' : 'Nome', + 'LBL_APPLY' : 'Applica', + 'LBL_FILENAME' : 'Nome file', + 'LBL_PATH' : 'Percorso', + 'LBL_SIZE' : 'Dimensione', + 'LBL_TYPE' : 'Tipo', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Caricamento', + 'LBL_SETTINGS' : 'Settaggi', + 'LBL_ADD_FILE' : 'Aggiungi file', + 'LBL_COMMENT' : 'Commenta', + 'LBL_ACCOUNT' : 'Account', + 'LBL_CONNECT' : 'Connetti', + 'LBL_ONLINE' : 'Online', + 'LBL_OFFLINE' : 'Offline', + 'LBL_AWAY' : 'Non presente', + 'LBL_BUSY' : 'Occupato', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Aiuto', + 'LBL_ABOUT' : 'Riguardo a', + 'LBL_PANELS' : 'Pannelli', + 'LBL_LOCALES' : 'Localizzazioni', + 'LBL_THEME' : 'Tema', + 'LBL_COLOR' : 'Colore', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Terminal (kill)', + 'LBL_ALIVE' : 'Mantieni (Alive)', + 'LBL_INDEX' : 'Indice', + 'LBL_ADD' : 'Aggiungi', + 'LBL_FONT' : 'Font', + 'LBL_YES' : 'Si', + 'LBL_NO' : 'No', + 'LBL_CANCEL' : 'Cancella', + 'LBL_TOP' : 'Sopra', + 'LBL_LEFT' : 'Sinistra', + 'LBL_RIGHT' : 'Destra', + 'LBL_BOTTOM' : 'Sotto', + 'LBL_CENTER' : 'Centro', + 'LBL_FILE' : 'File', + 'LBL_NEW' : 'Nuovo', + 'LBL_OPEN' : 'Apri', + 'LBL_SAVE' : 'Salva', + 'LBL_SAVEAS' : 'Salva come...', + 'LBL_CLOSE' : 'Chiudi', + 'LBL_MKDIR' : 'Crea cartella', + 'LBL_UPLOAD' : 'Carica', + 'LBL_VIEW' : 'Visualizza', + 'LBL_EDIT' : 'Modifica', + 'LBL_RENAME' : 'Rinomina', + 'LBL_DELETE' : 'Cancella', + 'LBL_OPENWITH' : 'Apri con...', + 'LBL_ICONVIEW' : 'Visualizzazione ad Icone', + 'LBL_TREEVIEW' : 'Visualizzazione ad Albero', + 'LBL_LISTVIEW' : 'Visualizzazione ad Lista', + 'LBL_REFRESH' : 'Aggiorna', + 'LBL_VIEWTYPE' : 'Visualizza tipo', + 'LBL_BOLD' : 'Grassetto', + 'LBL_ITALIC' : 'Corsivo', + 'LBL_UNDERLINE' : 'Sottolineato', + 'LBL_REGULAR' : 'Regolare', + 'LBL_STRIKE' : 'Strike', + 'LBL_INDENT' : 'Indenta', + 'LBL_OUTDENT' : 'Unindenta', + 'LBL_UNDO' : 'Torna indietro', + 'LBL_REDO' : 'Vai avanti', + 'LBL_CUT' : 'Taglia', + 'LBL_UNLINK' : 'Rimuovi link', + 'LBL_COPY' : 'Copia', + 'LBL_PASTE' : 'Incolla', + 'LBL_INSERT' : 'Inserisci', + 'LBL_IMAGE' : 'Immaggine', + 'LBL_LINK' : 'Link', + 'LBL_DISCONNECT' : 'Disconnetti', + 'LBL_APPLICATIONS' : 'Applicazioni', + 'LBL_ADD_FOLDER' : 'Aggiungi cartella', + 'LBL_INFORMATION' : 'Informazione', + 'LBL_TEXT_COLOR' : 'Colore testo', + 'LBL_BACK_COLOR' : 'Colore in secondo piano', + 'LBL_RESET_DEFAULT' : 'Resetta ai valori predefiniti', + 'LBL_DOWNLOAD_COMP' : 'Scarica sul computer', + 'LBL_ORDERED_LIST' : 'Lista ordinata', + 'LBL_BACKGROUND_IMAGE' : 'Immagine di sfondo', + 'LBL_BACKGROUND_COLOR' : 'Colore di sfondo', + 'LBL_UNORDERED_LIST' : 'Lista non ordinata', + 'LBL_STATUS' : 'Stato', + 'LBL_READONLY' : 'Di sola lettura', + 'LBL_CREATED' : 'Creato', + 'LBL_MODIFIED' : 'Modificato', + 'LBL_SHOW_COLUMNS' : 'Mostra colonne', + 'LBL_MOVE' : 'Muovi', + 'LBL_OPTIONS' : 'Opzioni', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Cartella', + 'LBL_CREATE' : 'Crea', + 'LBL_BUGREPORT' : 'Segnalazione bug', + 'LBL_INSTALL' : 'Installa', + 'LBL_UPDATE' : 'Aggiorna', + 'LBL_REMOVE' : 'Rimuovi', + 'LBL_SHOW_SIDEBAR' : 'Mostra barra laterale', + 'LBL_SHOW_NAVIGATION' : 'Mostra navigazione', + 'LBL_SHOW_HIDDENFILES' : 'Mostra file nascosti', + 'LBL_SHOW_FILEEXTENSIONS' : 'Mostra le estenzioni dei file', + 'LBL_MOUNT': 'Monta', + 'LBL_DESCRIPTION': 'Descrizione', + 'LBL_USERNAME': 'Nome utente', + 'LBL_PASSWORD': 'Password', + 'LBL_HOST': 'Host', + 'LBL_NAMESPACE': 'Namespace', + 'LBL_SEARCH': 'Ricerca', + 'LBL_SOUNDS' : 'Suoni', + 'LBL_ICONS' : 'Icone', + 'LBL_ICON' : 'Icona', + 'LBL_BACKGROUND' : 'Sfondo', + 'LBL_DESKTOP' : 'Scrivania', + 'LBL_PANEL' : 'Panello', + 'LBL_POSITION' : 'Posizione', + 'LBL_ONTOP' : 'In primo piano', + 'LBL_ITEMS' : 'Elementi', + 'LBL_GENERAL' : 'Generale', + 'LBL_DEBUG' : 'Risoluzione errori', + 'LBL_AUTOHIDE' : 'Nascondi automaticamente', + 'LBL_OPACITY' : 'Opacità', + 'LBL_PACKAGES' : 'Pacchetti', + 'LBL_PACKAGE' : 'Pacchetto', + 'LBL_GROUPS' : 'Gruppi', + 'LBL_VERSION' : 'Versione', + 'LBL_AUTHOR' : 'Autore', + 'LBL_HIDE' : 'Nascondi', + 'LBL_BACK': 'Indietro', + 'LBL_UNINSTALL': 'Disinstalla', + 'LBL_REGENERATE': 'Rigenera', + 'LBL_WINDOWMANAGER': 'Gestore Finestre Desktop', + 'LBL_HOTKEY': 'Tasto rapido', + 'LBL_HOTKEYS': 'Tasti rapidi', + 'LBL_MOUNTS': 'Monta', + 'LBL_ID': 'ID', + 'LBL_APPLICATION': 'Applicazione', + 'LBL_SCOPE': 'Scope', + 'LBL_REPOSITORY': 'Repository', + 'LBL_PERSONAL': 'Personale', + 'LBL_SYSTEM': 'Sistema', + 'LBL_STARTING': 'Avvio', + 'LBL_STORE': 'Store', + 'LBL_LOCALE': 'Lingue', + 'LBL_INPUT': 'Input', + 'LBL_MISC': 'Vari', + 'LBL_OTHER': 'Altro', + 'LBL_USERS': 'Utenti', + 'LBL_FONTS': 'Fonts', + 'LBL_OPEN_LOCATION': 'Apri percorso', + 'LBL_HOME': 'Cartella Home', + 'LBL_WIDGET': 'Widget', + 'LBL_WIDGETS': 'Widgets', + 'LBL_LOCK': 'Bloccare', + 'LBL_UNLOCK': 'Sbloccare' +}; diff --git a/src/client/javascript/locales/ko_KR.js b/src/client/javascript/locales/ko_KR.js index b7bd214915..c4119ed14e 100644 --- a/src/client/javascript/locales/ko_KR.js +++ b/src/client/javascript/locales/ko_KR.js @@ -27,410 +27,407 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.ko_KR = { - // - // CORE - // - - 'ERR_FILE_OPEN' : '파일을 열 수 없습니다', - 'ERR_WM_NOT_RUNNING' : '윈도우 관리자가 실행 중이지 않습니다', - 'ERR_FILE_OPEN_FMT' : '\'**{0}**\' 파일을 실행할 수 없습니다', - 'ERR_APP_MIME_NOT_FOUND_FMT': '\'{0}\' 파일을 실행할 수 있는 응용 프로그램을 찾을 수 없습니다', - 'ERR_APP_LAUNCH_FAILED' : '응용 프로그램을 실행할 수 없습니다', - 'ERR_APP_LAUNCH_FAILED_FMT' : '{0}을(를) 실행할 수 없습니다', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : '응용 프로그램 \'{0}\'을 준비할 수 없습니다: {1}', - 'ERR_APP_INIT_FAILED_FMT' : '응용 프로그램 \'{0}\'을 초기화할 수 없습니다: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : '응용 프로그램 \'{0}\' 리소스를 찾을 수 없거나 로드할 수 없습니다!', - 'ERR_APP_PRELOAD_FAILED_FMT' : '응용 프로그램 \'{0}\'을 준비할 수 없습니다: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '\'{0}\'은(는) 이미 실행중이며 하나의 인스턴스만 허용됩니다!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '\'{0}\'을(를) 실행할 수 없습니다. 응용 프로그램 manifest 데이터를 찾을 수 없습니다!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '\'{0}\'을(를) 실행할 수 없습니다. 사용중인 웹브라우저가 다음 기능을 지원하지 않습니다: {1}', - - 'ERR_NO_WM_RUNNING' : '윈도우 관리자가 실행 중이지 않습니다', - 'ERR_CORE_INIT_FAILED' : 'OS.js를 초기화할 수 없습니다', - 'ERR_CORE_INIT_FAILED_DESC' : 'OS.js를 초기화하던 중 오류가 발생했습니다', - 'ERR_CORE_INIT_NO_WM' : 'OS.js를 실행할 수 없습니다: 윈도우 관리자가 정의되지 않았습니다!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js를 실행할 수 없습니다: 윈도우 관리자를 실행할 수 없습니다: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'OS.js를 실행할 수 없습니다: 리소스를 준비할 수 없습니다...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript 오류 보고서', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : '오류가 발생했습니다. 버그일 수 있습니다', - - 'ERR_APP_API_ERROR' : '응용 프로그램 API 오류', - 'ERR_APP_API_ERROR_DESC_FMT' : '응용 프로그램 {0}이 명령을 실행할 수 없습니다\'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': '누락된 매개변수: {0}', - 'ERR_APP_UNKNOWN_ERROR' : '알 수 없는 오류입니다', - - 'ERR_OPERATION_TIMEOUT' : '시간초과', - 'ERR_OPERATION_TIMEOUT_FMT' : '시간초과 ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\'에서 \'{1}\'는 \'{2}\'이 되어야 하나 \'{3}\'가 주어졌습니다', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : '이미 \'{0}\' 창이 있습니다', - 'WINDOW_MINIMIZE' : '최소화', - 'WINDOW_MAXIMIZE' : '최대화', - 'WINDOW_RESTORE' : '이전 크기로', - 'WINDOW_CLOSE' : '닫기', - 'WINDOW_ONTOP_ON' : '위로 (활성화)', - 'WINDOW_ONTOP_OFF': '위로 (비활성화)', - - // Handler - 'TITLE_SIGN_OUT' : '로그아웃', - 'TITLE_SIGNED_IN_AS_FMT' : '{0}(으)로 로그인', - 'ERR_LOGIN_FMT' : '로그인 오류: {0}', - 'ERR_LOGIN_INVALID' : '비정상 로그인', - - // SESSION - 'MSG_SESSION_WARNING' : 'OS.js를 정말 종료하시겠습니까? 저장하지 않은 설정과 응용 프로그램 데이터가 손실될 수 있습니다!', - - // Service - 'BUGREPORT_MSG' : '버그라고 생각되면 보고해주십시요.\n오류가 어떻게 발생했는지 간단한 설명을 해주십시요. 가능하다면 재현 상황을 설명해주십시요', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : '{0}(으)로 외부 서비스 로그인', - - // Utils - 'ERR_UTILS_XHR_FATAL' : '심각한 오류', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR 오류: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : '로그아웃 (종료)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : '\'{0}\' 사용자 로그아웃.\n현재 세션을 저장하시겠습니까?', - - 'DIALOG_CLOSE' : '닫기', - 'DIALOG_CANCEL': '취소', - 'DIALOG_APPLY' : '적용', - 'DIALOG_OK' : '확인', - - 'DIALOG_ALERT_TITLE' : '알림 다이얼로그', - - 'DIALOG_COLOR_TITLE' : '색상 다이얼로그', - 'DIALOG_COLOR_R' : '빨강: {0}', - 'DIALOG_COLOR_G' : '초록: {0}', - 'DIALOG_COLOR_B' : '파랑: {0}', - 'DIALOG_COLOR_A' : '투명: {0}', - - 'DIALOG_CONFIRM_TITLE' : '확인 다이얼로그', - - 'DIALOG_ERROR_MESSAGE' : '메시지', - 'DIALOG_ERROR_SUMMARY' : '요약', - 'DIALOG_ERROR_TRACE' : '추적', - 'DIALOG_ERROR_BUGREPORT' : '오류 보고', - - 'DIALOG_FILE_SAVE' : '저장', - 'DIALOG_FILE_OPEN' : '열기', - 'DIALOG_FILE_MKDIR' : '디렉토리 생성', - 'DIALOG_FILE_MKDIR_MSG' : '**{0}**에 디렉토리 생성', - 'DIALOG_FILE_OVERWRITE' : '정말 \'{0}\'을 덮어쓰시겠습니까?', - 'DIALOG_FILE_MNU_VIEWTYPE' : '보기 타입', - 'DIALOG_FILE_MNU_LISTVIEW' : '자세히 보기', - 'DIALOG_FILE_MNU_TREEVIEW' : '간단히 보기', - 'DIALOG_FILE_MNU_ICONVIEW' : '아이콘으로 보기', - 'DIALOG_FILE_ERROR' : '파일 다이얼로그 오류', - 'DIALOG_FILE_ERROR_SCANDIR': '오류가 발생했습니다. \'{0}\' 폴더를 불러올 수 없습니다', - 'DIALOG_FILE_MISSING_FILENAME' : '파일을 선택하거나 새로운 파일 이름을 입력해주십시요!', - 'DIALOG_FILE_MISSING_SELECTION': '파일을 선택해야 합니다!', - - 'DIALOG_FILEINFO_TITLE' : '파일 정보', - 'DIALOG_FILEINFO_LOADING' : '파일 정보를 불러오는 중: {0}', - 'DIALOG_FILEINFO_ERROR' : '파일 정보 다이얼로그 오류', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : '파일 정보를 가져올 수 없습니다 **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '파일 정보를 가져올 수 없습니다: {0}', - - 'DIALOG_INPUT_TITLE' : '입력 다이얼로그', - - 'DIALOG_FILEPROGRESS_TITLE' : '파일 명령 처리', - 'DIALOG_FILEPROGRESS_LOADING' : '처리 중...', - - 'DIALOG_UPLOAD_TITLE' : '업로드 다이얼로그', - 'DIALOG_UPLOAD_DESC' : '**{0}**에 파일 업로드.
최대 용량: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : '\'{0}\' ({1} {2})을(를) {3}에 업로드 중', - 'DIALOG_UPLOAD_MSG' : '파일을 업로드 중...', - 'DIALOG_UPLOAD_FAILED' : '업로드 실패', - 'DIALOG_UPLOAD_FAILED_MSG' : '업로드에 실패했습니다', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : '알 수 없는 오류...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': '사용자에 의해 취소...', - 'DIALOG_UPLOAD_TOO_BIG': '파일이 너무 큽니다', - 'DIALOG_UPLOAD_TOO_BIG_FMT': '파일이 너무 큽니다, {0} 초과', - - 'DIALOG_FONT_TITLE' : '글꼴 다이얼로그', - - 'DIALOG_APPCHOOSER_TITLE' : '응용 프로그램 선택', - 'DIALOG_APPCHOOSER_MSG' : '열려는 응용 프로그램을 선택해주십시요', - 'DIALOG_APPCHOOSER_NO_SELECTION' : '응용 프로그램을 선택해야 합니다', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : '{0}을(를) 기본 응용 프로그램으로 설정', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI 모듈이 설정되지 않았거나 사용할 수 없습니다', - 'GAPI_SIGN_OUT' : 'Google API 서비스에서 로그아웃', - 'GAPI_REVOKE' : '권한을 해제하고 로그아웃', - 'GAPI_AUTH_FAILURE' : 'Google API 인증에 실패했습니다', - 'GAPI_AUTH_FAILURE_FMT' : '인증에 실패: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Google API 로드 실패', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API 모듈이 설정되지 않았거나 사용할 수 없습니다', - 'WLAPI_SIGN_OUT' : 'Window Live API 서비스에서 로그아웃', - 'WLAPI_LOAD_FAILURE' : 'Windows Live API 로드 실패', - 'WLAPI_LOGIN_FAILED' : 'Windows Live API에 로그인 실패', - 'WLAPI_LOGIN_FAILED_FMT' : 'Windows Live API에 로그인 실패: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API가 {0} 상태를 반환했습니다', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Database의 이름 없이는 IndexedDB를 생성할 수 없습니다', - 'IDB_NO_SUCH_ITEM' : '찾을 수 없습니다', - - // - // VFS - // - 'ERR_VFS_FATAL' : '심각한 오류', - 'ERR_VFS_UNAVAILABLE' : '사용할 수 없음', - 'ERR_VFS_FILE_ARGS' : '적어도 하나의 매개변수가 필요합니다', - 'ERR_VFS_NUM_ARGS' : '매개변수가 충분하지 않습니다', - 'ERR_VFS_EXPECT_FILE' : '파일 객체가 필요합니다', - 'ERR_VFS_EXPECT_SRC_FILE' : '원본 파일 객체가 필요합니다', - 'ERR_VFS_EXPECT_DST_FILE' : '대상 파일 객체가 필요합니다', - 'ERR_VFS_FILE_EXISTS' : '대상 파일이 이미 존재합니다', - 'ERR_VFS_TRANSFER_FMT' : '저장소 간 파일을 이동하는 중 오류가 발생했습니다: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : '파일을 업로드하려면 대상을 선택해주십시요', - 'ERR_VFS_UPLOAD_NO_FILES' : '업로드하려는 파일을 선택해주십시요', - 'ERR_VFS_UPLOAD_FAIL_FMT' : '파일을 업로드하는데 실패했습니다: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': '파일 업로드가 취소되었습니다', - 'ERR_VFS_DOWNLOAD_NO_FILE': '경로 없이 경로를 다운로드할 수 없습니다', - 'ERR_VFS_DOWNLOAD_FAILED' : '다운로드 중 오류가 발생하였습니다: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': '응답이 비어있습니다', - - 'ERR_VFSMODULE_INVALID' : '유효하지 않은 VFS 모듈', - 'ERR_VFSMODULE_INVALID_FMT' : '유효하지 않은 VFS 모듈: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : '유효하지 않은 VFS 메소드', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : '유효하지 않은 VFS 메소드: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : '유효하지 않은 VFS 모듈 타입', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : '유효하지 않은 VFS 모듈 타입: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : '유효하지 않은 VFS 모듈 설정', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : '유효하지 않은 VFS 모듈 설정: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS 모듈이 이미 마운트 되었습니다', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS 모듈 \'{0}\' 이(가) 이미 마운트 되었습니다', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS 모듈이 마운트 되지 않았습니다', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS 모듈 \'{0}\' 이(가) 마운트 되지 않았습니다', - 'ERR_VFSMODULE_EXCEPTION' : 'VFS 모듈 예외 발생', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS 모듈 예외 발생: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : '{0}와 같은 VFS 모듈이 존재하지 않습니다. 잘못된 경로나 형식일 수 있습니다', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': '파일 다운로드', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR 오류', - 'ERR_VFSMODULE_ROOT_ID' : '최상위 디렉토리 id를 찾을 수 없습니다', - 'ERR_VFSMODULE_NOSUCH' : '파일이 존재하지 않습니다', - 'ERR_VFSMODULE_PARENT' : '부모를 찾을 수 없습니다', - 'ERR_VFSMODULE_PARENT_FMT' : '부모를 찾을 수 없습니다: {0}', - 'ERR_VFSMODULE_SCANDIR' : '디렉토리 불러오기 실패', - 'ERR_VFSMODULE_SCANDIR_FMT' : '디렉토리를 불러올 수 없습니다: {0}', - 'ERR_VFSMODULE_READ' : '파일 읽기 실패', - 'ERR_VFSMODULE_READ_FMT' : '파일을 읽을 수 없습니다: {0}', - 'ERR_VFSMODULE_WRITE' : '파일 생성 실패', - 'ERR_VFSMODULE_WRITE_FMT' : '파일을 생성할 수 없습니다: {0}', - 'ERR_VFSMODULE_COPY' : '복사 실패', - 'ERR_VFSMODULE_COPY_FMT' : '복사할 수 없습니다: {0}', - 'ERR_VFSMODULE_UNLINK' : '바로가기 해제', - 'ERR_VFSMODULE_UNLINK_FMT' : '바로가기를 해제할 수 없습니다: {0}', - 'ERR_VFSMODULE_MOVE' : '파일 이동 실패', - 'ERR_VFSMODULE_MOVE_FMT' : '파일을 이동할 수 없습니다: {0}', - 'ERR_VFSMODULE_EXIST' : '파일 존재 여부 확인', - 'ERR_VFSMODULE_EXIST_FMT' : '파일이 존재하는지 확인할 수 없습니다: {0}', - 'ERR_VFSMODULE_FILEINFO' : '파일 정보 조회 실패', - 'ERR_VFSMODULE_FILEINFO_FMT' : '파일 정보를 읽을 수 없습니다: {0}', - 'ERR_VFSMODULE_MKDIR' : '디렉토리 생성 실패', - 'ERR_VFSMODULE_MKDIR_FMT' : '디렉토리를 생성할 수 없습니다: {0}', - 'ERR_VFSMODULE_URL' : '파일 경로 찾기 실패', - 'ERR_VFSMODULE_URL_FMT' : '파일의 경로를 찾을 수 없습니다: {0}', - 'ERR_VFSMODULE_TRASH' : '휴지통으로 보내기 실패', - 'ERR_VFSMODULE_TRASH_FMT' : '휴지통으로 보낼 수 없습니다: {0}', - 'ERR_VFSMODULE_UNTRASH' : '휴지통 복원 실패', - 'ERR_VFSMODULE_UNTRASH_FMT' : '휴지통에서 복원할 수 없습니다: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : '휴지통 비우기 실패', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : '휴지통을 비울 수 없습니다: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Dropbox API에 가입되어 있습니다', - 'DROPBOX_SIGN_OUT' : 'Google API Services에서 로그아웃', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : '경로 탐색 실패: 항목을 찾을 수 없습니다', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'zip.js를 불러오는 데 실패하였습니다', - 'ZIP_VENDOR_FAIL' : 'zip.js 라이브러리를 찾을 수 없습니다. 올바른 방법으로 불러왔는지 확인해주십시오', - 'ZIP_NO_RESOURCE' : 'zip 리소스가 주어지지 않았습니다', - 'ZIP_NO_PATH' : '경로가 주어지지 않았습니다', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': '패키지 설치 디렉토리가 이미 존재하여 설치를 계속 할 수 없습니다!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : '파일을 열 수 없습니다', - 'ERR_FILE_APP_OPEN_FMT' : '마임(MIME) {1} 이(가) 지원되지 않아 파일 {0} 을(를) 열지 못했습니다', - 'ERR_FILE_APP_OPEN_ALT_FMT' : '파일 {0} 을(를) 열지 못했습니다: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : '파일 {0} 을(를) 저장하지 못했습니다: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} 응용 프로그램 오류', - 'ERR_GENERIC_APP_ACTION_FMT': '\'{0}\' 수행에 실패하였습니다', - 'ERR_GENERIC_APP_UNKNOWN' : '알 수 없는 오류', - 'ERR_GENERIC_APP_REQUEST' : '명령을 처리하는 도중 오류가 발생하였습니다', - 'ERR_GENERIC_APP_FATAL_FMT' : '치명적인 오류: {0}', - 'MSG_GENERIC_APP_DISCARD' : '변경사항을 저장하지 않겠습니까?', - 'MSG_FILE_CHANGED' : '파일이 변경되었습니다. 새로고침 하시겠습니까?', - 'MSG_APPLICATION_WARNING' : '응용 프로그램 경고', - 'MSG_MIME_OVERRIDE' : '파일 타입 "{0}" 은(는) 지원되지 않습니다, "{1}" (으)로 대신합니다', - - // - // General - // - - 'LBL_UNKNOWN' : '알수없음', - 'LBL_APPEARANCE' : '모양', - 'LBL_USER' : '사용자', - 'LBL_NAME' : '이름', - 'LBL_APPLY' : '적용', - 'LBL_FILENAME' : '파일명', - 'LBL_PATH' : '경로', - 'LBL_SIZE' : '크기', - 'LBL_TYPE' : '타입', - 'LBL_MIME' : '마임(MIME)', - 'LBL_LOADING' : '로딩', - 'LBL_SETTINGS' : '설정', - 'LBL_ADD_FILE' : '파일 추가', - 'LBL_COMMENT' : '댓글', - 'LBL_ACCOUNT' : '계정', - 'LBL_CONNECT' : '연결', - 'LBL_ONLINE' : '온라인', - 'LBL_OFFLINE' : '오프라인', - 'LBL_AWAY' : '부재중', - 'LBL_BUSY' : '바쁨', - 'LBL_CHAT' : '채팅', - 'LBL_HELP' : '도움말', - 'LBL_ABOUT' : '정보', - 'LBL_PANELS' : '패널', - 'LBL_LOCALES' : '지역', - 'LBL_THEME' : '테마', - 'LBL_COLOR' : '색상', - 'LBL_PID' : '프로세스 ID', - 'LBL_KILL' : '종료', - 'LBL_ALIVE' : '활성', - 'LBL_INDEX' : '인덱스', - 'LBL_ADD' : '추가', - 'LBL_FONT' : '글꼴', - 'LBL_YES' : '예', - 'LBL_NO' : '아니오', - 'LBL_CANCEL' : '취소', - 'LBL_TOP' : '위', - 'LBL_LEFT' : '왼쪽', - 'LBL_RIGHT' : '오른쪽', - 'LBL_BOTTOM' : '아래', - 'LBL_CENTER' : '가운데', - 'LBL_FILE' : '파일', - 'LBL_NEW' : '새로 만들기', - 'LBL_OPEN' : '열기', - 'LBL_SAVE' : '저장', - 'LBL_SAVEAS' : '다른 이름으로 저장', - 'LBL_CLOSE' : '닫기', - 'LBL_MKDIR' : '디렉토리 생성', - 'LBL_UPLOAD' : '업로드', - 'LBL_VIEW' : '보기', - 'LBL_EDIT' : '편집', - 'LBL_RENAME' : '이름 변경', - 'LBL_DELETE' : '삭제', - 'LBL_OPENWITH' : '다른 프로그램으로 열기', - 'LBL_ICONVIEW' : '아이콘으로 보기', - 'LBL_TREEVIEW' : '트리로 보기', - 'LBL_LISTVIEW' : '리스트로 보기', - 'LBL_REFRESH' : '새로고침', - 'LBL_VIEWTYPE' : '보기 방식', - 'LBL_BOLD' : '굵게', - 'LBL_ITALIC' : '이탤릭체', - 'LBL_UNDERLINE' : '밑줄', - 'LBL_REGULAR' : '일반', - 'LBL_STRIKE' : '취소선', - 'LBL_INDENT' : '들여쓰기', - 'LBL_OUTDENT' : '내어쓰기', - 'LBL_UNDO' : '실행 취소', - 'LBL_REDO' : '다시 실행', - 'LBL_CUT' : '잘라내기', - 'LBL_UNLINK' : '링크 해제', - 'LBL_COPY' : '복사', - 'LBL_PASTE' : '붙여넣기', - 'LBL_INSERT' : '삽입', - 'LBL_IMAGE' : '이미지', - 'LBL_LINK' : '링크', - 'LBL_DISCONNECT' : '연결 해제', - 'LBL_APPLICATIONS' : '응용 프로그램', - 'LBL_ADD_FOLDER' : '폴더 추가', - 'LBL_INFORMATION' : '정보', - 'LBL_TEXT_COLOR' : '글자색', - 'LBL_BACK_COLOR' : '배경색', - 'LBL_RESET_DEFAULT' : '기본값으로 복원', - 'LBL_DOWNLOAD_COMP' : '컴퓨터로 다운로드', - 'LBL_ORDERED_LIST' : '정렬 된 리스트', - 'LBL_BACKGROUND_IMAGE' : '배경 이미지', - 'LBL_BACKGROUND_COLOR' : '배경 색상', - 'LBL_UNORDERED_LIST' : '정렬 되지 않은 리스트', - 'LBL_STATUS' : '상태', - 'LBL_READONLY' : '읽기 전용', - 'LBL_CREATED' : '생성됨', - 'LBL_MODIFIED' : '수정됨', - 'LBL_SHOW_COLUMNS' : '열 보기', - 'LBL_MOVE' : '이동', - 'LBL_OPTIONS' : '옵션', - 'LBL_OK' : '확인', - 'LBL_DIRECTORY' : '디렉토리', - 'LBL_CREATE' : '생성', - 'LBL_BUGREPORT' : '버그 리포트', - 'LBL_INSTALL' : '설치', - 'LBL_UPDATE' : '수정', - 'LBL_REMOVE' : '제거', - 'LBL_SHOW_SIDEBAR' : '사이드바 보이기', - 'LBL_SHOW_NAVIGATION' : '네비게이션 보이기', - 'LBL_SHOW_HIDDENFILES' : '숨긴 파일 보이기', - 'LBL_SHOW_FILEEXTENSIONS' : '파일 확장자 보이기', - 'LBL_MOUNT': '마운트', - 'LBL_DESCRIPTION': '설명', - 'LBL_USERNAME': '사용자 이름', - 'LBL_PASSWORD': '비밀번호', - 'LBL_HOST': '호스트', - 'LBL_NAMESPACE': '네임스페이스', - 'LBL_BACKGROUND' : '바탕화면', - 'LBL_DESKTOP' : '데스크탑', - 'LBL_PANEL' : '패널', - 'LBL_POSITION' : '위치', - 'LBL_ONTOP' : '상단바 자리 차지', - 'LBL_ITEMS' : '항목', - 'LBL_GENERAL': '일반', - 'LBL_SOUNDS': '소리', - 'LBL_ICONS': '아이콘', - 'LBL_DEBUG' : '디버그', - 'LBL_AUTOHIDE' : '자동 숨기기', - 'LBL_OPACITY' : '투명도', - 'LBL_PACKAGES' : '패키지', - 'LBL_GROUPS' : '그룹', - 'LBL_VERSION' : '버전', - 'LBL_AUTHOR' : '작성자', - 'LBL_Hide' : '숨기기', - 'LBL_APPLICATION' : '어플리케이션', - 'LBL_SCOPE' : '범위', - 'LBL_SEARCH' : '검색' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : '파일을 열 수 없습니다', + 'ERR_WM_NOT_RUNNING' : '윈도우 관리자가 실행 중이지 않습니다', + 'ERR_FILE_OPEN_FMT' : '\'**{0}**\' 파일을 실행할 수 없습니다', + 'ERR_APP_MIME_NOT_FOUND_FMT': '\'{0}\' 파일을 실행할 수 있는 응용 프로그램을 찾을 수 없습니다', + 'ERR_APP_LAUNCH_FAILED' : '응용 프로그램을 실행할 수 없습니다', + 'ERR_APP_LAUNCH_FAILED_FMT' : '{0}을(를) 실행할 수 없습니다', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : '응용 프로그램 \'{0}\'을 준비할 수 없습니다: {1}', + 'ERR_APP_INIT_FAILED_FMT' : '응용 프로그램 \'{0}\'을 초기화할 수 없습니다: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : '응용 프로그램 \'{0}\' 리소스를 찾을 수 없거나 로드할 수 없습니다!', + 'ERR_APP_PRELOAD_FAILED_FMT' : '응용 프로그램 \'{0}\'을 준비할 수 없습니다: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '\'{0}\'은(는) 이미 실행중이며 하나의 인스턴스만 허용됩니다!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '\'{0}\'을(를) 실행할 수 없습니다. 응용 프로그램 manifest 데이터를 찾을 수 없습니다!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '\'{0}\'을(를) 실행할 수 없습니다. 사용중인 웹브라우저가 다음 기능을 지원하지 않습니다: {1}', + + 'ERR_NO_WM_RUNNING' : '윈도우 관리자가 실행 중이지 않습니다', + 'ERR_CORE_INIT_FAILED' : 'OS.js를 초기화할 수 없습니다', + 'ERR_CORE_INIT_FAILED_DESC' : 'OS.js를 초기화하던 중 오류가 발생했습니다', + 'ERR_CORE_INIT_NO_WM' : 'OS.js를 실행할 수 없습니다: 윈도우 관리자가 정의되지 않았습니다!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js를 실행할 수 없습니다: 윈도우 관리자를 실행할 수 없습니다: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'OS.js를 실행할 수 없습니다: 리소스를 준비할 수 없습니다...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript 오류 보고서', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : '오류가 발생했습니다. 버그일 수 있습니다', + + 'ERR_APP_API_ERROR' : '응용 프로그램 API 오류', + 'ERR_APP_API_ERROR_DESC_FMT' : '응용 프로그램 {0}이 명령을 실행할 수 없습니다\'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': '누락된 매개변수: {0}', + 'ERR_APP_UNKNOWN_ERROR' : '알 수 없는 오류입니다', + + 'ERR_OPERATION_TIMEOUT' : '시간초과', + 'ERR_OPERATION_TIMEOUT_FMT' : '시간초과 ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\'에서 \'{1}\'는 \'{2}\'이 되어야 하나 \'{3}\'가 주어졌습니다', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : '이미 \'{0}\' 창이 있습니다', + 'WINDOW_MINIMIZE' : '최소화', + 'WINDOW_MAXIMIZE' : '최대화', + 'WINDOW_RESTORE' : '이전 크기로', + 'WINDOW_CLOSE' : '닫기', + 'WINDOW_ONTOP_ON' : '위로 (활성화)', + 'WINDOW_ONTOP_OFF': '위로 (비활성화)', + + // Handler + 'TITLE_SIGN_OUT' : '로그아웃', + 'TITLE_SIGNED_IN_AS_FMT' : '{0}(으)로 로그인', + 'ERR_LOGIN_FMT' : '로그인 오류: {0}', + 'ERR_LOGIN_INVALID' : '비정상 로그인', + + // SESSION + 'MSG_SESSION_WARNING' : 'OS.js를 정말 종료하시겠습니까? 저장하지 않은 설정과 응용 프로그램 데이터가 손실될 수 있습니다!', + + // Service + 'BUGREPORT_MSG' : '버그라고 생각되면 보고해주십시요.\n오류가 어떻게 발생했는지 간단한 설명을 해주십시요. 가능하다면 재현 상황을 설명해주십시요', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : '{0}(으)로 외부 서비스 로그인', + + // Utils + 'ERR_UTILS_XHR_FATAL' : '심각한 오류', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR 오류: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : '로그아웃 (종료)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : '\'{0}\' 사용자 로그아웃.\n현재 세션을 저장하시겠습니까?', + + 'DIALOG_CLOSE' : '닫기', + 'DIALOG_CANCEL': '취소', + 'DIALOG_APPLY' : '적용', + 'DIALOG_OK' : '확인', + + 'DIALOG_ALERT_TITLE' : '알림 다이얼로그', + + 'DIALOG_COLOR_TITLE' : '색상 다이얼로그', + 'DIALOG_COLOR_R' : '빨강: {0}', + 'DIALOG_COLOR_G' : '초록: {0}', + 'DIALOG_COLOR_B' : '파랑: {0}', + 'DIALOG_COLOR_A' : '투명: {0}', + + 'DIALOG_CONFIRM_TITLE' : '확인 다이얼로그', + + 'DIALOG_ERROR_MESSAGE' : '메시지', + 'DIALOG_ERROR_SUMMARY' : '요약', + 'DIALOG_ERROR_TRACE' : '추적', + 'DIALOG_ERROR_BUGREPORT' : '오류 보고', + + 'DIALOG_FILE_SAVE' : '저장', + 'DIALOG_FILE_OPEN' : '열기', + 'DIALOG_FILE_MKDIR' : '디렉토리 생성', + 'DIALOG_FILE_MKDIR_MSG' : '**{0}**에 디렉토리 생성', + 'DIALOG_FILE_OVERWRITE' : '정말 \'{0}\'을 덮어쓰시겠습니까?', + 'DIALOG_FILE_MNU_VIEWTYPE' : '보기 타입', + 'DIALOG_FILE_MNU_LISTVIEW' : '자세히 보기', + 'DIALOG_FILE_MNU_TREEVIEW' : '간단히 보기', + 'DIALOG_FILE_MNU_ICONVIEW' : '아이콘으로 보기', + 'DIALOG_FILE_ERROR' : '파일 다이얼로그 오류', + 'DIALOG_FILE_ERROR_SCANDIR': '오류가 발생했습니다. \'{0}\' 폴더를 불러올 수 없습니다', + 'DIALOG_FILE_MISSING_FILENAME' : '파일을 선택하거나 새로운 파일 이름을 입력해주십시요!', + 'DIALOG_FILE_MISSING_SELECTION': '파일을 선택해야 합니다!', + + 'DIALOG_FILEINFO_TITLE' : '파일 정보', + 'DIALOG_FILEINFO_LOADING' : '파일 정보를 불러오는 중: {0}', + 'DIALOG_FILEINFO_ERROR' : '파일 정보 다이얼로그 오류', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : '파일 정보를 가져올 수 없습니다 **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '파일 정보를 가져올 수 없습니다: {0}', + + 'DIALOG_INPUT_TITLE' : '입력 다이얼로그', + + 'DIALOG_FILEPROGRESS_TITLE' : '파일 명령 처리', + 'DIALOG_FILEPROGRESS_LOADING' : '처리 중...', + + 'DIALOG_UPLOAD_TITLE' : '업로드 다이얼로그', + 'DIALOG_UPLOAD_DESC' : '**{0}**에 파일 업로드.
최대 용량: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : '\'{0}\' ({1} {2})을(를) {3}에 업로드 중', + 'DIALOG_UPLOAD_MSG' : '파일을 업로드 중...', + 'DIALOG_UPLOAD_FAILED' : '업로드 실패', + 'DIALOG_UPLOAD_FAILED_MSG' : '업로드에 실패했습니다', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : '알 수 없는 오류...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': '사용자에 의해 취소...', + 'DIALOG_UPLOAD_TOO_BIG': '파일이 너무 큽니다', + 'DIALOG_UPLOAD_TOO_BIG_FMT': '파일이 너무 큽니다, {0} 초과', + + 'DIALOG_FONT_TITLE' : '글꼴 다이얼로그', + + 'DIALOG_APPCHOOSER_TITLE' : '응용 프로그램 선택', + 'DIALOG_APPCHOOSER_MSG' : '열려는 응용 프로그램을 선택해주십시요', + 'DIALOG_APPCHOOSER_NO_SELECTION' : '응용 프로그램을 선택해야 합니다', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : '{0}을(를) 기본 응용 프로그램으로 설정', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI 모듈이 설정되지 않았거나 사용할 수 없습니다', + 'GAPI_SIGN_OUT' : 'Google API 서비스에서 로그아웃', + 'GAPI_REVOKE' : '권한을 해제하고 로그아웃', + 'GAPI_AUTH_FAILURE' : 'Google API 인증에 실패했습니다', + 'GAPI_AUTH_FAILURE_FMT' : '인증에 실패: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Google API 로드 실패', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API 모듈이 설정되지 않았거나 사용할 수 없습니다', + 'WLAPI_SIGN_OUT' : 'Window Live API 서비스에서 로그아웃', + 'WLAPI_LOAD_FAILURE' : 'Windows Live API 로드 실패', + 'WLAPI_LOGIN_FAILED' : 'Windows Live API에 로그인 실패', + 'WLAPI_LOGIN_FAILED_FMT' : 'Windows Live API에 로그인 실패: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API가 {0} 상태를 반환했습니다', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Database의 이름 없이는 IndexedDB를 생성할 수 없습니다', + 'IDB_NO_SUCH_ITEM' : '찾을 수 없습니다', + + // + // VFS + // + 'ERR_VFS_FATAL' : '심각한 오류', + 'ERR_VFS_UNAVAILABLE' : '사용할 수 없음', + 'ERR_VFS_FILE_ARGS' : '적어도 하나의 매개변수가 필요합니다', + 'ERR_VFS_NUM_ARGS' : '매개변수가 충분하지 않습니다', + 'ERR_VFS_EXPECT_FILE' : '파일 객체가 필요합니다', + 'ERR_VFS_EXPECT_SRC_FILE' : '원본 파일 객체가 필요합니다', + 'ERR_VFS_EXPECT_DST_FILE' : '대상 파일 객체가 필요합니다', + 'ERR_VFS_FILE_EXISTS' : '대상 파일이 이미 존재합니다', + 'ERR_VFS_TRANSFER_FMT' : '저장소 간 파일을 이동하는 중 오류가 발생했습니다: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : '파일을 업로드하려면 대상을 선택해주십시요', + 'ERR_VFS_UPLOAD_NO_FILES' : '업로드하려는 파일을 선택해주십시요', + 'ERR_VFS_UPLOAD_FAIL_FMT' : '파일을 업로드하는데 실패했습니다: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': '파일 업로드가 취소되었습니다', + 'ERR_VFS_DOWNLOAD_NO_FILE': '경로 없이 경로를 다운로드할 수 없습니다', + 'ERR_VFS_DOWNLOAD_FAILED' : '다운로드 중 오류가 발생하였습니다: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': '응답이 비어있습니다', + + 'ERR_VFSMODULE_INVALID' : '유효하지 않은 VFS 모듈', + 'ERR_VFSMODULE_INVALID_FMT' : '유효하지 않은 VFS 모듈: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : '유효하지 않은 VFS 메소드', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : '유효하지 않은 VFS 메소드: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : '유효하지 않은 VFS 모듈 타입', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : '유효하지 않은 VFS 모듈 타입: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : '유효하지 않은 VFS 모듈 설정', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : '유효하지 않은 VFS 모듈 설정: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS 모듈이 이미 마운트 되었습니다', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS 모듈 \'{0}\' 이(가) 이미 마운트 되었습니다', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS 모듈이 마운트 되지 않았습니다', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS 모듈 \'{0}\' 이(가) 마운트 되지 않았습니다', + 'ERR_VFSMODULE_EXCEPTION' : 'VFS 모듈 예외 발생', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS 모듈 예외 발생: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : '{0}와 같은 VFS 모듈이 존재하지 않습니다. 잘못된 경로나 형식일 수 있습니다', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': '파일 다운로드', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR 오류', + 'ERR_VFSMODULE_ROOT_ID' : '최상위 디렉토리 id를 찾을 수 없습니다', + 'ERR_VFSMODULE_NOSUCH' : '파일이 존재하지 않습니다', + 'ERR_VFSMODULE_PARENT' : '부모를 찾을 수 없습니다', + 'ERR_VFSMODULE_PARENT_FMT' : '부모를 찾을 수 없습니다: {0}', + 'ERR_VFSMODULE_SCANDIR' : '디렉토리 불러오기 실패', + 'ERR_VFSMODULE_SCANDIR_FMT' : '디렉토리를 불러올 수 없습니다: {0}', + 'ERR_VFSMODULE_READ' : '파일 읽기 실패', + 'ERR_VFSMODULE_READ_FMT' : '파일을 읽을 수 없습니다: {0}', + 'ERR_VFSMODULE_WRITE' : '파일 생성 실패', + 'ERR_VFSMODULE_WRITE_FMT' : '파일을 생성할 수 없습니다: {0}', + 'ERR_VFSMODULE_COPY' : '복사 실패', + 'ERR_VFSMODULE_COPY_FMT' : '복사할 수 없습니다: {0}', + 'ERR_VFSMODULE_UNLINK' : '바로가기 해제', + 'ERR_VFSMODULE_UNLINK_FMT' : '바로가기를 해제할 수 없습니다: {0}', + 'ERR_VFSMODULE_MOVE' : '파일 이동 실패', + 'ERR_VFSMODULE_MOVE_FMT' : '파일을 이동할 수 없습니다: {0}', + 'ERR_VFSMODULE_EXIST' : '파일 존재 여부 확인', + 'ERR_VFSMODULE_EXIST_FMT' : '파일이 존재하는지 확인할 수 없습니다: {0}', + 'ERR_VFSMODULE_FILEINFO' : '파일 정보 조회 실패', + 'ERR_VFSMODULE_FILEINFO_FMT' : '파일 정보를 읽을 수 없습니다: {0}', + 'ERR_VFSMODULE_MKDIR' : '디렉토리 생성 실패', + 'ERR_VFSMODULE_MKDIR_FMT' : '디렉토리를 생성할 수 없습니다: {0}', + 'ERR_VFSMODULE_URL' : '파일 경로 찾기 실패', + 'ERR_VFSMODULE_URL_FMT' : '파일의 경로를 찾을 수 없습니다: {0}', + 'ERR_VFSMODULE_TRASH' : '휴지통으로 보내기 실패', + 'ERR_VFSMODULE_TRASH_FMT' : '휴지통으로 보낼 수 없습니다: {0}', + 'ERR_VFSMODULE_UNTRASH' : '휴지통 복원 실패', + 'ERR_VFSMODULE_UNTRASH_FMT' : '휴지통에서 복원할 수 없습니다: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : '휴지통 비우기 실패', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : '휴지통을 비울 수 없습니다: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Dropbox API에 가입되어 있습니다', + 'DROPBOX_SIGN_OUT' : 'Google API Services에서 로그아웃', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : '경로 탐색 실패: 항목을 찾을 수 없습니다', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'zip.js를 불러오는 데 실패하였습니다', + 'ZIP_VENDOR_FAIL' : 'zip.js 라이브러리를 찾을 수 없습니다. 올바른 방법으로 불러왔는지 확인해주십시오', + 'ZIP_NO_RESOURCE' : 'zip 리소스가 주어지지 않았습니다', + 'ZIP_NO_PATH' : '경로가 주어지지 않았습니다', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': '패키지 설치 디렉토리가 이미 존재하여 설치를 계속 할 수 없습니다!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : '파일을 열 수 없습니다', + 'ERR_FILE_APP_OPEN_FMT' : '마임(MIME) {1} 이(가) 지원되지 않아 파일 {0} 을(를) 열지 못했습니다', + 'ERR_FILE_APP_OPEN_ALT_FMT' : '파일 {0} 을(를) 열지 못했습니다: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : '파일 {0} 을(를) 저장하지 못했습니다: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} 응용 프로그램 오류', + 'ERR_GENERIC_APP_ACTION_FMT': '\'{0}\' 수행에 실패하였습니다', + 'ERR_GENERIC_APP_UNKNOWN' : '알 수 없는 오류', + 'ERR_GENERIC_APP_REQUEST' : '명령을 처리하는 도중 오류가 발생하였습니다', + 'ERR_GENERIC_APP_FATAL_FMT' : '치명적인 오류: {0}', + 'MSG_GENERIC_APP_DISCARD' : '변경사항을 저장하지 않겠습니까?', + 'MSG_FILE_CHANGED' : '파일이 변경되었습니다. 새로고침 하시겠습니까?', + 'MSG_APPLICATION_WARNING' : '응용 프로그램 경고', + 'MSG_MIME_OVERRIDE' : '파일 타입 "{0}" 은(는) 지원되지 않습니다, "{1}" (으)로 대신합니다', + + // + // General + // + + 'LBL_UNKNOWN' : '알수없음', + 'LBL_APPEARANCE' : '모양', + 'LBL_USER' : '사용자', + 'LBL_NAME' : '이름', + 'LBL_APPLY' : '적용', + 'LBL_FILENAME' : '파일명', + 'LBL_PATH' : '경로', + 'LBL_SIZE' : '크기', + 'LBL_TYPE' : '타입', + 'LBL_MIME' : '마임(MIME)', + 'LBL_LOADING' : '로딩', + 'LBL_SETTINGS' : '설정', + 'LBL_ADD_FILE' : '파일 추가', + 'LBL_COMMENT' : '댓글', + 'LBL_ACCOUNT' : '계정', + 'LBL_CONNECT' : '연결', + 'LBL_ONLINE' : '온라인', + 'LBL_OFFLINE' : '오프라인', + 'LBL_AWAY' : '부재중', + 'LBL_BUSY' : '바쁨', + 'LBL_CHAT' : '채팅', + 'LBL_HELP' : '도움말', + 'LBL_ABOUT' : '정보', + 'LBL_PANELS' : '패널', + 'LBL_LOCALES' : '지역', + 'LBL_THEME' : '테마', + 'LBL_COLOR' : '색상', + 'LBL_PID' : '프로세스 ID', + 'LBL_KILL' : '종료', + 'LBL_ALIVE' : '활성', + 'LBL_INDEX' : '인덱스', + 'LBL_ADD' : '추가', + 'LBL_FONT' : '글꼴', + 'LBL_YES' : '예', + 'LBL_NO' : '아니오', + 'LBL_CANCEL' : '취소', + 'LBL_TOP' : '위', + 'LBL_LEFT' : '왼쪽', + 'LBL_RIGHT' : '오른쪽', + 'LBL_BOTTOM' : '아래', + 'LBL_CENTER' : '가운데', + 'LBL_FILE' : '파일', + 'LBL_NEW' : '새로 만들기', + 'LBL_OPEN' : '열기', + 'LBL_SAVE' : '저장', + 'LBL_SAVEAS' : '다른 이름으로 저장', + 'LBL_CLOSE' : '닫기', + 'LBL_MKDIR' : '디렉토리 생성', + 'LBL_UPLOAD' : '업로드', + 'LBL_VIEW' : '보기', + 'LBL_EDIT' : '편집', + 'LBL_RENAME' : '이름 변경', + 'LBL_DELETE' : '삭제', + 'LBL_OPENWITH' : '다른 프로그램으로 열기', + 'LBL_ICONVIEW' : '아이콘으로 보기', + 'LBL_TREEVIEW' : '트리로 보기', + 'LBL_LISTVIEW' : '리스트로 보기', + 'LBL_REFRESH' : '새로고침', + 'LBL_VIEWTYPE' : '보기 방식', + 'LBL_BOLD' : '굵게', + 'LBL_ITALIC' : '이탤릭체', + 'LBL_UNDERLINE' : '밑줄', + 'LBL_REGULAR' : '일반', + 'LBL_STRIKE' : '취소선', + 'LBL_INDENT' : '들여쓰기', + 'LBL_OUTDENT' : '내어쓰기', + 'LBL_UNDO' : '실행 취소', + 'LBL_REDO' : '다시 실행', + 'LBL_CUT' : '잘라내기', + 'LBL_UNLINK' : '링크 해제', + 'LBL_COPY' : '복사', + 'LBL_PASTE' : '붙여넣기', + 'LBL_INSERT' : '삽입', + 'LBL_IMAGE' : '이미지', + 'LBL_LINK' : '링크', + 'LBL_DISCONNECT' : '연결 해제', + 'LBL_APPLICATIONS' : '응용 프로그램', + 'LBL_ADD_FOLDER' : '폴더 추가', + 'LBL_INFORMATION' : '정보', + 'LBL_TEXT_COLOR' : '글자색', + 'LBL_BACK_COLOR' : '배경색', + 'LBL_RESET_DEFAULT' : '기본값으로 복원', + 'LBL_DOWNLOAD_COMP' : '컴퓨터로 다운로드', + 'LBL_ORDERED_LIST' : '정렬 된 리스트', + 'LBL_BACKGROUND_IMAGE' : '배경 이미지', + 'LBL_BACKGROUND_COLOR' : '배경 색상', + 'LBL_UNORDERED_LIST' : '정렬 되지 않은 리스트', + 'LBL_STATUS' : '상태', + 'LBL_READONLY' : '읽기 전용', + 'LBL_CREATED' : '생성됨', + 'LBL_MODIFIED' : '수정됨', + 'LBL_SHOW_COLUMNS' : '열 보기', + 'LBL_MOVE' : '이동', + 'LBL_OPTIONS' : '옵션', + 'LBL_OK' : '확인', + 'LBL_DIRECTORY' : '디렉토리', + 'LBL_CREATE' : '생성', + 'LBL_BUGREPORT' : '버그 리포트', + 'LBL_INSTALL' : '설치', + 'LBL_UPDATE' : '수정', + 'LBL_REMOVE' : '제거', + 'LBL_SHOW_SIDEBAR' : '사이드바 보이기', + 'LBL_SHOW_NAVIGATION' : '네비게이션 보이기', + 'LBL_SHOW_HIDDENFILES' : '숨긴 파일 보이기', + 'LBL_SHOW_FILEEXTENSIONS' : '파일 확장자 보이기', + 'LBL_MOUNT': '마운트', + 'LBL_DESCRIPTION': '설명', + 'LBL_USERNAME': '사용자 이름', + 'LBL_PASSWORD': '비밀번호', + 'LBL_HOST': '호스트', + 'LBL_NAMESPACE': '네임스페이스', + 'LBL_BACKGROUND' : '바탕화면', + 'LBL_DESKTOP' : '데스크탑', + 'LBL_PANEL' : '패널', + 'LBL_POSITION' : '위치', + 'LBL_ONTOP' : '상단바 자리 차지', + 'LBL_ITEMS' : '항목', + 'LBL_GENERAL': '일반', + 'LBL_SOUNDS': '소리', + 'LBL_ICONS': '아이콘', + 'LBL_DEBUG' : '디버그', + 'LBL_AUTOHIDE' : '자동 숨기기', + 'LBL_OPACITY' : '투명도', + 'LBL_PACKAGES' : '패키지', + 'LBL_GROUPS' : '그룹', + 'LBL_VERSION' : '버전', + 'LBL_AUTHOR' : '작성자', + 'LBL_Hide' : '숨기기', + 'LBL_APPLICATION' : '어플리케이션', + 'LBL_SCOPE' : '범위', + 'LBL_SEARCH' : '검색' +}; diff --git a/src/client/javascript/locales/nl_NL.js b/src/client/javascript/locales/nl_NL.js index 3127796970..3ec13a5d01 100644 --- a/src/client/javascript/locales/nl_NL.js +++ b/src/client/javascript/locales/nl_NL.js @@ -28,398 +28,395 @@ * @licence Simplified BSD License * Dutch translation by Imre Biacsics */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.nl_NL = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Fout bij openen bestand', - 'ERR_WM_NOT_RUNNING' : 'Window manager is niet gestart', - 'ERR_FILE_OPEN_FMT' : 'Het bestand \'**{0}**\' kon niet worden geopend', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Kon geen programma vinden die \'{0}\' kan openen', - 'ERR_APP_LAUNCH_FAILED' : 'Starten van het programma is mislukt', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Er is een probleem opgetreden tijden het starten van: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Toepassing \'{0}\' construct failed: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Toepassing \'{0}\' init() failed: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Toepassing bronnen ontbreken \'{0}\' of kon niet laden!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Toepassing \'{0}\' preload niet geslaagd: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'De toepassing \'{0}\' is al gestart en staat geen tweede instantie toe!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Starten van \'{0}\' is niet geslaagd. Application manifest data niet gevonden!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Starteb van \'{0}\' is niet geslaagd. De browser wordt niet ondersteund: {1}', - - 'ERR_NO_WM_RUNNING' : 'Window manager is niet gestart', - 'ERR_CORE_INIT_FAILED' : 'Initialisatie van OS.js mislukt', - 'ERR_CORE_INIT_FAILED_DESC' : 'Er is een fout opgetreden tijdens de initialisatie van OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Kan OS.js niet starten: Geen window manager gedefineerd!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Kan OS.js niet starten: Window manager: {0} wil niet starten', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Kan OS.js niet starten: Fout bij het voorladen van bronnen...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Fout Rapportage', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Een onverwachte fout opgetreden, mogelijk een bug.', - - 'ERR_APP_API_ERROR' : 'Applicatie API fout', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Applicatie {0} Kan actie \'{1}\' niet uitvoeren', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Missend argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Onbekende fout', - - 'ERR_OPERATION_TIMEOUT' : 'Operatie Timeout', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Operatie Timeout ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' verwacht dat \'{1}\' een \'{2}\' is, niet \'{3}\'', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Er is al een venster met de naam: \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimaliseren', - 'WINDOW_MAXIMIZE' : 'Maximaliseren', - 'WINDOW_RESTORE' : 'Herstellen', - 'WINDOW_CLOSE' : 'Sluiten', - 'WINDOW_ONTOP_ON' : 'Naar voorgrond (Aan)', - 'WINDOW_ONTOP_OFF': 'Naar voorgrond (Uit)', - - // Handler - 'TITLE_SIGN_OUT' : 'Afmelden', - 'TITLE_SIGNED_IN_AS_FMT' : 'Aangemeld als: {0}', - 'ERR_LOGIN_FMT' : 'Login fout: {0}', - 'ERR_LOGIN_INVALID' : 'Onjuiste aanmelding', - - // SESSION - 'MSG_SESSION_WARNING' : 'Weet je zeker dat je OS.js wilt verlaten? Alle niet opgeslagen instellingen en applicatie data zal verloren gaan!', - - // Service - 'BUGREPORT_MSG' : 'Vriendelijk verzoek dit probleem te rapporteren.\nVoeg een korte omschrijving toe en als het lukt; Hoe we dit kunnen nabootsen', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Aangemeld bij externe service: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Fatale Fout', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Fout: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Afmelden', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : ' \'{0}\'.\nWilt u deze sessie opslaan?', - - 'DIALOG_CLOSE' : 'Sluiten', - 'DIALOG_CANCEL': 'Annuleren', - 'DIALOG_APPLY' : 'Bevestigen', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Waarschuwing', - - 'DIALOG_COLOR_TITLE' : 'Kleuren', - 'DIALOG_COLOR_R' : 'Rood: {0}', - 'DIALOG_COLOR_G' : 'Groen: {0}', - 'DIALOG_COLOR_B' : 'Blauw: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Bevestiging', - - 'DIALOG_ERROR_MESSAGE' : 'Bericht', - 'DIALOG_ERROR_SUMMARY' : 'Opsomming', - 'DIALOG_ERROR_TRACE' : 'Trace', - 'DIALOG_ERROR_BUGREPORT' : 'Fouten rapport', - - 'DIALOG_FILE_SAVE' : 'Opslaan', - 'DIALOG_FILE_OPEN' : 'Openen', - 'DIALOG_FILE_MKDIR' : 'Nieuwe map', - 'DIALOG_FILE_MKDIR_MSG' : 'Maak nieuwe map in **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Weet u zeker dat het bestand \'{0}\' overschreven moet worden?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Weergave', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Lijst weergave', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Boom weergave', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Icoontje', - 'DIALOG_FILE_ERROR' : 'BestandsDialoog Fout', - 'DIALOG_FILE_ERROR_SCANDIR': 'Kan de map niet doorzoeken \'{0}\' Er is een storing opgetreden', - 'DIALOG_FILE_MISSING_FILENAME' : 'Selecteer een bestand of geef een naam op!', - 'DIALOG_FILE_MISSING_SELECTION': 'Selecteer een bestand!', - - 'DIALOG_FILEINFO_TITLE' : 'Bestands informatie', - 'DIALOG_FILEINFO_LOADING' : 'Bestands informatie laden van: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Bestanda informatie Fout', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Ophalen van informatie van **{0}** is mislukt', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Ophalen van informatie van: {0} is mislukt', - - 'DIALOG_INPUT_TITLE' : 'Input Dialoog', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Voortgang', - 'DIALOG_FILEPROGRESS_LOADING' : 'Laden...', - - 'DIALOG_UPLOAD_TITLE' : 'Upload Dialoog', - 'DIALOG_UPLOAD_DESC' : 'Upload bestand naar **{0}**.
Maximum grootte: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Bezig met uploaden \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Bezig met uploaden...', - 'DIALOG_UPLOAD_FAILED' : 'Uploaden is niet gelukt', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Uploaden is niet gelukt', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Oorzaak onbekend...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Geannuleerd door de gebruiker...', - 'DIALOG_UPLOAD_TOO_BIG': 'Het bestand is te groot', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Het bestand is te groot, overschrijdt {0}', - - 'DIALOG_FONT_TITLE' : 'Lettertype', - - 'DIALOG_APPCHOOSER_TITLE' : 'Kies een programma', - 'DIALOG_APPCHOOSER_MSG' : 'Kies een programma om te openen', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'U moet een programma kiezen', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Instellen als standaard programma voor {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Module is niet geconfigureerd of uitgeschakeld', - 'GAPI_SIGN_OUT' : 'Afmelden bij Google API Services', - 'GAPI_REVOKE' : 'Permissies herstellen en afmelden', - 'GAPI_AUTH_FAILURE' : 'Google API Authentificatie niet gelukt of heeft niet plaatsgevonden', - 'GAPI_AUTH_FAILURE_FMT' : 'Authentificatie mislukt: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Google API laden is mislukt', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API module is niet geconfigureerd of uitgeschakeld', - 'WLAPI_SIGN_OUT' : 'Afmelden bij Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Windows Live API niet geladen', - 'WLAPI_LOGIN_FAILED' : 'Aanmelden bij Windows Live mislukt', - 'WLAPI_LOGIN_FAILED_FMT' : 'Aanmelden bij Windows Live misluk: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live status: {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Kan geen IndexedDB maken zonder database naam', - 'IDB_NO_SUCH_ITEM' : 'Item bestaat niet', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Fatale Fout', - 'ERR_VFS_UNAVAILABLE' : 'Niet beschikbaar', - 'ERR_VFS_FILE_ARGS' : 'Bestand verwacht tenminste 1 optie', - 'ERR_VFS_NUM_ARGS' : 'Onjuist aantal opties', - 'ERR_VFS_EXPECT_FILE' : 'Dit is geen bestands-object', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Dit is geen bronbestand', - 'ERR_VFS_EXPECT_DST_FILE' : 'Verwacht een bestemmings bestand', - 'ERR_VFS_FILE_EXISTS' : 'Bestemming bestaat al', - 'ERR_VFS_TRANSFER_FMT' : 'Er is een fout opgetreden bij het omzetten van opslag: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Kan het bestand niet uploaden zonder bestemming', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Geen bestand gedefineerd om te uploaden', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Bestand uploaden is mislukt: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Bestands upload is geannuleerd', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kan niet downloaden zonder pad', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Er is een fout opgetreden tijdens het downloaden: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'De reactie was leeg', - - 'ERR_VFSMODULE_INVALID' : 'Ongeldige VFS Module', - 'ERR_VFSMODULE_INVALID_FMT' : 'Ongeldige VFS Module: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Ongeldige VFS Methode', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Ongeldige VFS Methode: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Ongeldige VFS Module type', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Ongeldige VFS Module type: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Ongeldige VFS Module configuratie', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Ongeldige VFS Module configuratie: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Module reeds gekoppeld', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Module \'{0}\' reeds gekoppeld', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Module niet gekoppeld', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Module \'{0}\' niet gekoppeld', - 'ERR_VFSMODULE_EXCEPTION' : 'VFS Module Exceptie', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Module Exceptie: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Geen VFS Module komt overeen met {0}. Verkeerd pad or formaat ?', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Bestand downloaden', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Fout', - 'ERR_VFSMODULE_ROOT_ID' : 'ID van root map niet gevonden', - 'ERR_VFSMODULE_NOSUCH' : 'Het bestand bestaat niet', - 'ERR_VFSMODULE_PARENT' : 'Ouder bestaat niet', - 'ERR_VFSMODULE_PARENT_FMT' : 'Ouder opzoeken mislukt: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Mappen scannen mislukt', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Mappen scannen mislukt: {0}', - 'ERR_VFSMODULE_READ' : 'Bestand lezen mislukt', - 'ERR_VFSMODULE_READ_FMT' : 'Bestand lezen misluk: {0}', - 'ERR_VFSMODULE_WRITE' : 'Bestand schrijven misluk', - 'ERR_VFSMODULE_WRITE_FMT' : 'Bestand schrijven misluk: {0}', - 'ERR_VFSMODULE_COPY' : 'Kopieren mislukt', - 'ERR_VFSMODULE_COPY_FMT' : 'Kopieren mislukt: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Fout bij unlink opdracht', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Fout bij unlink opdrachte: {0}', - 'ERR_VFSMODULE_MOVE' : 'Bestand verplaatsen mislukt', - 'ERR_VFSMODULE_MOVE_FMT' : 'Bestand verplaatsen mislukt: {0}', - 'ERR_VFSMODULE_EXIST' : 'Fout tijdens het bepalen van het bestaan van een bestand', - 'ERR_VFSMODULE_EXIST_FMT' : 'Fout tijdens het bepalen van het bestaan van een bestand: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Bestands informatie lezen is mislukt', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Bestands informatie lezen is mislukt: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Map maken is mislukt', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Map maken is mislukt: {0}', - 'ERR_VFSMODULE_URL' : 'Fout bij het verkrijgen van een URL', - 'ERR_VFSMODULE_URL_FMT' : 'Fout bij het verkrijgen van een URL: {0}', - 'ERR_VFSMODULE_TRASH' : 'Fout bij het verplaatsen naar de prullebak', - 'ERR_VFSMODULE_TRASH_FMT' : 'Fout bij het verplaatsen naar de prullebak: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Fout bij het verplaatsen uit de prullebak', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Fout bij het verplaatsen uit de prullebak: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Fout bij het legen van de prullebak', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Fout bij het legen van de prullebak: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Aangemeld bij Dropbox', - 'DROPBOX_SIGN_OUT' : 'Afmelden bij Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Kan het pad niet oplossen: item niet gevonden', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'Laden van zip.js mislukt', - 'ZIP_VENDOR_FAIL' : 'zip.js niet gevonden. Is het correct geladen?', - 'ZIP_NO_RESOURCE' : 'Geen zip bestand opgegeven', - 'ZIP_NO_PATH' : 'Geen pad opgegeven', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Pakket installatie map bestaat al. Kan niet verder gaan!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Kan het bestand niet openen', - 'ERR_FILE_APP_OPEN_FMT' : 'Het bestand {0} kan niet worden geopend {1} wordt niet ondersteund', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Het bestand {0} kan niet worden geopend: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Het bestand {0} kan niet worden opgeslagen: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Toepassing Fout', - 'ERR_GENERIC_APP_ACTION_FMT': 'Kan de actie \'{0}\' niet voltooien', - 'ERR_GENERIC_APP_UNKNOWN' : 'Onbekende Fout', - 'ERR_GENERIC_APP_REQUEST' : 'Er is een fout opgetreden tijdens het afhandelen van dit verzoek', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatale Fout: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Wijzigingen ongedaan maken?', - 'MSG_FILE_CHANGED' : 'Het bestand is gewijzigd. Opnieuw laden?', - 'MSG_APPLICATION_WARNING' : 'Waarschuwing', - 'MSG_MIME_OVERRIDE' : 'Het bestandstype "{0}" wordt niet ondersteund, suggestie: "{1}"', - - // - // General - // - - 'LBL_UNKNOWN' : 'Onbekend', - 'LBL_APPEARANCE' : 'Weergave', - 'LBL_USER' : 'Gebruiker', - 'LBL_NAME' : 'Naam', - 'LBL_APPLY' : 'Bevestigen', - 'LBL_FILENAME' : 'Bestandsnaam', - 'LBL_PATH' : 'Map', - 'LBL_SIZE' : 'Grootte', - 'LBL_TYPE' : 'Type', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Laden', - 'LBL_SETTINGS' : 'Instellingen', - 'LBL_ADD_FILE' : 'Bestand toevoegen', - 'LBL_COMMENT' : 'Opmerking', - 'LBL_ACCOUNT' : 'Account', - 'LBL_CONNECT' : 'Verbinden', - 'LBL_ONLINE' : 'Verbonden', - 'LBL_OFFLINE' : 'Verbroken', - 'LBL_AWAY' : 'Afwezig', - 'LBL_BUSY' : 'Bezig', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Help', - 'LBL_ABOUT' : 'Over', - 'LBL_PANELS' : 'Panelen', - 'LBL_LOCALES' : 'Talen', - 'LBL_THEME' : 'Thema', - 'LBL_COLOR' : 'Kleur', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Stop', - 'LBL_ALIVE' : 'Aktief', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Toevoegen', - 'LBL_FONT' : 'Lettertype', - 'LBL_YES' : 'Ja', - 'LBL_NO' : 'Nee', - 'LBL_CANCEL' : 'Annuleren', - 'LBL_TOP' : 'Boven', - 'LBL_LEFT' : 'Links', - 'LBL_RIGHT' : 'Rechts', - 'LBL_BOTTOM' : 'Onder', - 'LBL_CENTER' : 'Midden', - 'LBL_FILE' : 'Bestand', - 'LBL_NEW' : 'Nieuw', - 'LBL_OPEN' : 'Open', - 'LBL_SAVE' : 'Opslaan', - 'LBL_SAVEAS' : 'opslaan als...', - 'LBL_CLOSE' : 'Sluiten', - 'LBL_MKDIR' : 'Nieuwe map maken', - 'LBL_UPLOAD' : 'Uploaden', - 'LBL_VIEW' : 'Beeld', - 'LBL_EDIT' : 'Bewerken', - 'LBL_RENAME' : 'Hernoemen', - 'LBL_DELETE' : 'Verwijderen', - 'LBL_OPENWITH' : 'Openen met ...', - 'LBL_ICONVIEW' : 'Icoon weergave', - 'LBL_TREEVIEW' : 'Boom weergave', - 'LBL_LISTVIEW' : 'Lijst weergave', - 'LBL_REFRESH' : 'Verversen', - 'LBL_VIEWTYPE' : 'Weergave type', - 'LBL_BOLD' : 'Vet', - 'LBL_ITALIC' : 'Schuin', - 'LBL_UNDERLINE' : 'Onderstreept', - 'LBL_REGULAR' : 'Normaal', - 'LBL_STRIKE' : 'Doorgehaald', - 'LBL_INDENT' : 'Inspringen', - 'LBL_OUTDENT' : 'Uitspringen', - 'LBL_UNDO' : 'Ongedaan maken', - 'LBL_REDO' : 'Ongedaan maken herstellen', - 'LBL_CUT' : 'Knip', - 'LBL_UNLINK' : 'Unlink', - 'LBL_COPY' : 'Kopieren', - 'LBL_PASTE' : 'Plakken', - 'LBL_INSERT' : 'Invoegen', - 'LBL_IMAGE' : 'Afbeelding', - 'LBL_LINK' : 'Link', - 'LBL_DISCONNECT' : 'Verbreken', - 'LBL_APPLICATIONS' : 'Toepassingen', - 'LBL_ADD_FOLDER' : 'Map toevoegen', - 'LBL_INFORMATION' : 'Informatie', - 'LBL_TEXT_COLOR' : 'Tekst kleur', - 'LBL_BACK_COLOR' : 'Achtergrond kleur', - 'LBL_RESET_DEFAULT' : 'Standaard instelling terug zetten', - 'LBL_DOWNLOAD_COMP' : 'Downloaden naar je computer', - 'LBL_ORDERED_LIST' : 'Gesorteerde lijst', - 'LBL_BACKGROUND_IMAGE' : 'Achtergrond afbeelding', - 'LBL_BACKGROUND_COLOR' : 'Achtergrond kleur', - 'LBL_UNORDERED_LIST' : 'Ongesorteerde lijst', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Alleen lezen', - 'LBL_CREATED' : 'Aangemaakt', - 'LBL_MODIFIED' : 'Gewijzigd', - 'LBL_SHOW_COLUMNS' : 'Kolommen tonen', - 'LBL_MOVE' : 'Verplaats', - 'LBL_OPTIONS' : 'Opties', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Map', - 'LBL_CREATE' : 'Aanmaken', - 'LBL_BUGREPORT' : 'Bugreport', - 'LBL_INSTALL' : 'Installeer', - 'LBL_UPDATE' : 'Update', - 'LBL_REMOVE' : 'Verwijder', - 'LBL_SHOW_SIDEBAR' : 'Zijbar tonen', - 'LBL_SHOW_NAVIGATION' : 'Navigatie tonen', - 'LBL_SHOW_HIDDENFILES' : 'Laat verborgen bestanden zien', - 'LBL_SHOW_FILEEXTENSIONS' : 'Toon bestandsextensies', - 'LBL_MOUNT': 'Koppelen', - 'LBL_DESCRIPTION': 'Omschrijving', - 'LBL_USERNAME': 'Gebruikersnaam', - 'LBL_PASSWORD': 'Wachtwoord', - 'LBL_HOST': 'Host', - 'LBL_NAMESPACE': 'Namespace', - 'LBL_BACKGROUND' : 'Achtergrond', - 'LBL_DESKTOP' : 'Bureaublad', - 'LBL_PANEL' : 'Paneel', - 'LBL_POSITION' : 'Positie', - 'LBL_ONTOP' : 'Voorgrond', - 'LBL_ITEMS' : 'Items', - 'LBL_GENERAL': 'Algemeen' - - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Fout bij openen bestand', + 'ERR_WM_NOT_RUNNING' : 'Window manager is niet gestart', + 'ERR_FILE_OPEN_FMT' : 'Het bestand \'**{0}**\' kon niet worden geopend', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Kon geen programma vinden die \'{0}\' kan openen', + 'ERR_APP_LAUNCH_FAILED' : 'Starten van het programma is mislukt', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Er is een probleem opgetreden tijden het starten van: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Toepassing \'{0}\' construct failed: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Toepassing \'{0}\' init() failed: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Toepassing bronnen ontbreken \'{0}\' of kon niet laden!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Toepassing \'{0}\' preload niet geslaagd: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'De toepassing \'{0}\' is al gestart en staat geen tweede instantie toe!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Starten van \'{0}\' is niet geslaagd. Application manifest data niet gevonden!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Starteb van \'{0}\' is niet geslaagd. De browser wordt niet ondersteund: {1}', + + 'ERR_NO_WM_RUNNING' : 'Window manager is niet gestart', + 'ERR_CORE_INIT_FAILED' : 'Initialisatie van OS.js mislukt', + 'ERR_CORE_INIT_FAILED_DESC' : 'Er is een fout opgetreden tijdens de initialisatie van OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Kan OS.js niet starten: Geen window manager gedefineerd!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Kan OS.js niet starten: Window manager: {0} wil niet starten', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Kan OS.js niet starten: Fout bij het voorladen van bronnen...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Fout Rapportage', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Een onverwachte fout opgetreden, mogelijk een bug.', + + 'ERR_APP_API_ERROR' : 'Applicatie API fout', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Applicatie {0} Kan actie \'{1}\' niet uitvoeren', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Missend argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Onbekende fout', + + 'ERR_OPERATION_TIMEOUT' : 'Operatie Timeout', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Operatie Timeout ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' verwacht dat \'{1}\' een \'{2}\' is, niet \'{3}\'', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Er is al een venster met de naam: \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimaliseren', + 'WINDOW_MAXIMIZE' : 'Maximaliseren', + 'WINDOW_RESTORE' : 'Herstellen', + 'WINDOW_CLOSE' : 'Sluiten', + 'WINDOW_ONTOP_ON' : 'Naar voorgrond (Aan)', + 'WINDOW_ONTOP_OFF': 'Naar voorgrond (Uit)', + + // Handler + 'TITLE_SIGN_OUT' : 'Afmelden', + 'TITLE_SIGNED_IN_AS_FMT' : 'Aangemeld als: {0}', + 'ERR_LOGIN_FMT' : 'Login fout: {0}', + 'ERR_LOGIN_INVALID' : 'Onjuiste aanmelding', + + // SESSION + 'MSG_SESSION_WARNING' : 'Weet je zeker dat je OS.js wilt verlaten? Alle niet opgeslagen instellingen en applicatie data zal verloren gaan!', + + // Service + 'BUGREPORT_MSG' : 'Vriendelijk verzoek dit probleem te rapporteren.\nVoeg een korte omschrijving toe en als het lukt; Hoe we dit kunnen nabootsen', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Aangemeld bij externe service: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Fatale Fout', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Fout: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Afmelden', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : ' \'{0}\'.\nWilt u deze sessie opslaan?', + + 'DIALOG_CLOSE' : 'Sluiten', + 'DIALOG_CANCEL': 'Annuleren', + 'DIALOG_APPLY' : 'Bevestigen', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Waarschuwing', + + 'DIALOG_COLOR_TITLE' : 'Kleuren', + 'DIALOG_COLOR_R' : 'Rood: {0}', + 'DIALOG_COLOR_G' : 'Groen: {0}', + 'DIALOG_COLOR_B' : 'Blauw: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Bevestiging', + + 'DIALOG_ERROR_MESSAGE' : 'Bericht', + 'DIALOG_ERROR_SUMMARY' : 'Opsomming', + 'DIALOG_ERROR_TRACE' : 'Trace', + 'DIALOG_ERROR_BUGREPORT' : 'Fouten rapport', + + 'DIALOG_FILE_SAVE' : 'Opslaan', + 'DIALOG_FILE_OPEN' : 'Openen', + 'DIALOG_FILE_MKDIR' : 'Nieuwe map', + 'DIALOG_FILE_MKDIR_MSG' : 'Maak nieuwe map in **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Weet u zeker dat het bestand \'{0}\' overschreven moet worden?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Weergave', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Lijst weergave', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Boom weergave', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Icoontje', + 'DIALOG_FILE_ERROR' : 'BestandsDialoog Fout', + 'DIALOG_FILE_ERROR_SCANDIR': 'Kan de map niet doorzoeken \'{0}\' Er is een storing opgetreden', + 'DIALOG_FILE_MISSING_FILENAME' : 'Selecteer een bestand of geef een naam op!', + 'DIALOG_FILE_MISSING_SELECTION': 'Selecteer een bestand!', + + 'DIALOG_FILEINFO_TITLE' : 'Bestands informatie', + 'DIALOG_FILEINFO_LOADING' : 'Bestands informatie laden van: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Bestanda informatie Fout', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Ophalen van informatie van **{0}** is mislukt', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Ophalen van informatie van: {0} is mislukt', + + 'DIALOG_INPUT_TITLE' : 'Input Dialoog', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Voortgang', + 'DIALOG_FILEPROGRESS_LOADING' : 'Laden...', + + 'DIALOG_UPLOAD_TITLE' : 'Upload Dialoog', + 'DIALOG_UPLOAD_DESC' : 'Upload bestand naar **{0}**.
Maximum grootte: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Bezig met uploaden \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Bezig met uploaden...', + 'DIALOG_UPLOAD_FAILED' : 'Uploaden is niet gelukt', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Uploaden is niet gelukt', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Oorzaak onbekend...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Geannuleerd door de gebruiker...', + 'DIALOG_UPLOAD_TOO_BIG': 'Het bestand is te groot', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Het bestand is te groot, overschrijdt {0}', + + 'DIALOG_FONT_TITLE' : 'Lettertype', + + 'DIALOG_APPCHOOSER_TITLE' : 'Kies een programma', + 'DIALOG_APPCHOOSER_MSG' : 'Kies een programma om te openen', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'U moet een programma kiezen', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Instellen als standaard programma voor {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Module is niet geconfigureerd of uitgeschakeld', + 'GAPI_SIGN_OUT' : 'Afmelden bij Google API Services', + 'GAPI_REVOKE' : 'Permissies herstellen en afmelden', + 'GAPI_AUTH_FAILURE' : 'Google API Authentificatie niet gelukt of heeft niet plaatsgevonden', + 'GAPI_AUTH_FAILURE_FMT' : 'Authentificatie mislukt: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Google API laden is mislukt', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API module is niet geconfigureerd of uitgeschakeld', + 'WLAPI_SIGN_OUT' : 'Afmelden bij Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Windows Live API niet geladen', + 'WLAPI_LOGIN_FAILED' : 'Aanmelden bij Windows Live mislukt', + 'WLAPI_LOGIN_FAILED_FMT' : 'Aanmelden bij Windows Live misluk: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live status: {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Kan geen IndexedDB maken zonder database naam', + 'IDB_NO_SUCH_ITEM' : 'Item bestaat niet', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Fatale Fout', + 'ERR_VFS_UNAVAILABLE' : 'Niet beschikbaar', + 'ERR_VFS_FILE_ARGS' : 'Bestand verwacht tenminste 1 optie', + 'ERR_VFS_NUM_ARGS' : 'Onjuist aantal opties', + 'ERR_VFS_EXPECT_FILE' : 'Dit is geen bestands-object', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Dit is geen bronbestand', + 'ERR_VFS_EXPECT_DST_FILE' : 'Verwacht een bestemmings bestand', + 'ERR_VFS_FILE_EXISTS' : 'Bestemming bestaat al', + 'ERR_VFS_TRANSFER_FMT' : 'Er is een fout opgetreden bij het omzetten van opslag: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Kan het bestand niet uploaden zonder bestemming', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Geen bestand gedefineerd om te uploaden', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Bestand uploaden is mislukt: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Bestands upload is geannuleerd', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kan niet downloaden zonder pad', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Er is een fout opgetreden tijdens het downloaden: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'De reactie was leeg', + + 'ERR_VFSMODULE_INVALID' : 'Ongeldige VFS Module', + 'ERR_VFSMODULE_INVALID_FMT' : 'Ongeldige VFS Module: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Ongeldige VFS Methode', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Ongeldige VFS Methode: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Ongeldige VFS Module type', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Ongeldige VFS Module type: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Ongeldige VFS Module configuratie', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Ongeldige VFS Module configuratie: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Module reeds gekoppeld', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Module \'{0}\' reeds gekoppeld', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Module niet gekoppeld', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Module \'{0}\' niet gekoppeld', + 'ERR_VFSMODULE_EXCEPTION' : 'VFS Module Exceptie', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Module Exceptie: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Geen VFS Module komt overeen met {0}. Verkeerd pad or formaat ?', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Bestand downloaden', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Fout', + 'ERR_VFSMODULE_ROOT_ID' : 'ID van root map niet gevonden', + 'ERR_VFSMODULE_NOSUCH' : 'Het bestand bestaat niet', + 'ERR_VFSMODULE_PARENT' : 'Ouder bestaat niet', + 'ERR_VFSMODULE_PARENT_FMT' : 'Ouder opzoeken mislukt: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Mappen scannen mislukt', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Mappen scannen mislukt: {0}', + 'ERR_VFSMODULE_READ' : 'Bestand lezen mislukt', + 'ERR_VFSMODULE_READ_FMT' : 'Bestand lezen misluk: {0}', + 'ERR_VFSMODULE_WRITE' : 'Bestand schrijven misluk', + 'ERR_VFSMODULE_WRITE_FMT' : 'Bestand schrijven misluk: {0}', + 'ERR_VFSMODULE_COPY' : 'Kopieren mislukt', + 'ERR_VFSMODULE_COPY_FMT' : 'Kopieren mislukt: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Fout bij unlink opdracht', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Fout bij unlink opdrachte: {0}', + 'ERR_VFSMODULE_MOVE' : 'Bestand verplaatsen mislukt', + 'ERR_VFSMODULE_MOVE_FMT' : 'Bestand verplaatsen mislukt: {0}', + 'ERR_VFSMODULE_EXIST' : 'Fout tijdens het bepalen van het bestaan van een bestand', + 'ERR_VFSMODULE_EXIST_FMT' : 'Fout tijdens het bepalen van het bestaan van een bestand: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Bestands informatie lezen is mislukt', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Bestands informatie lezen is mislukt: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Map maken is mislukt', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Map maken is mislukt: {0}', + 'ERR_VFSMODULE_URL' : 'Fout bij het verkrijgen van een URL', + 'ERR_VFSMODULE_URL_FMT' : 'Fout bij het verkrijgen van een URL: {0}', + 'ERR_VFSMODULE_TRASH' : 'Fout bij het verplaatsen naar de prullebak', + 'ERR_VFSMODULE_TRASH_FMT' : 'Fout bij het verplaatsen naar de prullebak: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Fout bij het verplaatsen uit de prullebak', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Fout bij het verplaatsen uit de prullebak: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Fout bij het legen van de prullebak', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Fout bij het legen van de prullebak: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Aangemeld bij Dropbox', + 'DROPBOX_SIGN_OUT' : 'Afmelden bij Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Kan het pad niet oplossen: item niet gevonden', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'Laden van zip.js mislukt', + 'ZIP_VENDOR_FAIL' : 'zip.js niet gevonden. Is het correct geladen?', + 'ZIP_NO_RESOURCE' : 'Geen zip bestand opgegeven', + 'ZIP_NO_PATH' : 'Geen pad opgegeven', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Pakket installatie map bestaat al. Kan niet verder gaan!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Kan het bestand niet openen', + 'ERR_FILE_APP_OPEN_FMT' : 'Het bestand {0} kan niet worden geopend {1} wordt niet ondersteund', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Het bestand {0} kan niet worden geopend: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Het bestand {0} kan niet worden opgeslagen: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Toepassing Fout', + 'ERR_GENERIC_APP_ACTION_FMT': 'Kan de actie \'{0}\' niet voltooien', + 'ERR_GENERIC_APP_UNKNOWN' : 'Onbekende Fout', + 'ERR_GENERIC_APP_REQUEST' : 'Er is een fout opgetreden tijdens het afhandelen van dit verzoek', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatale Fout: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Wijzigingen ongedaan maken?', + 'MSG_FILE_CHANGED' : 'Het bestand is gewijzigd. Opnieuw laden?', + 'MSG_APPLICATION_WARNING' : 'Waarschuwing', + 'MSG_MIME_OVERRIDE' : 'Het bestandstype "{0}" wordt niet ondersteund, suggestie: "{1}"', + + // + // General + // + + 'LBL_UNKNOWN' : 'Onbekend', + 'LBL_APPEARANCE' : 'Weergave', + 'LBL_USER' : 'Gebruiker', + 'LBL_NAME' : 'Naam', + 'LBL_APPLY' : 'Bevestigen', + 'LBL_FILENAME' : 'Bestandsnaam', + 'LBL_PATH' : 'Map', + 'LBL_SIZE' : 'Grootte', + 'LBL_TYPE' : 'Type', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Laden', + 'LBL_SETTINGS' : 'Instellingen', + 'LBL_ADD_FILE' : 'Bestand toevoegen', + 'LBL_COMMENT' : 'Opmerking', + 'LBL_ACCOUNT' : 'Account', + 'LBL_CONNECT' : 'Verbinden', + 'LBL_ONLINE' : 'Verbonden', + 'LBL_OFFLINE' : 'Verbroken', + 'LBL_AWAY' : 'Afwezig', + 'LBL_BUSY' : 'Bezig', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Help', + 'LBL_ABOUT' : 'Over', + 'LBL_PANELS' : 'Panelen', + 'LBL_LOCALES' : 'Talen', + 'LBL_THEME' : 'Thema', + 'LBL_COLOR' : 'Kleur', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Stop', + 'LBL_ALIVE' : 'Aktief', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Toevoegen', + 'LBL_FONT' : 'Lettertype', + 'LBL_YES' : 'Ja', + 'LBL_NO' : 'Nee', + 'LBL_CANCEL' : 'Annuleren', + 'LBL_TOP' : 'Boven', + 'LBL_LEFT' : 'Links', + 'LBL_RIGHT' : 'Rechts', + 'LBL_BOTTOM' : 'Onder', + 'LBL_CENTER' : 'Midden', + 'LBL_FILE' : 'Bestand', + 'LBL_NEW' : 'Nieuw', + 'LBL_OPEN' : 'Open', + 'LBL_SAVE' : 'Opslaan', + 'LBL_SAVEAS' : 'opslaan als...', + 'LBL_CLOSE' : 'Sluiten', + 'LBL_MKDIR' : 'Nieuwe map maken', + 'LBL_UPLOAD' : 'Uploaden', + 'LBL_VIEW' : 'Beeld', + 'LBL_EDIT' : 'Bewerken', + 'LBL_RENAME' : 'Hernoemen', + 'LBL_DELETE' : 'Verwijderen', + 'LBL_OPENWITH' : 'Openen met ...', + 'LBL_ICONVIEW' : 'Icoon weergave', + 'LBL_TREEVIEW' : 'Boom weergave', + 'LBL_LISTVIEW' : 'Lijst weergave', + 'LBL_REFRESH' : 'Verversen', + 'LBL_VIEWTYPE' : 'Weergave type', + 'LBL_BOLD' : 'Vet', + 'LBL_ITALIC' : 'Schuin', + 'LBL_UNDERLINE' : 'Onderstreept', + 'LBL_REGULAR' : 'Normaal', + 'LBL_STRIKE' : 'Doorgehaald', + 'LBL_INDENT' : 'Inspringen', + 'LBL_OUTDENT' : 'Uitspringen', + 'LBL_UNDO' : 'Ongedaan maken', + 'LBL_REDO' : 'Ongedaan maken herstellen', + 'LBL_CUT' : 'Knip', + 'LBL_UNLINK' : 'Unlink', + 'LBL_COPY' : 'Kopieren', + 'LBL_PASTE' : 'Plakken', + 'LBL_INSERT' : 'Invoegen', + 'LBL_IMAGE' : 'Afbeelding', + 'LBL_LINK' : 'Link', + 'LBL_DISCONNECT' : 'Verbreken', + 'LBL_APPLICATIONS' : 'Toepassingen', + 'LBL_ADD_FOLDER' : 'Map toevoegen', + 'LBL_INFORMATION' : 'Informatie', + 'LBL_TEXT_COLOR' : 'Tekst kleur', + 'LBL_BACK_COLOR' : 'Achtergrond kleur', + 'LBL_RESET_DEFAULT' : 'Standaard instelling terug zetten', + 'LBL_DOWNLOAD_COMP' : 'Downloaden naar je computer', + 'LBL_ORDERED_LIST' : 'Gesorteerde lijst', + 'LBL_BACKGROUND_IMAGE' : 'Achtergrond afbeelding', + 'LBL_BACKGROUND_COLOR' : 'Achtergrond kleur', + 'LBL_UNORDERED_LIST' : 'Ongesorteerde lijst', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Alleen lezen', + 'LBL_CREATED' : 'Aangemaakt', + 'LBL_MODIFIED' : 'Gewijzigd', + 'LBL_SHOW_COLUMNS' : 'Kolommen tonen', + 'LBL_MOVE' : 'Verplaats', + 'LBL_OPTIONS' : 'Opties', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Map', + 'LBL_CREATE' : 'Aanmaken', + 'LBL_BUGREPORT' : 'Bugreport', + 'LBL_INSTALL' : 'Installeer', + 'LBL_UPDATE' : 'Update', + 'LBL_REMOVE' : 'Verwijder', + 'LBL_SHOW_SIDEBAR' : 'Zijbar tonen', + 'LBL_SHOW_NAVIGATION' : 'Navigatie tonen', + 'LBL_SHOW_HIDDENFILES' : 'Laat verborgen bestanden zien', + 'LBL_SHOW_FILEEXTENSIONS' : 'Toon bestandsextensies', + 'LBL_MOUNT': 'Koppelen', + 'LBL_DESCRIPTION': 'Omschrijving', + 'LBL_USERNAME': 'Gebruikersnaam', + 'LBL_PASSWORD': 'Wachtwoord', + 'LBL_HOST': 'Host', + 'LBL_NAMESPACE': 'Namespace', + 'LBL_BACKGROUND' : 'Achtergrond', + 'LBL_DESKTOP' : 'Bureaublad', + 'LBL_PANEL' : 'Paneel', + 'LBL_POSITION' : 'Positie', + 'LBL_ONTOP' : 'Voorgrond', + 'LBL_ITEMS' : 'Items', + 'LBL_GENERAL': 'Algemeen' + +}; diff --git a/src/client/javascript/locales/no_NO.js b/src/client/javascript/locales/no_NO.js index f7f1e2dc3f..bf73511af8 100644 --- a/src/client/javascript/locales/no_NO.js +++ b/src/client/javascript/locales/no_NO.js @@ -27,444 +27,442 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.no_NO = { - 'ERR_FILE_OPEN' : 'Feil ved åpning av fil', - 'ERR_WM_NOT_RUNNING' : 'Window Manager kjører ikke', - 'ERR_FILE_OPEN_FMT' : 'Filen \'**{0}**\' kunne ikke bli åpnet', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Fant ingen Applikasjoner som støtter \'{0}\' filer', - 'ERR_APP_LAUNCH_FAILED' : 'Klarte ikke starte Applikasjon', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'En feil oppstod ved oppstart av: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Applikasjonen \'{0}\' construct feilet: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Applikasjonen \'{0}\' init() feilet: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Applikasjonen ressursjer mangler for \'{0}\', eller de feilet under lasting!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Applikasjonen \'{0}\' preloading feilet: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Applikasjonen \'{0}\' kjører allerede og bare en instans er tillatt!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Manifest ble ikke funnet!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Nettleseren din støtter ikke: {1}', - - 'ERR_NO_WM_RUNNING' : 'Window Manager kjører ikke', - 'ERR_CORE_INIT_FAILED' : 'Klarte ikke starte OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'En feil oppstod under oppstart av OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Kan ikke starte OS.js: Ingen window manager definert!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Kan ikke starte OS.js: Window Manager startet ikke: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Kan ikke starte OS.js: Feil under forhåndslasting...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Feilrapport', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'En uventet feil eller bug oppstod.', - - 'ERR_APP_API_ERROR' : 'Applikasjon API feil', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Applikasjon {0} feilet under operasjonen \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Mangler argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Ukjent feil', - - 'ERR_OPERATION_TIMEOUT' : 'Tidsavbrudd i operasjon', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Tidsavbrudd i operasjon ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' expects \'{1}\' to be a \'{2}\', \'{3}\' given', - 'ERR_INVALID_LOCATION': 'Ugyldig plassering', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Du har allerede et Window med navnet \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimiser', - 'WINDOW_MAXIMIZE' : 'Maksimer', - 'WINDOW_RESTORE' : 'Gjenopprett', - 'WINDOW_CLOSE' : 'Lukk', - 'WINDOW_ONTOP_ON' : 'På topp (På)', - 'WINDOW_ONTOP_OFF': 'På topp (Av)', - - // Handler - 'TITLE_SIGN_OUT' : 'Logg ut', - 'TITLE_SIGNED_IN_AS_FMT' : 'Logget inn som: {0}', - 'ERR_LOGIN_FMT' : 'Login feil: {0}', - 'ERR_LOGIN_INVALID' : 'Ugyldig innlogging', - - // SESSION - 'ERR_NO_SESSION': 'Ingen sessjon er aktiv. Vil du laste på nytt?', - 'MSG_SESSION_WARNING' : 'Er du sikker på at du vil avslutte OS.js? Du vil tape alle ulagrede data!', - - // Service - 'BUGREPORT_MSG' : 'Vennligst rapporter dette problemet hvis du tror det er en feil.\nLegg ved en beskrivelse om hvordan problemet oppstod og hvordan man kan reprodusere feilen.', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Innloget i eksterne tjenester: {0}', - 'CONNECTION_LOST': 'Kobling til tjener ble brutt. Gjenoppretter...', - 'CONNECTION_RESTORED': 'Kobling til tjener ble gjenopprettet', - 'CONNECTION_RESTORE_FAILED': 'Klarte ikke koble til tjener. Prøver på nytt', - 'CONNECTION_ERROR': 'Tilkoblingsfeil', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Fatal Feil', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Feil: {0}', - - // Dialogs - 'DIALOG_LOGOUT_TITLE' : 'Logg ut (Avslutt)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Logger ut bruker \'{0}\'.\nVil du lagre gjeldende sessjon?', - - 'DIALOG_CLOSE' : 'Lukk', - 'DIALOG_CANCEL': 'Avbryt', - 'DIALOG_APPLY' : 'Angi', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Advarsel Dialog', - - 'DIALOG_COLOR_TITLE' : 'Farge Dialog', - 'DIALOG_COLOR_R' : 'Rød: {0}', - 'DIALOG_COLOR_G' : 'Grønn: {0}', - 'DIALOG_COLOR_B' : 'Blå: {0}', - 'DIALOG_COLOR_A' : 'Alfa: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Bekreft Dialog', - - 'DIALOG_ERROR_MESSAGE' : 'Beskjed', - 'DIALOG_ERROR_SUMMARY' : 'Oppsummering', - 'DIALOG_ERROR_TRACE' : 'Trace', - 'DIALOG_ERROR_BUGREPORT' : 'Bugreport', - - 'DIALOG_FILE_SAVE' : 'Lagre', - 'DIALOG_FILE_OPEN' : 'Åpne', - 'DIALOG_FILE_MKDIR' : 'Ny Mappe', - 'DIALOG_FILE_MKDIR_MSG' : 'Lage ny mappe i **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Vil du overskrive filen \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Visningstype', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste-visning', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Tre-visining', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikon-visning', - 'DIALOG_FILE_ERROR' : 'FileDialog Error', - 'DIALOG_FILE_ERROR_SCANDIR': 'Klarte ikke liste innhold for mappen \'{0}\' fordi en feil oppstod', - 'DIALOG_FILE_ERROR_FIND': 'Klarte ikke søke i mappen \'{0}\' fordi en feil oppstod', - 'DIALOG_FILE_MISSING_FILENAME' : 'Du må velge en fil eller skrive inn filnavn!', - 'DIALOG_FILE_MISSING_SELECTION': 'Du må velge en fil!', - - 'DIALOG_FILEINFO_TITLE' : 'Fil Informasion', - 'DIALOG_FILEINFO_LOADING' : 'Laste informasjon for filen: {0}', - 'DIALOG_FILEINFO_ERROR' : 'FileInformationDialog Feil', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Klarte ikke hente informasjon for filen **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Klarte ikke hente informasjon for filen: {0}', - - 'DIALOG_INPUT_TITLE' : 'Inndata Dialog', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Fil-operasjon fremgang', - 'DIALOG_FILEPROGRESS_LOADING' : 'Laster...', - - 'DIALOG_UPLOAD_TITLE' : 'Opplasting Dialog', - 'DIALOG_UPLOAD_DESC' : 'Opplasting fil til **{0}**.
Maksimum størrelse: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Laster opp \'{0}\' ({1} {2}) til {3}', - 'DIALOG_UPLOAD_MSG' : 'Laster opp fil...', - 'DIALOG_UPLOAD_FAILED' : 'Opplasting feilet', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Opplastingen feilet', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Ukjent årsak...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Avbrutt av bruker...', - 'DIALOG_UPLOAD_TOO_BIG': 'Fil er for stor', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Fil er for stor, større en {0}', - - 'DIALOG_FONT_TITLE' : 'Tekst Dialog', - - 'DIALOG_APPCHOOSER_TITLE' : 'Velg Applikasjon', - 'DIALOG_APPCHOOSER_MSG' : 'Velg en applikasjon for åpning', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Du må velge en applikasjon', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Bruk som standard for {0}', - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Modul dekativert eller ikke konfigurert', - 'GAPI_SIGN_OUT' : 'Logg ut av Google API Services', - 'GAPI_REVOKE' : 'Tilbakekall tillatelse og Logg ut', - 'GAPI_AUTH_FAILURE' : 'Google API autentisering feilet eller tok ikke sted', - 'GAPI_AUTH_FAILURE_FMT' : 'Klarte ikke autentisere: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Klarte ikke laste Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API Modul deaktivert eller ikke konfigurert', - 'WLAPI_SIGN_OUT' : 'Logg ut av Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Klarte ikke laste Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Klarte ikke logge inn Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Klarte ikke logge inn Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returnerte {0} status', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Kan ikke opprette IndexedDB uten databasenavn', - 'IDB_NO_SUCH_ITEM' : 'Item ble ikke funnet', - - // VFS - 'ERR_VFS_FATAL' : 'Fatal Feil', - 'ERR_VFS_UNAVAILABLE' : 'Ikke tilgjenglig', - 'ERR_VFS_FILE_ARGS' : 'File forventer minst èt argument', - 'ERR_VFS_NUM_ARGS' : 'Ikke not argumenter', - 'ERR_VFS_EXPECT_FILE' : 'Forventer èt Fil-objekt', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Forventer èt kilde Fil-objekt', - 'ERR_VFS_EXPECT_DST_FILE' : 'Forventer èt destinasjon Fil-objekt', - 'ERR_VFS_FILE_EXISTS' : 'Destinasjonen finnes allerede', - 'ERR_VFS_TARGET_NOT_EXISTS': 'Destinasjon finnes ikke', - 'ERR_VFS_TRANSFER_FMT' : 'En feil oppstod under overføring av filen: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Kan ikke laste opp uten destinasjon', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Kan ikke laste opp uten noen filer definert', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Fil-opplasting feilet: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Fil-opplastingen ble avbrutt', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kan ikke laste ned uten en sti', - 'ERR_VFS_DOWNLOAD_FAILED' : 'En feil oppstod under nedlasting: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY' : 'Respons var tom', - 'ERR_VFS_NO_MIME_DETECT' : 'Ingen mime-type gjenkjent', - - 'ERR_VFSMODULE_INVALID' : 'Ugyldig VFS Modul', - 'ERR_VFSMODULE_INVALID_FMT' : 'Ugyldig VFS Modul: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Ugyldig VFS Metode', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Ugyldig VFS Metode: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Ugyldig VFS Modul type', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Ugyldig VFS Modul type: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Ugyldig VFS Modul konfigurasjon', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Ugyldig VFS Modul konfigurasjon: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Modul allerede montert', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Modul \'{0}\' allerede montert', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Modul ikke montert', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Modul \'{0}\' ikke montert', - 'ERR_VFSMODULE_EXCEPTION' : 'VFS Modul Exception', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Modul Exception: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Ingen VFS Modul lik {0}. Fil sti eller format ?', - 'ERR_VFSMODULE_READONLY' : 'VFS Modul er bare lesbar', - 'ERR_VFSMODULE_READONLY_FMT' : 'VFS Modul er bare lesbar: {0}', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Laster ned fil', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Feil', - 'ERR_VFSMODULE_ROOT_ID' : 'Klarte ikke hente id for rotmappe', - 'ERR_VFSMODULE_NOSUCH' : 'Filen eksister ikke', - 'ERR_VFSMODULE_PARENT' : 'Parent finnes ikke', - 'ERR_VFSMODULE_PARENT_FMT' : 'Klarte ikke lete opp parent: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Klarte ikke skanne mappe', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Klarte ikke skanne mappe: {0}', - 'ERR_VFSMODULE_READ' : 'Klarte ikke lese fil', - 'ERR_VFSMODULE_READ_FMT' : 'Klarte ikke lese fil: {0}', - 'ERR_VFSMODULE_WRITE' : 'Klarte ikke skrive fil', - 'ERR_VFSMODULE_WRITE_FMT' : 'Klarte ikke skrive fil: {0}', - 'ERR_VFSMODULE_COPY' : 'Klarte ikke kopiere', - 'ERR_VFSMODULE_COPY_FMT' : 'Klarte ikke kopiere: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Klarte ikke slette fil', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Klarte ikke slette fil: {0}', - 'ERR_VFSMODULE_MOVE' : 'Klarte ikke flytte fil', - 'ERR_VFSMODULE_MOVE_FMT' : 'Klarte ikke flytte fil: {0}', - 'ERR_VFSMODULE_EXIST' : 'Klarte ikke sjekke om fil eksisterer', - 'ERR_VFSMODULE_EXIST_FMT' : 'Klarte ikke sjekke om fil eksisterer: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Klarte ikke hente fil-informasjon', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Klarte ikke hente fil-informasjon: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Klarte ikke lage mappe', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Klarte ikke lage mapp: {0}', - 'ERR_VFSMODULE_MKFILE' : 'Klarte ikke lage fil', - 'ERR_VFSMODULE_MKFILE_FMT' : 'Klarte ikke lage fil: {0}', - 'ERR_VFSMODULE_URL' : 'Klarte ikke hente URL for fil', - 'ERR_VFSMODULE_URL_FMT' : 'Klarte ikke hente URL for fil: {0}', - 'ERR_VFSMODULE_TRASH' : 'Klarte ikke flytte fil til søppelkassen', - 'ERR_VFSMODULE_TRASH_FMT' : 'Klarte ikke flytte fil til søppelkassen: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Klarte ikke flytte fil ut av søppelkassen', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Klarte ikke flytte fil ut av søppelkassen: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Klarte ikke tømme søppel', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Klarte ikke tømme søppel: {0}', - 'ERR_VFSMODULE_FIND' : 'Klarte ikke søke', - 'ERR_VFSMODULE_FIND_FMT' : 'Klarte ikke søke: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'Klarte ikke hente ledig plass', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'Klarte ikke hente ledig plass: {0}', - 'ERR_VFSMODULE_EXISTS' : 'Klarte ikke sjekke destinasjon', - 'ERR_VFSMODULE_EXISTS_FMT' : 'Klarte ikke check sjekke destinasjon: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Du er logget inn i Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Logg ut fra Dropbox API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Klarte ikke løse sti: fant ikke filen', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'Klarte ikke laste zip.js', - 'ZIP_VENDOR_FAIL' : 'zip.js bliblioteket ble ikke funnet!', - 'ZIP_NO_RESOURCE' : 'Ingen zip ressursj angitt', - 'ZIP_NO_PATH' : 'Ingen sti angitt', - - // SearchEngine - 'SEARCH_LOADING': 'Søker...', - 'SEARCH_NO_RESULTS': 'Ingen resultater', - - // PackageManager - 'ERR_PACKAGE_EXISTS': 'Kan ikke fortsette. Pakkedestinasjonen finnes allerede!', - - // DefaultApplication - 'ERR_FILE_APP_OPEN' : 'Kan ikke åpne filen', - 'ERR_FILE_APP_OPEN_FMT' : 'Filen {0} ble ikke åpnet fordi MIME {1} ikke er støttet', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Filen {0} ble ikke åpnet: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Filen {0} ble ikke lagret: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Applikasjon Feil', - 'ERR_GENERIC_APP_ACTION_FMT': 'Klarte ikke utføre operasjon \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Ukjent feil', - 'ERR_GENERIC_APP_REQUEST' : 'En feil oppstod under håndteringen av din forespursel', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatal Feil: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Forkast endringer?', - 'MSG_FILE_CHANGED' : 'Filen har blitt endret. Last inn på nytt?', - 'MSG_APPLICATION_WARNING' : 'Applikasjon-advarsel', - 'MSG_MIME_OVERRIDE' : 'Filtypen "{0}" er ikke støttet, bruker "{1}" istedet.', - - 'ERR_OPEN_LOCATION' : 'Klarte ikke åpne sti', - 'ERR_OPEN_LOCATION_FMT' : 'Klarte ikke åpne sti: {0}', - - // General - - 'LBL_UNKNOWN' : 'Ukjent', - 'LBL_APPEARANCE' : 'Utseende', - 'LBL_USER' : 'Bruker', - 'LBL_NAME' : 'Navn', - 'LBL_APPLY' : 'Angi', - 'LBL_FILENAME' : 'Filnavn', - 'LBL_PATH' : 'Sti', - 'LBL_SIZE' : 'Størrelse', - 'LBL_TYPE' : 'Type', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Laster', - 'LBL_SETTINGS' : 'Instillinger', - 'LBL_ADD_FILE' : 'Legg til fil', - 'LBL_COMMENT' : 'Kommenter', - 'LBL_ACCOUNT' : 'Konto', - 'LBL_CONNECT' : 'Koble til', - 'LBL_ONLINE' : 'Online', - 'LBL_OFFLINE' : 'Offline', - 'LBL_AWAY' : 'Borte', - 'LBL_BUSY' : 'Opptatt', - 'LBL_CHAT' : 'Snakk', - 'LBL_HELP' : 'Hjelp', - 'LBL_ABOUT' : 'Om', - 'LBL_PANELS' : 'Paneler', - 'LBL_LOCALES' : 'Lokalisering', - 'LBL_THEME' : 'Temaer', - 'LBL_COLOR' : 'Farge', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Drep', - 'LBL_ALIVE' : 'I live', - 'LBL_INDEX' : 'Indeks', - 'LBL_ADD' : 'Legg til', - 'LBL_FONT' : 'Skrift', - 'LBL_YES' : 'Ja', - 'LBL_NO' : 'Nei', - 'LBL_CANCEL' : 'Avbryt', - 'LBL_TOP' : 'Topp', - 'LBL_LEFT' : 'Venstre', - 'LBL_RIGHT' : 'Høyre', - 'LBL_BOTTOM' : 'Bunn', - 'LBL_CENTER' : 'Midt', - 'LBL_FILE' : 'Fil', - 'LBL_NEW' : 'Ny', - 'LBL_OPEN' : 'Åpne', - 'LBL_SAVE' : 'Lagre', - 'LBL_SAVEAS' : 'Lagre som...', - 'LBL_CLOSE' : 'Lukk', - 'LBL_MKDIR' : 'Lag Mappe', - 'LBL_UPLOAD' : 'Last opp', - 'LBL_VIEW' : 'Visning', - 'LBL_EDIT' : 'Rediger', - 'LBL_RENAME' : 'Navngi', - 'LBL_DELETE' : 'Slett', - 'LBL_OPENWITH' : 'Åpne Med ...', - 'LBL_ICONVIEW' : 'Ikon-visning', - 'LBL_TREEVIEW' : 'Tre-visning', - 'LBL_LISTVIEW' : 'Liste-visning', - 'LBL_REFRESH' : 'Gjennoppfrisk', - 'LBL_VIEWTYPE' : 'Visningstype', - 'LBL_BOLD' : 'Feit', - 'LBL_ITALIC' : 'Skeiv', - 'LBL_UNDERLINE' : 'Underlinjet', - 'LBL_REGULAR' : 'Normal', - 'LBL_STRIKE' : 'Gjennomstrøk', - 'LBL_INDENT' : 'Innrykk', - 'LBL_OUTDENT' : 'Utrykk', - 'LBL_UNDO' : 'Angre', - 'LBL_REDO' : 'Gjør om igjen', - 'LBL_CUT' : 'Kutt', - 'LBL_UNLINK' : 'Fjern lenke', - 'LBL_COPY' : 'Kopier', - 'LBL_PASTE' : 'Lim inn', - 'LBL_INSERT' : 'Sett inn', - 'LBL_IMAGE' : 'Bilde', - 'LBL_LINK' : 'Lenke', - 'LBL_DISCONNECT' : 'Koble fra', - 'LBL_APPLICATIONS' : 'Applikasjoner', - 'LBL_ADD_FOLDER' : 'Legg til mappe', - 'LBL_INFORMATION' : 'Informasjon', - 'LBL_TEXT_COLOR' : 'Tekst-farge', - 'LBL_BACK_COLOR' : 'Bakgrunn-farge', - 'LBL_RESET_DEFAULT' : 'Omstill til standard', - 'LBL_DOWNLOAD_COMP' : 'Last ned til datamaskin', - 'LBL_ORDERED_LIST' : 'Ordnet liste', - 'LBL_BACKGROUND_IMAGE' : 'Bakgrunnsbilde', - 'LBL_BACKGROUND_COLOR' : 'Bakgrunnsfarge', - 'LBL_UNORDERED_LIST' : 'Uordnet Liste', - 'LBL_SHOW_SIDEBAR' : 'Vis Sidebar', - 'LBL_SEARCH': 'Søk', - 'LBL_STATUS': 'Status', - 'LBL_READONLY': 'Kun lesbar', - 'LBL_CREATED': 'Opprettet', - 'LBL_MODIFIED': 'Modifisert', - 'LBL_SHOW_COLUMNS': 'Vis Kolonner', - 'LBL_MOVE': 'Flytt', - 'LBL_OPTIONS': 'Opsjoner', - 'LBL_OK': 'OK', - 'LBL_DIRECTORY': 'Mappe', - 'LBL_CREATE': 'Opprett', - 'LBL_BUGREPORT': 'Bug-rapport', - 'LBL_INSTALL': 'Installer', - 'LBL_UPDATE': 'Oppdater', - 'LBL_REMOVE': 'Fjern', - 'LBL_SHOW_NAVIGATION': 'Vis navigasjon', - 'LBL_SHOW_HIDDENFILES': 'Vis skjulte filer', - 'LBL_SHOW_FILEEXTENSIONS': 'Vis fil-utvidelser', - 'LBL_MOUNT': 'Montere', - 'LBL_DESCRIPTION': 'Beskrivelse', - 'LBL_USERNAME': 'Brukernavn', - 'LBL_PASSWORD': 'Passord', - 'LBL_HOST': 'Vert', - 'LBL_NAMESPACE': 'Navneplass', - 'LBL_BACK': 'Tilbake', - 'LBL_ICONS': 'Ikoner', - 'LBL_ICON': 'Ikon', - 'LBL_UNINSTALL': 'Avinstaller', - 'LBL_REGENERATE': 'Regenerer', - 'LBL_DESKTOP': 'Skrivebord', - 'LBL_WINDOWMANAGER': 'Vindu-håndterer', - 'LBL_HOTKEY': 'Snarknapp', - 'LBL_HOTKEYS': 'Snarknapper', - 'LBL_MOUNTS': 'Monteringer', - 'LBL_ID': 'ID', - 'LBL_APPLICATION': 'Applikasjon', - 'LBL_SCOPE': 'Skop', - 'LBL_HIDE': 'Skjul', - 'LBL_REPOSITORY': 'Repository', - 'LBL_VERSION': 'Versjon', - 'LBL_AUTHOR': 'Forfatter', - 'LBL_GROUPS': 'Grupper', - 'LBL_AUTOHIDE': 'Auto-skjul', - 'LBL_PERSONAL': 'Personlig', - 'LBL_SYSTEM': 'System', - 'LBL_STARTING': 'Starter', - 'LBL_SOUNDS': 'Lyder', - 'LBL_STORE': 'Butikk', - 'LBL_LOCALE': 'Språkvalg', - 'LBL_PACKAGE': 'Pakke', - 'LBL_PACKAGES': 'Pakker', - 'LBL_INPUT': 'Inndata', - 'LBL_MISC': 'Annet', - 'LBL_OTHER': 'Annet', - 'LBL_USERS': 'Brukere', - 'LBL_FONTS': 'Skrift', - 'LBL_BACKGROUND' : 'Bakgrunn', - 'LBL_PANEL' : 'Panel', - 'LBL_POSITION' : 'Posisjon', - 'LBL_OPACITY' : 'Gjennomsiktighet', - 'LBL_ONTOP' : 'Topp', - 'LBL_ITEMS' : 'Objekter', - 'LBL_GENERAL' : 'Generelt', - 'LBL_LOCK': 'Lås', - 'LBL_UNLOCK': 'Lås opp', - 'LBL_OPEN_LOCATION': 'Åpne sti', - 'LBL_HOME': 'Hjem', - 'LBL_WIDGET': 'Widget', - 'LBL_WIDGETS': 'Widgets', - 'LBL_WARNING': 'Advarsel', - 'LBL_INFO': 'Info' - }; -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + 'ERR_FILE_OPEN' : 'Feil ved åpning av fil', + 'ERR_WM_NOT_RUNNING' : 'Window Manager kjører ikke', + 'ERR_FILE_OPEN_FMT' : 'Filen \'**{0}**\' kunne ikke bli åpnet', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Fant ingen Applikasjoner som støtter \'{0}\' filer', + 'ERR_APP_LAUNCH_FAILED' : 'Klarte ikke starte Applikasjon', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'En feil oppstod ved oppstart av: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Applikasjonen \'{0}\' construct feilet: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Applikasjonen \'{0}\' init() feilet: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Applikasjonen ressursjer mangler for \'{0}\', eller de feilet under lasting!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Applikasjonen \'{0}\' preloading feilet: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Applikasjonen \'{0}\' kjører allerede og bare en instans er tillatt!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Manifest ble ikke funnet!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Klarte ikke starte \'{0}\'. Nettleseren din støtter ikke: {1}', + + 'ERR_NO_WM_RUNNING' : 'Window Manager kjører ikke', + 'ERR_CORE_INIT_FAILED' : 'Klarte ikke starte OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'En feil oppstod under oppstart av OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Kan ikke starte OS.js: Ingen window manager definert!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Kan ikke starte OS.js: Window Manager startet ikke: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Kan ikke starte OS.js: Feil under forhåndslasting...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Feilrapport', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'En uventet feil eller bug oppstod.', + + 'ERR_APP_API_ERROR' : 'Applikasjon API feil', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Applikasjon {0} feilet under operasjonen \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Mangler argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Ukjent feil', + + 'ERR_OPERATION_TIMEOUT' : 'Tidsavbrudd i operasjon', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Tidsavbrudd i operasjon ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' expects \'{1}\' to be a \'{2}\', \'{3}\' given', + 'ERR_INVALID_LOCATION': 'Ugyldig plassering', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Du har allerede et Window med navnet \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimiser', + 'WINDOW_MAXIMIZE' : 'Maksimer', + 'WINDOW_RESTORE' : 'Gjenopprett', + 'WINDOW_CLOSE' : 'Lukk', + 'WINDOW_ONTOP_ON' : 'På topp (På)', + 'WINDOW_ONTOP_OFF': 'På topp (Av)', + + // Handler + 'TITLE_SIGN_OUT' : 'Logg ut', + 'TITLE_SIGNED_IN_AS_FMT' : 'Logget inn som: {0}', + 'ERR_LOGIN_FMT' : 'Login feil: {0}', + 'ERR_LOGIN_INVALID' : 'Ugyldig innlogging', + + // SESSION + 'ERR_NO_SESSION': 'Ingen sessjon er aktiv. Vil du laste på nytt?', + 'MSG_SESSION_WARNING' : 'Er du sikker på at du vil avslutte OS.js? Du vil tape alle ulagrede data!', + + // Service + 'BUGREPORT_MSG' : 'Vennligst rapporter dette problemet hvis du tror det er en feil.\nLegg ved en beskrivelse om hvordan problemet oppstod og hvordan man kan reprodusere feilen.', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Innloget i eksterne tjenester: {0}', + 'CONNECTION_LOST': 'Kobling til tjener ble brutt. Gjenoppretter...', + 'CONNECTION_RESTORED': 'Kobling til tjener ble gjenopprettet', + 'CONNECTION_RESTORE_FAILED': 'Klarte ikke koble til tjener. Prøver på nytt', + 'CONNECTION_ERROR': 'Tilkoblingsfeil', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Fatal Feil', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Feil: {0}', + + // Dialogs + 'DIALOG_LOGOUT_TITLE' : 'Logg ut (Avslutt)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Logger ut bruker \'{0}\'.\nVil du lagre gjeldende sessjon?', + + 'DIALOG_CLOSE' : 'Lukk', + 'DIALOG_CANCEL': 'Avbryt', + 'DIALOG_APPLY' : 'Angi', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Advarsel Dialog', + + 'DIALOG_COLOR_TITLE' : 'Farge Dialog', + 'DIALOG_COLOR_R' : 'Rød: {0}', + 'DIALOG_COLOR_G' : 'Grønn: {0}', + 'DIALOG_COLOR_B' : 'Blå: {0}', + 'DIALOG_COLOR_A' : 'Alfa: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Bekreft Dialog', + + 'DIALOG_ERROR_MESSAGE' : 'Beskjed', + 'DIALOG_ERROR_SUMMARY' : 'Oppsummering', + 'DIALOG_ERROR_TRACE' : 'Trace', + 'DIALOG_ERROR_BUGREPORT' : 'Bugreport', + + 'DIALOG_FILE_SAVE' : 'Lagre', + 'DIALOG_FILE_OPEN' : 'Åpne', + 'DIALOG_FILE_MKDIR' : 'Ny Mappe', + 'DIALOG_FILE_MKDIR_MSG' : 'Lage ny mappe i **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Vil du overskrive filen \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Visningstype', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste-visning', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Tre-visining', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikon-visning', + 'DIALOG_FILE_ERROR' : 'FileDialog Error', + 'DIALOG_FILE_ERROR_SCANDIR': 'Klarte ikke liste innhold for mappen \'{0}\' fordi en feil oppstod', + 'DIALOG_FILE_ERROR_FIND': 'Klarte ikke søke i mappen \'{0}\' fordi en feil oppstod', + 'DIALOG_FILE_MISSING_FILENAME' : 'Du må velge en fil eller skrive inn filnavn!', + 'DIALOG_FILE_MISSING_SELECTION': 'Du må velge en fil!', + + 'DIALOG_FILEINFO_TITLE' : 'Fil Informasion', + 'DIALOG_FILEINFO_LOADING' : 'Laste informasjon for filen: {0}', + 'DIALOG_FILEINFO_ERROR' : 'FileInformationDialog Feil', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Klarte ikke hente informasjon for filen **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Klarte ikke hente informasjon for filen: {0}', + + 'DIALOG_INPUT_TITLE' : 'Inndata Dialog', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Fil-operasjon fremgang', + 'DIALOG_FILEPROGRESS_LOADING' : 'Laster...', + + 'DIALOG_UPLOAD_TITLE' : 'Opplasting Dialog', + 'DIALOG_UPLOAD_DESC' : 'Opplasting fil til **{0}**.
Maksimum størrelse: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Laster opp \'{0}\' ({1} {2}) til {3}', + 'DIALOG_UPLOAD_MSG' : 'Laster opp fil...', + 'DIALOG_UPLOAD_FAILED' : 'Opplasting feilet', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Opplastingen feilet', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Ukjent årsak...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Avbrutt av bruker...', + 'DIALOG_UPLOAD_TOO_BIG': 'Fil er for stor', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Fil er for stor, større en {0}', + + 'DIALOG_FONT_TITLE' : 'Tekst Dialog', + + 'DIALOG_APPCHOOSER_TITLE' : 'Velg Applikasjon', + 'DIALOG_APPCHOOSER_MSG' : 'Velg en applikasjon for åpning', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Du må velge en applikasjon', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Bruk som standard for {0}', + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Modul dekativert eller ikke konfigurert', + 'GAPI_SIGN_OUT' : 'Logg ut av Google API Services', + 'GAPI_REVOKE' : 'Tilbakekall tillatelse og Logg ut', + 'GAPI_AUTH_FAILURE' : 'Google API autentisering feilet eller tok ikke sted', + 'GAPI_AUTH_FAILURE_FMT' : 'Klarte ikke autentisere: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Klarte ikke laste Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API Modul deaktivert eller ikke konfigurert', + 'WLAPI_SIGN_OUT' : 'Logg ut av Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Klarte ikke laste Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Klarte ikke logge inn Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Klarte ikke logge inn Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API returnerte {0} status', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Kan ikke opprette IndexedDB uten databasenavn', + 'IDB_NO_SUCH_ITEM' : 'Item ble ikke funnet', + + // VFS + 'ERR_VFS_FATAL' : 'Fatal Feil', + 'ERR_VFS_UNAVAILABLE' : 'Ikke tilgjenglig', + 'ERR_VFS_FILE_ARGS' : 'File forventer minst èt argument', + 'ERR_VFS_NUM_ARGS' : 'Ikke not argumenter', + 'ERR_VFS_EXPECT_FILE' : 'Forventer èt Fil-objekt', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Forventer èt kilde Fil-objekt', + 'ERR_VFS_EXPECT_DST_FILE' : 'Forventer èt destinasjon Fil-objekt', + 'ERR_VFS_FILE_EXISTS' : 'Destinasjonen finnes allerede', + 'ERR_VFS_TARGET_NOT_EXISTS': 'Destinasjon finnes ikke', + 'ERR_VFS_TRANSFER_FMT' : 'En feil oppstod under overføring av filen: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Kan ikke laste opp uten destinasjon', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Kan ikke laste opp uten noen filer definert', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Fil-opplasting feilet: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Fil-opplastingen ble avbrutt', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Kan ikke laste ned uten en sti', + 'ERR_VFS_DOWNLOAD_FAILED' : 'En feil oppstod under nedlasting: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY' : 'Respons var tom', + 'ERR_VFS_NO_MIME_DETECT' : 'Ingen mime-type gjenkjent', + + 'ERR_VFSMODULE_INVALID' : 'Ugyldig VFS Modul', + 'ERR_VFSMODULE_INVALID_FMT' : 'Ugyldig VFS Modul: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Ugyldig VFS Metode', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Ugyldig VFS Metode: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Ugyldig VFS Modul type', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Ugyldig VFS Modul type: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Ugyldig VFS Modul konfigurasjon', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Ugyldig VFS Modul konfigurasjon: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'VFS Modul allerede montert', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'VFS Modul \'{0}\' allerede montert', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'VFS Modul ikke montert', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'VFS Modul \'{0}\' ikke montert', + 'ERR_VFSMODULE_EXCEPTION' : 'VFS Modul Exception', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'VFS Modul Exception: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Ingen VFS Modul lik {0}. Fil sti eller format ?', + 'ERR_VFSMODULE_READONLY' : 'VFS Modul er bare lesbar', + 'ERR_VFSMODULE_READONLY_FMT' : 'VFS Modul er bare lesbar: {0}', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Laster ned fil', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Feil', + 'ERR_VFSMODULE_ROOT_ID' : 'Klarte ikke hente id for rotmappe', + 'ERR_VFSMODULE_NOSUCH' : 'Filen eksister ikke', + 'ERR_VFSMODULE_PARENT' : 'Parent finnes ikke', + 'ERR_VFSMODULE_PARENT_FMT' : 'Klarte ikke lete opp parent: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Klarte ikke skanne mappe', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Klarte ikke skanne mappe: {0}', + 'ERR_VFSMODULE_READ' : 'Klarte ikke lese fil', + 'ERR_VFSMODULE_READ_FMT' : 'Klarte ikke lese fil: {0}', + 'ERR_VFSMODULE_WRITE' : 'Klarte ikke skrive fil', + 'ERR_VFSMODULE_WRITE_FMT' : 'Klarte ikke skrive fil: {0}', + 'ERR_VFSMODULE_COPY' : 'Klarte ikke kopiere', + 'ERR_VFSMODULE_COPY_FMT' : 'Klarte ikke kopiere: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Klarte ikke slette fil', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Klarte ikke slette fil: {0}', + 'ERR_VFSMODULE_MOVE' : 'Klarte ikke flytte fil', + 'ERR_VFSMODULE_MOVE_FMT' : 'Klarte ikke flytte fil: {0}', + 'ERR_VFSMODULE_EXIST' : 'Klarte ikke sjekke om fil eksisterer', + 'ERR_VFSMODULE_EXIST_FMT' : 'Klarte ikke sjekke om fil eksisterer: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Klarte ikke hente fil-informasjon', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Klarte ikke hente fil-informasjon: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Klarte ikke lage mappe', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Klarte ikke lage mapp: {0}', + 'ERR_VFSMODULE_MKFILE' : 'Klarte ikke lage fil', + 'ERR_VFSMODULE_MKFILE_FMT' : 'Klarte ikke lage fil: {0}', + 'ERR_VFSMODULE_URL' : 'Klarte ikke hente URL for fil', + 'ERR_VFSMODULE_URL_FMT' : 'Klarte ikke hente URL for fil: {0}', + 'ERR_VFSMODULE_TRASH' : 'Klarte ikke flytte fil til søppelkassen', + 'ERR_VFSMODULE_TRASH_FMT' : 'Klarte ikke flytte fil til søppelkassen: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Klarte ikke flytte fil ut av søppelkassen', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Klarte ikke flytte fil ut av søppelkassen: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Klarte ikke tømme søppel', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Klarte ikke tømme søppel: {0}', + 'ERR_VFSMODULE_FIND' : 'Klarte ikke søke', + 'ERR_VFSMODULE_FIND_FMT' : 'Klarte ikke søke: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'Klarte ikke hente ledig plass', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'Klarte ikke hente ledig plass: {0}', + 'ERR_VFSMODULE_EXISTS' : 'Klarte ikke sjekke destinasjon', + 'ERR_VFSMODULE_EXISTS_FMT' : 'Klarte ikke check sjekke destinasjon: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Du er logget inn i Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Logg ut fra Dropbox API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Klarte ikke løse sti: fant ikke filen', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'Klarte ikke laste zip.js', + 'ZIP_VENDOR_FAIL' : 'zip.js bliblioteket ble ikke funnet!', + 'ZIP_NO_RESOURCE' : 'Ingen zip ressursj angitt', + 'ZIP_NO_PATH' : 'Ingen sti angitt', + + // SearchEngine + 'SEARCH_LOADING': 'Søker...', + 'SEARCH_NO_RESULTS': 'Ingen resultater', + + // PackageManager + 'ERR_PACKAGE_EXISTS': 'Kan ikke fortsette. Pakkedestinasjonen finnes allerede!', + + // DefaultApplication + 'ERR_FILE_APP_OPEN' : 'Kan ikke åpne filen', + 'ERR_FILE_APP_OPEN_FMT' : 'Filen {0} ble ikke åpnet fordi MIME {1} ikke er støttet', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Filen {0} ble ikke åpnet: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Filen {0} ble ikke lagret: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Applikasjon Feil', + 'ERR_GENERIC_APP_ACTION_FMT': 'Klarte ikke utføre operasjon \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Ukjent feil', + 'ERR_GENERIC_APP_REQUEST' : 'En feil oppstod under håndteringen av din forespursel', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatal Feil: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Forkast endringer?', + 'MSG_FILE_CHANGED' : 'Filen har blitt endret. Last inn på nytt?', + 'MSG_APPLICATION_WARNING' : 'Applikasjon-advarsel', + 'MSG_MIME_OVERRIDE' : 'Filtypen "{0}" er ikke støttet, bruker "{1}" istedet.', + + 'ERR_OPEN_LOCATION' : 'Klarte ikke åpne sti', + 'ERR_OPEN_LOCATION_FMT' : 'Klarte ikke åpne sti: {0}', + + // General + + 'LBL_UNKNOWN' : 'Ukjent', + 'LBL_APPEARANCE' : 'Utseende', + 'LBL_USER' : 'Bruker', + 'LBL_NAME' : 'Navn', + 'LBL_APPLY' : 'Angi', + 'LBL_FILENAME' : 'Filnavn', + 'LBL_PATH' : 'Sti', + 'LBL_SIZE' : 'Størrelse', + 'LBL_TYPE' : 'Type', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Laster', + 'LBL_SETTINGS' : 'Instillinger', + 'LBL_ADD_FILE' : 'Legg til fil', + 'LBL_COMMENT' : 'Kommenter', + 'LBL_ACCOUNT' : 'Konto', + 'LBL_CONNECT' : 'Koble til', + 'LBL_ONLINE' : 'Online', + 'LBL_OFFLINE' : 'Offline', + 'LBL_AWAY' : 'Borte', + 'LBL_BUSY' : 'Opptatt', + 'LBL_CHAT' : 'Snakk', + 'LBL_HELP' : 'Hjelp', + 'LBL_ABOUT' : 'Om', + 'LBL_PANELS' : 'Paneler', + 'LBL_LOCALES' : 'Lokalisering', + 'LBL_THEME' : 'Temaer', + 'LBL_COLOR' : 'Farge', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Drep', + 'LBL_ALIVE' : 'I live', + 'LBL_INDEX' : 'Indeks', + 'LBL_ADD' : 'Legg til', + 'LBL_FONT' : 'Skrift', + 'LBL_YES' : 'Ja', + 'LBL_NO' : 'Nei', + 'LBL_CANCEL' : 'Avbryt', + 'LBL_TOP' : 'Topp', + 'LBL_LEFT' : 'Venstre', + 'LBL_RIGHT' : 'Høyre', + 'LBL_BOTTOM' : 'Bunn', + 'LBL_CENTER' : 'Midt', + 'LBL_FILE' : 'Fil', + 'LBL_NEW' : 'Ny', + 'LBL_OPEN' : 'Åpne', + 'LBL_SAVE' : 'Lagre', + 'LBL_SAVEAS' : 'Lagre som...', + 'LBL_CLOSE' : 'Lukk', + 'LBL_MKDIR' : 'Lag Mappe', + 'LBL_UPLOAD' : 'Last opp', + 'LBL_VIEW' : 'Visning', + 'LBL_EDIT' : 'Rediger', + 'LBL_RENAME' : 'Navngi', + 'LBL_DELETE' : 'Slett', + 'LBL_OPENWITH' : 'Åpne Med ...', + 'LBL_ICONVIEW' : 'Ikon-visning', + 'LBL_TREEVIEW' : 'Tre-visning', + 'LBL_LISTVIEW' : 'Liste-visning', + 'LBL_REFRESH' : 'Gjennoppfrisk', + 'LBL_VIEWTYPE' : 'Visningstype', + 'LBL_BOLD' : 'Feit', + 'LBL_ITALIC' : 'Skeiv', + 'LBL_UNDERLINE' : 'Underlinjet', + 'LBL_REGULAR' : 'Normal', + 'LBL_STRIKE' : 'Gjennomstrøk', + 'LBL_INDENT' : 'Innrykk', + 'LBL_OUTDENT' : 'Utrykk', + 'LBL_UNDO' : 'Angre', + 'LBL_REDO' : 'Gjør om igjen', + 'LBL_CUT' : 'Kutt', + 'LBL_UNLINK' : 'Fjern lenke', + 'LBL_COPY' : 'Kopier', + 'LBL_PASTE' : 'Lim inn', + 'LBL_INSERT' : 'Sett inn', + 'LBL_IMAGE' : 'Bilde', + 'LBL_LINK' : 'Lenke', + 'LBL_DISCONNECT' : 'Koble fra', + 'LBL_APPLICATIONS' : 'Applikasjoner', + 'LBL_ADD_FOLDER' : 'Legg til mappe', + 'LBL_INFORMATION' : 'Informasjon', + 'LBL_TEXT_COLOR' : 'Tekst-farge', + 'LBL_BACK_COLOR' : 'Bakgrunn-farge', + 'LBL_RESET_DEFAULT' : 'Omstill til standard', + 'LBL_DOWNLOAD_COMP' : 'Last ned til datamaskin', + 'LBL_ORDERED_LIST' : 'Ordnet liste', + 'LBL_BACKGROUND_IMAGE' : 'Bakgrunnsbilde', + 'LBL_BACKGROUND_COLOR' : 'Bakgrunnsfarge', + 'LBL_UNORDERED_LIST' : 'Uordnet Liste', + 'LBL_SHOW_SIDEBAR' : 'Vis Sidebar', + 'LBL_SEARCH': 'Søk', + 'LBL_STATUS': 'Status', + 'LBL_READONLY': 'Kun lesbar', + 'LBL_CREATED': 'Opprettet', + 'LBL_MODIFIED': 'Modifisert', + 'LBL_SHOW_COLUMNS': 'Vis Kolonner', + 'LBL_MOVE': 'Flytt', + 'LBL_OPTIONS': 'Opsjoner', + 'LBL_OK': 'OK', + 'LBL_DIRECTORY': 'Mappe', + 'LBL_CREATE': 'Opprett', + 'LBL_BUGREPORT': 'Bug-rapport', + 'LBL_INSTALL': 'Installer', + 'LBL_UPDATE': 'Oppdater', + 'LBL_REMOVE': 'Fjern', + 'LBL_SHOW_NAVIGATION': 'Vis navigasjon', + 'LBL_SHOW_HIDDENFILES': 'Vis skjulte filer', + 'LBL_SHOW_FILEEXTENSIONS': 'Vis fil-utvidelser', + 'LBL_MOUNT': 'Montere', + 'LBL_DESCRIPTION': 'Beskrivelse', + 'LBL_USERNAME': 'Brukernavn', + 'LBL_PASSWORD': 'Passord', + 'LBL_HOST': 'Vert', + 'LBL_NAMESPACE': 'Navneplass', + 'LBL_BACK': 'Tilbake', + 'LBL_ICONS': 'Ikoner', + 'LBL_ICON': 'Ikon', + 'LBL_UNINSTALL': 'Avinstaller', + 'LBL_REGENERATE': 'Regenerer', + 'LBL_DESKTOP': 'Skrivebord', + 'LBL_WINDOWMANAGER': 'Vindu-håndterer', + 'LBL_HOTKEY': 'Snarknapp', + 'LBL_HOTKEYS': 'Snarknapper', + 'LBL_MOUNTS': 'Monteringer', + 'LBL_ID': 'ID', + 'LBL_APPLICATION': 'Applikasjon', + 'LBL_SCOPE': 'Skop', + 'LBL_HIDE': 'Skjul', + 'LBL_REPOSITORY': 'Repository', + 'LBL_VERSION': 'Versjon', + 'LBL_AUTHOR': 'Forfatter', + 'LBL_GROUPS': 'Grupper', + 'LBL_AUTOHIDE': 'Auto-skjul', + 'LBL_PERSONAL': 'Personlig', + 'LBL_SYSTEM': 'System', + 'LBL_STARTING': 'Starter', + 'LBL_SOUNDS': 'Lyder', + 'LBL_STORE': 'Butikk', + 'LBL_LOCALE': 'Språkvalg', + 'LBL_PACKAGE': 'Pakke', + 'LBL_PACKAGES': 'Pakker', + 'LBL_INPUT': 'Inndata', + 'LBL_MISC': 'Annet', + 'LBL_OTHER': 'Annet', + 'LBL_USERS': 'Brukere', + 'LBL_FONTS': 'Skrift', + 'LBL_BACKGROUND' : 'Bakgrunn', + 'LBL_PANEL' : 'Panel', + 'LBL_POSITION' : 'Posisjon', + 'LBL_OPACITY' : 'Gjennomsiktighet', + 'LBL_ONTOP' : 'Topp', + 'LBL_ITEMS' : 'Objekter', + 'LBL_GENERAL' : 'Generelt', + 'LBL_LOCK': 'Lås', + 'LBL_UNLOCK': 'Lås opp', + 'LBL_OPEN_LOCATION': 'Åpne sti', + 'LBL_HOME': 'Hjem', + 'LBL_WIDGET': 'Widget', + 'LBL_WIDGETS': 'Widgets', + 'LBL_WARNING': 'Advarsel', + 'LBL_INFO': 'Info' +}; diff --git a/src/client/javascript/locales/pl_PL.js b/src/client/javascript/locales/pl_PL.js index c8ecf56cde..80a8f5122a 100644 --- a/src/client/javascript/locales/pl_PL.js +++ b/src/client/javascript/locales/pl_PL.js @@ -27,374 +27,371 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.pl_PL = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Błąd otwierania pliku', - 'ERR_WM_NOT_RUNNING' : 'Menedżer okien nie jest włączony', - 'ERR_FILE_OPEN_FMT' : 'Nie można otworzyć \'**{0}**\'', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Nie można znaleźć aplikacji wspierającej \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Błąd otwierania aplikacji', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Błąd podczas uruchamiania aplikacji: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Konstruowanie aplikacji \'{0}\' nie powiodło się: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'init() aplikacji \'{0}\' nie powiodło się: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Brakuje zasobów dla aplikacji \'{0}\' lub ładowanie nie powiodło się!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Wstępne ładowanie aplikacji \'{0}\' nie powiodło się: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Aplikacja \'{0}\' została juz otwarta, a nie może być uruchomiona wielokrotnie!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Nie można otworzyć \'{0}\'. Nie znaleziono danych manifestu aplikacji!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Nie można otworzyć \'{0}\'. Twoja przeglądarka nie wspiera: {1}', - - 'ERR_NO_WM_RUNNING' : 'Menedżer okien nie został uruchomiony', - 'ERR_CORE_INIT_FAILED' : 'Nie można zainicjalizować OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Błąd podczas inicjalizacji OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Nie można uruchomić OS.js: Nie wybrano Menedżera Okien!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Nie można uruchomić OS.js: Błąd uruchamiania Menedżera Okien: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Nie można uruchomić OS.js: Błąd przeładowywania plików...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Błąd Javascript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Nieznany błąd.', - - 'ERR_APP_API_ERROR' : 'Błąd API Aplikacji', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplikacja {0} nie może wykonać operacji \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Brakujący argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Nieznany błąd', - - 'ERR_OPERATION_TIMEOUT' : 'Przekroczono Czas Operacji', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Przekroczono Czas Operacji ({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Masz już uruchomione Okno z nazwą \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimalizuj', - 'WINDOW_MAXIMIZE' : 'Maksymalizuj', - 'WINDOW_RESTORE' : 'Przywroć', - 'WINDOW_CLOSE' : 'Zamknij', - 'WINDOW_ONTOP_ON' : 'U Góry (Włączone)', - 'WINDOW_ONTOP_OFF': 'U Góry (Wyłączone)', - - // Handler - 'TITLE_SIGN_OUT' : 'Wyloguj', - 'TITLE_SIGNED_IN_AS_FMT' : 'Zalogowano jako: {0}', - - // SESSION - 'MSG_SESSION_WARNING' : 'Czy na pewno chcesz opuścić OS.js? Wszystkie niezapisane ustawienia i dane aplikacji zostaną utracone!', - - // Service - 'BUGREPORT_MSG' : 'Wyślij proszę raport błędu jesli uważasz, że jest to błąd.\nDołącz opis błędu', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Zalogowano w zewnętrznych serwisach: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Błąd krytyczny', - 'ERR_UTILS_XHR_FMT' : 'Błąd AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Wylogowywanie (Exit)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Wylogowywanie \'{0}\'.\nCzy chcesz zapisać sesję?', - - 'DIALOG_CLOSE' : 'Zamknij', - 'DIALOG_CANCEL': 'Anuluj', - 'DIALOG_APPLY' : 'Zastosuj', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Powiadomienia', - - 'DIALOG_COLOR_TITLE' : 'Kolor', - 'DIALOG_COLOR_R' : 'Czerwony: {0}', - 'DIALOG_COLOR_G' : 'Zielony: {0}', - 'DIALOG_COLOR_B' : 'Niebieski: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Potwierdź', - - 'DIALOG_ERROR_MESSAGE' : 'Wiadomość', - 'DIALOG_ERROR_SUMMARY' : 'Podsumowanie', - 'DIALOG_ERROR_TRACE' : 'Śledzenie', - 'DIALOG_ERROR_BUGREPORT' : 'Raport błędu', - - 'DIALOG_FILE_SAVE' : 'Zapisz', - 'DIALOG_FILE_OPEN' : 'Otwórz', - 'DIALOG_FILE_MKDIR' : 'Nowy folder', - 'DIALOG_FILE_MKDIR_MSG' : 'Nowy folder w **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Czy chcesz nadpisać plik \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Widok', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Lista', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Drzewo', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikony', - 'DIALOG_FILE_ERROR' : 'Błąd okna dialogowego pliku', - 'DIALOG_FILE_ERROR_SCANDIR': 'Nie udało się wylistować katalogu \'{0}\' z powodu wystąpienia błędu', - 'DIALOG_FILE_MISSING_FILENAME' : 'Zaznacz plik albo wpisz nazwę nowego pliku!', - 'DIALOG_FILE_MISSING_SELECTION': 'Zaznacz plik!', - - 'DIALOG_FILEINFO_TITLE' : 'Informacje', - 'DIALOG_FILEINFO_LOADING' : 'Ładowanie informacji dla: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Błąd okna Informacji o pliku', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Nie udało się uzyskać informacji dla **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Nie udało się uzyskać informacji dla: {0}', - - 'DIALOG_INPUT_TITLE' : 'Wprowadzanie', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Postęp', - 'DIALOG_FILEPROGRESS_LOADING' : 'Ładowanie...', - - 'DIALOG_UPLOAD_TITLE' : 'Wysyłanie', - 'DIALOG_UPLOAD_DESC' : 'Wysyłanie pliku do **{0}**.
Maksymalny rozmiar: {1} bitów', - 'DIALOG_UPLOAD_MSG_FMT' : 'Wysyłanie \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Wysyłanie pliku...', - 'DIALOG_UPLOAD_FAILED' : 'Błąd wywołania', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Wywołanie nie powiodło się', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Powód nieznany...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Anulowane przez użytkownika...', - 'DIALOG_UPLOAD_TOO_BIG': 'Plik jest za duży', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Plik jest za duży, przekracza {0}', - - 'DIALOG_FONT_TITLE' : 'Czcionka', - - 'DIALOG_APPCHOOSER_TITLE' : 'Wybierz aplikację', - 'DIALOG_APPCHOOSER_MSG' : 'Wybierz aplikację do otwarcia', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Wybierz aplikację', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Używaj jako domyślną aplikację do {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'Moduł GoogleAPI jest nie skonfigurowany albo jest wyłączony', - 'GAPI_SIGN_OUT' : 'Wyloguj z Serwisu Google API', - 'GAPI_REVOKE' : 'Odwołaj uprawnienia i wyloguj', - 'GAPI_AUTH_FAILURE' : 'Autentykacja Google API nie powiodła się lub nie miała miejsca', - 'GAPI_AUTH_FAILURE_FMT' : 'Nie można uwierzytelnić: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Nie można załadować Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Moduł Windows Live API nie jest skonfigurowany albo jest wyłączony', - 'WLAPI_SIGN_OUT' : 'Wyloguj z Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Nie można załadować Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Nie można zalogować do Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Nie można zalogować do Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API zwróciło status {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Nie mozna utworzyć IndexedDB bez Nazwy Bazy Danych', - 'IDB_NO_SUCH_ITEM' : 'Brak takiego elementu', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Błąd krytyczny', - 'ERR_VFS_UNAVAILABLE' : 'Niedostępne', - 'ERR_VFS_FILE_ARGS' : 'Plik oczekuje co najmniej jednego argumentu', - 'ERR_VFS_NUM_ARGS' : 'Za mało argumentów', - 'ERR_VFS_EXPECT_FILE' : 'Oczekuje obiektu-pliku', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Oczekuje źródłowego obiektu-pliku', - 'ERR_VFS_EXPECT_DST_FILE' : 'Oczekuje docelowego obiektu-pliku', - 'ERR_VFS_FILE_EXISTS' : 'Plik docelowy istnieje', - 'ERR_VFS_TRANSFER_FMT' : 'Wystąpił błąd podczas transferu pomiędzy magazynem: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Nie można wysłać pliku bez celu', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Nie można wysłać bez okreslenia plików', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Wysyłanie pliku: {0} nie powiodło się', - 'ERR_VFS_UPLOAD_CANCELLED': 'Wysyłanie pliku zostało anulowane', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Nie można pobrać ścieżki bez wskazania ścieżki', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Wystąpił błąd podczas pobierania: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Odpowiedź była pusta', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Pobieranie pliku', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Błąd XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'Nie odnaleziono id głównego folderu', - 'ERR_VFSMODULE_NOSUCH' : 'Nie ma takiego pliku', - 'ERR_VFSMODULE_PARENT' : 'Nie ma takiego rodzica', - 'ERR_VFSMODULE_PARENT_FMT' : 'Nie odnaleziono rodzica: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Nie udało się przeskanować folderu', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Nie udało się przeskanować folderu: {0}', - 'ERR_VFSMODULE_READ' : 'Nie udało się odczytać pliku', - 'ERR_VFSMODULE_READ_FMT' : 'Nie udało się odczytać pliku: {0}', - 'ERR_VFSMODULE_WRITE' : 'Nie udało się zapisać pliku', - 'ERR_VFSMODULE_WRITE_FMT' : 'Nie udało się zapisać pliku: {0}', - 'ERR_VFSMODULE_COPY' : 'Nie można skopiować', - 'ERR_VFSMODULE_COPY_FMT' : 'Kopiowanie: {0} nie powiodło się', - 'ERR_VFSMODULE_UNLINK' : 'Nie można odlinkować pliku', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Odlinkowanie pliku: {0} nie powiodło się', - 'ERR_VFSMODULE_MOVE' : 'Nie można przenieść', - 'ERR_VFSMODULE_MOVE_FMT' : 'Przenoszenie: {0} nie powiodło się', - 'ERR_VFSMODULE_EXIST' : 'Nie udało się sprawdzić czy plik instnieje', - 'ERR_VFSMODULE_EXIST_FMT' : 'Nie udało się sprawdzić czy plik instnieje: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Nie udało się uzyskać informacji o pliku', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Nie udało się uzyskać informacji o pliku: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Nie można stworzyć folderu', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Tworzenie folderu: {0} nie powiodło się', - 'ERR_VFSMODULE_URL' : 'Nie udało się uzyskać adresu URL pliku', - 'ERR_VFSMODULE_URL_FMT' : 'Nie udało się uzyskać adresu URL pliku: {0}', - 'ERR_VFSMODULE_TRASH' : 'Nie udało się przenieść pliku do kosza', - 'ERR_VFSMODULE_TRASH_FMT' : 'Nie udało się przenieść pliku do kosza: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Nie udało się przenieść pliku z kosza', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Nie udało się przenieść pliku z kosza: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Nie udało się wyczyścić kosza', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Nie udało się wyczyścić kosza: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Jesteś zalogowany do Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Wylogowano z serwisu Dropbox API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Nie znaleziono pozycji', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Folder instalacyjny pakietów już istnieje. Nie można kontynuować!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Nie można otworzyć', - 'ERR_FILE_APP_OPEN_FMT' : 'Plik {0} nie może zostać otwarty ,ponieważ mime {1} nie jest wspierane', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Plik {0} nie może zostać otwarty: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Plik {0} nie może zostać zapisany: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Błąd Aplikacji', - 'ERR_GENERIC_APP_ACTION_FMT': 'Nie udało się przeprowadzić akcji \'{0}\'.', - 'ERR_GENERIC_APP_UNKNOWN' : 'Nieznany błąd', - 'ERR_GENERIC_APP_REQUEST' : 'Wystąpił błąd podczas obsługi żądania', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Błąd krytyczny: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Odrzucić zmiany?', - 'MSG_FILE_CHANGED' : 'Plik został zmieniony. Przeładować?', - 'MSG_APPLICATION_WARNING' : 'Ostrzeżenie Aplikacji', - 'MSG_MIME_OVERRIDE' : 'Typ pliku "{0}" nie jest wspierany, używając w zamian "{1}".', - - // - // General - // - - 'LBL_UNKNOWN' : 'Nieznany', - 'LBL_APPEARANCE' : 'Wygląd', - 'LBL_USER' : 'Użytkownik', - 'LBL_NAME' : 'Nazwa', - 'LBL_APPLY' : 'Zastosuj', - 'LBL_FILENAME' : 'Nazwa pliku', - 'LBL_PATH' : 'Ścieżka', - 'LBL_SIZE' : 'Rozmiar', - 'LBL_TYPE' : 'Typ', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Ładowanie', - 'LBL_SETTINGS' : 'Ustawienia', - 'LBL_ADD_FILE' : 'Dodaj plik', - 'LBL_COMMENT' : 'Komentarz', - 'LBL_ACCOUNT' : 'Konto', - 'LBL_CONNECT' : 'Połącz', - 'LBL_ONLINE' : 'Połączono', - 'LBL_OFFLINE' : 'Rozłączono', - 'LBL_AWAY' : 'Zaraz wracam', - 'LBL_BUSY' : 'Zajęty', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Pomoc', - 'LBL_ABOUT' : 'O', - 'LBL_PANELS' : 'Panele', - 'LBL_LOCALES' : 'Języki', - 'LBL_THEME' : 'Motyw', - 'LBL_COLOR' : 'Kolor', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Zabij', - 'LBL_ALIVE' : 'Aktywne', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Dodaj', - 'LBL_FONT' : 'Czcionka', - 'LBL_YES' : 'Tak', - 'LBL_NO' : 'Nie', - 'LBL_CANCEL' : 'Anuluj', - 'LBL_TOP' : 'Góra', - 'LBL_LEFT' : 'Lewo', - 'LBL_RIGHT' : 'Prawo', - 'LBL_BOTTOM' : 'Dół', - 'LBL_CENTER' : 'Środek', - 'LBL_FILE' : 'Plik', - 'LBL_NEW' : 'Nowy', - 'LBL_OPEN' : 'Otwórz', - 'LBL_SAVE' : 'Zapisz', - 'LBL_SAVEAS' : 'Zapisz jako...', - 'LBL_CLOSE' : 'Zamknij', - 'LBL_MKDIR' : 'Nowy folder', - 'LBL_UPLOAD' : 'Wyślij', - 'LBL_VIEW' : 'Widok', - 'LBL_EDIT' : 'Edytuj', - 'LBL_RENAME' : 'Zmień nazwę', - 'LBL_DELETE' : 'Usuń', - 'LBL_OPENWITH' : 'Otwórz za pomocą ...', - 'LBL_ICONVIEW' : 'Ikony', - 'LBL_TREEVIEW' : 'Drzewo', - 'LBL_LISTVIEW' : 'Lista', - 'LBL_REFRESH' : 'Odśwież', - 'LBL_VIEWTYPE' : 'Typ widoku', - 'LBL_BOLD' : 'Pogrubienie', - 'LBL_ITALIC' : 'Kursywa', - 'LBL_UNDERLINE' : 'Podkreślenie', - 'LBL_REGULAR' : 'Regularne', - 'LBL_STRIKE' : 'Przekreślenie', - 'LBL_INDENT' : 'Wcięcie', - 'LBL_OUTDENT' : 'Outdent', - 'LBL_UNDO' : 'Cofnij', - 'LBL_REDO' : 'Przywróć', - 'LBL_CUT' : 'Wytnij', - 'LBL_UNLINK' : 'Odlinkuj', - 'LBL_COPY' : 'Kopiuj', - 'LBL_PASTE' : 'Wklej', - 'LBL_INSERT' : 'Wstaw', - 'LBL_IMAGE' : 'Obraz', - 'LBL_LINK' : 'Linkuj', - 'LBL_DISCONNECT' : 'Rozłącz', - 'LBL_APPLICATIONS' : 'Aplikacje', - 'LBL_ADD_FOLDER' : 'Dodaj folder', - 'LBL_INFORMATION' : 'Informacje', - 'LBL_TEXT_COLOR' : 'Kolor tekstu', - 'LBL_BACK_COLOR' : 'Kolor tła', - 'LBL_RESET_DEFAULT' : 'Przywróć fabryczne', - 'LBL_DOWNLOAD_COMP' : 'Pobierz', - 'LBL_ORDERED_LIST' : 'Lista', - 'LBL_BACKGROUND_IMAGE' : 'Tapeta', - 'LBL_BACKGROUND_COLOR' : 'Kolor tła', - 'LBL_UNORDERED_LIST' : 'Lista nieuporządkowana', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Tylko-odczyt', - 'LBL_CREATED' : 'Utworzono', - 'LBL_MODIFIED' : 'Zmodyfikowano', - 'LBL_SHOW_COLUMNS' : 'Pokaż kolumny', - 'LBL_MOVE' : 'Przenieś', - 'LBL_OPTIONS' : 'Opcje', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Folder', - 'LBL_CREATE' : 'Utwórz', - 'LBL_BUGREPORT' : 'Raport błędu', - 'LBL_INSTALL' : 'Instaluj', - 'LBL_UPDATE' : 'Aktualizuj', - 'LBL_REMOVE' : 'Usuń', - 'LBL_SHOW_SIDEBAR' : 'Pokaż pasek', - 'LBL_BACKGROUND' : 'Tło', - 'LBL_DESKTOP' : 'Pulpit', - 'LBL_PANEL' : 'Panel', - 'LBL_POSITION' : 'Pozycja', - 'LBL_ONTOP' : 'Na wierzchu', - 'LBL_ITEMS' : 'Elementy', - 'LBL_SOUNDS' : 'Dźwięki', - 'LBL_ICONS' : 'Ikony', - 'LBL_AUTOHIDE' : 'Automatyczne ukrywanie', - 'LBL_OPACITY' : 'Przeźroczystość', - 'LBL_USERNAME' : 'Nazwa konta', - 'LBL_GROUPS' : 'Grupy', - 'LBL_VERSION' : 'Wersja', - 'LBL_AUTHOR' : 'Autor', - 'LBL_HIDE' : 'Ukryj', - 'LBL_APPLICATION' : 'Aplikacja', - 'LBL_SCOPE' : 'Zasięg', - 'LBL_PACKAGES' : 'Pakiety', - 'LBL_GENERAL' : 'Ogólne', - 'LBL_DEBUG' : 'Debugowanie' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Błąd otwierania pliku', + 'ERR_WM_NOT_RUNNING' : 'Menedżer okien nie jest włączony', + 'ERR_FILE_OPEN_FMT' : 'Nie można otworzyć \'**{0}**\'', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Nie można znaleźć aplikacji wspierającej \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Błąd otwierania aplikacji', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Błąd podczas uruchamiania aplikacji: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Konstruowanie aplikacji \'{0}\' nie powiodło się: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'init() aplikacji \'{0}\' nie powiodło się: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Brakuje zasobów dla aplikacji \'{0}\' lub ładowanie nie powiodło się!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Wstępne ładowanie aplikacji \'{0}\' nie powiodło się: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Aplikacja \'{0}\' została juz otwarta, a nie może być uruchomiona wielokrotnie!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Nie można otworzyć \'{0}\'. Nie znaleziono danych manifestu aplikacji!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Nie można otworzyć \'{0}\'. Twoja przeglądarka nie wspiera: {1}', + + 'ERR_NO_WM_RUNNING' : 'Menedżer okien nie został uruchomiony', + 'ERR_CORE_INIT_FAILED' : 'Nie można zainicjalizować OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Błąd podczas inicjalizacji OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Nie można uruchomić OS.js: Nie wybrano Menedżera Okien!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Nie można uruchomić OS.js: Błąd uruchamiania Menedżera Okien: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Nie można uruchomić OS.js: Błąd przeładowywania plików...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Błąd Javascript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Nieznany błąd.', + + 'ERR_APP_API_ERROR' : 'Błąd API Aplikacji', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplikacja {0} nie może wykonać operacji \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Brakujący argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Nieznany błąd', + + 'ERR_OPERATION_TIMEOUT' : 'Przekroczono Czas Operacji', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Przekroczono Czas Operacji ({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Masz już uruchomione Okno z nazwą \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimalizuj', + 'WINDOW_MAXIMIZE' : 'Maksymalizuj', + 'WINDOW_RESTORE' : 'Przywroć', + 'WINDOW_CLOSE' : 'Zamknij', + 'WINDOW_ONTOP_ON' : 'U Góry (Włączone)', + 'WINDOW_ONTOP_OFF': 'U Góry (Wyłączone)', + + // Handler + 'TITLE_SIGN_OUT' : 'Wyloguj', + 'TITLE_SIGNED_IN_AS_FMT' : 'Zalogowano jako: {0}', + + // SESSION + 'MSG_SESSION_WARNING' : 'Czy na pewno chcesz opuścić OS.js? Wszystkie niezapisane ustawienia i dane aplikacji zostaną utracone!', + + // Service + 'BUGREPORT_MSG' : 'Wyślij proszę raport błędu jesli uważasz, że jest to błąd.\nDołącz opis błędu', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Zalogowano w zewnętrznych serwisach: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Błąd krytyczny', + 'ERR_UTILS_XHR_FMT' : 'Błąd AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Wylogowywanie (Exit)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Wylogowywanie \'{0}\'.\nCzy chcesz zapisać sesję?', + + 'DIALOG_CLOSE' : 'Zamknij', + 'DIALOG_CANCEL': 'Anuluj', + 'DIALOG_APPLY' : 'Zastosuj', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Powiadomienia', + + 'DIALOG_COLOR_TITLE' : 'Kolor', + 'DIALOG_COLOR_R' : 'Czerwony: {0}', + 'DIALOG_COLOR_G' : 'Zielony: {0}', + 'DIALOG_COLOR_B' : 'Niebieski: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Potwierdź', + + 'DIALOG_ERROR_MESSAGE' : 'Wiadomość', + 'DIALOG_ERROR_SUMMARY' : 'Podsumowanie', + 'DIALOG_ERROR_TRACE' : 'Śledzenie', + 'DIALOG_ERROR_BUGREPORT' : 'Raport błędu', + + 'DIALOG_FILE_SAVE' : 'Zapisz', + 'DIALOG_FILE_OPEN' : 'Otwórz', + 'DIALOG_FILE_MKDIR' : 'Nowy folder', + 'DIALOG_FILE_MKDIR_MSG' : 'Nowy folder w **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Czy chcesz nadpisać plik \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Widok', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Lista', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Drzewo', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikony', + 'DIALOG_FILE_ERROR' : 'Błąd okna dialogowego pliku', + 'DIALOG_FILE_ERROR_SCANDIR': 'Nie udało się wylistować katalogu \'{0}\' z powodu wystąpienia błędu', + 'DIALOG_FILE_MISSING_FILENAME' : 'Zaznacz plik albo wpisz nazwę nowego pliku!', + 'DIALOG_FILE_MISSING_SELECTION': 'Zaznacz plik!', + + 'DIALOG_FILEINFO_TITLE' : 'Informacje', + 'DIALOG_FILEINFO_LOADING' : 'Ładowanie informacji dla: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Błąd okna Informacji o pliku', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Nie udało się uzyskać informacji dla **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Nie udało się uzyskać informacji dla: {0}', + + 'DIALOG_INPUT_TITLE' : 'Wprowadzanie', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Postęp', + 'DIALOG_FILEPROGRESS_LOADING' : 'Ładowanie...', + + 'DIALOG_UPLOAD_TITLE' : 'Wysyłanie', + 'DIALOG_UPLOAD_DESC' : 'Wysyłanie pliku do **{0}**.
Maksymalny rozmiar: {1} bitów', + 'DIALOG_UPLOAD_MSG_FMT' : 'Wysyłanie \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Wysyłanie pliku...', + 'DIALOG_UPLOAD_FAILED' : 'Błąd wywołania', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Wywołanie nie powiodło się', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Powód nieznany...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Anulowane przez użytkownika...', + 'DIALOG_UPLOAD_TOO_BIG': 'Plik jest za duży', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Plik jest za duży, przekracza {0}', + + 'DIALOG_FONT_TITLE' : 'Czcionka', + + 'DIALOG_APPCHOOSER_TITLE' : 'Wybierz aplikację', + 'DIALOG_APPCHOOSER_MSG' : 'Wybierz aplikację do otwarcia', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Wybierz aplikację', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Używaj jako domyślną aplikację do {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'Moduł GoogleAPI jest nie skonfigurowany albo jest wyłączony', + 'GAPI_SIGN_OUT' : 'Wyloguj z Serwisu Google API', + 'GAPI_REVOKE' : 'Odwołaj uprawnienia i wyloguj', + 'GAPI_AUTH_FAILURE' : 'Autentykacja Google API nie powiodła się lub nie miała miejsca', + 'GAPI_AUTH_FAILURE_FMT' : 'Nie można uwierzytelnić: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Nie można załadować Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Moduł Windows Live API nie jest skonfigurowany albo jest wyłączony', + 'WLAPI_SIGN_OUT' : 'Wyloguj z Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Nie można załadować Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Nie można zalogować do Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Nie można zalogować do Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API zwróciło status {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Nie mozna utworzyć IndexedDB bez Nazwy Bazy Danych', + 'IDB_NO_SUCH_ITEM' : 'Brak takiego elementu', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Błąd krytyczny', + 'ERR_VFS_UNAVAILABLE' : 'Niedostępne', + 'ERR_VFS_FILE_ARGS' : 'Plik oczekuje co najmniej jednego argumentu', + 'ERR_VFS_NUM_ARGS' : 'Za mało argumentów', + 'ERR_VFS_EXPECT_FILE' : 'Oczekuje obiektu-pliku', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Oczekuje źródłowego obiektu-pliku', + 'ERR_VFS_EXPECT_DST_FILE' : 'Oczekuje docelowego obiektu-pliku', + 'ERR_VFS_FILE_EXISTS' : 'Plik docelowy istnieje', + 'ERR_VFS_TRANSFER_FMT' : 'Wystąpił błąd podczas transferu pomiędzy magazynem: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Nie można wysłać pliku bez celu', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Nie można wysłać bez okreslenia plików', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Wysyłanie pliku: {0} nie powiodło się', + 'ERR_VFS_UPLOAD_CANCELLED': 'Wysyłanie pliku zostało anulowane', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Nie można pobrać ścieżki bez wskazania ścieżki', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Wystąpił błąd podczas pobierania: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Odpowiedź była pusta', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Pobieranie pliku', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Błąd XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'Nie odnaleziono id głównego folderu', + 'ERR_VFSMODULE_NOSUCH' : 'Nie ma takiego pliku', + 'ERR_VFSMODULE_PARENT' : 'Nie ma takiego rodzica', + 'ERR_VFSMODULE_PARENT_FMT' : 'Nie odnaleziono rodzica: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Nie udało się przeskanować folderu', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Nie udało się przeskanować folderu: {0}', + 'ERR_VFSMODULE_READ' : 'Nie udało się odczytać pliku', + 'ERR_VFSMODULE_READ_FMT' : 'Nie udało się odczytać pliku: {0}', + 'ERR_VFSMODULE_WRITE' : 'Nie udało się zapisać pliku', + 'ERR_VFSMODULE_WRITE_FMT' : 'Nie udało się zapisać pliku: {0}', + 'ERR_VFSMODULE_COPY' : 'Nie można skopiować', + 'ERR_VFSMODULE_COPY_FMT' : 'Kopiowanie: {0} nie powiodło się', + 'ERR_VFSMODULE_UNLINK' : 'Nie można odlinkować pliku', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Odlinkowanie pliku: {0} nie powiodło się', + 'ERR_VFSMODULE_MOVE' : 'Nie można przenieść', + 'ERR_VFSMODULE_MOVE_FMT' : 'Przenoszenie: {0} nie powiodło się', + 'ERR_VFSMODULE_EXIST' : 'Nie udało się sprawdzić czy plik instnieje', + 'ERR_VFSMODULE_EXIST_FMT' : 'Nie udało się sprawdzić czy plik instnieje: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Nie udało się uzyskać informacji o pliku', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Nie udało się uzyskać informacji o pliku: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Nie można stworzyć folderu', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Tworzenie folderu: {0} nie powiodło się', + 'ERR_VFSMODULE_URL' : 'Nie udało się uzyskać adresu URL pliku', + 'ERR_VFSMODULE_URL_FMT' : 'Nie udało się uzyskać adresu URL pliku: {0}', + 'ERR_VFSMODULE_TRASH' : 'Nie udało się przenieść pliku do kosza', + 'ERR_VFSMODULE_TRASH_FMT' : 'Nie udało się przenieść pliku do kosza: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Nie udało się przenieść pliku z kosza', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Nie udało się przenieść pliku z kosza: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Nie udało się wyczyścić kosza', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Nie udało się wyczyścić kosza: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Jesteś zalogowany do Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Wylogowano z serwisu Dropbox API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Nie znaleziono pozycji', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Folder instalacyjny pakietów już istnieje. Nie można kontynuować!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Nie można otworzyć', + 'ERR_FILE_APP_OPEN_FMT' : 'Plik {0} nie może zostać otwarty ,ponieważ mime {1} nie jest wspierane', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Plik {0} nie może zostać otwarty: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Plik {0} nie może zostać zapisany: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Błąd Aplikacji', + 'ERR_GENERIC_APP_ACTION_FMT': 'Nie udało się przeprowadzić akcji \'{0}\'.', + 'ERR_GENERIC_APP_UNKNOWN' : 'Nieznany błąd', + 'ERR_GENERIC_APP_REQUEST' : 'Wystąpił błąd podczas obsługi żądania', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Błąd krytyczny: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Odrzucić zmiany?', + 'MSG_FILE_CHANGED' : 'Plik został zmieniony. Przeładować?', + 'MSG_APPLICATION_WARNING' : 'Ostrzeżenie Aplikacji', + 'MSG_MIME_OVERRIDE' : 'Typ pliku "{0}" nie jest wspierany, używając w zamian "{1}".', + + // + // General + // + + 'LBL_UNKNOWN' : 'Nieznany', + 'LBL_APPEARANCE' : 'Wygląd', + 'LBL_USER' : 'Użytkownik', + 'LBL_NAME' : 'Nazwa', + 'LBL_APPLY' : 'Zastosuj', + 'LBL_FILENAME' : 'Nazwa pliku', + 'LBL_PATH' : 'Ścieżka', + 'LBL_SIZE' : 'Rozmiar', + 'LBL_TYPE' : 'Typ', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Ładowanie', + 'LBL_SETTINGS' : 'Ustawienia', + 'LBL_ADD_FILE' : 'Dodaj plik', + 'LBL_COMMENT' : 'Komentarz', + 'LBL_ACCOUNT' : 'Konto', + 'LBL_CONNECT' : 'Połącz', + 'LBL_ONLINE' : 'Połączono', + 'LBL_OFFLINE' : 'Rozłączono', + 'LBL_AWAY' : 'Zaraz wracam', + 'LBL_BUSY' : 'Zajęty', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Pomoc', + 'LBL_ABOUT' : 'O', + 'LBL_PANELS' : 'Panele', + 'LBL_LOCALES' : 'Języki', + 'LBL_THEME' : 'Motyw', + 'LBL_COLOR' : 'Kolor', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Zabij', + 'LBL_ALIVE' : 'Aktywne', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Dodaj', + 'LBL_FONT' : 'Czcionka', + 'LBL_YES' : 'Tak', + 'LBL_NO' : 'Nie', + 'LBL_CANCEL' : 'Anuluj', + 'LBL_TOP' : 'Góra', + 'LBL_LEFT' : 'Lewo', + 'LBL_RIGHT' : 'Prawo', + 'LBL_BOTTOM' : 'Dół', + 'LBL_CENTER' : 'Środek', + 'LBL_FILE' : 'Plik', + 'LBL_NEW' : 'Nowy', + 'LBL_OPEN' : 'Otwórz', + 'LBL_SAVE' : 'Zapisz', + 'LBL_SAVEAS' : 'Zapisz jako...', + 'LBL_CLOSE' : 'Zamknij', + 'LBL_MKDIR' : 'Nowy folder', + 'LBL_UPLOAD' : 'Wyślij', + 'LBL_VIEW' : 'Widok', + 'LBL_EDIT' : 'Edytuj', + 'LBL_RENAME' : 'Zmień nazwę', + 'LBL_DELETE' : 'Usuń', + 'LBL_OPENWITH' : 'Otwórz za pomocą ...', + 'LBL_ICONVIEW' : 'Ikony', + 'LBL_TREEVIEW' : 'Drzewo', + 'LBL_LISTVIEW' : 'Lista', + 'LBL_REFRESH' : 'Odśwież', + 'LBL_VIEWTYPE' : 'Typ widoku', + 'LBL_BOLD' : 'Pogrubienie', + 'LBL_ITALIC' : 'Kursywa', + 'LBL_UNDERLINE' : 'Podkreślenie', + 'LBL_REGULAR' : 'Regularne', + 'LBL_STRIKE' : 'Przekreślenie', + 'LBL_INDENT' : 'Wcięcie', + 'LBL_OUTDENT' : 'Outdent', + 'LBL_UNDO' : 'Cofnij', + 'LBL_REDO' : 'Przywróć', + 'LBL_CUT' : 'Wytnij', + 'LBL_UNLINK' : 'Odlinkuj', + 'LBL_COPY' : 'Kopiuj', + 'LBL_PASTE' : 'Wklej', + 'LBL_INSERT' : 'Wstaw', + 'LBL_IMAGE' : 'Obraz', + 'LBL_LINK' : 'Linkuj', + 'LBL_DISCONNECT' : 'Rozłącz', + 'LBL_APPLICATIONS' : 'Aplikacje', + 'LBL_ADD_FOLDER' : 'Dodaj folder', + 'LBL_INFORMATION' : 'Informacje', + 'LBL_TEXT_COLOR' : 'Kolor tekstu', + 'LBL_BACK_COLOR' : 'Kolor tła', + 'LBL_RESET_DEFAULT' : 'Przywróć fabryczne', + 'LBL_DOWNLOAD_COMP' : 'Pobierz', + 'LBL_ORDERED_LIST' : 'Lista', + 'LBL_BACKGROUND_IMAGE' : 'Tapeta', + 'LBL_BACKGROUND_COLOR' : 'Kolor tła', + 'LBL_UNORDERED_LIST' : 'Lista nieuporządkowana', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Tylko-odczyt', + 'LBL_CREATED' : 'Utworzono', + 'LBL_MODIFIED' : 'Zmodyfikowano', + 'LBL_SHOW_COLUMNS' : 'Pokaż kolumny', + 'LBL_MOVE' : 'Przenieś', + 'LBL_OPTIONS' : 'Opcje', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Folder', + 'LBL_CREATE' : 'Utwórz', + 'LBL_BUGREPORT' : 'Raport błędu', + 'LBL_INSTALL' : 'Instaluj', + 'LBL_UPDATE' : 'Aktualizuj', + 'LBL_REMOVE' : 'Usuń', + 'LBL_SHOW_SIDEBAR' : 'Pokaż pasek', + 'LBL_BACKGROUND' : 'Tło', + 'LBL_DESKTOP' : 'Pulpit', + 'LBL_PANEL' : 'Panel', + 'LBL_POSITION' : 'Pozycja', + 'LBL_ONTOP' : 'Na wierzchu', + 'LBL_ITEMS' : 'Elementy', + 'LBL_SOUNDS' : 'Dźwięki', + 'LBL_ICONS' : 'Ikony', + 'LBL_AUTOHIDE' : 'Automatyczne ukrywanie', + 'LBL_OPACITY' : 'Przeźroczystość', + 'LBL_USERNAME' : 'Nazwa konta', + 'LBL_GROUPS' : 'Grupy', + 'LBL_VERSION' : 'Wersja', + 'LBL_AUTHOR' : 'Autor', + 'LBL_HIDE' : 'Ukryj', + 'LBL_APPLICATION' : 'Aplikacja', + 'LBL_SCOPE' : 'Zasięg', + 'LBL_PACKAGES' : 'Pakiety', + 'LBL_GENERAL' : 'Ogólne', + 'LBL_DEBUG' : 'Debugowanie' +}; diff --git a/src/client/javascript/locales/pt_BR.js b/src/client/javascript/locales/pt_BR.js index 1b3dbfd97a..e817533765 100644 --- a/src/client/javascript/locales/pt_BR.js +++ b/src/client/javascript/locales/pt_BR.js @@ -27,353 +27,350 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.pt_BR = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Erro ao abrir arquivo', - 'ERR_WM_NOT_RUNNING' : 'Gerenciador de janelas não está executando', - 'ERR_FILE_OPEN_FMT' : 'O arquivo \'**{0}**\' não pôde ser aberto', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Não foi encontrado nenhum aplicativo com suporte para arquivos \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Falha em abrir aplicativo', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Um erro ocorreu na tentativa de abrir: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Falha em construção do aplicativo \'{0}\': {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Falha no init() do aplicativo \'{0}\': {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'O aplicativo \'{0}\' está faltando recursos ou falhou em inicializar!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'O aplicativo \'{0}\' falhou no pré-carregamento: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'O aplicativo \'{0}\' já está aberto e só permite uma instância!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Falha em abrir \'{0}\'. Faltando informação sobre o pacote do aplicativo!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Falha em abrir \'{0}\'. Seu navegador não suporta: {1}', - - 'ERR_NO_WM_RUNNING' : 'Gerenciador de janelas não está executando', - 'ERR_CORE_INIT_FAILED' : 'Falha em inicializar OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Um erro ocorreu enquanto OS.js se inicializava', - 'ERR_CORE_INIT_NO_WM' : 'Não é possivel começar OS.js: Nenhum Gerenciador de Janelas encontrado!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Não é possível inciar OS.js: Falha em lançar o Gerenciador de Janelas: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Não é possível iniciar OS.js: Falha em pré-carregar recursos...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Erro no JavaScript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Um erro inexperado ocorreu, talvez seja um bug.', - - 'ERR_APP_API_ERROR' : 'Erro na API do aplicativo', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplicativo {0} falhou em executar \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Faltando argumento: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Erro desconhecido', - - 'ERR_OPERATION_TIMEOUT' : 'Operação está demorando muito', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Operação está demorando muito ({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Você já possui uma janela chamada \'{0}\'', - 'WINDOW_MINIMIZE' : 'Minimizar', - 'WINDOW_MAXIMIZE' : 'Maximizar', - 'WINDOW_RESTORE' : 'Restaurar', - 'WINDOW_CLOSE' : 'Fechar', - 'WINDOW_ONTOP_ON' : 'No topo (Habilitar)', - 'WINDOW_ONTOP_OFF': 'No topo (Desabilitar)', - - // Handler - 'TITLE_SIGN_OUT' : 'Deslogar', - 'TITLE_SIGNED_IN_AS_FMT' : 'Logado como: {0}', - - // SESSION - 'MSG_SESSION_WARNING' : 'Você tem certeza que quer sair do OS.js? Todas as configurações e dados das aplicações não salvas serão perdidas!', - - // Service - 'BUGREPORT_MSG' : 'Por favor, reporte se você achar que isto é um bug.\nInclue uma breve descrição sobre como ocorreu o erro e, se possível, como refazê-lo', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Logado em serviços externos: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Erro fatal', - 'ERR_UTILS_XHR_FMT' : 'Erro de AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Logout (Sair)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Deslogando usuário \'{0}\'.\nVocê quer salvar sessão atual?', - - 'DIALOG_CLOSE' : 'Fechar', - 'DIALOG_CANCEL': 'Cancelar', - 'DIALOG_APPLY' : 'Aplicar', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Mensagem de Atenção', - - 'DIALOG_COLOR_TITLE' : 'Cores', - 'DIALOG_COLOR_R' : 'Vermelho: {0}', - 'DIALOG_COLOR_G' : 'Verde: {0}', - 'DIALOG_COLOR_B' : 'Azul: {0}', - 'DIALOG_COLOR_A' : 'Alfa: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Mensagem de Confirmação', - - 'DIALOG_ERROR_MESSAGE' : 'Mensagem', - 'DIALOG_ERROR_SUMMARY' : 'Resumo', - 'DIALOG_ERROR_TRACE' : 'Rastro', - 'DIALOG_ERROR_BUGREPORT' : 'Relate Bug', - - 'DIALOG_FILE_SAVE' : 'Salvar', - 'DIALOG_FILE_OPEN' : 'Abrir', - 'DIALOG_FILE_MKDIR' : 'Novo diretório', - 'DIALOG_FILE_MKDIR_MSG' : 'Criar novo diretório em **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Você realmente quer sobrescrever o arquivo \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Visuaizar tipo', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Visualizar em lista', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Visualizar em árvore', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Visualizar em ícones', - 'DIALOG_FILE_ERROR' : 'Mensagem de erro com arquivo', - 'DIALOG_FILE_ERROR_SCANDIR': 'Falha na listagem do diretório \'{0}\' por um erro', - 'DIALOG_FILE_MISSING_FILENAME' : 'Você precisa selecionar um arquivo ou introduzir um nome para o novo arquivo!', - 'DIALOG_FILE_MISSING_SELECTION': 'Você precisa selecionar um arquivo!', - - 'DIALOG_FILEINFO_TITLE' : 'Informação do arquivo', - 'DIALOG_FILEINFO_LOADING' : 'Carregando informação do arquivo: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Mensagem de erro sobre informação de arquivo', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Falha em obter informação do arquivo **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Falha em obter informação do arquivo: {0}', - - 'DIALOG_INPUT_TITLE' : 'Diálogo de entrada', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Operação em progresso', - 'DIALOG_FILEPROGRESS_LOADING' : 'Carregando...', - - 'DIALOG_UPLOAD_TITLE' : 'Janela de Upload', - 'DIALOG_UPLOAD_DESC' : 'Upload de arquivo **{0}**.
Tamanho máximo: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Fazendo upload \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Fazendo upload do arquivo...', - 'DIALOG_UPLOAD_FAILED' : 'Upload falhou', - 'DIALOG_UPLOAD_FAILED_MSG' : 'O upload falhou', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Razão desconhecida...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelado pelo usuário...', - 'DIALOG_UPLOAD_TOO_BIG': 'O arquivo é muito grande', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'O arqyuvo é muito grande, excede {0}', - - 'DIALOG_FONT_TITLE' : 'Janela de tipografia', - - 'DIALOG_APPCHOOSER_TITLE' : 'Escolher aplicação', - 'DIALOG_APPCHOOSER_MSG' : 'Escolhar uma aplicação para abrir', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Precisa escolher uma aplicação', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usar como aplicação padrão para {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'Módulo do GoogleAPI não está configurado ou está desativado', - 'GAPI_SIGN_OUT' : 'Desconectar dos serviços do Google API', - 'GAPI_REVOKE' : 'Retirar permissões e desconectar', - 'GAPI_AUTH_FAILURE' : 'A tentativa de autenticação com o Google API falhou', - 'GAPI_AUTH_FAILURE_FMT' : 'Falha ao tentar autenticar: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Não pôde carregar Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Módulo do Windows Live API não está configurado ou está desativado', - 'WLAPI_SIGN_OUT' : 'Desconectar do Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Falha em carregar Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Falha em conectar ao Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Falha em conectar ao Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API retornou código {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Não é possível criar IndexedDB sem nome do Banco de Dados', - 'IDB_NO_SUCH_ITEM' : 'Não existe este elemento', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Erro fatal', - 'ERR_VFS_UNAVAILABLE' : 'Não está disponível', - 'ERR_VFS_FILE_ARGS' : 'Arquivo espera ao menos um argumento', - 'ERR_VFS_NUM_ARGS' : 'Argumentos insuficientes', - 'ERR_VFS_EXPECT_FILE' : 'Espera ao menos um objeto de arquivo', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Espera ao menos a origem de um objeto de arquivo', - 'ERR_VFS_EXPECT_DST_FILE' : 'Espera ao menos o destino de um objeto de arquivo', - 'ERR_VFS_FILE_EXISTS' : 'Destino já existe', - 'ERR_VFS_TRANSFER_FMT' : 'Um erro ocorreu ao transferir entre discos de armazenamento: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Não é possível fazer upload de arquivo sem destino', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Não é possível fazer upload sem arquivos definidos', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Falha em upload: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Upload foi cancelado', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Não é possível fazer download de destino sem destino', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Ocorreu um erro enquanto fazia download: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Resposta vazia', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Fazendo download de arquivo', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Erro XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'Falha em achar a raiz do diretório', - 'ERR_VFSMODULE_NOSUCH' : 'Arquivo não existe', - 'ERR_VFSMODULE_PARENT' : 'Não existe o pai', - 'ERR_VFSMODULE_PARENT_FMT' : 'Falha em encontrar o pai: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Falhou em localizar o diretório', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Falhou em localizar o diretório: {0}', - 'ERR_VFSMODULE_READ' : 'Falha em ler o arquivo', - 'ERR_VFSMODULE_READ_FMT' : 'Falha em ler o arquivo: {0}', - 'ERR_VFSMODULE_WRITE' : 'Falha em escrever o arquivo', - 'ERR_VFSMODULE_WRITE_FMT' : 'Falha em escrever o arquivo: {0}', - 'ERR_VFSMODULE_COPY' : 'Cópia falhou', - 'ERR_VFSMODULE_COPY_FMT' : 'Cópia falhou: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Falha em desvincular o arquivo', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Falha em desvincular o arquivo: {0}', - 'ERR_VFSMODULE_MOVE' : 'Falha em mover o arquivo', - 'ERR_VFSMODULE_MOVE_FMT' : 'Falha em mover o arquivo: {0}', - 'ERR_VFSMODULE_EXIST' : 'Falha em conferir a existência do arquivo', - 'ERR_VFSMODULE_EXIST_FMT' : 'Falha em conferir a existência do arquivo: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Falha em obter informação do arquivo', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Falha em obter informação do arquivo: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Falha em criar diretório', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Falha em criar diretório: {0}', - 'ERR_VFSMODULE_URL' : 'Falha em obter URL do arquivo', - 'ERR_VFSMODULE_URL_FMT' : 'Falha em obter URL do arquivo: {0}', - 'ERR_VFSMODULE_TRASH' : 'Falha em mover arquivo para lixeira', - 'ERR_VFSMODULE_TRASH_FMT' : 'Falha em mover arquivo para lixeira: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Falha em recuperar arquivo da lixeira', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Falha em recuperar arquivo da lixeira: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Falha em esvaziar a lixeira', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Falha em esvaziar a lixeira: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Você logou à API do Dropbox', - 'DROPBOX_SIGN_OUT' : 'Desconectar dos serviços da API do Google', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Falha em encontrar a rota: arquivo não encontrado', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Diretório de instalação já existe, por favor escolha outro para continuar', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Não é possível abrir o arquivo', - 'ERR_FILE_APP_OPEN_FMT' : 'O arquivo {0} não pode ser aberto pois não existe suporte para {1}', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'O arquivo {0} não pode ser aberto: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'O arquivo {0} Não pode ser salvo: {1}', - 'ERR_GENERIC_APP_FMT' : 'O aplicativo encontrou um erro {0}', - 'ERR_GENERIC_APP_ACTION_FMT': 'Falha em realizar ação \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Erro desconhecido', - 'ERR_GENERIC_APP_REQUEST' : 'Um erro ocorreu durante sua requisição', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Erro fatal: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Descartar mudanças?', - 'MSG_FILE_CHANGED' : 'O arquivo sofreu alterações. Recarregar?', - 'MSG_APPLICATION_WARNING' : 'Advertência do aplicativo', - 'MSG_MIME_OVERRIDE' : 'A extensão "{0}" não é suportada, usando "{1}".', - - // - // General - // - - 'LBL_UNKNOWN' : 'Desconhecido', - 'LBL_APPEARANCE' : 'Aparência', - 'LBL_USER' : 'Usuário', - 'LBL_NAME' : 'Nome', - 'LBL_APPLY' : 'Aplicar', - 'LBL_FILENAME' : 'Nome do arquivo', - 'LBL_PATH' : 'Caminho', - 'LBL_SIZE' : 'Tamanho', - 'LBL_TYPE' : 'Tipo', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Carregando', - 'LBL_SETTINGS' : 'Configurações', - 'LBL_ADD_FILE' : 'Adicionar arquivo', - 'LBL_COMMENT' : 'Comentário', - 'LBL_ACCOUNT' : 'Conta', - 'LBL_CONNECT' : 'Conectar', - 'LBL_ONLINE' : 'Online', - 'LBL_OFFLINE' : 'Offline', - 'LBL_AWAY' : 'Indisponível', - 'LBL_BUSY' : 'Ocupado', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Ajuda', - 'LBL_ABOUT' : 'Sobre', - 'LBL_PANELS' : 'Paineis', - 'LBL_LOCALES' : 'Internacionalização', - 'LBL_THEME' : 'Tema', - 'LBL_COLOR' : 'Cor', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Kill', - 'LBL_ALIVE' : 'Alive', - 'LBL_INDEX' : 'Índice', - 'LBL_ADD' : 'Adicionar', - 'LBL_FONT' : 'Tipografia', - 'LBL_YES' : 'Sim', - 'LBL_NO' : 'Não', - 'LBL_CANCEL' : 'Cancelar', - 'LBL_TOP' : 'Acima', - 'LBL_LEFT' : 'Esquerda', - 'LBL_RIGHT' : 'Direita', - 'LBL_BOTTOM' : 'Abaixo', - 'LBL_CENTER' : 'Centro', - 'LBL_FILE' : 'Arquivo', - 'LBL_NEW' : 'Novo', - 'LBL_OPEN' : 'Abrir', - 'LBL_SAVE' : 'Salvar', - 'LBL_SAVEAS' : 'Salvar como...', - 'LBL_CLOSE' : 'Fechar', - 'LBL_MKDIR' : 'Criar diretório', - 'LBL_UPLOAD' : 'Fazer upload', - 'LBL_VIEW' : 'Visualizar', - 'LBL_EDIT' : 'Editar', - 'LBL_RENAME' : 'Renomear', - 'LBL_DELETE' : 'Excluir', - 'LBL_OPENWITH' : 'Abrir com...', - 'LBL_ICONVIEW' : 'Visualização por ícones', - 'LBL_TREEVIEW' : 'Visualização por árvore', - 'LBL_LISTVIEW' : 'Visualização por lista', - 'LBL_REFRESH' : 'Recarregar', - 'LBL_VIEWTYPE' : 'Ver tipo', - 'LBL_BOLD' : 'Negrito', - 'LBL_ITALIC' : 'Itálico', - 'LBL_UNDERLINE' : 'Sublinhado', - 'LBL_REGULAR' : 'Regular', - 'LBL_STRIKE' : 'Rsicado', - 'LBL_INDENT' : 'Indentar', - 'LBL_OUTDENT' : 'Voltar', - 'LBL_UNDO' : 'Desfazer', - 'LBL_REDO' : 'Refazer', - 'LBL_CUT' : 'Cortar', - 'LBL_UNLINK' : 'Desvincular', - 'LBL_COPY' : 'Copiar', - 'LBL_PASTE' : 'Colar', - 'LBL_INSERT' : 'Inserir', - 'LBL_IMAGE' : 'Imagem', - 'LBL_LINK' : 'Link', - 'LBL_DISCONNECT' : 'Desconectar', - 'LBL_APPLICATIONS' : 'Aplicativos', - 'LBL_ADD_FOLDER' : 'Adicionar diretório', - 'LBL_INFORMATION' : 'Informação', - 'LBL_TEXT_COLOR' : 'Cor do texto', - 'LBL_BACK_COLOR' : 'Cor de fundo', - 'LBL_RESET_DEFAULT' : 'Redefinir usando valores padrões', - 'LBL_DOWNLOAD_COMP' : 'Fazer download para o computador', - 'LBL_ORDERED_LIST' : 'Lista ordenada', - 'LBL_BACKGROUND_IMAGE' : 'Imagem de fundo', - 'LBL_BACKGROUND_COLOR' : 'Cor de fundo', - 'LBL_UNORDERED_LIST' : 'Lista não ordenada', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Somente leitura', - 'LBL_CREATED' : 'Criado', - 'LBL_MODIFIED' : 'Modificado', - 'LBL_SHOW_COLUMNS' : 'Mostrar colunas', - 'LBL_MOVE' : 'Mover', - 'LBL_OPTIONS' : 'Opções', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Diretório', - 'LBL_CREATE' : 'Criar', - 'LBL_BUGREPORT' : 'Reportar Bug', - 'LBL_INSTALL' : 'Instalar', - 'LBL_UPDATE' : 'Atualizar', - 'LBL_REMOVE' : 'Remover' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Erro ao abrir arquivo', + 'ERR_WM_NOT_RUNNING' : 'Gerenciador de janelas não está executando', + 'ERR_FILE_OPEN_FMT' : 'O arquivo \'**{0}**\' não pôde ser aberto', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Não foi encontrado nenhum aplicativo com suporte para arquivos \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Falha em abrir aplicativo', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Um erro ocorreu na tentativa de abrir: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Falha em construção do aplicativo \'{0}\': {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Falha no init() do aplicativo \'{0}\': {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'O aplicativo \'{0}\' está faltando recursos ou falhou em inicializar!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'O aplicativo \'{0}\' falhou no pré-carregamento: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'O aplicativo \'{0}\' já está aberto e só permite uma instância!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Falha em abrir \'{0}\'. Faltando informação sobre o pacote do aplicativo!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Falha em abrir \'{0}\'. Seu navegador não suporta: {1}', + + 'ERR_NO_WM_RUNNING' : 'Gerenciador de janelas não está executando', + 'ERR_CORE_INIT_FAILED' : 'Falha em inicializar OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Um erro ocorreu enquanto OS.js se inicializava', + 'ERR_CORE_INIT_NO_WM' : 'Não é possivel começar OS.js: Nenhum Gerenciador de Janelas encontrado!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Não é possível inciar OS.js: Falha em lançar o Gerenciador de Janelas: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Não é possível iniciar OS.js: Falha em pré-carregar recursos...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Erro no JavaScript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Um erro inexperado ocorreu, talvez seja um bug.', + + 'ERR_APP_API_ERROR' : 'Erro na API do aplicativo', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplicativo {0} falhou em executar \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Faltando argumento: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Erro desconhecido', + + 'ERR_OPERATION_TIMEOUT' : 'Operação está demorando muito', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Operação está demorando muito ({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Você já possui uma janela chamada \'{0}\'', + 'WINDOW_MINIMIZE' : 'Minimizar', + 'WINDOW_MAXIMIZE' : 'Maximizar', + 'WINDOW_RESTORE' : 'Restaurar', + 'WINDOW_CLOSE' : 'Fechar', + 'WINDOW_ONTOP_ON' : 'No topo (Habilitar)', + 'WINDOW_ONTOP_OFF': 'No topo (Desabilitar)', + + // Handler + 'TITLE_SIGN_OUT' : 'Deslogar', + 'TITLE_SIGNED_IN_AS_FMT' : 'Logado como: {0}', + + // SESSION + 'MSG_SESSION_WARNING' : 'Você tem certeza que quer sair do OS.js? Todas as configurações e dados das aplicações não salvas serão perdidas!', + + // Service + 'BUGREPORT_MSG' : 'Por favor, reporte se você achar que isto é um bug.\nInclue uma breve descrição sobre como ocorreu o erro e, se possível, como refazê-lo', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Logado em serviços externos: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Erro fatal', + 'ERR_UTILS_XHR_FMT' : 'Erro de AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Logout (Sair)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Deslogando usuário \'{0}\'.\nVocê quer salvar sessão atual?', + + 'DIALOG_CLOSE' : 'Fechar', + 'DIALOG_CANCEL': 'Cancelar', + 'DIALOG_APPLY' : 'Aplicar', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Mensagem de Atenção', + + 'DIALOG_COLOR_TITLE' : 'Cores', + 'DIALOG_COLOR_R' : 'Vermelho: {0}', + 'DIALOG_COLOR_G' : 'Verde: {0}', + 'DIALOG_COLOR_B' : 'Azul: {0}', + 'DIALOG_COLOR_A' : 'Alfa: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Mensagem de Confirmação', + + 'DIALOG_ERROR_MESSAGE' : 'Mensagem', + 'DIALOG_ERROR_SUMMARY' : 'Resumo', + 'DIALOG_ERROR_TRACE' : 'Rastro', + 'DIALOG_ERROR_BUGREPORT' : 'Relate Bug', + + 'DIALOG_FILE_SAVE' : 'Salvar', + 'DIALOG_FILE_OPEN' : 'Abrir', + 'DIALOG_FILE_MKDIR' : 'Novo diretório', + 'DIALOG_FILE_MKDIR_MSG' : 'Criar novo diretório em **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Você realmente quer sobrescrever o arquivo \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Visuaizar tipo', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Visualizar em lista', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Visualizar em árvore', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Visualizar em ícones', + 'DIALOG_FILE_ERROR' : 'Mensagem de erro com arquivo', + 'DIALOG_FILE_ERROR_SCANDIR': 'Falha na listagem do diretório \'{0}\' por um erro', + 'DIALOG_FILE_MISSING_FILENAME' : 'Você precisa selecionar um arquivo ou introduzir um nome para o novo arquivo!', + 'DIALOG_FILE_MISSING_SELECTION': 'Você precisa selecionar um arquivo!', + + 'DIALOG_FILEINFO_TITLE' : 'Informação do arquivo', + 'DIALOG_FILEINFO_LOADING' : 'Carregando informação do arquivo: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Mensagem de erro sobre informação de arquivo', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Falha em obter informação do arquivo **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Falha em obter informação do arquivo: {0}', + + 'DIALOG_INPUT_TITLE' : 'Diálogo de entrada', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Operação em progresso', + 'DIALOG_FILEPROGRESS_LOADING' : 'Carregando...', + + 'DIALOG_UPLOAD_TITLE' : 'Janela de Upload', + 'DIALOG_UPLOAD_DESC' : 'Upload de arquivo **{0}**.
Tamanho máximo: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Fazendo upload \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Fazendo upload do arquivo...', + 'DIALOG_UPLOAD_FAILED' : 'Upload falhou', + 'DIALOG_UPLOAD_FAILED_MSG' : 'O upload falhou', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Razão desconhecida...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Cancelado pelo usuário...', + 'DIALOG_UPLOAD_TOO_BIG': 'O arquivo é muito grande', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'O arqyuvo é muito grande, excede {0}', + + 'DIALOG_FONT_TITLE' : 'Janela de tipografia', + + 'DIALOG_APPCHOOSER_TITLE' : 'Escolher aplicação', + 'DIALOG_APPCHOOSER_MSG' : 'Escolhar uma aplicação para abrir', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Precisa escolher uma aplicação', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Usar como aplicação padrão para {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'Módulo do GoogleAPI não está configurado ou está desativado', + 'GAPI_SIGN_OUT' : 'Desconectar dos serviços do Google API', + 'GAPI_REVOKE' : 'Retirar permissões e desconectar', + 'GAPI_AUTH_FAILURE' : 'A tentativa de autenticação com o Google API falhou', + 'GAPI_AUTH_FAILURE_FMT' : 'Falha ao tentar autenticar: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Não pôde carregar Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Módulo do Windows Live API não está configurado ou está desativado', + 'WLAPI_SIGN_OUT' : 'Desconectar do Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Falha em carregar Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Falha em conectar ao Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Falha em conectar ao Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API retornou código {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Não é possível criar IndexedDB sem nome do Banco de Dados', + 'IDB_NO_SUCH_ITEM' : 'Não existe este elemento', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Erro fatal', + 'ERR_VFS_UNAVAILABLE' : 'Não está disponível', + 'ERR_VFS_FILE_ARGS' : 'Arquivo espera ao menos um argumento', + 'ERR_VFS_NUM_ARGS' : 'Argumentos insuficientes', + 'ERR_VFS_EXPECT_FILE' : 'Espera ao menos um objeto de arquivo', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Espera ao menos a origem de um objeto de arquivo', + 'ERR_VFS_EXPECT_DST_FILE' : 'Espera ao menos o destino de um objeto de arquivo', + 'ERR_VFS_FILE_EXISTS' : 'Destino já existe', + 'ERR_VFS_TRANSFER_FMT' : 'Um erro ocorreu ao transferir entre discos de armazenamento: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Não é possível fazer upload de arquivo sem destino', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Não é possível fazer upload sem arquivos definidos', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Falha em upload: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Upload foi cancelado', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Não é possível fazer download de destino sem destino', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Ocorreu um erro enquanto fazia download: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Resposta vazia', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Fazendo download de arquivo', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Erro XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'Falha em achar a raiz do diretório', + 'ERR_VFSMODULE_NOSUCH' : 'Arquivo não existe', + 'ERR_VFSMODULE_PARENT' : 'Não existe o pai', + 'ERR_VFSMODULE_PARENT_FMT' : 'Falha em encontrar o pai: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Falhou em localizar o diretório', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Falhou em localizar o diretório: {0}', + 'ERR_VFSMODULE_READ' : 'Falha em ler o arquivo', + 'ERR_VFSMODULE_READ_FMT' : 'Falha em ler o arquivo: {0}', + 'ERR_VFSMODULE_WRITE' : 'Falha em escrever o arquivo', + 'ERR_VFSMODULE_WRITE_FMT' : 'Falha em escrever o arquivo: {0}', + 'ERR_VFSMODULE_COPY' : 'Cópia falhou', + 'ERR_VFSMODULE_COPY_FMT' : 'Cópia falhou: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Falha em desvincular o arquivo', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Falha em desvincular o arquivo: {0}', + 'ERR_VFSMODULE_MOVE' : 'Falha em mover o arquivo', + 'ERR_VFSMODULE_MOVE_FMT' : 'Falha em mover o arquivo: {0}', + 'ERR_VFSMODULE_EXIST' : 'Falha em conferir a existência do arquivo', + 'ERR_VFSMODULE_EXIST_FMT' : 'Falha em conferir a existência do arquivo: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Falha em obter informação do arquivo', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Falha em obter informação do arquivo: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Falha em criar diretório', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Falha em criar diretório: {0}', + 'ERR_VFSMODULE_URL' : 'Falha em obter URL do arquivo', + 'ERR_VFSMODULE_URL_FMT' : 'Falha em obter URL do arquivo: {0}', + 'ERR_VFSMODULE_TRASH' : 'Falha em mover arquivo para lixeira', + 'ERR_VFSMODULE_TRASH_FMT' : 'Falha em mover arquivo para lixeira: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Falha em recuperar arquivo da lixeira', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Falha em recuperar arquivo da lixeira: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Falha em esvaziar a lixeira', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Falha em esvaziar a lixeira: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Você logou à API do Dropbox', + 'DROPBOX_SIGN_OUT' : 'Desconectar dos serviços da API do Google', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Falha em encontrar a rota: arquivo não encontrado', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Diretório de instalação já existe, por favor escolha outro para continuar', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Não é possível abrir o arquivo', + 'ERR_FILE_APP_OPEN_FMT' : 'O arquivo {0} não pode ser aberto pois não existe suporte para {1}', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'O arquivo {0} não pode ser aberto: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'O arquivo {0} Não pode ser salvo: {1}', + 'ERR_GENERIC_APP_FMT' : 'O aplicativo encontrou um erro {0}', + 'ERR_GENERIC_APP_ACTION_FMT': 'Falha em realizar ação \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Erro desconhecido', + 'ERR_GENERIC_APP_REQUEST' : 'Um erro ocorreu durante sua requisição', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Erro fatal: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Descartar mudanças?', + 'MSG_FILE_CHANGED' : 'O arquivo sofreu alterações. Recarregar?', + 'MSG_APPLICATION_WARNING' : 'Advertência do aplicativo', + 'MSG_MIME_OVERRIDE' : 'A extensão "{0}" não é suportada, usando "{1}".', + + // + // General + // + + 'LBL_UNKNOWN' : 'Desconhecido', + 'LBL_APPEARANCE' : 'Aparência', + 'LBL_USER' : 'Usuário', + 'LBL_NAME' : 'Nome', + 'LBL_APPLY' : 'Aplicar', + 'LBL_FILENAME' : 'Nome do arquivo', + 'LBL_PATH' : 'Caminho', + 'LBL_SIZE' : 'Tamanho', + 'LBL_TYPE' : 'Tipo', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Carregando', + 'LBL_SETTINGS' : 'Configurações', + 'LBL_ADD_FILE' : 'Adicionar arquivo', + 'LBL_COMMENT' : 'Comentário', + 'LBL_ACCOUNT' : 'Conta', + 'LBL_CONNECT' : 'Conectar', + 'LBL_ONLINE' : 'Online', + 'LBL_OFFLINE' : 'Offline', + 'LBL_AWAY' : 'Indisponível', + 'LBL_BUSY' : 'Ocupado', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Ajuda', + 'LBL_ABOUT' : 'Sobre', + 'LBL_PANELS' : 'Paineis', + 'LBL_LOCALES' : 'Internacionalização', + 'LBL_THEME' : 'Tema', + 'LBL_COLOR' : 'Cor', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Kill', + 'LBL_ALIVE' : 'Alive', + 'LBL_INDEX' : 'Índice', + 'LBL_ADD' : 'Adicionar', + 'LBL_FONT' : 'Tipografia', + 'LBL_YES' : 'Sim', + 'LBL_NO' : 'Não', + 'LBL_CANCEL' : 'Cancelar', + 'LBL_TOP' : 'Acima', + 'LBL_LEFT' : 'Esquerda', + 'LBL_RIGHT' : 'Direita', + 'LBL_BOTTOM' : 'Abaixo', + 'LBL_CENTER' : 'Centro', + 'LBL_FILE' : 'Arquivo', + 'LBL_NEW' : 'Novo', + 'LBL_OPEN' : 'Abrir', + 'LBL_SAVE' : 'Salvar', + 'LBL_SAVEAS' : 'Salvar como...', + 'LBL_CLOSE' : 'Fechar', + 'LBL_MKDIR' : 'Criar diretório', + 'LBL_UPLOAD' : 'Fazer upload', + 'LBL_VIEW' : 'Visualizar', + 'LBL_EDIT' : 'Editar', + 'LBL_RENAME' : 'Renomear', + 'LBL_DELETE' : 'Excluir', + 'LBL_OPENWITH' : 'Abrir com...', + 'LBL_ICONVIEW' : 'Visualização por ícones', + 'LBL_TREEVIEW' : 'Visualização por árvore', + 'LBL_LISTVIEW' : 'Visualização por lista', + 'LBL_REFRESH' : 'Recarregar', + 'LBL_VIEWTYPE' : 'Ver tipo', + 'LBL_BOLD' : 'Negrito', + 'LBL_ITALIC' : 'Itálico', + 'LBL_UNDERLINE' : 'Sublinhado', + 'LBL_REGULAR' : 'Regular', + 'LBL_STRIKE' : 'Rsicado', + 'LBL_INDENT' : 'Indentar', + 'LBL_OUTDENT' : 'Voltar', + 'LBL_UNDO' : 'Desfazer', + 'LBL_REDO' : 'Refazer', + 'LBL_CUT' : 'Cortar', + 'LBL_UNLINK' : 'Desvincular', + 'LBL_COPY' : 'Copiar', + 'LBL_PASTE' : 'Colar', + 'LBL_INSERT' : 'Inserir', + 'LBL_IMAGE' : 'Imagem', + 'LBL_LINK' : 'Link', + 'LBL_DISCONNECT' : 'Desconectar', + 'LBL_APPLICATIONS' : 'Aplicativos', + 'LBL_ADD_FOLDER' : 'Adicionar diretório', + 'LBL_INFORMATION' : 'Informação', + 'LBL_TEXT_COLOR' : 'Cor do texto', + 'LBL_BACK_COLOR' : 'Cor de fundo', + 'LBL_RESET_DEFAULT' : 'Redefinir usando valores padrões', + 'LBL_DOWNLOAD_COMP' : 'Fazer download para o computador', + 'LBL_ORDERED_LIST' : 'Lista ordenada', + 'LBL_BACKGROUND_IMAGE' : 'Imagem de fundo', + 'LBL_BACKGROUND_COLOR' : 'Cor de fundo', + 'LBL_UNORDERED_LIST' : 'Lista não ordenada', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Somente leitura', + 'LBL_CREATED' : 'Criado', + 'LBL_MODIFIED' : 'Modificado', + 'LBL_SHOW_COLUMNS' : 'Mostrar colunas', + 'LBL_MOVE' : 'Mover', + 'LBL_OPTIONS' : 'Opções', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Diretório', + 'LBL_CREATE' : 'Criar', + 'LBL_BUGREPORT' : 'Reportar Bug', + 'LBL_INSTALL' : 'Instalar', + 'LBL_UPDATE' : 'Atualizar', + 'LBL_REMOVE' : 'Remover' +}; diff --git a/src/client/javascript/locales/ru_RU.js b/src/client/javascript/locales/ru_RU.js index 2103a70e9c..a02d406328 100644 --- a/src/client/javascript/locales/ru_RU.js +++ b/src/client/javascript/locales/ru_RU.js @@ -27,260 +27,257 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - OSjs.Locales.ru_RU = { - 'ERR_FILE_OPEN' : 'Ошибка открытия файла', - 'ERR_WM_NOT_RUNNING' : 'Менеджер окон не запущен', - 'ERR_FILE_OPEN_FMT' : 'Файл \'**{0}**\' не может быть открыт', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Неудалось найти приложение, способное открыть файл \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Ошибка запуска приложения', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'При попытке запуска, произошла следующая ошибка: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Ошибка при построении приложения \'{0}\': {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Ошибка инициализации в приложении \'{0}\' (init()): {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Для приложения \'{0}\' отсутсвует ресурс или ошибка при его загрузке!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Ошибка предварительной загрузки приложения \'{0}\': \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Приложение \'{0}\' уже запущено и единовременно поддерживает только одну копию!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Ошибка запуска \'{0}\'. Отсутствует манифест данных для приложения!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Ошибка запуска \'{0}\'. Ваш браузер не поддерживает: {1}', +/*eslint key-spacing: "off"*/ - 'ERR_NO_WM_RUNNING' : 'Не запущен оконный менеджер', - 'ERR_CORE_INIT_FAILED' : 'Ошибка инициализации OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Произошла ошибка в момент инициализации OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Невозможно запустить OS.js: Оконный менеджер не определен!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Невозможно запустить OS.js из-за ошибки при запуске оконного менеджера: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Невозможно запустить OS.js: Ошибка при предзагрузке ресурсов..', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Отчет об ошибке в JavaScript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Произошла непредвиденная ошибка, возможно баг.', +module.exports = { + 'ERR_FILE_OPEN' : 'Ошибка открытия файла', + 'ERR_WM_NOT_RUNNING' : 'Менеджер окон не запущен', + 'ERR_FILE_OPEN_FMT' : 'Файл \'**{0}**\' не может быть открыт', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Неудалось найти приложение, способное открыть файл \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Ошибка запуска приложения', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'При попытке запуска, произошла следующая ошибка: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Ошибка при построении приложения \'{0}\': {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Ошибка инициализации в приложении \'{0}\' (init()): {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Для приложения \'{0}\' отсутсвует ресурс или ошибка при его загрузке!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Ошибка предварительной загрузки приложения \'{0}\': \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Приложение \'{0}\' уже запущено и единовременно поддерживает только одну копию!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Ошибка запуска \'{0}\'. Отсутствует манифест данных для приложения!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Ошибка запуска \'{0}\'. Ваш браузер не поддерживает: {1}', - 'ERR_APP_API_ERROR' : 'Ошибка связанная с API приложения', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Приложению {0} не удалось выполнить операцию \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Пропущен аргумент: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Неизвестная ошибка', + 'ERR_NO_WM_RUNNING' : 'Не запущен оконный менеджер', + 'ERR_CORE_INIT_FAILED' : 'Ошибка инициализации OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Произошла ошибка в момент инициализации OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Невозможно запустить OS.js: Оконный менеджер не определен!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Невозможно запустить OS.js из-за ошибки при запуске оконного менеджера: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Невозможно запустить OS.js: Ошибка при предзагрузке ресурсов..', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Отчет об ошибке в JavaScript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Произошла непредвиденная ошибка, возможно баг.', - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'У вас уже присутствует окно с названием \'{0}\'', - 'WINDOW_MINIMIZE' : 'Свернуть', - 'WINDOW_MAXIMIZE' : 'Развернуть', - 'WINDOW_RESTORE' : 'Восстановить', - 'WINDOW_CLOSE' : 'Закрыть', - 'WINDOW_ONTOP_ON' : 'Поверх всех окон (Включить)', - 'WINDOW_ONTOP_OFF': 'Поверх всех окон (Выключить)', + 'ERR_APP_API_ERROR' : 'Ошибка связанная с API приложения', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Приложению {0} не удалось выполнить операцию \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Пропущен аргумент: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Неизвестная ошибка', - // Handler - 'TITLE_SIGN_OUT' : 'Выйти', - 'TITLE_SIGNED_IN_AS_FMT' : 'Вы вошли как: {0}', + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'У вас уже присутствует окно с названием \'{0}\'', + 'WINDOW_MINIMIZE' : 'Свернуть', + 'WINDOW_MAXIMIZE' : 'Развернуть', + 'WINDOW_RESTORE' : 'Восстановить', + 'WINDOW_CLOSE' : 'Закрыть', + 'WINDOW_ONTOP_ON' : 'Поверх всех окон (Включить)', + 'WINDOW_ONTOP_OFF': 'Поверх всех окон (Выключить)', - // Dialogs - 'DIALOG_LOGOUT_TITLE' : 'Выйти (Выход)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Выход как пользователь: \'{0}\'.\nЖелаете сохранить текущую сессию?', + // Handler + 'TITLE_SIGN_OUT' : 'Выйти', + 'TITLE_SIGNED_IN_AS_FMT' : 'Вы вошли как: {0}', - 'DIALOG_CLOSE' : 'Закрыть', - 'DIALOG_CANCEL': 'Отменить', - 'DIALOG_APPLY' : 'Применить', - 'DIALOG_OK' : 'OK', + // Dialogs + 'DIALOG_LOGOUT_TITLE' : 'Выйти (Выход)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Выход как пользователь: \'{0}\'.\nЖелаете сохранить текущую сессию?', - 'DIALOG_ALERT_TITLE' : 'Внимание', + 'DIALOG_CLOSE' : 'Закрыть', + 'DIALOG_CANCEL': 'Отменить', + 'DIALOG_APPLY' : 'Применить', + 'DIALOG_OK' : 'OK', - 'DIALOG_COLOR_TITLE' : 'Цвет', - 'DIALOG_COLOR_R' : 'Красный: {0}', - 'DIALOG_COLOR_G' : 'Зеленый: {0}', - 'DIALOG_COLOR_B' : 'Синий: {0}', - 'DIALOG_COLOR_A' : 'Прозрачность: {0}', + 'DIALOG_ALERT_TITLE' : 'Внимание', - 'DIALOG_CONFIRM_TITLE' : 'Подтверждение', + 'DIALOG_COLOR_TITLE' : 'Цвет', + 'DIALOG_COLOR_R' : 'Красный: {0}', + 'DIALOG_COLOR_G' : 'Зеленый: {0}', + 'DIALOG_COLOR_B' : 'Синий: {0}', + 'DIALOG_COLOR_A' : 'Прозрачность: {0}', - 'DIALOG_ERROR_MESSAGE' : 'Сообщение', - 'DIALOG_ERROR_SUMMARY' : 'Сводка', - 'DIALOG_ERROR_TRACE' : 'Цепочка вызовов', - 'DIALOG_ERROR_BUGREPORT' : 'Отчет об ошибке', + 'DIALOG_CONFIRM_TITLE' : 'Подтверждение', - 'DIALOG_FILE_SAVE' : 'Сохранить', - 'DIALOG_FILE_OPEN' : 'Открыть', - 'DIALOG_FILE_MKDIR' : 'Новая папка', - 'DIALOG_FILE_MKDIR_MSG' : 'Создать новый каталог в **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Вы уверены, что хотите перезаписать файл \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Режим просмотра', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Список', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Древовидный', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Значки', - 'DIALOG_FILE_ERROR' : 'Ошибка связанная с FileDialog', - 'DIALOG_FILE_ERROR_SCANDIR': 'Не удалось отобразить содержимое \'{0}\', произошла ошибка', - 'DIALOG_FILE_MISSING_FILENAME' : 'Выберите файл или введите новое имя файла!', - 'DIALOG_FILE_MISSING_SELECTION': 'Выберите файл!', + 'DIALOG_ERROR_MESSAGE' : 'Сообщение', + 'DIALOG_ERROR_SUMMARY' : 'Сводка', + 'DIALOG_ERROR_TRACE' : 'Цепочка вызовов', + 'DIALOG_ERROR_BUGREPORT' : 'Отчет об ошибке', - 'DIALOG_FILEINFO_TITLE' : 'Информация о файле', - 'DIALOG_FILEINFO_LOADING' : 'Загрузка информации о файле: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Ошибка связанная с FileInformationDialog', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Ошибка при получения информации о файле **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Ошибка при получения информации о файле: {0}', + 'DIALOG_FILE_SAVE' : 'Сохранить', + 'DIALOG_FILE_OPEN' : 'Открыть', + 'DIALOG_FILE_MKDIR' : 'Новая папка', + 'DIALOG_FILE_MKDIR_MSG' : 'Создать новый каталог в **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Вы уверены, что хотите перезаписать файл \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Режим просмотра', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Список', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Древовидный', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Значки', + 'DIALOG_FILE_ERROR' : 'Ошибка связанная с FileDialog', + 'DIALOG_FILE_ERROR_SCANDIR': 'Не удалось отобразить содержимое \'{0}\', произошла ошибка', + 'DIALOG_FILE_MISSING_FILENAME' : 'Выберите файл или введите новое имя файла!', + 'DIALOG_FILE_MISSING_SELECTION': 'Выберите файл!', - 'DIALOG_INPUT_TITLE' : 'Диалог ввода', + 'DIALOG_FILEINFO_TITLE' : 'Информация о файле', + 'DIALOG_FILEINFO_LOADING' : 'Загрузка информации о файле: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Ошибка связанная с FileInformationDialog', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Ошибка при получения информации о файле **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Ошибка при получения информации о файле: {0}', - 'DIALOG_FILEPROGRESS_TITLE' : 'Состояние операции над файлом', - 'DIALOG_FILEPROGRESS_LOADING' : 'Загрузка...', + 'DIALOG_INPUT_TITLE' : 'Диалог ввода', - 'DIALOG_UPLOAD_TITLE' : 'Загрузка', - 'DIALOG_UPLOAD_DESC' : 'Загрузка файла **{0}**.
Максимальный размер: {1} байт', - 'DIALOG_UPLOAD_MSG_FMT' : 'Загрузка \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Загрузка файла...', - 'DIALOG_UPLOAD_FAILED' : 'Загрузка не удалась', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Загрузка завершилась неудачей', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Причина неизвестна...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Отменено пользователем...', + 'DIALOG_FILEPROGRESS_TITLE' : 'Состояние операции над файлом', + 'DIALOG_FILEPROGRESS_LOADING' : 'Загрузка...', - 'DIALOG_FONT_TITLE' : 'Шрифт', + 'DIALOG_UPLOAD_TITLE' : 'Загрузка', + 'DIALOG_UPLOAD_DESC' : 'Загрузка файла **{0}**.
Максимальный размер: {1} байт', + 'DIALOG_UPLOAD_MSG_FMT' : 'Загрузка \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Загрузка файла...', + 'DIALOG_UPLOAD_FAILED' : 'Загрузка не удалась', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Загрузка завершилась неудачей', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Причина неизвестна...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Отменено пользователем...', - 'DIALOG_APPCHOOSER_TITLE' : 'Выберите приложение', - 'DIALOG_APPCHOOSER_MSG' : 'Выберите приложение для открытия', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Вам необходимо выбрать приложение', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Использовать в качестве приложения по умолчанию для {0}', + 'DIALOG_FONT_TITLE' : 'Шрифт', - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI модуль не настроен или отключен', - 'GAPI_SIGN_OUT' : 'Выйти из API служб Google', - 'GAPI_REVOKE' : 'Отозвать права доступа и выйти', - 'GAPI_AUTH_FAILURE' : 'Не удалось аутентифицировать Google API', - 'GAPI_AUTH_FAILURE_FMT' : 'Не удалось проверить подлинность: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Не удалось загрузить Google API', + 'DIALOG_APPCHOOSER_TITLE' : 'Выберите приложение', + 'DIALOG_APPCHOOSER_MSG' : 'Выберите приложение для открытия', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Вам необходимо выбрать приложение', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Использовать в качестве приложения по умолчанию для {0}', - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Не удается создать IndexedDB без названия', - 'IDB_NO_SUCH_ITEM' : 'Ничего не удалось найти', + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI модуль не настроен или отключен', + 'GAPI_SIGN_OUT' : 'Выйти из API служб Google', + 'GAPI_REVOKE' : 'Отозвать права доступа и выйти', + 'GAPI_AUTH_FAILURE' : 'Не удалось аутентифицировать Google API', + 'GAPI_AUTH_FAILURE_FMT' : 'Не удалось проверить подлинность: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Не удалось загрузить Google API', - // VFS - 'ERR_VFS_FATAL' : 'Критическая ошибка', - 'ERR_VFS_FILE_ARGS' : 'Файл ожидает по меньшей мере один аргумент', - 'ERR_VFS_NUM_ARGS' : 'Недостаточно аргументов', - 'ERR_VFS_EXPECT_FILE' : 'Ожидается file-object', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Ожидается источник file-object', - 'ERR_VFS_EXPECT_DST_FILE' : 'Ожидается имя файла file-object', - 'ERR_VFS_FILE_EXISTS' : 'Файл с таким именем уже существует', - 'ERR_VFS_TRANSFER_FMT' : 'Произошла ошибка во время переноса между хранилищами: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Невозможно загрузить файл, без указания имени', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Не определены файлы для загрузки', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Загрузка файла не удалась: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Загрузка файла была отменена', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Невозможно скачать каталог без пути', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Произошла ошибка при загрузке: {0}', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Скачивание файла', + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Не удается создать IndexedDB без названия', + 'IDB_NO_SUCH_ITEM' : 'Ничего не удалось найти', - // DefaultApplication - 'ERR_FILE_APP_OPEN' : 'Невозможно открыть файл', - 'ERR_FILE_APP_OPEN_FMT' : 'Файл {0} не может быть открыт, mime-type {1} не поддерживается', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Файл {0} не может быть открыт: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Файл {0} не может быть сохранен: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Ошибка приложения', - 'ERR_GENERIC_APP_ACTION_FMT': 'Не удалось выполнить действие \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Неизвестная ошибка', - 'ERR_GENERIC_APP_REQUEST' : 'Произошла ошибка при обработке вашего запроса', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Критическая ошибка: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Отменить изменения?', - 'MSG_FILE_CHANGED' : 'Файл был изменен. Перезагрузить?', - 'MSG_APPLICATION_WARNING' : 'Предупреждение', - 'MSG_MIME_OVERRIDE' : 'Тип файла "{0}" не поддерживается, используете "{1}".', + // VFS + 'ERR_VFS_FATAL' : 'Критическая ошибка', + 'ERR_VFS_FILE_ARGS' : 'Файл ожидает по меньшей мере один аргумент', + 'ERR_VFS_NUM_ARGS' : 'Недостаточно аргументов', + 'ERR_VFS_EXPECT_FILE' : 'Ожидается file-object', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Ожидается источник file-object', + 'ERR_VFS_EXPECT_DST_FILE' : 'Ожидается имя файла file-object', + 'ERR_VFS_FILE_EXISTS' : 'Файл с таким именем уже существует', + 'ERR_VFS_TRANSFER_FMT' : 'Произошла ошибка во время переноса между хранилищами: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Невозможно загрузить файл, без указания имени', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Не определены файлы для загрузки', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Загрузка файла не удалась: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Загрузка файла была отменена', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Невозможно скачать каталог без пути', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Произошла ошибка при загрузке: {0}', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Скачивание файла', - // General - 'LBL_UNKNOWN' : 'Неизвестный', - 'LBL_APPEARANCE' : 'Появление', - 'LBL_USER' : 'Пользователь', - 'LBL_NAME' : 'Название', - 'LBL_APPLY' : 'Применить', - 'LBL_FILENAME' : 'Имя файла', - 'LBL_PATH' : 'Путь', - 'LBL_SIZE' : 'Размер', - 'LBL_TYPE' : 'Тип', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Загрузка', - 'LBL_SETTINGS' : 'Настройки', - 'LBL_ADD_FILE' : 'Добавить файл', - 'LBL_COMMENT' : 'Комментарий', - 'LBL_ACCOUNT' : 'Учетная запись', - 'LBL_CONNECT' : 'Подключиться', - 'LBL_ONLINE' : 'В сети', - 'LBL_OFFLINE' : 'Не в сети', - 'LBL_AWAY' : 'Отошел', - 'LBL_BUSY' : 'Занят', - 'LBL_CHAT' : 'Чат', - 'LBL_HELP' : 'Помощь', - 'LBL_ABOUT' : 'О программе', - 'LBL_PANELS' : 'Панели', - 'LBL_LOCALES' : 'Языки', - 'LBL_THEME' : 'Тема', - 'LBL_COLOR' : 'Цвет', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Завершить', - 'LBL_ALIVE' : 'Работает', - 'LBL_INDEX' : 'Индекс', - 'LBL_ADD' : 'Добавить', - 'LBL_FONT' : 'Шрифт', - 'LBL_YES' : 'Да', - 'LBL_NO' : 'Нет', - 'LBL_CANCEL' : 'Отмена', - 'LBL_TOP' : 'Верх', - 'LBL_LEFT' : 'Лево', - 'LBL_RIGHT' : 'Право', - 'LBL_BOTTOM' : 'Низ', - 'LBL_CENTER' : 'Центр', - 'LBL_FILE' : 'Файл', - 'LBL_NEW' : 'Новый', - 'LBL_OPEN' : 'Открыть', - 'LBL_SAVE' : 'Сохранить', - 'LBL_SAVEAS' : 'Сохранить как...', - 'LBL_CLOSE' : 'Закрыть', - 'LBL_MKDIR' : 'Создать каталог', - 'LBL_UPLOAD' : 'Загрузить', - 'LBL_VIEW' : 'Вид', - 'LBL_EDIT' : 'Редактировать', - 'LBL_RENAME' : 'Переименовать', - 'LBL_DELETE' : 'Удалить', - 'LBL_OPENWITH' : 'Открыть в ...', - 'LBL_ICONVIEW' : 'Значки', - 'LBL_TREEVIEW' : 'Древовидный', - 'LBL_LISTVIEW' : 'Список', - 'LBL_REFRESH' : 'Обновить', - 'LBL_VIEWTYPE' : 'Режим просмотра', - 'LBL_BOLD' : 'Полужирный', - 'LBL_ITALIC' : 'Курсив', - 'LBL_UNDERLINE' : 'Подчеркнутый', - 'LBL_REGULAR' : 'Обычный', - 'LBL_STRIKE' : 'Перечеркнутый', - 'LBL_INDENT' : 'Уменьшить отступ', - 'LBL_OUTDENT' : 'Увеличить отступ', - 'LBL_UNDO' : 'Отменить', - 'LBL_REDO' : 'Повторить', - 'LBL_CUT' : 'Вырезать', - 'LBL_UNLINK' : 'Удалить ссылку', - 'LBL_COPY' : 'Копировать', - 'LBL_PASTE' : 'Вставить', - 'LBL_INSERT' : 'Вставка', - 'LBL_IMAGE' : 'Изображение', - 'LBL_LINK' : 'Ссылка', - 'LBL_DISCONNECT' : 'Отключиться', - 'LBL_APPLICATIONS' : 'Приложения', - 'LBL_ADD_FOLDER' : 'Добавить папку', - 'LBL_INFORMATION' : 'Информация', - 'LBL_TEXT_COLOR' : 'Цвет текста', - 'LBL_BACK_COLOR' : 'Цвет фона', - 'LBL_RESET_DEFAULT' : 'Сбросить к стандартным', - 'LBL_DOWNLOAD_COMP' : 'Скачать', - 'LBL_ORDERED_LIST' : 'Нумерованный список', - 'LBL_BACKGROUND_IMAGE' : 'Фоновое изображение', - 'LBL_BACKGROUND_COLOR' : 'Фоновый цвет', - 'LBL_UNORDERED_LIST' : 'Неупорядоченный список', - 'LBL_SHOW_SIDEBAR' : 'Отобразить боковую панель', - 'LBL_BACKGROUND' : 'Фон', - 'LBL_DESKTOP' : 'Настройки', - 'LBL_PANEL' : 'Панель', - 'LBL_POSITION' : 'Расположение', - 'LBL_ONTOP' : 'Вверху', - 'LBL_ITEMS' : 'Элементы', - 'LBL_AUTOHIDE' : 'Автоматически скрывать', - 'LBL_OPACITY' : 'Прозрачность', - 'LBL_GENERAL' : 'Основные', - 'LBL_DEBUG' : 'Отладка' - }; + // DefaultApplication + 'ERR_FILE_APP_OPEN' : 'Невозможно открыть файл', + 'ERR_FILE_APP_OPEN_FMT' : 'Файл {0} не может быть открыт, mime-type {1} не поддерживается', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Файл {0} не может быть открыт: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Файл {0} не может быть сохранен: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Ошибка приложения', + 'ERR_GENERIC_APP_ACTION_FMT': 'Не удалось выполнить действие \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Неизвестная ошибка', + 'ERR_GENERIC_APP_REQUEST' : 'Произошла ошибка при обработке вашего запроса', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Критическая ошибка: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Отменить изменения?', + 'MSG_FILE_CHANGED' : 'Файл был изменен. Перезагрузить?', + 'MSG_APPLICATION_WARNING' : 'Предупреждение', + 'MSG_MIME_OVERRIDE' : 'Тип файла "{0}" не поддерживается, используете "{1}".', -})(); + // General + 'LBL_UNKNOWN' : 'Неизвестный', + 'LBL_APPEARANCE' : 'Появление', + 'LBL_USER' : 'Пользователь', + 'LBL_NAME' : 'Название', + 'LBL_APPLY' : 'Применить', + 'LBL_FILENAME' : 'Имя файла', + 'LBL_PATH' : 'Путь', + 'LBL_SIZE' : 'Размер', + 'LBL_TYPE' : 'Тип', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Загрузка', + 'LBL_SETTINGS' : 'Настройки', + 'LBL_ADD_FILE' : 'Добавить файл', + 'LBL_COMMENT' : 'Комментарий', + 'LBL_ACCOUNT' : 'Учетная запись', + 'LBL_CONNECT' : 'Подключиться', + 'LBL_ONLINE' : 'В сети', + 'LBL_OFFLINE' : 'Не в сети', + 'LBL_AWAY' : 'Отошел', + 'LBL_BUSY' : 'Занят', + 'LBL_CHAT' : 'Чат', + 'LBL_HELP' : 'Помощь', + 'LBL_ABOUT' : 'О программе', + 'LBL_PANELS' : 'Панели', + 'LBL_LOCALES' : 'Языки', + 'LBL_THEME' : 'Тема', + 'LBL_COLOR' : 'Цвет', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Завершить', + 'LBL_ALIVE' : 'Работает', + 'LBL_INDEX' : 'Индекс', + 'LBL_ADD' : 'Добавить', + 'LBL_FONT' : 'Шрифт', + 'LBL_YES' : 'Да', + 'LBL_NO' : 'Нет', + 'LBL_CANCEL' : 'Отмена', + 'LBL_TOP' : 'Верх', + 'LBL_LEFT' : 'Лево', + 'LBL_RIGHT' : 'Право', + 'LBL_BOTTOM' : 'Низ', + 'LBL_CENTER' : 'Центр', + 'LBL_FILE' : 'Файл', + 'LBL_NEW' : 'Новый', + 'LBL_OPEN' : 'Открыть', + 'LBL_SAVE' : 'Сохранить', + 'LBL_SAVEAS' : 'Сохранить как...', + 'LBL_CLOSE' : 'Закрыть', + 'LBL_MKDIR' : 'Создать каталог', + 'LBL_UPLOAD' : 'Загрузить', + 'LBL_VIEW' : 'Вид', + 'LBL_EDIT' : 'Редактировать', + 'LBL_RENAME' : 'Переименовать', + 'LBL_DELETE' : 'Удалить', + 'LBL_OPENWITH' : 'Открыть в ...', + 'LBL_ICONVIEW' : 'Значки', + 'LBL_TREEVIEW' : 'Древовидный', + 'LBL_LISTVIEW' : 'Список', + 'LBL_REFRESH' : 'Обновить', + 'LBL_VIEWTYPE' : 'Режим просмотра', + 'LBL_BOLD' : 'Полужирный', + 'LBL_ITALIC' : 'Курсив', + 'LBL_UNDERLINE' : 'Подчеркнутый', + 'LBL_REGULAR' : 'Обычный', + 'LBL_STRIKE' : 'Перечеркнутый', + 'LBL_INDENT' : 'Уменьшить отступ', + 'LBL_OUTDENT' : 'Увеличить отступ', + 'LBL_UNDO' : 'Отменить', + 'LBL_REDO' : 'Повторить', + 'LBL_CUT' : 'Вырезать', + 'LBL_UNLINK' : 'Удалить ссылку', + 'LBL_COPY' : 'Копировать', + 'LBL_PASTE' : 'Вставить', + 'LBL_INSERT' : 'Вставка', + 'LBL_IMAGE' : 'Изображение', + 'LBL_LINK' : 'Ссылка', + 'LBL_DISCONNECT' : 'Отключиться', + 'LBL_APPLICATIONS' : 'Приложения', + 'LBL_ADD_FOLDER' : 'Добавить папку', + 'LBL_INFORMATION' : 'Информация', + 'LBL_TEXT_COLOR' : 'Цвет текста', + 'LBL_BACK_COLOR' : 'Цвет фона', + 'LBL_RESET_DEFAULT' : 'Сбросить к стандартным', + 'LBL_DOWNLOAD_COMP' : 'Скачать', + 'LBL_ORDERED_LIST' : 'Нумерованный список', + 'LBL_BACKGROUND_IMAGE' : 'Фоновое изображение', + 'LBL_BACKGROUND_COLOR' : 'Фоновый цвет', + 'LBL_UNORDERED_LIST' : 'Неупорядоченный список', + 'LBL_SHOW_SIDEBAR' : 'Отобразить боковую панель', + 'LBL_BACKGROUND' : 'Фон', + 'LBL_DESKTOP' : 'Настройки', + 'LBL_PANEL' : 'Панель', + 'LBL_POSITION' : 'Расположение', + 'LBL_ONTOP' : 'Вверху', + 'LBL_ITEMS' : 'Элементы', + 'LBL_AUTOHIDE' : 'Автоматически скрывать', + 'LBL_OPACITY' : 'Прозрачность', + 'LBL_GENERAL' : 'Основные', + 'LBL_DEBUG' : 'Отладка' +}; diff --git a/src/client/javascript/locales/sk_SK.js b/src/client/javascript/locales/sk_SK.js index 30b3a50dd1..029f5ba218 100644 --- a/src/client/javascript/locales/sk_SK.js +++ b/src/client/javascript/locales/sk_SK.js @@ -27,354 +27,351 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.sk_SK = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Chyba pri otváraní súboru', - 'ERR_WM_NOT_RUNNING' : 'Správca okien nebeží', - 'ERR_FILE_OPEN_FMT' : 'Súbor \'**{0}**\' sa nedá otvoriť', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Neviem nájsť Aplikáciu pre otvorenie súboru \'{0}\'', - 'ERR_APP_LAUNCH_FAILED' : 'Chyba pri spúšťaní Aplikácie', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Nastala chyba pri spúšťaní Aplikácie: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri konštrukcii: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri funkcii init(): {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Aplikácia \'{0}\' chýbajú prostriedky pre spustenie alebo nastala chyba pri zavádzaní!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri zavádzaní: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Aplikácia \'{0}\' už beží a je povolená iba jedna inštancia!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Chyba pri spustení \'{0}\'. Súpisné dáta Aplikácie sa nenašli!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Chyba pri spustení \'{0}\'. Váš prehliadač nie je podporovaný: {1}', - - 'ERR_NO_WM_RUNNING' : 'Správca okien nebeží', - 'ERR_CORE_INIT_FAILED' : 'Chyba pri inicializácii OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Nastala chyba pri inicializácii OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Nemôžem spustiť OS.js: Nie je definovaný žiadny Správca okien!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Nemôžem spustiť OS.js: Chyba pri spúšťaní Správcu okien: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Nemôžem spustiť OS.js: Chyba pri zavádzaní prostriedkov...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Chybová správa JavaScript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Vyskytla sa neočakávaná chyba, možno sa jedná o chybu v programe.', - - 'ERR_APP_API_ERROR' : 'Chyba v API Aplikácie', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplikácia {0} chyba pri vykonávaní operácie \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Chýbajúci argument: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Neznáma chyba', - - 'ERR_OPERATION_TIMEOUT' : 'Časový limit vypršal', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Časový limit vypršal ({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Okno s názvom \'{0}\' už existuje', - 'WINDOW_MINIMIZE' : 'Minimalizovať', - 'WINDOW_MAXIMIZE' : 'Maximalizovať', - 'WINDOW_RESTORE' : 'Obnoviť', - 'WINDOW_CLOSE' : 'Zatvoriť', - 'WINDOW_ONTOP_ON' : 'Vždy na vrchu (Zapnúť)', - 'WINDOW_ONTOP_OFF': 'Vždy na vrchu (Vypnúť)', - - // Handler - 'TITLE_SIGN_OUT' : 'Odhlásiť sa', - 'TITLE_SIGNED_IN_AS_FMT' : 'Prihlásený ako: {0}', - - // SESSION - 'MSG_SESSION_WARNING' : 'Ste si istý že chcete opustiť OS.js? Všetky neuložené nastavenia a dáta aplikácii budú vymazané!', - - // Service - 'BUGREPORT_MSG' : 'Prosím nahláste túto chybu, ak si myslíte že sa jedná o chybu aplikácie.\nPripojte krátky popis ako k chybe došlo, a ak je to možné informáciu ako ju môžeme zopakovať', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Prihlásený k externej službe: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Fatálna chyba', - 'ERR_UTILS_XHR_FMT' : 'Chyba AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Odhlásiť sa (Ukončiť)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Odhlásenie užívateľa \'{0}\'.\nŽeláte si uložiť nastavenia?', - - 'DIALOG_CLOSE' : 'Zatvor', - 'DIALOG_CANCEL': 'Zrušiť', - 'DIALOG_APPLY' : 'Použiť', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Výstraha', - - 'DIALOG_COLOR_TITLE' : 'Výber farby', - 'DIALOG_COLOR_R' : 'Červená: {0}', - 'DIALOG_COLOR_G' : 'Zelená: {0}', - 'DIALOG_COLOR_B' : 'Modrá: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Potvrdiť', - - 'DIALOG_ERROR_MESSAGE' : 'Správa', - 'DIALOG_ERROR_SUMMARY' : 'Sumár', - 'DIALOG_ERROR_TRACE' : 'Stopovanie', - 'DIALOG_ERROR_BUGREPORT' : 'Nahlásiť chybu', - - 'DIALOG_FILE_SAVE' : 'Uložiť', - 'DIALOG_FILE_OPEN' : 'Otvoriť', - 'DIALOG_FILE_MKDIR' : 'Nový adresár', - 'DIALOG_FILE_MKDIR_MSG' : 'Vytvor nový adresár v **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Ste si istý že chcete nahradiť súbor \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Zobraziť ako', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Zoznam', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Strom', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikony', - 'DIALOG_FILE_ERROR' : 'Chyba pri práci so súborom', - 'DIALOG_FILE_ERROR_SCANDIR': 'Chyba pri čítaní adresára \'{0}\'', - 'DIALOG_FILE_MISSING_FILENAME' : 'Vyberte si súbor alebo zadajte meno nového súboru', - 'DIALOG_FILE_MISSING_SELECTION': 'Vyberte si súbor!', - - 'DIALOG_FILEINFO_TITLE' : 'Informácie o súbore', - 'DIALOG_FILEINFO_LOADING' : 'Nahrávam informácie o súbore: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Chyba pri získavaní informácií o súbore', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Nie je možné získať informácie o **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Nie je možné získať informácie o súbore: {0}', - - 'DIALOG_INPUT_TITLE' : 'Vstupný dialóg', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Stav práce so súborom', - 'DIALOG_FILEPROGRESS_LOADING' : 'Nahrávam...', - - 'DIALOG_UPLOAD_TITLE' : 'Nahraj na server', - 'DIALOG_UPLOAD_DESC' : 'Nahrávam súbor do **{0}**.
Maximálna veľkosť" {1} bajtov', - 'DIALOG_UPLOAD_MSG_FMT' : 'Nahrávam na server \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Nahrávam súbor na server...', - 'DIALOG_UPLOAD_FAILED' : 'Nahrávanie na server sa nepodarilo', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Nahrávanie na server sa nepodarilo', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Neznámy dôvod...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Zrušené užívateľom...', - 'DIALOG_UPLOAD_TOO_BIG': 'Súbor je príliš veľký', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Súbor je príliš veľký, presahuje {0}', - - 'DIALOG_FONT_TITLE' : 'Výber písma', - - 'DIALOG_APPCHOOSER_TITLE' : 'Vyberte Aplikáciu', - 'DIALOG_APPCHOOSER_MSG' : 'Vyberte Aplikáciu ktorou chcete otvoriť', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Vyberte si aplikáciu', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Použi ako východziu aplikáciu pre {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Modul je vypnutý alebo nie je nakonfigurovaný', - 'GAPI_SIGN_OUT' : 'Odhlásiť sa z Google API Services', - 'GAPI_REVOKE' : 'Odobrať práva a odhlásiť', - 'GAPI_AUTH_FAILURE' : 'Google API autentifikácia sa nepodarila alebo sa neuskutočnila', - 'GAPI_AUTH_FAILURE_FMT' : 'Nepodarilo sa autentifikovať: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Chyba pri nahrávaní Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API modul je vypnutý alebo nie je nakonfigurovaný', - 'WLAPI_SIGN_OUT' : 'Odhlásiť sa z Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Chyba pri nahrávaní Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Chyba pri prihlasovaní do Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Chyba pri prihlasovaní do Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API vrátil status {0}', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Nemôžem vytvoriť IndexedDB bez mena databázy', - 'IDB_NO_SUCH_ITEM' : 'Položka neexistuje', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Fatálna chyba', - 'ERR_VFS_UNAVAILABLE' : 'Nie je dostupný', - 'ERR_VFS_FILE_ARGS' : 'Súbor vyžaduje aspoň jeden argument', - 'ERR_VFS_NUM_ARGS' : 'Málo argumentov', - 'ERR_VFS_EXPECT_FILE' : 'Očakáva súbor-objekt', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Očakáva zdrojový súbor-objekt', - 'ERR_VFS_EXPECT_DST_FILE' : 'Očakáva cieľový súbor-objekt', - 'ERR_VFS_FILE_EXISTS' : 'Cieľ už existuje', - 'ERR_VFS_TRANSFER_FMT' : 'Nastala chyba počas prenosu medzi úložiskom: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Nemôžem nahrať na server súbor bez špecifikovaného cieľa', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Nemôžem nahrať na server bez špecifikovaných súborov', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Nepodarilo sa nahrať na server: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Nahrávanie na server bolo zrušené', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Nemôžem stiahnuť cestu k súboru', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Nastala chyba pri sťahovaní: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Prázdna odpoveď', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Sťahujem súbor', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Chyba XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'Nepodarilo sa nájsť id hlavného (koreňového) adresára', - 'ERR_VFSMODULE_NOSUCH' : 'Súbor neexistuje', - 'ERR_VFSMODULE_PARENT' : 'Nadradený adresár neexistuje', - 'ERR_VFSMODULE_PARENT_FMT' : 'Nepodarilo sa nájsť nadradený adresár: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Chyba pri čítaní adresára', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Chyba pri čítaní adresára: {0}', - 'ERR_VFSMODULE_READ' : 'Chyba pri čítaní súboru', - 'ERR_VFSMODULE_READ_FMT' : 'Chyba pri čítaní súboru: {0}', - 'ERR_VFSMODULE_WRITE' : 'Chyba pri zápise do súboru', - 'ERR_VFSMODULE_WRITE_FMT' : 'Chyba pri zápise do súboru: {0}', - 'ERR_VFSMODULE_COPY' : 'Chyba pri kopírovaní', - 'ERR_VFSMODULE_COPY_FMT' : 'Chyba pri kopírovaní: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Chyba pri mazaní súboru', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Chyba pri mazaní súboru: {0}', - 'ERR_VFSMODULE_MOVE' : 'Chyba pri presune súboru', - 'ERR_VFSMODULE_MOVE_FMT' : 'Chyba pri presune súboru: {0}', - 'ERR_VFSMODULE_EXIST' : 'Chyba pri overovaní existenciu súboru', - 'ERR_VFSMODULE_EXIST_FMT' : 'Chyba pri overovaní existenciu súboru: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Chyba pri získavaní informácií o súbore', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Chyba pri získavaní informácií o súbore: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Chyba pri vytváraní adresára', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Chyba pri vytváraní adresára: {0}', - 'ERR_VFSMODULE_URL' : 'Chyba pri získavaní URL pre súbor', - 'ERR_VFSMODULE_URL_FMT' : 'Chyba pri získavaní URL pre súbor: {0}', - 'ERR_VFSMODULE_TRASH' : 'Chyba pri presune súboru do koša', - 'ERR_VFSMODULE_TRASH_FMT' : 'Chyba pri presune súboru do koša: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Chyba pri presune súboru z koša', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Chyba pri presune súboru z koša: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Chyba pri vysýpaní koša', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Chyba pri vysýpaní koša: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Ste prihlásený do Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Odhlásiť z Google API Services', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Chyba v ceste: Položka nebola nájdená', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Adresár pre inštaláciu balíkov už existuje. Nemôžem pokračovať!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Nemôžem otvoriť súbor', - 'ERR_FILE_APP_OPEN_FMT' : 'Súbor {0} sa nedá otvoriť pretože mime typ {1} nie je podporovaný', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Súbor {0} sa nedá otvoriť: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Súbor {0} sa nedá uložiť: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Chyba Aplikácie', - 'ERR_GENERIC_APP_ACTION_FMT': 'Nepodarilo sa uskutočniť akciu \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Neznáma chyba', - 'ERR_GENERIC_APP_REQUEST' : 'Chyba počas obsluhy Vášho požiadavku', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatálna chyba: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Zrušiť zmeny?', - 'MSG_FILE_CHANGED' : 'Súbor sa zmenil. Chcete zmeny načítať?', - 'MSG_APPLICATION_WARNING' : 'Varovanie Aplikácie', - 'MSG_MIME_OVERRIDE' : 'Typ súboru "{0}" nie je podporovaný, použijem "{1}".', - - // - // General - // - - 'LBL_UNKNOWN' : 'Neznámi', - 'LBL_APPEARANCE' : 'Výskyt', - 'LBL_USER' : 'Užívateľ', - 'LBL_NAME' : 'Meno', - 'LBL_APPLY' : 'Použiť', - 'LBL_FILENAME' : 'Názov súboru', - 'LBL_PATH' : 'Cesta', - 'LBL_SIZE' : 'Veľkosť', - 'LBL_TYPE' : 'Typ', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Nahrávam', - 'LBL_SETTINGS' : 'Nastavenia', - 'LBL_ADD_FILE' : 'Pridať súbor', - 'LBL_COMMENT' : 'Komentár', - 'LBL_ACCOUNT' : 'Účet', - 'LBL_CONNECT' : 'Pripojiť', - 'LBL_ONLINE' : 'Prihlásený', - 'LBL_OFFLINE' : 'Neprihlásený', - 'LBL_AWAY' : 'Preč', - 'LBL_BUSY' : 'Zaneprázdnený', - 'LBL_CHAT' : 'Rozhovor', - 'LBL_HELP' : 'Pomoc', - 'LBL_ABOUT' : 'O programe', - 'LBL_PANELS' : 'Panely', - 'LBL_LOCALES' : 'Lokalizácie', - 'LBL_THEME' : 'Témy', - 'LBL_COLOR' : 'Farba', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Ukončiť', - 'LBL_ALIVE' : 'živý', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Pridať', - 'LBL_FONT' : 'Písmo', - 'LBL_YES' : 'Áno', - 'LBL_NO' : 'Nie', - 'LBL_CANCEL' : 'Zrušiť', - 'LBL_TOP' : 'Hore', - 'LBL_LEFT' : 'V ľavo', - 'LBL_RIGHT' : 'V pravo', - 'LBL_BOTTOM' : 'Dole', - 'LBL_CENTER' : 'V strede', - 'LBL_FILE' : 'Súbor', - 'LBL_NEW' : 'Nový', - 'LBL_OPEN' : 'Otvoriť', - 'LBL_SAVE' : 'Uložiť', - 'LBL_SAVEAS' : 'Uložiť ako...', - 'LBL_CLOSE' : 'Zatvoriť', - 'LBL_MKDIR' : 'Vytvor adresár', - 'LBL_UPLOAD' : 'Nahrať na server', - 'LBL_VIEW' : 'Zobraziť', - 'LBL_EDIT' : 'Upraviť', - 'LBL_RENAME' : 'Premenovať', - 'LBL_DELETE' : 'Vymazať', - 'LBL_OPENWITH' : 'Otvoriť pomocou ...', - 'LBL_ICONVIEW' : 'Ikony', - 'LBL_TREEVIEW' : 'Strom', - 'LBL_LISTVIEW' : 'Zoznam', - 'LBL_REFRESH' : 'Obnoviť', - 'LBL_VIEWTYPE' : 'Zobraziť ako', - 'LBL_BOLD' : 'Bold', - 'LBL_ITALIC' : 'Italic', - 'LBL_UNDERLINE' : 'Podčiarknuť', - 'LBL_REGULAR' : 'Regulárny', - 'LBL_STRIKE' : 'Strike', - 'LBL_INDENT' : 'Odrážka', - 'LBL_OUTDENT' : 'Outdate', - 'LBL_UNDO' : 'Undo', - 'LBL_REDO' : 'Redo', - 'LBL_CUT' : 'Vystrihnúť', - 'LBL_UNLINK' : 'Zrušiť odkaz (URL)', - 'LBL_COPY' : 'Kopírovať', - 'LBL_PASTE' : 'Prilepiť', - 'LBL_INSERT' : 'Vložiť', - 'LBL_IMAGE' : 'Obrázok', - 'LBL_LINK' : 'Odkaz (URL)', - 'LBL_DISCONNECT' : 'Odpojiť', - 'LBL_APPLICATIONS' : 'Aplikácie', - 'LBL_ADD_FOLDER' : 'Pridaj adresár', - 'LBL_INFORMATION' : 'Informácie', - 'LBL_TEXT_COLOR' : 'Farba textu', - 'LBL_BACK_COLOR' : 'Farba pozadia', - 'LBL_RESET_DEFAULT' : 'Obnoviť predvolené nastavenia', - 'LBL_DOWNLOAD_COMP' : 'Stiahnuť do počítača', - 'LBL_ORDERED_LIST' : 'Zotriedený zoznam', - 'LBL_BACKGROUND_IMAGE' : 'Obrázok na pozadí', - 'LBL_BACKGROUND_COLOR' : 'Farba pozadia', - 'LBL_UNORDERED_LIST' : 'Nezotriedený zoznam', - 'LBL_STATUS' : 'Status', - 'LBL_READONLY' : 'Iba na čítanie', - 'LBL_CREATED' : 'Vytvorený', - 'LBL_MODIFIED' : 'Zmenený', - 'LBL_SHOW_COLUMNS' : 'Ukáž stĺpce', - 'LBL_MOVE' : 'Presuň', - 'LBL_OPTIONS' : 'Možnosti', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Adresár', - 'LBL_CREATE' : 'Vytvoriť', - 'LBL_BUGREPORT' : 'Bugreport', - 'LBL_INSTALL' : 'Inštalovať', - 'LBL_UPDATE' : 'Aktualizovať', - 'LBL_REMOVE' : 'Odstrániť', - 'LBL_SHOW_SIDEBAR' : 'Ukáž bočnú lištu' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Chyba pri otváraní súboru', + 'ERR_WM_NOT_RUNNING' : 'Správca okien nebeží', + 'ERR_FILE_OPEN_FMT' : 'Súbor \'**{0}**\' sa nedá otvoriť', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Neviem nájsť Aplikáciu pre otvorenie súboru \'{0}\'', + 'ERR_APP_LAUNCH_FAILED' : 'Chyba pri spúšťaní Aplikácie', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Nastala chyba pri spúšťaní Aplikácie: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri konštrukcii: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri funkcii init(): {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Aplikácia \'{0}\' chýbajú prostriedky pre spustenie alebo nastala chyba pri zavádzaní!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Aplikácia \'{0}\' chyba pri zavádzaní: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Aplikácia \'{0}\' už beží a je povolená iba jedna inštancia!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Chyba pri spustení \'{0}\'. Súpisné dáta Aplikácie sa nenašli!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Chyba pri spustení \'{0}\'. Váš prehliadač nie je podporovaný: {1}', + + 'ERR_NO_WM_RUNNING' : 'Správca okien nebeží', + 'ERR_CORE_INIT_FAILED' : 'Chyba pri inicializácii OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Nastala chyba pri inicializácii OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Nemôžem spustiť OS.js: Nie je definovaný žiadny Správca okien!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Nemôžem spustiť OS.js: Chyba pri spúšťaní Správcu okien: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Nemôžem spustiť OS.js: Chyba pri zavádzaní prostriedkov...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Chybová správa JavaScript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Vyskytla sa neočakávaná chyba, možno sa jedná o chybu v programe.', + + 'ERR_APP_API_ERROR' : 'Chyba v API Aplikácie', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Aplikácia {0} chyba pri vykonávaní operácie \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Chýbajúci argument: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Neznáma chyba', + + 'ERR_OPERATION_TIMEOUT' : 'Časový limit vypršal', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Časový limit vypršal ({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Okno s názvom \'{0}\' už existuje', + 'WINDOW_MINIMIZE' : 'Minimalizovať', + 'WINDOW_MAXIMIZE' : 'Maximalizovať', + 'WINDOW_RESTORE' : 'Obnoviť', + 'WINDOW_CLOSE' : 'Zatvoriť', + 'WINDOW_ONTOP_ON' : 'Vždy na vrchu (Zapnúť)', + 'WINDOW_ONTOP_OFF': 'Vždy na vrchu (Vypnúť)', + + // Handler + 'TITLE_SIGN_OUT' : 'Odhlásiť sa', + 'TITLE_SIGNED_IN_AS_FMT' : 'Prihlásený ako: {0}', + + // SESSION + 'MSG_SESSION_WARNING' : 'Ste si istý že chcete opustiť OS.js? Všetky neuložené nastavenia a dáta aplikácii budú vymazané!', + + // Service + 'BUGREPORT_MSG' : 'Prosím nahláste túto chybu, ak si myslíte že sa jedná o chybu aplikácie.\nPripojte krátky popis ako k chybe došlo, a ak je to možné informáciu ako ju môžeme zopakovať', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Prihlásený k externej službe: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Fatálna chyba', + 'ERR_UTILS_XHR_FMT' : 'Chyba AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Odhlásiť sa (Ukončiť)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Odhlásenie užívateľa \'{0}\'.\nŽeláte si uložiť nastavenia?', + + 'DIALOG_CLOSE' : 'Zatvor', + 'DIALOG_CANCEL': 'Zrušiť', + 'DIALOG_APPLY' : 'Použiť', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Výstraha', + + 'DIALOG_COLOR_TITLE' : 'Výber farby', + 'DIALOG_COLOR_R' : 'Červená: {0}', + 'DIALOG_COLOR_G' : 'Zelená: {0}', + 'DIALOG_COLOR_B' : 'Modrá: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Potvrdiť', + + 'DIALOG_ERROR_MESSAGE' : 'Správa', + 'DIALOG_ERROR_SUMMARY' : 'Sumár', + 'DIALOG_ERROR_TRACE' : 'Stopovanie', + 'DIALOG_ERROR_BUGREPORT' : 'Nahlásiť chybu', + + 'DIALOG_FILE_SAVE' : 'Uložiť', + 'DIALOG_FILE_OPEN' : 'Otvoriť', + 'DIALOG_FILE_MKDIR' : 'Nový adresár', + 'DIALOG_FILE_MKDIR_MSG' : 'Vytvor nový adresár v **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Ste si istý že chcete nahradiť súbor \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Zobraziť ako', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Zoznam', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Strom', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Ikony', + 'DIALOG_FILE_ERROR' : 'Chyba pri práci so súborom', + 'DIALOG_FILE_ERROR_SCANDIR': 'Chyba pri čítaní adresára \'{0}\'', + 'DIALOG_FILE_MISSING_FILENAME' : 'Vyberte si súbor alebo zadajte meno nového súboru', + 'DIALOG_FILE_MISSING_SELECTION': 'Vyberte si súbor!', + + 'DIALOG_FILEINFO_TITLE' : 'Informácie o súbore', + 'DIALOG_FILEINFO_LOADING' : 'Nahrávam informácie o súbore: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Chyba pri získavaní informácií o súbore', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Nie je možné získať informácie o **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Nie je možné získať informácie o súbore: {0}', + + 'DIALOG_INPUT_TITLE' : 'Vstupný dialóg', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Stav práce so súborom', + 'DIALOG_FILEPROGRESS_LOADING' : 'Nahrávam...', + + 'DIALOG_UPLOAD_TITLE' : 'Nahraj na server', + 'DIALOG_UPLOAD_DESC' : 'Nahrávam súbor do **{0}**.
Maximálna veľkosť" {1} bajtov', + 'DIALOG_UPLOAD_MSG_FMT' : 'Nahrávam na server \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Nahrávam súbor na server...', + 'DIALOG_UPLOAD_FAILED' : 'Nahrávanie na server sa nepodarilo', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Nahrávanie na server sa nepodarilo', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Neznámy dôvod...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Zrušené užívateľom...', + 'DIALOG_UPLOAD_TOO_BIG': 'Súbor je príliš veľký', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Súbor je príliš veľký, presahuje {0}', + + 'DIALOG_FONT_TITLE' : 'Výber písma', + + 'DIALOG_APPCHOOSER_TITLE' : 'Vyberte Aplikáciu', + 'DIALOG_APPCHOOSER_MSG' : 'Vyberte Aplikáciu ktorou chcete otvoriť', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Vyberte si aplikáciu', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Použi ako východziu aplikáciu pre {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Modul je vypnutý alebo nie je nakonfigurovaný', + 'GAPI_SIGN_OUT' : 'Odhlásiť sa z Google API Services', + 'GAPI_REVOKE' : 'Odobrať práva a odhlásiť', + 'GAPI_AUTH_FAILURE' : 'Google API autentifikácia sa nepodarila alebo sa neuskutočnila', + 'GAPI_AUTH_FAILURE_FMT' : 'Nepodarilo sa autentifikovať: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Chyba pri nahrávaní Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API modul je vypnutý alebo nie je nakonfigurovaný', + 'WLAPI_SIGN_OUT' : 'Odhlásiť sa z Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Chyba pri nahrávaní Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Chyba pri prihlasovaní do Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Chyba pri prihlasovaní do Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API vrátil status {0}', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Nemôžem vytvoriť IndexedDB bez mena databázy', + 'IDB_NO_SUCH_ITEM' : 'Položka neexistuje', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Fatálna chyba', + 'ERR_VFS_UNAVAILABLE' : 'Nie je dostupný', + 'ERR_VFS_FILE_ARGS' : 'Súbor vyžaduje aspoň jeden argument', + 'ERR_VFS_NUM_ARGS' : 'Málo argumentov', + 'ERR_VFS_EXPECT_FILE' : 'Očakáva súbor-objekt', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Očakáva zdrojový súbor-objekt', + 'ERR_VFS_EXPECT_DST_FILE' : 'Očakáva cieľový súbor-objekt', + 'ERR_VFS_FILE_EXISTS' : 'Cieľ už existuje', + 'ERR_VFS_TRANSFER_FMT' : 'Nastala chyba počas prenosu medzi úložiskom: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Nemôžem nahrať na server súbor bez špecifikovaného cieľa', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Nemôžem nahrať na server bez špecifikovaných súborov', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Nepodarilo sa nahrať na server: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Nahrávanie na server bolo zrušené', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Nemôžem stiahnuť cestu k súboru', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Nastala chyba pri sťahovaní: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Prázdna odpoveď', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Sťahujem súbor', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Chyba XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'Nepodarilo sa nájsť id hlavného (koreňového) adresára', + 'ERR_VFSMODULE_NOSUCH' : 'Súbor neexistuje', + 'ERR_VFSMODULE_PARENT' : 'Nadradený adresár neexistuje', + 'ERR_VFSMODULE_PARENT_FMT' : 'Nepodarilo sa nájsť nadradený adresár: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Chyba pri čítaní adresára', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Chyba pri čítaní adresára: {0}', + 'ERR_VFSMODULE_READ' : 'Chyba pri čítaní súboru', + 'ERR_VFSMODULE_READ_FMT' : 'Chyba pri čítaní súboru: {0}', + 'ERR_VFSMODULE_WRITE' : 'Chyba pri zápise do súboru', + 'ERR_VFSMODULE_WRITE_FMT' : 'Chyba pri zápise do súboru: {0}', + 'ERR_VFSMODULE_COPY' : 'Chyba pri kopírovaní', + 'ERR_VFSMODULE_COPY_FMT' : 'Chyba pri kopírovaní: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Chyba pri mazaní súboru', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Chyba pri mazaní súboru: {0}', + 'ERR_VFSMODULE_MOVE' : 'Chyba pri presune súboru', + 'ERR_VFSMODULE_MOVE_FMT' : 'Chyba pri presune súboru: {0}', + 'ERR_VFSMODULE_EXIST' : 'Chyba pri overovaní existenciu súboru', + 'ERR_VFSMODULE_EXIST_FMT' : 'Chyba pri overovaní existenciu súboru: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Chyba pri získavaní informácií o súbore', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Chyba pri získavaní informácií o súbore: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Chyba pri vytváraní adresára', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Chyba pri vytváraní adresára: {0}', + 'ERR_VFSMODULE_URL' : 'Chyba pri získavaní URL pre súbor', + 'ERR_VFSMODULE_URL_FMT' : 'Chyba pri získavaní URL pre súbor: {0}', + 'ERR_VFSMODULE_TRASH' : 'Chyba pri presune súboru do koša', + 'ERR_VFSMODULE_TRASH_FMT' : 'Chyba pri presune súboru do koša: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Chyba pri presune súboru z koša', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Chyba pri presune súboru z koša: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Chyba pri vysýpaní koša', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Chyba pri vysýpaní koša: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Ste prihlásený do Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Odhlásiť z Google API Services', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Chyba v ceste: Položka nebola nájdená', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Adresár pre inštaláciu balíkov už existuje. Nemôžem pokračovať!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Nemôžem otvoriť súbor', + 'ERR_FILE_APP_OPEN_FMT' : 'Súbor {0} sa nedá otvoriť pretože mime typ {1} nie je podporovaný', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Súbor {0} sa nedá otvoriť: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Súbor {0} sa nedá uložiť: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Chyba Aplikácie', + 'ERR_GENERIC_APP_ACTION_FMT': 'Nepodarilo sa uskutočniť akciu \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Neznáma chyba', + 'ERR_GENERIC_APP_REQUEST' : 'Chyba počas obsluhy Vášho požiadavku', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Fatálna chyba: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Zrušiť zmeny?', + 'MSG_FILE_CHANGED' : 'Súbor sa zmenil. Chcete zmeny načítať?', + 'MSG_APPLICATION_WARNING' : 'Varovanie Aplikácie', + 'MSG_MIME_OVERRIDE' : 'Typ súboru "{0}" nie je podporovaný, použijem "{1}".', + + // + // General + // + + 'LBL_UNKNOWN' : 'Neznámi', + 'LBL_APPEARANCE' : 'Výskyt', + 'LBL_USER' : 'Užívateľ', + 'LBL_NAME' : 'Meno', + 'LBL_APPLY' : 'Použiť', + 'LBL_FILENAME' : 'Názov súboru', + 'LBL_PATH' : 'Cesta', + 'LBL_SIZE' : 'Veľkosť', + 'LBL_TYPE' : 'Typ', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Nahrávam', + 'LBL_SETTINGS' : 'Nastavenia', + 'LBL_ADD_FILE' : 'Pridať súbor', + 'LBL_COMMENT' : 'Komentár', + 'LBL_ACCOUNT' : 'Účet', + 'LBL_CONNECT' : 'Pripojiť', + 'LBL_ONLINE' : 'Prihlásený', + 'LBL_OFFLINE' : 'Neprihlásený', + 'LBL_AWAY' : 'Preč', + 'LBL_BUSY' : 'Zaneprázdnený', + 'LBL_CHAT' : 'Rozhovor', + 'LBL_HELP' : 'Pomoc', + 'LBL_ABOUT' : 'O programe', + 'LBL_PANELS' : 'Panely', + 'LBL_LOCALES' : 'Lokalizácie', + 'LBL_THEME' : 'Témy', + 'LBL_COLOR' : 'Farba', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Ukončiť', + 'LBL_ALIVE' : 'živý', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Pridať', + 'LBL_FONT' : 'Písmo', + 'LBL_YES' : 'Áno', + 'LBL_NO' : 'Nie', + 'LBL_CANCEL' : 'Zrušiť', + 'LBL_TOP' : 'Hore', + 'LBL_LEFT' : 'V ľavo', + 'LBL_RIGHT' : 'V pravo', + 'LBL_BOTTOM' : 'Dole', + 'LBL_CENTER' : 'V strede', + 'LBL_FILE' : 'Súbor', + 'LBL_NEW' : 'Nový', + 'LBL_OPEN' : 'Otvoriť', + 'LBL_SAVE' : 'Uložiť', + 'LBL_SAVEAS' : 'Uložiť ako...', + 'LBL_CLOSE' : 'Zatvoriť', + 'LBL_MKDIR' : 'Vytvor adresár', + 'LBL_UPLOAD' : 'Nahrať na server', + 'LBL_VIEW' : 'Zobraziť', + 'LBL_EDIT' : 'Upraviť', + 'LBL_RENAME' : 'Premenovať', + 'LBL_DELETE' : 'Vymazať', + 'LBL_OPENWITH' : 'Otvoriť pomocou ...', + 'LBL_ICONVIEW' : 'Ikony', + 'LBL_TREEVIEW' : 'Strom', + 'LBL_LISTVIEW' : 'Zoznam', + 'LBL_REFRESH' : 'Obnoviť', + 'LBL_VIEWTYPE' : 'Zobraziť ako', + 'LBL_BOLD' : 'Bold', + 'LBL_ITALIC' : 'Italic', + 'LBL_UNDERLINE' : 'Podčiarknuť', + 'LBL_REGULAR' : 'Regulárny', + 'LBL_STRIKE' : 'Strike', + 'LBL_INDENT' : 'Odrážka', + 'LBL_OUTDENT' : 'Outdate', + 'LBL_UNDO' : 'Undo', + 'LBL_REDO' : 'Redo', + 'LBL_CUT' : 'Vystrihnúť', + 'LBL_UNLINK' : 'Zrušiť odkaz (URL)', + 'LBL_COPY' : 'Kopírovať', + 'LBL_PASTE' : 'Prilepiť', + 'LBL_INSERT' : 'Vložiť', + 'LBL_IMAGE' : 'Obrázok', + 'LBL_LINK' : 'Odkaz (URL)', + 'LBL_DISCONNECT' : 'Odpojiť', + 'LBL_APPLICATIONS' : 'Aplikácie', + 'LBL_ADD_FOLDER' : 'Pridaj adresár', + 'LBL_INFORMATION' : 'Informácie', + 'LBL_TEXT_COLOR' : 'Farba textu', + 'LBL_BACK_COLOR' : 'Farba pozadia', + 'LBL_RESET_DEFAULT' : 'Obnoviť predvolené nastavenia', + 'LBL_DOWNLOAD_COMP' : 'Stiahnuť do počítača', + 'LBL_ORDERED_LIST' : 'Zotriedený zoznam', + 'LBL_BACKGROUND_IMAGE' : 'Obrázok na pozadí', + 'LBL_BACKGROUND_COLOR' : 'Farba pozadia', + 'LBL_UNORDERED_LIST' : 'Nezotriedený zoznam', + 'LBL_STATUS' : 'Status', + 'LBL_READONLY' : 'Iba na čítanie', + 'LBL_CREATED' : 'Vytvorený', + 'LBL_MODIFIED' : 'Zmenený', + 'LBL_SHOW_COLUMNS' : 'Ukáž stĺpce', + 'LBL_MOVE' : 'Presuň', + 'LBL_OPTIONS' : 'Možnosti', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Adresár', + 'LBL_CREATE' : 'Vytvoriť', + 'LBL_BUGREPORT' : 'Bugreport', + 'LBL_INSTALL' : 'Inštalovať', + 'LBL_UPDATE' : 'Aktualizovať', + 'LBL_REMOVE' : 'Odstrániť', + 'LBL_SHOW_SIDEBAR' : 'Ukáž bočnú lištu' +}; diff --git a/src/client/javascript/locales/tr_TR.js b/src/client/javascript/locales/tr_TR.js index 8db59d33cf..45d655ed1d 100644 --- a/src/client/javascript/locales/tr_TR.js +++ b/src/client/javascript/locales/tr_TR.js @@ -27,360 +27,357 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.tr_TR = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Dosya açılırken hata oluştu', - 'ERR_WM_NOT_RUNNING' : 'Window manager çalışır halde değil', - 'ERR_FILE_OPEN_FMT' : '\'**{0}**\' dosya açılamadı', - 'ERR_APP_MIME_NOT_FOUND_FMT': ' \'{0}\' dosyalarını destekleyen herhangi bir program bulunamadı', - 'ERR_APP_LAUNCH_FAILED' : 'Program açılırken hata oluştun', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Dosyanın açılmaya çalışıldığı sırada br hata meydana geldi: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : ' \'{0}\' programının inşası sırasında bir hata oluştu: {1}', - 'ERR_APP_INIT_FAILED_FMT' : ' \'{0}\' programında init() hatası: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : ' \'{0}\' dosyasında kaynak dosyası eksik ya da yüklenirken hata oluştu!', - 'ERR_APP_PRELOAD_FAILED_FMT' : ' \'{0}\' programında önyükleme hatası: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '\'{0}\' programı zaten açık.Aynı anda yalnızca bir kez kullanabilirsiniz.', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : ' \'{0}\' açılamadı. Program bulunamadı!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : ' \'{0}\' açılamadı. Tarayıcınız deskteklemiyor: {1}', - - 'ERR_NO_WM_RUNNING' : 'Çalışan bir pencere bulunamadı', - 'ERR_CORE_INIT_FAILED' : ' OS.js başlatılma hatası', - 'ERR_CORE_INIT_FAILED_DESC' : ' OS.js başlatılırken bir hata meydana geldi', - 'ERR_CORE_INIT_NO_WM' : 'Cannot launch OS.js: No window manager defined!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js başlatılamaz: Window Manager yüklenirken hata oluştu: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : ' OS.js başlatılamaz: Kaynakların önyükleme işlemi sırasında hata oluştu...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Hata Bildir', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Beklenmedik bir hata meydana geldi.', - - 'ERR_APP_API_ERROR' : 'Program API hatası', - 'ERR_APP_API_ERROR_DESC_FMT' : '{0} programı \'{1}\' işlemini gerçekleşirken hata oluştu', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Gözden kaçırdığınız değişken: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Bilinmeyen bir hata', - - 'ERR_OPERATION_TIMEOUT' : 'Zaman aşımına ugradı', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Zaman aşımı({0})', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Zaten \'{0}\' adına sahip bir pencere var', - 'WINDOW_MINIMIZE' : 'Küçült', - 'WINDOW_MAXIMIZE' : 'Büyült', - 'WINDOW_RESTORE' : 'geri yükle', - 'WINDOW_CLOSE' : 'Kapat', - 'WINDOW_ONTOP_ON' : 'en üstte (aktif)', - 'WINDOW_ONTOP_OFF': 'en üstte (aktif değil)', - - // Handler - 'TITLE_SIGN_OUT' : 'Çıkış Yap', - 'TITLE_SIGNED_IN_AS_FMT' : '{0} olarak giriş yap', - - // SESSION - 'MSG_SESSION_WARNING' : 'OS.jsda çıkmak istedigine emin misin? Kaydedilmemiş tüm veriler silinecek!', - - // Service - 'BUGREPORT_MSG' : 'Hata olduğunu düşünüyorsan lütfen bizimle irtibata geç.\nHatanın nasıl oluştuğunu kısa bir şekilde yaz ve eğer yapabiliyorsan bir kopyasını bize gönder', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Harici bir servise girildi: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Ölümcül Hata', - 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Hatası: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Oturumu Kapat (Çıkış)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Oturum Kapatılıyor user \'{0}\'.\nKaydetmek ister misin?', - - 'DIALOG_CLOSE' : 'Kapat', - 'DIALOG_CANCEL': 'İptal', - 'DIALOG_APPLY' : 'Uygula', - 'DIALOG_OK' : 'Tamam', - - 'DIALOG_ALERT_TITLE' : 'Uyarı Penceresi', - - 'DIALOG_COLOR_TITLE' : 'Renk Penceresi', - 'DIALOG_COLOR_R' : 'Kırmızı: {0}', - 'DIALOG_COLOR_G' : 'Yeşil: {0}', - 'DIALOG_COLOR_B' : 'Mavi: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Onay Penceresi', - - 'DIALOG_ERROR_MESSAGE' : 'Mesaj', - 'DIALOG_ERROR_SUMMARY' : 'Özet', - 'DIALOG_ERROR_TRACE' : 'İzle', - 'DIALOG_ERROR_BUGREPORT' : ' Hata bildir', - - 'DIALOG_FILE_SAVE' : 'Kaydet', - 'DIALOG_FILE_OPEN' : 'Aç', - 'DIALOG_FILE_MKDIR' : 'Yeni Klasör', - 'DIALOG_FILE_MKDIR_MSG' : '**{0}**da yeni bir Klasör oluştur', - 'DIALOG_FILE_OVERWRITE' : 'Dosyanın üzerine yazmak konusunda emin misin \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Görünüm Seçenekleri', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste Görünümü', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Tree Görünümü', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Icon Görünümü', - 'DIALOG_FILE_ERROR' : 'Dosya Penceresi Hatası', - 'DIALOG_FILE_ERROR_SCANDIR': 'Bir hatadan dolayı \'{0}\' dosyaları listelenemedi', - 'DIALOG_FILE_MISSING_FILENAME' : 'Bir dosya seçmeli veya yeni bir dosya ismi girmelisin!', - 'DIALOG_FILE_MISSING_SELECTION': 'Bir dosya seçmelisin!', - - 'DIALOG_FILEINFO_TITLE' : 'Dosya Bilgileri', - 'DIALOG_FILEINFO_LOADING' : 'Dosya bilgileri yükleniyor: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Dosya Bilgi Penceresi Hatası', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : ' **{0}** hakkında bilgi alınırken hata meydana geldi', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '{0} Hakkında bilgi alınırken hata meydana geldi', - - 'DIALOG_INPUT_TITLE' : 'Giriş Penceresi', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Dosya İşlemlerinin İlerleme Durumu', - 'DIALOG_FILEPROGRESS_LOADING' : 'Yükleniyor...', - - 'DIALOG_UPLOAD_TITLE' : 'Yükleme Penceresi', - 'DIALOG_UPLOAD_DESC' : 'Yükle **{0}**.
Maksimum boyut: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : 'Yükleniyor \'{0}\' ({1} {2}) to {3}', - 'DIALOG_UPLOAD_MSG' : 'Yükleniyor...', - 'DIALOG_UPLOAD_FAILED' : 'Yükleme başarısız oldu', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Yükleme başarısız oldu', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'bilinmeyen bir sebepten dolayı hata oluştu...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Kullanıcı tarafından iptal edildi...', - 'DIALOG_UPLOAD_TOO_BIG': 'Dosya Boyutu çok fazla', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Dosya Boyutu çok fazla, {0} sınırını aştı', - - 'DIALOG_FONT_TITLE' : 'Yazı Tipi Penceresi', - - 'DIALOG_APPCHOOSER_TITLE' : 'Program Seç', - 'DIALOG_APPCHOOSER_MSG' : 'Açmak İçin Bir Program Seçiniz', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Bir Program Seçmeniz Gerek', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : ' {0} için varsayılan bir program seçiniz', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI Modulü inaktif veya kurulu değil', - 'GAPI_SIGN_OUT' : 'Google API Services uygulamasında çık', - 'GAPI_REVOKE' : 'İzinleri İptal Et ve Çık', - 'GAPI_AUTH_FAILURE' : 'Google API Kimlik Doğrulama Hatası', - 'GAPI_AUTH_FAILURE_FMT' : 'Kimlik Doğrulama Hatası: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Google API yüklenemedi', - - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API inaktif veya kurulu değil', - 'WLAPI_SIGN_OUT' : 'Window Live API uygulamasında çık', - 'WLAPI_LOAD_FAILURE' : 'Windows Live API yüklenirken hata oluştu', - 'WLAPI_LOGIN_FAILED' : 'Windows Live APIe girerken hata oluştu', - 'WLAPI_LOGIN_FAILED_FMT' : 'Windows Live APIe girerken hata oluştu: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API {0} hatası verdi', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Veritabanı ismi olmadan IndexedDB Oluşturulamaz', - 'IDB_NO_SUCH_ITEM' : 'Öge mevcut değil', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Ölümcül Hata', - 'ERR_VFS_UNAVAILABLE' : 'Kullanılamaz', - 'ERR_VFS_FILE_ARGS' : 'Dosyaya en az bir değişken girilmeli', - 'ERR_VFS_NUM_ARGS' : 'Yeyersiz Değişken', - 'ERR_VFS_EXPECT_FILE' : 'Dosya Bekleniyordu', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Kaynak Kod Dosyası Bekleniyordu', - 'ERR_VFS_EXPECT_DST_FILE' : 'Hedef Dosyası Bekleniyordu', - 'ERR_VFS_FILE_EXISTS' : 'Hedef Dosyası Zaten Mevcut', - 'ERR_VFS_TRANSFER_FMT' : 'depo ile {0} arasında aktarım sırasında bir hata meydana geldi', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Hedef Dosyası olmadan yükleme yapılamaz', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Dosya tanımlamadan yükleme yapılamaz', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Dosya yükleme hatası: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Dosya yükleme iptal edildi', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Hedef belli değilken dosya indirilemez', - 'ERR_VFS_DOWNLOAD_FAILED' : 'İndirilme sırasında bir hata meydana geldi: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Geri Dönüş Boş', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Dosya İndiriliyor', - - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Hatası', - 'ERR_VFSMODULE_ROOT_ID' : 'Root idsi bulunamadı', - 'ERR_VFSMODULE_NOSUCH' : 'Dosya kullanımda değil', - 'ERR_VFSMODULE_PARENT' : 'Üst Öge Bulunmuyors', - 'ERR_VFSMODULE_PARENT_FMT' : 'Üst Öge aranırken hata oluştu: {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Klasör Görüntülenirken Hata Meydana Geldi', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Klasör Görüntülenirken Hata Meydana Geldi: {0}', - 'ERR_VFSMODULE_READ' : 'Dosya Okunurken Hata oluştu', - 'ERR_VFSMODULE_READ_FMT' : 'Dosya Okunurken Hata oluştu: {0}', - 'ERR_VFSMODULE_WRITE' : 'Dosyaya yazılırken Hata oluştu', - 'ERR_VFSMODULE_WRITE_FMT' : 'Dosyaya yazılırken Hata oluştu: {0}', - 'ERR_VFSMODULE_COPY' : 'Kopyalanırken Hata meydana geldi.', - 'ERR_VFSMODULE_COPY_FMT' : 'Kopyalanırken Hata meydana geldi: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Bağlantısız Dosya', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Bağlantısız Dosya: {0}', - 'ERR_VFSMODULE_MOVE' : 'Dosya Taşınırken Hata Oluştu', - 'ERR_VFSMODULE_MOVE_FMT' : 'Dosya Taşınırken Hata Oluştu: {0}', - 'ERR_VFSMODULE_EXIST' : 'Dosyanın varlığı teyit edilirken hata meydana geldi', - 'ERR_VFSMODULE_EXIST_FMT' : 'Dosyanın varlığı teyit edilirken hata meydana geldi: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Dosya Hakkında Bilgi Toplanırken Hata Oluştu', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Dosya Hakkında Bilgi Toplanırken Hata Oluştu: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Klasör Oluşturulurken Hata Oluştu', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Klasör Oluşturulurken Hata Oluştu: {0}', - 'ERR_VFSMODULE_URL' : 'Dosyanın url adresi getirilirken hata meydana geldi', - 'ERR_VFSMODULE_URL_FMT' : 'Dosyanın url adresi getirilirken hata meydana geldi: {0}', - 'ERR_VFSMODULE_TRASH' : 'Çöp Kutusuna Taşınırken Hata Oluştu', - 'ERR_VFSMODULE_TRASH_FMT' : 'Çöp Kutusuna Taşınırken Hata Oluştu: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Çöp Kutusundan Çıkarılırken Hata Meydana Geldi', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Çöp Kutusundan Çıkarılırken Hata Meydana Geldi: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Çöpü boşaltırken hata meydana geldi', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Çöpü boşaltırken hata meydana geldi: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Dropbox APIya girdiniz', - 'DROPBOX_SIGN_OUT' : 'Google API servisi oturumunu kapat', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Öge bulunamadı', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Paketlenecek yer zaten mevcut.Yine de devam etmek istiyor musun?', - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Dosya Açılamadı', - 'ERR_FILE_APP_OPEN_FMT' : '{0} dosyası açılmadı çünkü {1} desteklenmiyor', - 'ERR_FILE_APP_OPEN_ALT_FMT' : '{0} dosyası açılamadı: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : '{0} dosyası kaydedilemedi: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} program hatası', - 'ERR_GENERIC_APP_ACTION_FMT': ' \'{0}\' gerçekleşirken hata oluştu', - 'ERR_GENERIC_APP_UNKNOWN' : 'Bilinmeyen Hata', - 'ERR_GENERIC_APP_REQUEST' : 'İstek cevaplanırken bir hata meydana geldi.', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Ölümcül Hata: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Değişiklikleri Çıkar?', - 'MSG_FILE_CHANGED' : 'Dosya değişmiş.Tekrar yüklemek ister misin?', - 'MSG_APPLICATION_WARNING' : 'Program Uyarısı', - 'MSG_MIME_OVERRIDE' : ' "{0}" türü desteklenmiyor :( .Bunun yerine "{1}" kullanının.', - - // - // General - // - - 'LBL_UNKNOWN' : 'Bilinmiyor', - 'LBL_APPEARANCE' : 'Görünüm', - 'LBL_USER' : 'Kullanıcı', - 'LBL_NAME' : 'İsim', - 'LBL_APPLY' : 'Uygula', - 'LBL_FILENAME' : 'Dosya adı', - 'LBL_PATH' : 'Dosya yolu', - 'LBL_SIZE' : 'Boyut', - 'LBL_TYPE' : 'Tür', - 'LBL_MIME' : 'MIME', //Eklenecektir - 'LBL_LOADING' : 'Yükleniyor', - 'LBL_SETTINGS' : 'Ayarlar', - 'LBL_ADD_FILE' : 'Dosya ekle', - 'LBL_COMMENT' : 'Yorum', - 'LBL_ACCOUNT' : 'Hesap', - 'LBL_CONNECT' : 'Bağlan', - 'LBL_ONLINE' : 'Aktif', - 'LBL_OFFLINE' : 'Aktif değil', - 'LBL_AWAY' : 'Yolda', - 'LBL_BUSY' : 'Meşgul', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Yardım', - 'LBL_ABOUT' : 'Hakkında', - 'LBL_PANELS' : 'Panels', - 'LBL_LOCALES' : 'Yerler', - 'LBL_THEME' : 'Tema', - 'LBL_COLOR' : 'Renk', - 'LBL_PID' : 'Kişisel Kimlik', - 'LBL_KILL' : 'Kes', - 'LBL_ALIVE' : 'Alive', - 'LBL_INDEX' : 'Index', - 'LBL_ADD' : 'Ekle', - 'LBL_FONT' : 'Yazı Tipi', - 'LBL_YES' : 'Evet', - 'LBL_NO' : 'Hayır', - 'LBL_CANCEL' : 'İptal', - 'LBL_TOP' : 'Üst', - 'LBL_LEFT' : 'Sol', - 'LBL_RIGHT' : 'Sağ', - 'LBL_BOTTOM' : 'Alt', - 'LBL_CENTER' : 'Orta', - 'LBL_FILE' : 'Dosya', - 'LBL_NEW' : 'Yeni', - 'LBL_OPEN' : 'Aç', - 'LBL_SAVE' : 'Kaydet', - 'LBL_SAVEAS' : '-olarak kaydet...', - 'LBL_CLOSE' : 'Kapat', - 'LBL_MKDIR' : 'Klasör oluştur', - 'LBL_UPLOAD' : 'Yükle', - 'LBL_VIEW' : 'Görünüm', - 'LBL_EDIT' : 'Düzenle', - 'LBL_RENAME' : 'İsmi Değiştir', - 'LBL_DELETE' : 'Sil', - 'LBL_OPENWITH' : '-ile aç ...', - 'LBL_ICONVIEW' : 'icon görünüm', - 'LBL_TREEVIEW' : 'Tree View', - 'LBL_LISTVIEW' : 'Liste Görünüm', - 'LBL_REFRESH' : 'Yenile', - 'LBL_VIEWTYPE' : 'Görünüm Türü', - 'LBL_BOLD' : 'Kalım', - 'LBL_ITALIC' : 'İtalik', - 'LBL_UNDERLINE' : 'Altı Çizili', - 'LBL_REGULAR' : 'Düzenli', - 'LBL_STRIKE' : 'Vurgulu', - 'LBL_INDENT' : 'Indent', //eklenecek - 'LBL_OUTDENT' : 'Outdate', //eklenecek - 'LBL_UNDO' : 'Geri Al', - 'LBL_REDO' : 'İleri Al', - 'LBL_CUT' : 'Kes', - 'LBL_UNLINK' : 'Bağlantıyı Kaldır', - 'LBL_COPY' : 'Kopyala', - 'LBL_PASTE' : 'Yapıştır', - 'LBL_INSERT' : 'Araya Ekle', - 'LBL_IMAGE' : 'Resim', - 'LBL_LINK' : 'Link', - 'LBL_DISCONNECT' : 'Bağlantıyı Kes', - 'LBL_APPLICATIONS' : 'Programlar', - 'LBL_ADD_FOLDER' : 'Klasör Ekle', - 'LBL_INFORMATION' : 'Bilgi', - 'LBL_TEXT_COLOR' : 'Yazı Rengi', - 'LBL_BACK_COLOR' : 'Zemin Rengi', - 'LBL_RESET_DEFAULT' : 'Reset to defaults', - 'LBL_DOWNLOAD_COMP' : 'Bilgisayara İndir', - 'LBL_ORDERED_LIST' : 'Sıralı Liste', - 'LBL_BACKGROUND_IMAGE' : 'Arkaplan Resmi', - 'LBL_BACKGROUND_COLOR' : 'Arkaplan Rengi', - 'LBL_UNORDERED_LIST' : 'Sırasız Liste', - 'LBL_STATUS' : 'Durum', - 'LBL_READONLY' : 'Sadece Oku', - 'LBL_CREATED' : 'Oluşturulma Tarihi', - 'LBL_MODIFIED' : 'Değiştirilme Tarihi', - 'LBL_SHOW_COLUMNS' : 'Sütunları Göster', - 'LBL_MOVE' : 'Taşı', - 'LBL_OPTIONS' : 'Ayarlar', - 'LBL_OK' : 'Tamam', - 'LBL_DIRECTORY' : 'Klasör', - 'LBL_CREATE' : 'oluştur', - 'LBL_BUGREPORT' : 'Hata Bildir', - 'LBL_INSTALL' : 'Yükle', - 'LBL_UPDATE' : 'Güncelle', - 'LBL_REMOVE' : 'Kaldır', - 'LBL_SHOW_SIDEBAR' : 'Kenar çubuğunu göster', - 'LBL_BACKGROUND' : 'arkaplan', - 'LBL_DESKTOP' : 'masaüstü', - 'LBL_PANEL' : 'Panel', - 'LBL_POSITION' : 'pozisyon', - 'LBL_ONTOP' : 'en üst', - 'LBL_ITEMS' : 'nesneler', - 'LBL_GENERAL' : 'genel' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Dosya açılırken hata oluştu', + 'ERR_WM_NOT_RUNNING' : 'Window manager çalışır halde değil', + 'ERR_FILE_OPEN_FMT' : '\'**{0}**\' dosya açılamadı', + 'ERR_APP_MIME_NOT_FOUND_FMT': ' \'{0}\' dosyalarını destekleyen herhangi bir program bulunamadı', + 'ERR_APP_LAUNCH_FAILED' : 'Program açılırken hata oluştun', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Dosyanın açılmaya çalışıldığı sırada br hata meydana geldi: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : ' \'{0}\' programının inşası sırasında bir hata oluştu: {1}', + 'ERR_APP_INIT_FAILED_FMT' : ' \'{0}\' programında init() hatası: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : ' \'{0}\' dosyasında kaynak dosyası eksik ya da yüklenirken hata oluştu!', + 'ERR_APP_PRELOAD_FAILED_FMT' : ' \'{0}\' programında önyükleme hatası: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '\'{0}\' programı zaten açık.Aynı anda yalnızca bir kez kullanabilirsiniz.', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : ' \'{0}\' açılamadı. Program bulunamadı!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : ' \'{0}\' açılamadı. Tarayıcınız deskteklemiyor: {1}', + + 'ERR_NO_WM_RUNNING' : 'Çalışan bir pencere bulunamadı', + 'ERR_CORE_INIT_FAILED' : ' OS.js başlatılma hatası', + 'ERR_CORE_INIT_FAILED_DESC' : ' OS.js başlatılırken bir hata meydana geldi', + 'ERR_CORE_INIT_NO_WM' : 'Cannot launch OS.js: No window manager defined!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'OS.js başlatılamaz: Window Manager yüklenirken hata oluştu: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : ' OS.js başlatılamaz: Kaynakların önyükleme işlemi sırasında hata oluştu...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'JavaScript Hata Bildir', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Beklenmedik bir hata meydana geldi.', + + 'ERR_APP_API_ERROR' : 'Program API hatası', + 'ERR_APP_API_ERROR_DESC_FMT' : '{0} programı \'{1}\' işlemini gerçekleşirken hata oluştu', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Gözden kaçırdığınız değişken: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Bilinmeyen bir hata', + + 'ERR_OPERATION_TIMEOUT' : 'Zaman aşımına ugradı', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Zaman aşımı({0})', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Zaten \'{0}\' adına sahip bir pencere var', + 'WINDOW_MINIMIZE' : 'Küçült', + 'WINDOW_MAXIMIZE' : 'Büyült', + 'WINDOW_RESTORE' : 'geri yükle', + 'WINDOW_CLOSE' : 'Kapat', + 'WINDOW_ONTOP_ON' : 'en üstte (aktif)', + 'WINDOW_ONTOP_OFF': 'en üstte (aktif değil)', + + // Handler + 'TITLE_SIGN_OUT' : 'Çıkış Yap', + 'TITLE_SIGNED_IN_AS_FMT' : '{0} olarak giriş yap', + + // SESSION + 'MSG_SESSION_WARNING' : 'OS.jsda çıkmak istedigine emin misin? Kaydedilmemiş tüm veriler silinecek!', + + // Service + 'BUGREPORT_MSG' : 'Hata olduğunu düşünüyorsan lütfen bizimle irtibata geç.\nHatanın nasıl oluştuğunu kısa bir şekilde yaz ve eğer yapabiliyorsan bir kopyasını bize gönder', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Harici bir servise girildi: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Ölümcül Hata', + 'ERR_UTILS_XHR_FMT' : 'AJAX/XHR Hatası: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Oturumu Kapat (Çıkış)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Oturum Kapatılıyor user \'{0}\'.\nKaydetmek ister misin?', + + 'DIALOG_CLOSE' : 'Kapat', + 'DIALOG_CANCEL': 'İptal', + 'DIALOG_APPLY' : 'Uygula', + 'DIALOG_OK' : 'Tamam', + + 'DIALOG_ALERT_TITLE' : 'Uyarı Penceresi', + + 'DIALOG_COLOR_TITLE' : 'Renk Penceresi', + 'DIALOG_COLOR_R' : 'Kırmızı: {0}', + 'DIALOG_COLOR_G' : 'Yeşil: {0}', + 'DIALOG_COLOR_B' : 'Mavi: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Onay Penceresi', + + 'DIALOG_ERROR_MESSAGE' : 'Mesaj', + 'DIALOG_ERROR_SUMMARY' : 'Özet', + 'DIALOG_ERROR_TRACE' : 'İzle', + 'DIALOG_ERROR_BUGREPORT' : ' Hata bildir', + + 'DIALOG_FILE_SAVE' : 'Kaydet', + 'DIALOG_FILE_OPEN' : 'Aç', + 'DIALOG_FILE_MKDIR' : 'Yeni Klasör', + 'DIALOG_FILE_MKDIR_MSG' : '**{0}**da yeni bir Klasör oluştur', + 'DIALOG_FILE_OVERWRITE' : 'Dosyanın üzerine yazmak konusunda emin misin \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Görünüm Seçenekleri', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Liste Görünümü', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Tree Görünümü', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Icon Görünümü', + 'DIALOG_FILE_ERROR' : 'Dosya Penceresi Hatası', + 'DIALOG_FILE_ERROR_SCANDIR': 'Bir hatadan dolayı \'{0}\' dosyaları listelenemedi', + 'DIALOG_FILE_MISSING_FILENAME' : 'Bir dosya seçmeli veya yeni bir dosya ismi girmelisin!', + 'DIALOG_FILE_MISSING_SELECTION': 'Bir dosya seçmelisin!', + + 'DIALOG_FILEINFO_TITLE' : 'Dosya Bilgileri', + 'DIALOG_FILEINFO_LOADING' : 'Dosya bilgileri yükleniyor: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Dosya Bilgi Penceresi Hatası', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : ' **{0}** hakkında bilgi alınırken hata meydana geldi', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '{0} Hakkında bilgi alınırken hata meydana geldi', + + 'DIALOG_INPUT_TITLE' : 'Giriş Penceresi', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Dosya İşlemlerinin İlerleme Durumu', + 'DIALOG_FILEPROGRESS_LOADING' : 'Yükleniyor...', + + 'DIALOG_UPLOAD_TITLE' : 'Yükleme Penceresi', + 'DIALOG_UPLOAD_DESC' : 'Yükle **{0}**.
Maksimum boyut: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : 'Yükleniyor \'{0}\' ({1} {2}) to {3}', + 'DIALOG_UPLOAD_MSG' : 'Yükleniyor...', + 'DIALOG_UPLOAD_FAILED' : 'Yükleme başarısız oldu', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Yükleme başarısız oldu', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'bilinmeyen bir sebepten dolayı hata oluştu...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Kullanıcı tarafından iptal edildi...', + 'DIALOG_UPLOAD_TOO_BIG': 'Dosya Boyutu çok fazla', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Dosya Boyutu çok fazla, {0} sınırını aştı', + + 'DIALOG_FONT_TITLE' : 'Yazı Tipi Penceresi', + + 'DIALOG_APPCHOOSER_TITLE' : 'Program Seç', + 'DIALOG_APPCHOOSER_MSG' : 'Açmak İçin Bir Program Seçiniz', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Bir Program Seçmeniz Gerek', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : ' {0} için varsayılan bir program seçiniz', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI Modulü inaktif veya kurulu değil', + 'GAPI_SIGN_OUT' : 'Google API Services uygulamasında çık', + 'GAPI_REVOKE' : 'İzinleri İptal Et ve Çık', + 'GAPI_AUTH_FAILURE' : 'Google API Kimlik Doğrulama Hatası', + 'GAPI_AUTH_FAILURE_FMT' : 'Kimlik Doğrulama Hatası: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Google API yüklenemedi', + + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API inaktif veya kurulu değil', + 'WLAPI_SIGN_OUT' : 'Window Live API uygulamasında çık', + 'WLAPI_LOAD_FAILURE' : 'Windows Live API yüklenirken hata oluştu', + 'WLAPI_LOGIN_FAILED' : 'Windows Live APIe girerken hata oluştu', + 'WLAPI_LOGIN_FAILED_FMT' : 'Windows Live APIe girerken hata oluştu: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API {0} hatası verdi', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Veritabanı ismi olmadan IndexedDB Oluşturulamaz', + 'IDB_NO_SUCH_ITEM' : 'Öge mevcut değil', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Ölümcül Hata', + 'ERR_VFS_UNAVAILABLE' : 'Kullanılamaz', + 'ERR_VFS_FILE_ARGS' : 'Dosyaya en az bir değişken girilmeli', + 'ERR_VFS_NUM_ARGS' : 'Yeyersiz Değişken', + 'ERR_VFS_EXPECT_FILE' : 'Dosya Bekleniyordu', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Kaynak Kod Dosyası Bekleniyordu', + 'ERR_VFS_EXPECT_DST_FILE' : 'Hedef Dosyası Bekleniyordu', + 'ERR_VFS_FILE_EXISTS' : 'Hedef Dosyası Zaten Mevcut', + 'ERR_VFS_TRANSFER_FMT' : 'depo ile {0} arasında aktarım sırasında bir hata meydana geldi', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Hedef Dosyası olmadan yükleme yapılamaz', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Dosya tanımlamadan yükleme yapılamaz', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Dosya yükleme hatası: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Dosya yükleme iptal edildi', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Hedef belli değilken dosya indirilemez', + 'ERR_VFS_DOWNLOAD_FAILED' : 'İndirilme sırasında bir hata meydana geldi: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Geri Dönüş Boş', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Dosya İndiriliyor', + + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR Hatası', + 'ERR_VFSMODULE_ROOT_ID' : 'Root idsi bulunamadı', + 'ERR_VFSMODULE_NOSUCH' : 'Dosya kullanımda değil', + 'ERR_VFSMODULE_PARENT' : 'Üst Öge Bulunmuyors', + 'ERR_VFSMODULE_PARENT_FMT' : 'Üst Öge aranırken hata oluştu: {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Klasör Görüntülenirken Hata Meydana Geldi', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Klasör Görüntülenirken Hata Meydana Geldi: {0}', + 'ERR_VFSMODULE_READ' : 'Dosya Okunurken Hata oluştu', + 'ERR_VFSMODULE_READ_FMT' : 'Dosya Okunurken Hata oluştu: {0}', + 'ERR_VFSMODULE_WRITE' : 'Dosyaya yazılırken Hata oluştu', + 'ERR_VFSMODULE_WRITE_FMT' : 'Dosyaya yazılırken Hata oluştu: {0}', + 'ERR_VFSMODULE_COPY' : 'Kopyalanırken Hata meydana geldi.', + 'ERR_VFSMODULE_COPY_FMT' : 'Kopyalanırken Hata meydana geldi: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Bağlantısız Dosya', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Bağlantısız Dosya: {0}', + 'ERR_VFSMODULE_MOVE' : 'Dosya Taşınırken Hata Oluştu', + 'ERR_VFSMODULE_MOVE_FMT' : 'Dosya Taşınırken Hata Oluştu: {0}', + 'ERR_VFSMODULE_EXIST' : 'Dosyanın varlığı teyit edilirken hata meydana geldi', + 'ERR_VFSMODULE_EXIST_FMT' : 'Dosyanın varlığı teyit edilirken hata meydana geldi: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Dosya Hakkında Bilgi Toplanırken Hata Oluştu', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Dosya Hakkında Bilgi Toplanırken Hata Oluştu: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Klasör Oluşturulurken Hata Oluştu', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Klasör Oluşturulurken Hata Oluştu: {0}', + 'ERR_VFSMODULE_URL' : 'Dosyanın url adresi getirilirken hata meydana geldi', + 'ERR_VFSMODULE_URL_FMT' : 'Dosyanın url adresi getirilirken hata meydana geldi: {0}', + 'ERR_VFSMODULE_TRASH' : 'Çöp Kutusuna Taşınırken Hata Oluştu', + 'ERR_VFSMODULE_TRASH_FMT' : 'Çöp Kutusuna Taşınırken Hata Oluştu: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Çöp Kutusundan Çıkarılırken Hata Meydana Geldi', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Çöp Kutusundan Çıkarılırken Hata Meydana Geldi: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Çöpü boşaltırken hata meydana geldi', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Çöpü boşaltırken hata meydana geldi: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Dropbox APIya girdiniz', + 'DROPBOX_SIGN_OUT' : 'Google API servisi oturumunu kapat', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Öge bulunamadı', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Paketlenecek yer zaten mevcut.Yine de devam etmek istiyor musun?', + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Dosya Açılamadı', + 'ERR_FILE_APP_OPEN_FMT' : '{0} dosyası açılmadı çünkü {1} desteklenmiyor', + 'ERR_FILE_APP_OPEN_ALT_FMT' : '{0} dosyası açılamadı: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : '{0} dosyası kaydedilemedi: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} program hatası', + 'ERR_GENERIC_APP_ACTION_FMT': ' \'{0}\' gerçekleşirken hata oluştu', + 'ERR_GENERIC_APP_UNKNOWN' : 'Bilinmeyen Hata', + 'ERR_GENERIC_APP_REQUEST' : 'İstek cevaplanırken bir hata meydana geldi.', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Ölümcül Hata: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Değişiklikleri Çıkar?', + 'MSG_FILE_CHANGED' : 'Dosya değişmiş.Tekrar yüklemek ister misin?', + 'MSG_APPLICATION_WARNING' : 'Program Uyarısı', + 'MSG_MIME_OVERRIDE' : ' "{0}" türü desteklenmiyor :( .Bunun yerine "{1}" kullanının.', + + // + // General + // + + 'LBL_UNKNOWN' : 'Bilinmiyor', + 'LBL_APPEARANCE' : 'Görünüm', + 'LBL_USER' : 'Kullanıcı', + 'LBL_NAME' : 'İsim', + 'LBL_APPLY' : 'Uygula', + 'LBL_FILENAME' : 'Dosya adı', + 'LBL_PATH' : 'Dosya yolu', + 'LBL_SIZE' : 'Boyut', + 'LBL_TYPE' : 'Tür', + 'LBL_MIME' : 'MIME', //Eklenecektir + 'LBL_LOADING' : 'Yükleniyor', + 'LBL_SETTINGS' : 'Ayarlar', + 'LBL_ADD_FILE' : 'Dosya ekle', + 'LBL_COMMENT' : 'Yorum', + 'LBL_ACCOUNT' : 'Hesap', + 'LBL_CONNECT' : 'Bağlan', + 'LBL_ONLINE' : 'Aktif', + 'LBL_OFFLINE' : 'Aktif değil', + 'LBL_AWAY' : 'Yolda', + 'LBL_BUSY' : 'Meşgul', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Yardım', + 'LBL_ABOUT' : 'Hakkında', + 'LBL_PANELS' : 'Panels', + 'LBL_LOCALES' : 'Yerler', + 'LBL_THEME' : 'Tema', + 'LBL_COLOR' : 'Renk', + 'LBL_PID' : 'Kişisel Kimlik', + 'LBL_KILL' : 'Kes', + 'LBL_ALIVE' : 'Alive', + 'LBL_INDEX' : 'Index', + 'LBL_ADD' : 'Ekle', + 'LBL_FONT' : 'Yazı Tipi', + 'LBL_YES' : 'Evet', + 'LBL_NO' : 'Hayır', + 'LBL_CANCEL' : 'İptal', + 'LBL_TOP' : 'Üst', + 'LBL_LEFT' : 'Sol', + 'LBL_RIGHT' : 'Sağ', + 'LBL_BOTTOM' : 'Alt', + 'LBL_CENTER' : 'Orta', + 'LBL_FILE' : 'Dosya', + 'LBL_NEW' : 'Yeni', + 'LBL_OPEN' : 'Aç', + 'LBL_SAVE' : 'Kaydet', + 'LBL_SAVEAS' : '-olarak kaydet...', + 'LBL_CLOSE' : 'Kapat', + 'LBL_MKDIR' : 'Klasör oluştur', + 'LBL_UPLOAD' : 'Yükle', + 'LBL_VIEW' : 'Görünüm', + 'LBL_EDIT' : 'Düzenle', + 'LBL_RENAME' : 'İsmi Değiştir', + 'LBL_DELETE' : 'Sil', + 'LBL_OPENWITH' : '-ile aç ...', + 'LBL_ICONVIEW' : 'icon görünüm', + 'LBL_TREEVIEW' : 'Tree View', + 'LBL_LISTVIEW' : 'Liste Görünüm', + 'LBL_REFRESH' : 'Yenile', + 'LBL_VIEWTYPE' : 'Görünüm Türü', + 'LBL_BOLD' : 'Kalım', + 'LBL_ITALIC' : 'İtalik', + 'LBL_UNDERLINE' : 'Altı Çizili', + 'LBL_REGULAR' : 'Düzenli', + 'LBL_STRIKE' : 'Vurgulu', + 'LBL_INDENT' : 'Indent', //eklenecek + 'LBL_OUTDENT' : 'Outdate', //eklenecek + 'LBL_UNDO' : 'Geri Al', + 'LBL_REDO' : 'İleri Al', + 'LBL_CUT' : 'Kes', + 'LBL_UNLINK' : 'Bağlantıyı Kaldır', + 'LBL_COPY' : 'Kopyala', + 'LBL_PASTE' : 'Yapıştır', + 'LBL_INSERT' : 'Araya Ekle', + 'LBL_IMAGE' : 'Resim', + 'LBL_LINK' : 'Link', + 'LBL_DISCONNECT' : 'Bağlantıyı Kes', + 'LBL_APPLICATIONS' : 'Programlar', + 'LBL_ADD_FOLDER' : 'Klasör Ekle', + 'LBL_INFORMATION' : 'Bilgi', + 'LBL_TEXT_COLOR' : 'Yazı Rengi', + 'LBL_BACK_COLOR' : 'Zemin Rengi', + 'LBL_RESET_DEFAULT' : 'Reset to defaults', + 'LBL_DOWNLOAD_COMP' : 'Bilgisayara İndir', + 'LBL_ORDERED_LIST' : 'Sıralı Liste', + 'LBL_BACKGROUND_IMAGE' : 'Arkaplan Resmi', + 'LBL_BACKGROUND_COLOR' : 'Arkaplan Rengi', + 'LBL_UNORDERED_LIST' : 'Sırasız Liste', + 'LBL_STATUS' : 'Durum', + 'LBL_READONLY' : 'Sadece Oku', + 'LBL_CREATED' : 'Oluşturulma Tarihi', + 'LBL_MODIFIED' : 'Değiştirilme Tarihi', + 'LBL_SHOW_COLUMNS' : 'Sütunları Göster', + 'LBL_MOVE' : 'Taşı', + 'LBL_OPTIONS' : 'Ayarlar', + 'LBL_OK' : 'Tamam', + 'LBL_DIRECTORY' : 'Klasör', + 'LBL_CREATE' : 'oluştur', + 'LBL_BUGREPORT' : 'Hata Bildir', + 'LBL_INSTALL' : 'Yükle', + 'LBL_UPDATE' : 'Güncelle', + 'LBL_REMOVE' : 'Kaldır', + 'LBL_SHOW_SIDEBAR' : 'Kenar çubuğunu göster', + 'LBL_BACKGROUND' : 'arkaplan', + 'LBL_DESKTOP' : 'masaüstü', + 'LBL_PANEL' : 'Panel', + 'LBL_POSITION' : 'pozisyon', + 'LBL_ONTOP' : 'en üst', + 'LBL_ITEMS' : 'nesneler', + 'LBL_GENERAL' : 'genel' +}; diff --git a/src/client/javascript/locales/vi_VN.js b/src/client/javascript/locales/vi_VN.js index 7c5beff02c..121a8ea0d5 100644 --- a/src/client/javascript/locales/vi_VN.js +++ b/src/client/javascript/locales/vi_VN.js @@ -27,436 +27,433 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - - OSjs.Locales.vi_VN = { - // - // CORE - // - - 'ERR_FILE_OPEN' : 'Lỗi khi mở tệp', - 'ERR_WM_NOT_RUNNING' : 'Trình quản lí cửa sổ không hoạt động', - 'ERR_FILE_OPEN_FMT' : 'Tập tin \'**{0}**\' không mở được', - 'ERR_APP_MIME_NOT_FOUND_FMT': 'Không thể tìm thấy bất kỳ ứng dụng hỗ trợ cho \'{0}\' files', - 'ERR_APP_LAUNCH_FAILED' : 'Không thể khởi động ứng dụng', - 'ERR_APP_LAUNCH_FAILED_FMT' : 'Có lỗi xảy ra trong khi cố gắng khởi động: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Phần mềm \'{0}\' xây dựng thất bại: {1}', - 'ERR_APP_INIT_FAILED_FMT' : 'Phần mềm \'{0}\' init() thất bại: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : 'Tài nguyên ứng dụng còn thiếu cho \'{0}\' hoặc nó không tải được!', - 'ERR_APP_PRELOAD_FAILED_FMT' : 'Nạp trước phần mềm \'{0}\' thất bại: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Phần mềm \'{0}\' đã được khởi chạy và chỉ cho phép một hoạt động!', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Không thể khởi động \'{0}\'. Application manifest không tìm thấy!', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Không thể khởi động\'{0}\'. Trình duyệt của bạn không hỗ trợ: {1}', - - 'ERR_NO_WM_RUNNING' : 'Quản lí cửa sổ không chạy', - 'ERR_CORE_INIT_FAILED' : 'Không thể khởi động OS.js', - 'ERR_CORE_INIT_FAILED_DESC' : 'Một lỗi đã xảy ra trong khi khởi tạo OS.js', - 'ERR_CORE_INIT_NO_WM' : 'Không thể khởi động OS.js: Không có quản lí cửa sổ nào được xác định!', - 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Không thể khởi động OS.js: Không thể khởi động Window Manager: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Không thể khởi động OS.js: Không thể tải trước tài nguyên...', - 'ERR_JAVASCRIPT_EXCEPTION' : 'Báo cáo lỗi JavaScript', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Một lỗi không mong muốn xảy ra, có thể là một bug.', - - 'ERR_APP_API_ERROR' : 'Lỗi ứng dụng API', - 'ERR_APP_API_ERROR_DESC_FMT' : 'Phần mềm {0} không thực hiện hoạt động \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': 'Thiếu đối số: {0}', - 'ERR_APP_UNKNOWN_ERROR' : 'Lỗi không xác định', - - 'ERR_OPERATION_TIMEOUT' : 'Hết thời gian phản hồi', - 'ERR_OPERATION_TIMEOUT_FMT' : 'Hết thời gian phản hồi trong ({0})', - - 'ERR_ARGUMENT_FMT' : '\'{0}\' dự kiến \'{1}\' là một \'{2}\',cho \'{3}\'', - - // Window - 'ERR_WIN_DUPLICATE_FMT' : 'Bạn đã có một cửa sổ có tên \'{0}\'', - 'WINDOW_MINIMIZE' : 'Giảm thiểu', - 'WINDOW_MAXIMIZE' : 'Tối đa hóa', - 'WINDOW_RESTORE' : 'Khôi phục', - 'WINDOW_CLOSE' : 'Đóng', - 'WINDOW_ONTOP_ON' : 'Ở trên (Bật)', - 'WINDOW_ONTOP_OFF': 'Ở trên (Tắt)', - - // Handler - 'TITLE_SIGN_OUT' : 'Đăng xuất', - 'TITLE_SIGNED_IN_AS_FMT' : 'Đăng nhập như: {0}', - 'ERR_LOGIN_FMT' : 'Đăng nhập thất bại: {0}', - 'ERR_LOGIN_INVALID' : 'Đăng nhập không hợp lệ', - - // SESSION - 'ERR_NO_SESSION': 'Chưa có phiên chạy nào được tạo bởi máy chủ. Bạn có muốn đăng nhập lại không?', - 'MSG_SESSION_WARNING' : 'Bạn có muốn thoát khỏi phiên OS.js này? Mọi cài đặt và dữ liệu sẽ bị mất!', - - // Service - 'BUGREPORT_MSG' : 'Xin hãy báo lỗi này nếu bạn nghĩ rằng đây là một lỗi.\nHãy viết một mô tả ngắn gọn về lỗi đã xảy ra như thế nào, và nếu có thể, làm cách nào để tái hiện lại nó!', - - // API - 'SERVICENOTIFICATION_TOOLTIP' : 'Đăng nhập vào các dịch vụ bên ngoài: {0}', - - // Utils - 'ERR_UTILS_XHR_FATAL' : 'Lỗi nghiêm trọng', - 'ERR_UTILS_XHR_FMT' : 'Lỗi AJAX/XHR: {0}', - - // - // DIALOGS - // - 'DIALOG_LOGOUT_TITLE' : 'Đăng xuất (Thoát)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : 'Đăng xuất người dùng \'{0}\'.\nBạn có muốn lưu lại phiên chạy hiện thời?', - - 'DIALOG_CLOSE' : 'Đóng', - 'DIALOG_CANCEL': 'Hủy', - 'DIALOG_APPLY' : 'Áp dụng', - 'DIALOG_OK' : 'OK', - - 'DIALOG_ALERT_TITLE' : 'Cảnh báo', - - 'DIALOG_COLOR_TITLE' : 'Bảng màu', - 'DIALOG_COLOR_R' : 'Đỏ: {0}', - 'DIALOG_COLOR_G' : 'Xanh lá cây: {0}', - 'DIALOG_COLOR_B' : 'Xanh da trời: {0}', - 'DIALOG_COLOR_A' : 'Alpha: {0}', - - 'DIALOG_CONFIRM_TITLE' : 'Xác nhận', - - 'DIALOG_ERROR_MESSAGE' : 'Thông điệp', - 'DIALOG_ERROR_SUMMARY' : 'Tóm tắt', - 'DIALOG_ERROR_TRACE' : 'Dấu vết', - 'DIALOG_ERROR_BUGREPORT' : 'Báo cáo lỗi', - - 'DIALOG_FILE_SAVE' : 'Lưu', - 'DIALOG_FILE_OPEN' : 'Mở', - 'DIALOG_FILE_MKDIR' : 'Thư mục mới', - 'DIALOG_FILE_MKDIR_MSG' : 'Tạo một thư mục mới trong **{0}**', - 'DIALOG_FILE_OVERWRITE' : 'Bạn có chắc muốn ghi đè lên tập tin \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : 'Kiểu xem', - 'DIALOG_FILE_MNU_LISTVIEW' : 'Danh sách', - 'DIALOG_FILE_MNU_TREEVIEW' : 'Cây', - 'DIALOG_FILE_MNU_ICONVIEW' : 'Biểu tượng', - 'DIALOG_FILE_ERROR' : 'Lỗi FileDialog', - 'DIALOG_FILE_ERROR_SCANDIR': 'Không thể liệt kê thư mục \'{0}\' vì đã xảy ra lỗi', - 'DIALOG_FILE_ERROR_FIND': 'Không thể tìm kiếm trong thư mục \'{0}\' bởi một lỗi đã xảy ra', - 'DIALOG_FILE_MISSING_FILENAME' : 'Bạn cần phải chọn một tập tin hoặc nhập tên tập tin mới!', - 'DIALOG_FILE_MISSING_SELECTION': 'Bạn cần phải chọn một tập tin!', - - 'DIALOG_FILEINFO_TITLE' : 'Thông tin tập tin', - 'DIALOG_FILEINFO_LOADING' : 'Đang tải thông tin tập tin cho: {0}', - 'DIALOG_FILEINFO_ERROR' : 'Lỗi FileInformationDialog', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Không thể có được thông tin tập tin cho **{0}**', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Không thể có được thông tin tập tin cho: {0}', - - 'DIALOG_INPUT_TITLE' : 'Nhập liệu', - - 'DIALOG_FILEPROGRESS_TITLE' : 'Tiến độ của tập tin', - 'DIALOG_FILEPROGRESS_LOADING' : 'Đang nạp...', - - 'DIALOG_UPLOAD_TITLE' : 'Tải lên', - 'DIALOG_UPLOAD_DESC' : 'Tải tập tin lên đến **{0}**.
Kích thước tối đa: {1} byte', - 'DIALOG_UPLOAD_MSG_FMT' : 'Đang tải lên \'{0}\' ({1} {2}) đến {3}', - 'DIALOG_UPLOAD_MSG' : 'Đang tải lên tập tin...', - 'DIALOG_UPLOAD_FAILED' : 'Tải lên thất bại', - 'DIALOG_UPLOAD_FAILED_MSG' : 'Việc tải lên đã thất bại', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Không rõ lý do...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Hủy bỏ bởi người dùng...', - 'DIALOG_UPLOAD_TOO_BIG': 'Tập tin quá lớn', - 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Tập tin quá lớn, vượt quá {0}', - - 'DIALOG_FONT_TITLE' : 'Chọn phông', - - 'DIALOG_APPCHOOSER_TITLE' : 'Chọn ứng dụng', - 'DIALOG_APPCHOOSER_MSG' : 'Chọn một ứng dụng để mở', - 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Bạn cần phải chọn một ứng dụng', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Sử dụng như là ứng dụng mặc định cho {0}', - - // - // HELPERS - // - - // GoogleAPI - 'GAPI_DISABLED' : 'Mô-đun GoogleAPI không được cấu hình hoặc vô hiệu hóa', - 'GAPI_SIGN_OUT' : 'Đăng xuất khỏi dịch vụ Google API', - 'GAPI_REVOKE' : 'Thu hồi giấy phép và Đăng xuất', - 'GAPI_AUTH_FAILURE' : 'Google API Xác thực không thành công hoặc không diễn ra', - 'GAPI_AUTH_FAILURE_FMT' : 'Không xác thực được: {0}:{1}', - 'GAPI_LOAD_FAILURE' : 'Không tải được Google API', - - // Windows Live API - 'WLAPI_DISABLED' : 'Mô-đun Windows Live API không được cấu hình hoặc vô hiệu', - 'WLAPI_SIGN_OUT' : 'Đăng xuất khỏi Window Live API', - 'WLAPI_LOAD_FAILURE' : 'Không tải được Windows Live API', - 'WLAPI_LOGIN_FAILED' : 'Không thể đăng nhập vào Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : 'Không thể đăng nhập vào Windows Live API: {0}', - 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API gửi lại {0} status', - - // IndexedDB - 'IDB_MISSING_DBNAME' : 'Không thể tạo IndexedDB mà không có Tên cơ sở dữ liệu', - 'IDB_NO_SUCH_ITEM' : 'Không có item', - - // - // VFS - // - 'ERR_VFS_FATAL' : 'Lỗi nghiêm trọng', - 'ERR_VFS_UNAVAILABLE' : 'Không khả dụng', - 'ERR_VFS_FILE_ARGS' : 'Tập cần ít nhất một tham số', - 'ERR_VFS_NUM_ARGS' : 'Không đủ đối số', - 'ERR_VFS_EXPECT_FILE' : 'Cần một file-object', - 'ERR_VFS_EXPECT_SRC_FILE' : 'Cần một nguồn file-object', - 'ERR_VFS_EXPECT_DST_FILE' : 'Cần một điểm đến file-object', - 'ERR_VFS_FILE_EXISTS' : 'Điểm đến đã tồn tại', - 'ERR_VFS_TARGET_NOT_EXISTS': 'Mục tiêu không tồn tại', - 'ERR_VFS_TRANSFER_FMT' : 'Có lỗi xảy ra trong khi chuyển giao lưu trữ tới ổ cứng: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : 'Không thể tải lên một tập tin mà không có một điểm đến', - 'ERR_VFS_UPLOAD_NO_FILES' : 'Không thể tải lên bất kỳ tập tin mà không có định nghĩa', - 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Tải lên không thành công: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': 'Quá trình tải lên đã bị hủy bỏ', - 'ERR_VFS_DOWNLOAD_NO_FILE': 'Không thể tải về một đường dẫn mà không có một đường dẫn', - 'ERR_VFS_DOWNLOAD_FAILED' : 'Một lỗi đã xảy ra trong khi tải về: {0}', - 'ERR_VFS_REMOTEREAD_EMPTY': 'Không có phản hồi', - - 'ERR_VFSMODULE_INVALID' : 'Invalid VFS Module', - 'ERR_VFSMODULE_INVALID_FMT' : 'Invalid VFS Module: {0}', - 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Không có mô đun VFS nào khớp với {0}. Sai đường dẫn hoặc định dạng ?', - 'ERR_VFSMODULE_READONLY' : 'Mô đun VFS này là chỉ đọc', - 'ERR_VFSMODULE_READONLY_FMT' : 'Mô đun VFS này là chỉ đọc: {0}', - 'ERR_VFSMODULE_EXCEPTION' : 'Lỗi mô-đun VFS', - 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Lỗi mô-đun VFS: {0}', - 'ERR_VFSMODULE_INVALID_METHOD' : 'Sai phương thức VFS', - 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Sai phương thức VFS: {0}', - 'ERR_VFSMODULE_INVALID_TYPE' : 'Sai kiểu mô-đun VFS', - 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Sai kiểu mô-đun VFS: {0}', - 'ERR_VFSMODULE_INVALID_CONFIG' : 'Sai thiết lập mô-đun VFS', - 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Sai thiết lập mô-đun VFS: {0}', - 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Mô-đun VFS đã được gắn', - 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Mô-đun VFS \'{0}\' đã được gắn', - 'ERR_VFSMODULE_NOT_MOUNTED' : 'Mô-đun VFS chưa được gắn', - 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Mô-đun VFS \'{0}\' chưa được gắn', - - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Đang tải xuống tập tin', - - 'ERR_VFSMODULE_XHR_ERROR' : 'Lỗi XHR', - 'ERR_VFSMODULE_ROOT_ID' : 'Không thể tìm thấy id thư mục gốc', - 'ERR_VFSMODULE_NOSUCH' : 'Tập tin không tồn tại', - 'ERR_VFSMODULE_PARENT' : 'Không có thư mục cha nào như vậy', - 'ERR_VFSMODULE_PARENT_FMT' : 'Không thể tìm thư mục cha : {0}', - 'ERR_VFSMODULE_SCANDIR' : 'Không thể quét thư mục', - 'ERR_VFSMODULE_SCANDIR_FMT' : 'Không thể quét thư mục: {0}', - 'ERR_VFSMODULE_READ' : 'Không thể đọc tập tin', - 'ERR_VFSMODULE_READ_FMT' : 'Không thể đọc tập tin: {0}', - 'ERR_VFSMODULE_WRITE' : 'Không thể ghi tập tin', - 'ERR_VFSMODULE_WRITE_FMT' : 'Không thể ghi tập tin: {0}', - 'ERR_VFSMODULE_COPY' : 'Không thể sao chép', - 'ERR_VFSMODULE_COPY_FMT' : 'Không thể sao chép: {0}', - 'ERR_VFSMODULE_UNLINK' : 'Không thể bỏ liên kết tập tin', - 'ERR_VFSMODULE_UNLINK_FMT' : 'Không thể bỏ liên kết tập tin: {0}', - 'ERR_VFSMODULE_MOVE' : 'Không thể di chuyển tập tin', - 'ERR_VFSMODULE_MOVE_FMT' : 'Không thể di chuyển tập tin: {0}', - 'ERR_VFSMODULE_EXIST' : 'Không thể kiểm tra sự tồn tại của tập tin', - 'ERR_VFSMODULE_EXIST_FMT' : 'Không thể kiểm tra sự tồn tại của tập tin: {0}', - 'ERR_VFSMODULE_FILEINFO' : 'Không thể lấy thông tin file', - 'ERR_VFSMODULE_FILEINFO_FMT' : 'Không thể lấy thông tin file: {0}', - 'ERR_VFSMODULE_MKDIR' : 'Không thể tạo thư mục', - 'ERR_VFSMODULE_MKDIR_FMT' : 'Không thể tạo thư mục: {0}', - 'ERR_VFSMODULE_MKFILE' : 'Không thể tạo tập tin', - 'ERR_VFSMODULE_MKFILE_FMT' : 'Không thể tạo tập tin: {0}', - 'ERR_VFSMODULE_URL' : 'Không thể lấy URL cho file', - 'ERR_VFSMODULE_URL_FMT' : 'Không thể lấy URL cho file: {0}', - 'ERR_VFSMODULE_TRASH' : 'Không thể di chuyển tập tin vào thùng rác', - 'ERR_VFSMODULE_TRASH_FMT' : 'Không thể di chuyển tập tin vào thùng rác: {0}', - 'ERR_VFSMODULE_UNTRASH' : 'Không thể di chuyển tập tin ra khỏi thùng rác', - 'ERR_VFSMODULE_UNTRASH_FMT' : 'Không thể di chuyển tập tin ra khỏi thùng rác: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : 'Không thể làm rỗng thùng rác', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Không thể làm rỗng thùng rác : {0}', - 'ERR_VFSMODULE_FIND' : 'Không thể tìm kiếm', - 'ERR_VFSMODULE_FIND_FMT' : 'Lỗi khi tìm kiếm: {0}', - 'ERR_VFSMODULE_FREESPACE' : 'Không thể làm sạch bộ nhớ', - 'ERR_VFSMODULE_FREESPACE_FMT' : 'Lỗi khi làm sạch bộ nhớ: {0}', - - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : 'Bạn đã đăng nhập vào Dropbox API', - 'DROPBOX_SIGN_OUT' : 'Đăng xuất khỏi dịch vụ Google API', - - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : 'Không thể giải quyết đường dẫn: mục không tìm thấy', - - // ZIP - 'ZIP_PRELOAD_FAIL' : 'Không thể tải zip.js', - 'ZIP_VENDOR_FAIL' : 'Không tìm thấy zip.js, bạn có chắc chắn đã thiết lập nó chưa?', - 'ZIP_NO_RESOURCE' : 'Không có nguồn zip đã được đưa ra', - 'ZIP_NO_PATH' : 'Không có đường dẫn', - - // - // SearchEngine - // - 'SEARCH_LOADING': 'Đang tìm kiếm...', - 'SEARCH_NO_RESULTS': 'Không có kết quả', - - // - // PackageManager - // - - 'ERR_PACKAGE_EXISTS': 'Thư mục cài đặt gói phần mềm đã tồn tại. Không thể tiếp tục!', - - // - // DefaultApplication - // - 'ERR_FILE_APP_OPEN' : 'Không thể mở tập tin', - 'ERR_FILE_APP_OPEN_FMT' : 'Tập tin {0} không thể mở được vì mime {1} không được hỗ trợ', - 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Tập tin {0} không mở được: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Tập tin {0} không lưu được: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} Lỗi phần mềm', - 'ERR_GENERIC_APP_ACTION_FMT': 'Không thể thực hiện hành động \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : 'Lỗi không xác định', - 'ERR_GENERIC_APP_REQUEST' : 'Một lỗi đã xảy ra trong khi xử lý yêu cầu của bạn', - 'ERR_GENERIC_APP_FATAL_FMT' : 'Lỗi nghiêm trọng: {0}', - 'MSG_GENERIC_APP_DISCARD' : 'Hủy các thay đổi?', - 'MSG_FILE_CHANGED' : 'Các tập tin đã thay đổi. Nạp lại?', - 'MSG_APPLICATION_WARNING' : 'Cảnh báo ứng dụng', - 'MSG_MIME_OVERRIDE' : 'Loại tập tin "{0}" không được hỗ trợ, sử dụng "{1}" thay thế.', - - // - // General - // - - 'LBL_UNKNOWN' : 'Không biết', - 'LBL_APPEARANCE' : 'Giao diện', - 'LBL_USER' : 'Người dùng', - 'LBL_NAME' : 'Tên', - 'LBL_APPLY' : 'Áp dụng', - 'LBL_FILENAME' : 'Tên tệp', - 'LBL_PATH' : 'Đường dẫn', - 'LBL_SIZE' : 'Kích cỡ', - 'LBL_TYPE' : 'Kiểu', - 'LBL_MIME' : 'MIME', - 'LBL_LOADING' : 'Đang tải', - 'LBL_SETTINGS' : 'Cài đặt', - 'LBL_ADD_FILE' : 'Thêm tệp', - 'LBL_COMMENT' : 'Chú thích', - 'LBL_ACCOUNT' : 'Tài khoản', - 'LBL_CONNECT' : 'Kết nối', - 'LBL_ONLINE' : 'Trực tuyến', - 'LBL_OFFLINE' : 'Ngoại tuyến', - 'LBL_AWAY' : 'Ở xa', - 'LBL_BUSY' : 'Bận', - 'LBL_CHAT' : 'Chat', - 'LBL_HELP' : 'Hướng dẫn', - 'LBL_ABOUT' : 'Thông tin', - 'LBL_PANELS' : 'Panels', - 'LBL_LOCALES' : 'Ngôn ngữ', - 'LBL_THEME' : 'Giao diện', - 'LBL_COLOR' : 'Màu', - 'LBL_PID' : 'PID', - 'LBL_KILL' : 'Đóng', - 'LBL_ALIVE' : 'Còn sống', - 'LBL_INDEX' : 'Chỉ mục', - 'LBL_ADD' : 'Thêm', - 'LBL_FONT' : 'Phông', - 'LBL_YES' : 'Có', - 'LBL_NO' : 'Không', - 'LBL_CANCEL' : 'Hủy bỏ', - 'LBL_TOP' : 'Trên', - 'LBL_LEFT' : 'Trái', - 'LBL_RIGHT' : 'Phải', - 'LBL_BOTTOM' : 'Dưới', - 'LBL_CENTER' : 'Giữa', - 'LBL_FILE' : 'Tệp', - 'LBL_NEW' : 'Mới', - 'LBL_OPEN' : 'Mở', - 'LBL_SAVE' : 'Lưu', - 'LBL_SAVEAS' : 'Lưu như...', - 'LBL_CLOSE' : 'Đóng', - 'LBL_MKDIR' : 'Tạo thư mục', - 'LBL_UPLOAD' : 'Tải lên', - 'LBL_VIEW' : 'Xem', - 'LBL_EDIT' : 'Chỉnh sửa', - 'LBL_RENAME' : 'Đổi tên', - 'LBL_DELETE' : 'Xóa', - 'LBL_OPENWITH' : 'Mở với...', - 'LBL_ICONVIEW' : 'Biểu tượng', - 'LBL_TREEVIEW' : 'Cây', - 'LBL_LISTVIEW' : 'Danh sách', - 'LBL_REFRESH' : 'Làm mới', - 'LBL_VIEWTYPE' : 'Kiểu xem', - 'LBL_BOLD' : 'In đậm', - 'LBL_ITALIC' : 'In Ngiêng', - 'LBL_UNDERLINE' : 'Gạch dưới', - 'LBL_REGULAR' : 'Bình thường', - 'LBL_STRIKE' : 'Gạch ngang', - 'LBL_INDENT' : 'Thụt về', - 'LBL_OUTDENT' : 'Quá hạn', - 'LBL_UNDO' : 'Trở lại', - 'LBL_REDO' : 'Làm lại', - 'LBL_CUT' : 'Cắt', - 'LBL_UNLINK' : 'Hủy liên kết', - 'LBL_COPY' : 'Sao chép', - 'LBL_PASTE' : 'Dán', - 'LBL_INSERT' : 'Chèn', - 'LBL_IMAGE' : 'Ảnh', - 'LBL_LINK' : 'Liên kết', - 'LBL_DISCONNECT' : 'Mất kết nối', - 'LBL_APPLICATIONS' : 'Các ứng dụng', - 'LBL_ADD_FOLDER' : 'Thêm thư mục', - 'LBL_INFORMATION' : 'Thông tin', - 'LBL_TEXT_COLOR' : 'Màu chữ', - 'LBL_BACK_COLOR' : 'Màu nền', - 'LBL_RESET_DEFAULT' : 'Khôi phục về mặc định', - 'LBL_DOWNLOAD_COMP' : 'Tải về máy', - 'LBL_ORDERED_LIST' : 'Danh sách có thứ tự', - 'LBL_BACKGROUND_IMAGE' : 'Ảnh nền', - 'LBL_BACKGROUND_COLOR' : 'Màu nền', - 'LBL_UNORDERED_LIST' : 'Danh sách không có thứ tự', - 'LBL_STATUS' : 'Trạng thái', - 'LBL_READONLY' : 'Chỉ đọc', - 'LBL_CREATED' : 'Tạo lúc', - 'LBL_MODIFIED' : 'Sửa lúc', - 'LBL_SHOW_COLUMNS' : 'Hiện các cột', - 'LBL_MOVE' : 'Di chuyển', - 'LBL_OPTIONS' : 'Tùy chọn', - 'LBL_OK' : 'OK', - 'LBL_DIRECTORY' : 'Thư mục', - 'LBL_CREATE' : 'Tạo', - 'LBL_BUGREPORT' : 'Báo lỗi', - 'LBL_INSTALL' : 'Cài đặt', - 'LBL_UPDATE' : 'Cập nhật', - 'LBL_REMOVE' : 'Gỡ bỏ', - 'LBL_SHOW_SIDEBAR' : 'Hiện thanh bên', - 'LBL_SHOW_NAVIGATION' : 'Hiện nút điều hướng', - 'LBL_SHOW_HIDDENFILES' : 'Hiện tập tin ẩn', - 'LBL_SHOW_FILEEXTENSIONS' : 'Hiện đuôi tập tin', - 'LBL_MOUNT': 'Gắn', - 'LBL_DESCRIPTION': 'Mô tả', - 'LBL_USERNAME': 'Tên người dùng', - 'LBL_PASSWORD': 'Mật khẩu', - 'LBL_HOST': 'Host', - 'LBL_NAMESPACE': 'Namespace', - 'LBL_SEARCH': 'Tìm kiếm', - 'LBL_BACKGROUND' : 'Ảnh nền', - 'LBL_DESKTOP' : 'Màn hình chính', - 'LBL_PANEL' : 'Khung', - 'LBL_POSITION' : 'Vị trí', - 'LBL_ONTOP' : 'Ở trên', - 'LBL_ITEMS' : 'Các mục', - 'LBL_AUTOHIDE' : 'Tự động ẩn', - 'LBL_OPACITY' : 'Độ trong suốt', - 'LBL_GROUPS' : 'Nhóm', - 'LBL_VERSION' : 'Phiên bản', - 'LBL_AUTHOR' : 'Tác giả', - 'LBL_HIDE' : 'Ẩn', - 'LBL_APPLICATION' : 'Phần mềm', - 'LBL_SCOPE' : 'Phạm vi', - 'LBL_GENERAL': 'Tổng quát', - 'LBL_PERSONAL': 'Cá nhân', - 'LBL_SYSTEM': 'Hệ thống', - 'LBL_STARTING': 'Đang khởi động', - 'LBL_SOUNDS': 'Âm thanh', - 'LBL_STORE': 'Chợ ứng dụng', - 'LBL_LOCALE': 'Ngôn ngữ', - 'LBL_PACKAGE': 'Phần mềm', - 'LBL_PACKAGES': 'Các phần mềm', - 'LBL_INPUT': 'Đầu vào', - 'LBL_MISC': 'Linh tinh', - 'LBL_OTHER': 'Khác', - 'LBL_USERS': 'Người dùng', - 'LBL_FONTS': 'Phông' - }; - -})(); + +/*eslint key-spacing: "off"*/ + +module.exports = { + // + // CORE + // + + 'ERR_FILE_OPEN' : 'Lỗi khi mở tệp', + 'ERR_WM_NOT_RUNNING' : 'Trình quản lí cửa sổ không hoạt động', + 'ERR_FILE_OPEN_FMT' : 'Tập tin \'**{0}**\' không mở được', + 'ERR_APP_MIME_NOT_FOUND_FMT': 'Không thể tìm thấy bất kỳ ứng dụng hỗ trợ cho \'{0}\' files', + 'ERR_APP_LAUNCH_FAILED' : 'Không thể khởi động ứng dụng', + 'ERR_APP_LAUNCH_FAILED_FMT' : 'Có lỗi xảy ra trong khi cố gắng khởi động: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : 'Phần mềm \'{0}\' xây dựng thất bại: {1}', + 'ERR_APP_INIT_FAILED_FMT' : 'Phần mềm \'{0}\' init() thất bại: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : 'Tài nguyên ứng dụng còn thiếu cho \'{0}\' hoặc nó không tải được!', + 'ERR_APP_PRELOAD_FAILED_FMT' : 'Nạp trước phần mềm \'{0}\' thất bại: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : 'Phần mềm \'{0}\' đã được khởi chạy và chỉ cho phép một hoạt động!', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : 'Không thể khởi động \'{0}\'. Application manifest không tìm thấy!', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : 'Không thể khởi động\'{0}\'. Trình duyệt của bạn không hỗ trợ: {1}', + + 'ERR_NO_WM_RUNNING' : 'Quản lí cửa sổ không chạy', + 'ERR_CORE_INIT_FAILED' : 'Không thể khởi động OS.js', + 'ERR_CORE_INIT_FAILED_DESC' : 'Một lỗi đã xảy ra trong khi khởi tạo OS.js', + 'ERR_CORE_INIT_NO_WM' : 'Không thể khởi động OS.js: Không có quản lí cửa sổ nào được xác định!', + 'ERR_CORE_INIT_WM_FAILED_FMT' : 'Không thể khởi động OS.js: Không thể khởi động Window Manager: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : 'Không thể khởi động OS.js: Không thể tải trước tài nguyên...', + 'ERR_JAVASCRIPT_EXCEPTION' : 'Báo cáo lỗi JavaScript', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : 'Một lỗi không mong muốn xảy ra, có thể là một bug.', + + 'ERR_APP_API_ERROR' : 'Lỗi ứng dụng API', + 'ERR_APP_API_ERROR_DESC_FMT' : 'Phần mềm {0} không thực hiện hoạt động \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': 'Thiếu đối số: {0}', + 'ERR_APP_UNKNOWN_ERROR' : 'Lỗi không xác định', + + 'ERR_OPERATION_TIMEOUT' : 'Hết thời gian phản hồi', + 'ERR_OPERATION_TIMEOUT_FMT' : 'Hết thời gian phản hồi trong ({0})', + + 'ERR_ARGUMENT_FMT' : '\'{0}\' dự kiến \'{1}\' là một \'{2}\',cho \'{3}\'', + + // Window + 'ERR_WIN_DUPLICATE_FMT' : 'Bạn đã có một cửa sổ có tên \'{0}\'', + 'WINDOW_MINIMIZE' : 'Giảm thiểu', + 'WINDOW_MAXIMIZE' : 'Tối đa hóa', + 'WINDOW_RESTORE' : 'Khôi phục', + 'WINDOW_CLOSE' : 'Đóng', + 'WINDOW_ONTOP_ON' : 'Ở trên (Bật)', + 'WINDOW_ONTOP_OFF': 'Ở trên (Tắt)', + + // Handler + 'TITLE_SIGN_OUT' : 'Đăng xuất', + 'TITLE_SIGNED_IN_AS_FMT' : 'Đăng nhập như: {0}', + 'ERR_LOGIN_FMT' : 'Đăng nhập thất bại: {0}', + 'ERR_LOGIN_INVALID' : 'Đăng nhập không hợp lệ', + + // SESSION + 'ERR_NO_SESSION': 'Chưa có phiên chạy nào được tạo bởi máy chủ. Bạn có muốn đăng nhập lại không?', + 'MSG_SESSION_WARNING' : 'Bạn có muốn thoát khỏi phiên OS.js này? Mọi cài đặt và dữ liệu sẽ bị mất!', + + // Service + 'BUGREPORT_MSG' : 'Xin hãy báo lỗi này nếu bạn nghĩ rằng đây là một lỗi.\nHãy viết một mô tả ngắn gọn về lỗi đã xảy ra như thế nào, và nếu có thể, làm cách nào để tái hiện lại nó!', + + // API + 'SERVICENOTIFICATION_TOOLTIP' : 'Đăng nhập vào các dịch vụ bên ngoài: {0}', + + // Utils + 'ERR_UTILS_XHR_FATAL' : 'Lỗi nghiêm trọng', + 'ERR_UTILS_XHR_FMT' : 'Lỗi AJAX/XHR: {0}', + + // + // DIALOGS + // + 'DIALOG_LOGOUT_TITLE' : 'Đăng xuất (Thoát)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : 'Đăng xuất người dùng \'{0}\'.\nBạn có muốn lưu lại phiên chạy hiện thời?', + + 'DIALOG_CLOSE' : 'Đóng', + 'DIALOG_CANCEL': 'Hủy', + 'DIALOG_APPLY' : 'Áp dụng', + 'DIALOG_OK' : 'OK', + + 'DIALOG_ALERT_TITLE' : 'Cảnh báo', + + 'DIALOG_COLOR_TITLE' : 'Bảng màu', + 'DIALOG_COLOR_R' : 'Đỏ: {0}', + 'DIALOG_COLOR_G' : 'Xanh lá cây: {0}', + 'DIALOG_COLOR_B' : 'Xanh da trời: {0}', + 'DIALOG_COLOR_A' : 'Alpha: {0}', + + 'DIALOG_CONFIRM_TITLE' : 'Xác nhận', + + 'DIALOG_ERROR_MESSAGE' : 'Thông điệp', + 'DIALOG_ERROR_SUMMARY' : 'Tóm tắt', + 'DIALOG_ERROR_TRACE' : 'Dấu vết', + 'DIALOG_ERROR_BUGREPORT' : 'Báo cáo lỗi', + + 'DIALOG_FILE_SAVE' : 'Lưu', + 'DIALOG_FILE_OPEN' : 'Mở', + 'DIALOG_FILE_MKDIR' : 'Thư mục mới', + 'DIALOG_FILE_MKDIR_MSG' : 'Tạo một thư mục mới trong **{0}**', + 'DIALOG_FILE_OVERWRITE' : 'Bạn có chắc muốn ghi đè lên tập tin \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : 'Kiểu xem', + 'DIALOG_FILE_MNU_LISTVIEW' : 'Danh sách', + 'DIALOG_FILE_MNU_TREEVIEW' : 'Cây', + 'DIALOG_FILE_MNU_ICONVIEW' : 'Biểu tượng', + 'DIALOG_FILE_ERROR' : 'Lỗi FileDialog', + 'DIALOG_FILE_ERROR_SCANDIR': 'Không thể liệt kê thư mục \'{0}\' vì đã xảy ra lỗi', + 'DIALOG_FILE_ERROR_FIND': 'Không thể tìm kiếm trong thư mục \'{0}\' bởi một lỗi đã xảy ra', + 'DIALOG_FILE_MISSING_FILENAME' : 'Bạn cần phải chọn một tập tin hoặc nhập tên tập tin mới!', + 'DIALOG_FILE_MISSING_SELECTION': 'Bạn cần phải chọn một tập tin!', + + 'DIALOG_FILEINFO_TITLE' : 'Thông tin tập tin', + 'DIALOG_FILEINFO_LOADING' : 'Đang tải thông tin tập tin cho: {0}', + 'DIALOG_FILEINFO_ERROR' : 'Lỗi FileInformationDialog', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : 'Không thể có được thông tin tập tin cho **{0}**', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : 'Không thể có được thông tin tập tin cho: {0}', + + 'DIALOG_INPUT_TITLE' : 'Nhập liệu', + + 'DIALOG_FILEPROGRESS_TITLE' : 'Tiến độ của tập tin', + 'DIALOG_FILEPROGRESS_LOADING' : 'Đang nạp...', + + 'DIALOG_UPLOAD_TITLE' : 'Tải lên', + 'DIALOG_UPLOAD_DESC' : 'Tải tập tin lên đến **{0}**.
Kích thước tối đa: {1} byte', + 'DIALOG_UPLOAD_MSG_FMT' : 'Đang tải lên \'{0}\' ({1} {2}) đến {3}', + 'DIALOG_UPLOAD_MSG' : 'Đang tải lên tập tin...', + 'DIALOG_UPLOAD_FAILED' : 'Tải lên thất bại', + 'DIALOG_UPLOAD_FAILED_MSG' : 'Việc tải lên đã thất bại', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : 'Không rõ lý do...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': 'Hủy bỏ bởi người dùng...', + 'DIALOG_UPLOAD_TOO_BIG': 'Tập tin quá lớn', + 'DIALOG_UPLOAD_TOO_BIG_FMT': 'Tập tin quá lớn, vượt quá {0}', + + 'DIALOG_FONT_TITLE' : 'Chọn phông', + + 'DIALOG_APPCHOOSER_TITLE' : 'Chọn ứng dụng', + 'DIALOG_APPCHOOSER_MSG' : 'Chọn một ứng dụng để mở', + 'DIALOG_APPCHOOSER_NO_SELECTION' : 'Bạn cần phải chọn một ứng dụng', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : 'Sử dụng như là ứng dụng mặc định cho {0}', + + // + // HELPERS + // + + // GoogleAPI + 'GAPI_DISABLED' : 'Mô-đun GoogleAPI không được cấu hình hoặc vô hiệu hóa', + 'GAPI_SIGN_OUT' : 'Đăng xuất khỏi dịch vụ Google API', + 'GAPI_REVOKE' : 'Thu hồi giấy phép và Đăng xuất', + 'GAPI_AUTH_FAILURE' : 'Google API Xác thực không thành công hoặc không diễn ra', + 'GAPI_AUTH_FAILURE_FMT' : 'Không xác thực được: {0}:{1}', + 'GAPI_LOAD_FAILURE' : 'Không tải được Google API', + + // Windows Live API + 'WLAPI_DISABLED' : 'Mô-đun Windows Live API không được cấu hình hoặc vô hiệu', + 'WLAPI_SIGN_OUT' : 'Đăng xuất khỏi Window Live API', + 'WLAPI_LOAD_FAILURE' : 'Không tải được Windows Live API', + 'WLAPI_LOGIN_FAILED' : 'Không thể đăng nhập vào Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : 'Không thể đăng nhập vào Windows Live API: {0}', + 'WLAPI_INIT_FAILED_FMT' : 'Windows Live API gửi lại {0} status', + + // IndexedDB + 'IDB_MISSING_DBNAME' : 'Không thể tạo IndexedDB mà không có Tên cơ sở dữ liệu', + 'IDB_NO_SUCH_ITEM' : 'Không có item', + + // + // VFS + // + 'ERR_VFS_FATAL' : 'Lỗi nghiêm trọng', + 'ERR_VFS_UNAVAILABLE' : 'Không khả dụng', + 'ERR_VFS_FILE_ARGS' : 'Tập cần ít nhất một tham số', + 'ERR_VFS_NUM_ARGS' : 'Không đủ đối số', + 'ERR_VFS_EXPECT_FILE' : 'Cần một file-object', + 'ERR_VFS_EXPECT_SRC_FILE' : 'Cần một nguồn file-object', + 'ERR_VFS_EXPECT_DST_FILE' : 'Cần một điểm đến file-object', + 'ERR_VFS_FILE_EXISTS' : 'Điểm đến đã tồn tại', + 'ERR_VFS_TARGET_NOT_EXISTS': 'Mục tiêu không tồn tại', + 'ERR_VFS_TRANSFER_FMT' : 'Có lỗi xảy ra trong khi chuyển giao lưu trữ tới ổ cứng: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : 'Không thể tải lên một tập tin mà không có một điểm đến', + 'ERR_VFS_UPLOAD_NO_FILES' : 'Không thể tải lên bất kỳ tập tin mà không có định nghĩa', + 'ERR_VFS_UPLOAD_FAIL_FMT' : 'Tải lên không thành công: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': 'Quá trình tải lên đã bị hủy bỏ', + 'ERR_VFS_DOWNLOAD_NO_FILE': 'Không thể tải về một đường dẫn mà không có một đường dẫn', + 'ERR_VFS_DOWNLOAD_FAILED' : 'Một lỗi đã xảy ra trong khi tải về: {0}', + 'ERR_VFS_REMOTEREAD_EMPTY': 'Không có phản hồi', + + 'ERR_VFSMODULE_INVALID' : 'Invalid VFS Module', + 'ERR_VFSMODULE_INVALID_FMT' : 'Invalid VFS Module: {0}', + 'ERR_VFSMODULE_NOT_FOUND_FMT' : 'Không có mô đun VFS nào khớp với {0}. Sai đường dẫn hoặc định dạng ?', + 'ERR_VFSMODULE_READONLY' : 'Mô đun VFS này là chỉ đọc', + 'ERR_VFSMODULE_READONLY_FMT' : 'Mô đun VFS này là chỉ đọc: {0}', + 'ERR_VFSMODULE_EXCEPTION' : 'Lỗi mô-đun VFS', + 'ERR_VFSMODULE_EXCEPTION_FMT' : 'Lỗi mô-đun VFS: {0}', + 'ERR_VFSMODULE_INVALID_METHOD' : 'Sai phương thức VFS', + 'ERR_VFSMODULE_INVALID_METHOD_FMT' : 'Sai phương thức VFS: {0}', + 'ERR_VFSMODULE_INVALID_TYPE' : 'Sai kiểu mô-đun VFS', + 'ERR_VFSMODULE_INVALID_TYPE_FMT' : 'Sai kiểu mô-đun VFS: {0}', + 'ERR_VFSMODULE_INVALID_CONFIG' : 'Sai thiết lập mô-đun VFS', + 'ERR_VFSMODULE_INVALID_CONFIG_FMT' : 'Sai thiết lập mô-đun VFS: {0}', + 'ERR_VFSMODULE_ALREADY_MOUNTED' : 'Mô-đun VFS đã được gắn', + 'ERR_VFSMODULE_ALREADY_MOUNTED_FMT': 'Mô-đun VFS \'{0}\' đã được gắn', + 'ERR_VFSMODULE_NOT_MOUNTED' : 'Mô-đun VFS chưa được gắn', + 'ERR_VFSMODULE_NOT_MOUNTED_FMT' : 'Mô-đun VFS \'{0}\' chưa được gắn', + + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': 'Đang tải xuống tập tin', + + 'ERR_VFSMODULE_XHR_ERROR' : 'Lỗi XHR', + 'ERR_VFSMODULE_ROOT_ID' : 'Không thể tìm thấy id thư mục gốc', + 'ERR_VFSMODULE_NOSUCH' : 'Tập tin không tồn tại', + 'ERR_VFSMODULE_PARENT' : 'Không có thư mục cha nào như vậy', + 'ERR_VFSMODULE_PARENT_FMT' : 'Không thể tìm thư mục cha : {0}', + 'ERR_VFSMODULE_SCANDIR' : 'Không thể quét thư mục', + 'ERR_VFSMODULE_SCANDIR_FMT' : 'Không thể quét thư mục: {0}', + 'ERR_VFSMODULE_READ' : 'Không thể đọc tập tin', + 'ERR_VFSMODULE_READ_FMT' : 'Không thể đọc tập tin: {0}', + 'ERR_VFSMODULE_WRITE' : 'Không thể ghi tập tin', + 'ERR_VFSMODULE_WRITE_FMT' : 'Không thể ghi tập tin: {0}', + 'ERR_VFSMODULE_COPY' : 'Không thể sao chép', + 'ERR_VFSMODULE_COPY_FMT' : 'Không thể sao chép: {0}', + 'ERR_VFSMODULE_UNLINK' : 'Không thể bỏ liên kết tập tin', + 'ERR_VFSMODULE_UNLINK_FMT' : 'Không thể bỏ liên kết tập tin: {0}', + 'ERR_VFSMODULE_MOVE' : 'Không thể di chuyển tập tin', + 'ERR_VFSMODULE_MOVE_FMT' : 'Không thể di chuyển tập tin: {0}', + 'ERR_VFSMODULE_EXIST' : 'Không thể kiểm tra sự tồn tại của tập tin', + 'ERR_VFSMODULE_EXIST_FMT' : 'Không thể kiểm tra sự tồn tại của tập tin: {0}', + 'ERR_VFSMODULE_FILEINFO' : 'Không thể lấy thông tin file', + 'ERR_VFSMODULE_FILEINFO_FMT' : 'Không thể lấy thông tin file: {0}', + 'ERR_VFSMODULE_MKDIR' : 'Không thể tạo thư mục', + 'ERR_VFSMODULE_MKDIR_FMT' : 'Không thể tạo thư mục: {0}', + 'ERR_VFSMODULE_MKFILE' : 'Không thể tạo tập tin', + 'ERR_VFSMODULE_MKFILE_FMT' : 'Không thể tạo tập tin: {0}', + 'ERR_VFSMODULE_URL' : 'Không thể lấy URL cho file', + 'ERR_VFSMODULE_URL_FMT' : 'Không thể lấy URL cho file: {0}', + 'ERR_VFSMODULE_TRASH' : 'Không thể di chuyển tập tin vào thùng rác', + 'ERR_VFSMODULE_TRASH_FMT' : 'Không thể di chuyển tập tin vào thùng rác: {0}', + 'ERR_VFSMODULE_UNTRASH' : 'Không thể di chuyển tập tin ra khỏi thùng rác', + 'ERR_VFSMODULE_UNTRASH_FMT' : 'Không thể di chuyển tập tin ra khỏi thùng rác: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : 'Không thể làm rỗng thùng rác', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : 'Không thể làm rỗng thùng rác : {0}', + 'ERR_VFSMODULE_FIND' : 'Không thể tìm kiếm', + 'ERR_VFSMODULE_FIND_FMT' : 'Lỗi khi tìm kiếm: {0}', + 'ERR_VFSMODULE_FREESPACE' : 'Không thể làm sạch bộ nhớ', + 'ERR_VFSMODULE_FREESPACE_FMT' : 'Lỗi khi làm sạch bộ nhớ: {0}', + + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : 'Bạn đã đăng nhập vào Dropbox API', + 'DROPBOX_SIGN_OUT' : 'Đăng xuất khỏi dịch vụ Google API', + + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : 'Không thể giải quyết đường dẫn: mục không tìm thấy', + + // ZIP + 'ZIP_PRELOAD_FAIL' : 'Không thể tải zip.js', + 'ZIP_VENDOR_FAIL' : 'Không tìm thấy zip.js, bạn có chắc chắn đã thiết lập nó chưa?', + 'ZIP_NO_RESOURCE' : 'Không có nguồn zip đã được đưa ra', + 'ZIP_NO_PATH' : 'Không có đường dẫn', + + // + // SearchEngine + // + 'SEARCH_LOADING': 'Đang tìm kiếm...', + 'SEARCH_NO_RESULTS': 'Không có kết quả', + + // + // PackageManager + // + + 'ERR_PACKAGE_EXISTS': 'Thư mục cài đặt gói phần mềm đã tồn tại. Không thể tiếp tục!', + + // + // DefaultApplication + // + 'ERR_FILE_APP_OPEN' : 'Không thể mở tập tin', + 'ERR_FILE_APP_OPEN_FMT' : 'Tập tin {0} không thể mở được vì mime {1} không được hỗ trợ', + 'ERR_FILE_APP_OPEN_ALT_FMT' : 'Tập tin {0} không mở được: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : 'Tập tin {0} không lưu được: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} Lỗi phần mềm', + 'ERR_GENERIC_APP_ACTION_FMT': 'Không thể thực hiện hành động \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : 'Lỗi không xác định', + 'ERR_GENERIC_APP_REQUEST' : 'Một lỗi đã xảy ra trong khi xử lý yêu cầu của bạn', + 'ERR_GENERIC_APP_FATAL_FMT' : 'Lỗi nghiêm trọng: {0}', + 'MSG_GENERIC_APP_DISCARD' : 'Hủy các thay đổi?', + 'MSG_FILE_CHANGED' : 'Các tập tin đã thay đổi. Nạp lại?', + 'MSG_APPLICATION_WARNING' : 'Cảnh báo ứng dụng', + 'MSG_MIME_OVERRIDE' : 'Loại tập tin "{0}" không được hỗ trợ, sử dụng "{1}" thay thế.', + + // + // General + // + + 'LBL_UNKNOWN' : 'Không biết', + 'LBL_APPEARANCE' : 'Giao diện', + 'LBL_USER' : 'Người dùng', + 'LBL_NAME' : 'Tên', + 'LBL_APPLY' : 'Áp dụng', + 'LBL_FILENAME' : 'Tên tệp', + 'LBL_PATH' : 'Đường dẫn', + 'LBL_SIZE' : 'Kích cỡ', + 'LBL_TYPE' : 'Kiểu', + 'LBL_MIME' : 'MIME', + 'LBL_LOADING' : 'Đang tải', + 'LBL_SETTINGS' : 'Cài đặt', + 'LBL_ADD_FILE' : 'Thêm tệp', + 'LBL_COMMENT' : 'Chú thích', + 'LBL_ACCOUNT' : 'Tài khoản', + 'LBL_CONNECT' : 'Kết nối', + 'LBL_ONLINE' : 'Trực tuyến', + 'LBL_OFFLINE' : 'Ngoại tuyến', + 'LBL_AWAY' : 'Ở xa', + 'LBL_BUSY' : 'Bận', + 'LBL_CHAT' : 'Chat', + 'LBL_HELP' : 'Hướng dẫn', + 'LBL_ABOUT' : 'Thông tin', + 'LBL_PANELS' : 'Panels', + 'LBL_LOCALES' : 'Ngôn ngữ', + 'LBL_THEME' : 'Giao diện', + 'LBL_COLOR' : 'Màu', + 'LBL_PID' : 'PID', + 'LBL_KILL' : 'Đóng', + 'LBL_ALIVE' : 'Còn sống', + 'LBL_INDEX' : 'Chỉ mục', + 'LBL_ADD' : 'Thêm', + 'LBL_FONT' : 'Phông', + 'LBL_YES' : 'Có', + 'LBL_NO' : 'Không', + 'LBL_CANCEL' : 'Hủy bỏ', + 'LBL_TOP' : 'Trên', + 'LBL_LEFT' : 'Trái', + 'LBL_RIGHT' : 'Phải', + 'LBL_BOTTOM' : 'Dưới', + 'LBL_CENTER' : 'Giữa', + 'LBL_FILE' : 'Tệp', + 'LBL_NEW' : 'Mới', + 'LBL_OPEN' : 'Mở', + 'LBL_SAVE' : 'Lưu', + 'LBL_SAVEAS' : 'Lưu như...', + 'LBL_CLOSE' : 'Đóng', + 'LBL_MKDIR' : 'Tạo thư mục', + 'LBL_UPLOAD' : 'Tải lên', + 'LBL_VIEW' : 'Xem', + 'LBL_EDIT' : 'Chỉnh sửa', + 'LBL_RENAME' : 'Đổi tên', + 'LBL_DELETE' : 'Xóa', + 'LBL_OPENWITH' : 'Mở với...', + 'LBL_ICONVIEW' : 'Biểu tượng', + 'LBL_TREEVIEW' : 'Cây', + 'LBL_LISTVIEW' : 'Danh sách', + 'LBL_REFRESH' : 'Làm mới', + 'LBL_VIEWTYPE' : 'Kiểu xem', + 'LBL_BOLD' : 'In đậm', + 'LBL_ITALIC' : 'In Ngiêng', + 'LBL_UNDERLINE' : 'Gạch dưới', + 'LBL_REGULAR' : 'Bình thường', + 'LBL_STRIKE' : 'Gạch ngang', + 'LBL_INDENT' : 'Thụt về', + 'LBL_OUTDENT' : 'Quá hạn', + 'LBL_UNDO' : 'Trở lại', + 'LBL_REDO' : 'Làm lại', + 'LBL_CUT' : 'Cắt', + 'LBL_UNLINK' : 'Hủy liên kết', + 'LBL_COPY' : 'Sao chép', + 'LBL_PASTE' : 'Dán', + 'LBL_INSERT' : 'Chèn', + 'LBL_IMAGE' : 'Ảnh', + 'LBL_LINK' : 'Liên kết', + 'LBL_DISCONNECT' : 'Mất kết nối', + 'LBL_APPLICATIONS' : 'Các ứng dụng', + 'LBL_ADD_FOLDER' : 'Thêm thư mục', + 'LBL_INFORMATION' : 'Thông tin', + 'LBL_TEXT_COLOR' : 'Màu chữ', + 'LBL_BACK_COLOR' : 'Màu nền', + 'LBL_RESET_DEFAULT' : 'Khôi phục về mặc định', + 'LBL_DOWNLOAD_COMP' : 'Tải về máy', + 'LBL_ORDERED_LIST' : 'Danh sách có thứ tự', + 'LBL_BACKGROUND_IMAGE' : 'Ảnh nền', + 'LBL_BACKGROUND_COLOR' : 'Màu nền', + 'LBL_UNORDERED_LIST' : 'Danh sách không có thứ tự', + 'LBL_STATUS' : 'Trạng thái', + 'LBL_READONLY' : 'Chỉ đọc', + 'LBL_CREATED' : 'Tạo lúc', + 'LBL_MODIFIED' : 'Sửa lúc', + 'LBL_SHOW_COLUMNS' : 'Hiện các cột', + 'LBL_MOVE' : 'Di chuyển', + 'LBL_OPTIONS' : 'Tùy chọn', + 'LBL_OK' : 'OK', + 'LBL_DIRECTORY' : 'Thư mục', + 'LBL_CREATE' : 'Tạo', + 'LBL_BUGREPORT' : 'Báo lỗi', + 'LBL_INSTALL' : 'Cài đặt', + 'LBL_UPDATE' : 'Cập nhật', + 'LBL_REMOVE' : 'Gỡ bỏ', + 'LBL_SHOW_SIDEBAR' : 'Hiện thanh bên', + 'LBL_SHOW_NAVIGATION' : 'Hiện nút điều hướng', + 'LBL_SHOW_HIDDENFILES' : 'Hiện tập tin ẩn', + 'LBL_SHOW_FILEEXTENSIONS' : 'Hiện đuôi tập tin', + 'LBL_MOUNT': 'Gắn', + 'LBL_DESCRIPTION': 'Mô tả', + 'LBL_USERNAME': 'Tên người dùng', + 'LBL_PASSWORD': 'Mật khẩu', + 'LBL_HOST': 'Host', + 'LBL_NAMESPACE': 'Namespace', + 'LBL_SEARCH': 'Tìm kiếm', + 'LBL_BACKGROUND' : 'Ảnh nền', + 'LBL_DESKTOP' : 'Màn hình chính', + 'LBL_PANEL' : 'Khung', + 'LBL_POSITION' : 'Vị trí', + 'LBL_ONTOP' : 'Ở trên', + 'LBL_ITEMS' : 'Các mục', + 'LBL_AUTOHIDE' : 'Tự động ẩn', + 'LBL_OPACITY' : 'Độ trong suốt', + 'LBL_GROUPS' : 'Nhóm', + 'LBL_VERSION' : 'Phiên bản', + 'LBL_AUTHOR' : 'Tác giả', + 'LBL_HIDE' : 'Ẩn', + 'LBL_APPLICATION' : 'Phần mềm', + 'LBL_SCOPE' : 'Phạm vi', + 'LBL_GENERAL': 'Tổng quát', + 'LBL_PERSONAL': 'Cá nhân', + 'LBL_SYSTEM': 'Hệ thống', + 'LBL_STARTING': 'Đang khởi động', + 'LBL_SOUNDS': 'Âm thanh', + 'LBL_STORE': 'Chợ ứng dụng', + 'LBL_LOCALE': 'Ngôn ngữ', + 'LBL_PACKAGE': 'Phần mềm', + 'LBL_PACKAGES': 'Các phần mềm', + 'LBL_INPUT': 'Đầu vào', + 'LBL_MISC': 'Linh tinh', + 'LBL_OTHER': 'Khác', + 'LBL_USERS': 'Người dùng', + 'LBL_FONTS': 'Phông' +}; diff --git a/src/client/javascript/locales/zh_CN.js b/src/client/javascript/locales/zh_CN.js index 49b7a18443..4af824a0e8 100644 --- a/src/client/javascript/locales/zh_CN.js +++ b/src/client/javascript/locales/zh_CN.js @@ -27,305 +27,302 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - /*eslint key-spacing: "off"*/ - 'use strict'; - OSjs.Locales.zh_CN = { - 'ERR_FILE_OPEN' : '打开文件错误', - 'ERR_WM_NOT_RUNNING' : '窗口管理器未支持', - 'ERR_FILE_OPEN_FMT' : '文件 \'**{0}**\' 无法打开', - 'ERR_APP_MIME_NOT_FOUND_FMT': '找不到能打开此 \'{0}\' 文件的应用', - 'ERR_APP_LAUNCH_FAILED' : '应用运行失败', - 'ERR_APP_LAUNCH_FAILED_FMT' : '运行时出现错误: {0}', - 'ERR_APP_CONSTRUCT_FAILED_FMT' : '应用 \'{0}\' 构建失败: {1}', - 'ERR_APP_INIT_FAILED_FMT' : '应用 \'{0}\' 初始化失败: {1}', - 'ERR_APP_RESOURCES_MISSING_FMT' : '应用资源文件丢失 \'{0}\' 或加载失败', - 'ERR_APP_PRELOAD_FAILED_FMT' : '应用 \'{0}\' 载入失败: \n{1}', - 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '这个应用 \'{0}\' 已经运行,且只支持单实例运行', - 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '运行应用失败 \'{0}\'. 未找到清单文件', - 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '运行应用失败 \'{0}\'. 你的浏览器支持: {1}', +/*eslint key-spacing: "off"*/ - 'ERR_NO_WM_RUNNING' : '没有窗口管理器在运行', - 'ERR_CORE_INIT_FAILED' : '初始化OS.js失败', - 'ERR_CORE_INIT_FAILED_DESC' : '初始化OS.js时出现一个错误', - 'ERR_CORE_INIT_NO_WM' : '无法运行OS.js: 没有指定窗口管理器', - 'ERR_CORE_INIT_WM_FAILED_FMT' : '无法运行OS.js: 运行窗口管理器失败: {0}', - 'ERR_CORE_INIT_PRELOAD_FAILED' : '无法运行OS.js: 无法加载资源文件...', - 'ERR_JAVASCRIPT_EXCEPTION' : '脚本错误报告', - 'ERR_JAVACSRIPT_EXCEPTION_DESC' : '发生未知异常, 也许是个BUG.', +module.exports = { + 'ERR_FILE_OPEN' : '打开文件错误', + 'ERR_WM_NOT_RUNNING' : '窗口管理器未支持', + 'ERR_FILE_OPEN_FMT' : '文件 \'**{0}**\' 无法打开', + 'ERR_APP_MIME_NOT_FOUND_FMT': '找不到能打开此 \'{0}\' 文件的应用', + 'ERR_APP_LAUNCH_FAILED' : '应用运行失败', + 'ERR_APP_LAUNCH_FAILED_FMT' : '运行时出现错误: {0}', + 'ERR_APP_CONSTRUCT_FAILED_FMT' : '应用 \'{0}\' 构建失败: {1}', + 'ERR_APP_INIT_FAILED_FMT' : '应用 \'{0}\' 初始化失败: {1}', + 'ERR_APP_RESOURCES_MISSING_FMT' : '应用资源文件丢失 \'{0}\' 或加载失败', + 'ERR_APP_PRELOAD_FAILED_FMT' : '应用 \'{0}\' 载入失败: \n{1}', + 'ERR_APP_LAUNCH_ALREADY_RUNNING_FMT' : '这个应用 \'{0}\' 已经运行,且只支持单实例运行', + 'ERR_APP_LAUNCH_MANIFEST_FAILED_FMT' : '运行应用失败 \'{0}\'. 未找到清单文件', + 'ERR_APP_LAUNCH_COMPABILITY_FAILED_FMT' : '运行应用失败 \'{0}\'. 你的浏览器支持: {1}', - 'ERR_APP_API_ERROR' : '应用API错误', - 'ERR_APP_API_ERROR_DESC_FMT' : '应用 {0} 执行操作失败 \'{1}\'', - 'ERR_APP_MISSING_ARGUMENT_FMT': '缺少参数: {0}', - 'ERR_APP_UNKNOWN_ERROR' : '未知错误', + 'ERR_NO_WM_RUNNING' : '没有窗口管理器在运行', + 'ERR_CORE_INIT_FAILED' : '初始化OS.js失败', + 'ERR_CORE_INIT_FAILED_DESC' : '初始化OS.js时出现一个错误', + 'ERR_CORE_INIT_NO_WM' : '无法运行OS.js: 没有指定窗口管理器', + 'ERR_CORE_INIT_WM_FAILED_FMT' : '无法运行OS.js: 运行窗口管理器失败: {0}', + 'ERR_CORE_INIT_PRELOAD_FAILED' : '无法运行OS.js: 无法加载资源文件...', + 'ERR_JAVASCRIPT_EXCEPTION' : '脚本错误报告', + 'ERR_JAVACSRIPT_EXCEPTION_DESC' : '发生未知异常, 也许是个BUG.', - // Window - 'ERR_WIN_DUPLICATE_FMT' : '你已经有了一个被命名的窗口 \'{0}\'', - 'WINDOW_MINIMIZE' : '最小化', - 'WINDOW_MAXIMIZE' : '最大化', - 'WINDOW_RESTORE' : '还原', - 'WINDOW_CLOSE' : '关闭', - 'WINDOW_ONTOP_ON' : '置顶 (开)', - 'WINDOW_ONTOP_OFF': '置顶 (关)', + 'ERR_APP_API_ERROR' : '应用API错误', + 'ERR_APP_API_ERROR_DESC_FMT' : '应用 {0} 执行操作失败 \'{1}\'', + 'ERR_APP_MISSING_ARGUMENT_FMT': '缺少参数: {0}', + 'ERR_APP_UNKNOWN_ERROR' : '未知错误', - // Handler - 'TITLE_SIGN_OUT' : '退出', - 'TITLE_SIGNED_IN_AS_FMT' : '登录: {0}', + // Window + 'ERR_WIN_DUPLICATE_FMT' : '你已经有了一个被命名的窗口 \'{0}\'', + 'WINDOW_MINIMIZE' : '最小化', + 'WINDOW_MAXIMIZE' : '最大化', + 'WINDOW_RESTORE' : '还原', + 'WINDOW_CLOSE' : '关闭', + 'WINDOW_ONTOP_ON' : '置顶 (开)', + 'WINDOW_ONTOP_OFF': '置顶 (关)', - // Dialogs - 'DIALOG_LOGOUT_TITLE' : '退出 (Exit)', // Actually located in session.js - 'DIALOG_LOGOUT_MSG_FMT' : '注册用户 \'{0}\'.\n你是否想保留当前会话?', + // Handler + 'TITLE_SIGN_OUT' : '退出', + 'TITLE_SIGNED_IN_AS_FMT' : '登录: {0}', - 'DIALOG_CLOSE' : '关闭', - 'DIALOG_CANCEL': '取消', - 'DIALOG_APPLY' : '应用', - 'DIALOG_OK' : '确定', + // Dialogs + 'DIALOG_LOGOUT_TITLE' : '退出 (Exit)', // Actually located in session.js + 'DIALOG_LOGOUT_MSG_FMT' : '注册用户 \'{0}\'.\n你是否想保留当前会话?', - 'DIALOG_ALERT_TITLE' : '错误', + 'DIALOG_CLOSE' : '关闭', + 'DIALOG_CANCEL': '取消', + 'DIALOG_APPLY' : '应用', + 'DIALOG_OK' : '确定', - 'DIALOG_COLOR_TITLE' : '调色板', - 'DIALOG_COLOR_R' : '红: {0}', - 'DIALOG_COLOR_G' : '绿: {0}', - 'DIALOG_COLOR_B' : '蓝: {0}', - 'DIALOG_COLOR_A' : '透明度: {0}', + 'DIALOG_ALERT_TITLE' : '错误', - 'DIALOG_CONFIRM_TITLE' : '确认', + 'DIALOG_COLOR_TITLE' : '调色板', + 'DIALOG_COLOR_R' : '红: {0}', + 'DIALOG_COLOR_G' : '绿: {0}', + 'DIALOG_COLOR_B' : '蓝: {0}', + 'DIALOG_COLOR_A' : '透明度: {0}', - 'DIALOG_ERROR_MESSAGE' : '错误信息', - 'DIALOG_ERROR_SUMMARY' : '错误概要', - 'DIALOG_ERROR_TRACE' : '错误跟踪', - 'DIALOG_ERROR_BUGREPORT' : 'BUG反馈', + 'DIALOG_CONFIRM_TITLE' : '确认', - 'DIALOG_FILE_SAVE' : '保存', - 'DIALOG_FILE_OPEN' : '打开', - 'DIALOG_FILE_MKDIR' : '新建目录', - 'DIALOG_FILE_MKDIR_MSG' : '在 **{0}** 里创建一个目录', - 'DIALOG_FILE_OVERWRITE' : '你确定要覆盖 \'{0}\'?', - 'DIALOG_FILE_MNU_VIEWTYPE' : '视图类型', - 'DIALOG_FILE_MNU_LISTVIEW' : '列表', - 'DIALOG_FILE_MNU_TREEVIEW' : '树型框', - 'DIALOG_FILE_MNU_ICONVIEW' : '图标', - 'DIALOG_FILE_ERROR' : '文件错误', - 'DIALOG_FILE_ERROR_SCANDIR': '有错误发生,导致无法显示目录 \'{0}\' 列表', - 'DIALOG_FILE_MISSING_FILENAME' : '你需要选择一个文件或者输入一个文件名!', - 'DIALOG_FILE_MISSING_SELECTION': '你需要选择一个文件!', + 'DIALOG_ERROR_MESSAGE' : '错误信息', + 'DIALOG_ERROR_SUMMARY' : '错误概要', + 'DIALOG_ERROR_TRACE' : '错误跟踪', + 'DIALOG_ERROR_BUGREPORT' : 'BUG反馈', - 'DIALOG_FILEINFO_TITLE' : '文件信息', - 'DIALOG_FILEINFO_LOADING' : '从 {0} 加载文件信息', - 'DIALOG_FILEINFO_ERROR' : '读取文件信息错误', - 'DIALOG_FILEINFO_ERROR_LOOKUP' : '无法获取**{0}**的文件信息', - 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '无法获取文件信息: {0}', + 'DIALOG_FILE_SAVE' : '保存', + 'DIALOG_FILE_OPEN' : '打开', + 'DIALOG_FILE_MKDIR' : '新建目录', + 'DIALOG_FILE_MKDIR_MSG' : '在 **{0}** 里创建一个目录', + 'DIALOG_FILE_OVERWRITE' : '你确定要覆盖 \'{0}\'?', + 'DIALOG_FILE_MNU_VIEWTYPE' : '视图类型', + 'DIALOG_FILE_MNU_LISTVIEW' : '列表', + 'DIALOG_FILE_MNU_TREEVIEW' : '树型框', + 'DIALOG_FILE_MNU_ICONVIEW' : '图标', + 'DIALOG_FILE_ERROR' : '文件错误', + 'DIALOG_FILE_ERROR_SCANDIR': '有错误发生,导致无法显示目录 \'{0}\' 列表', + 'DIALOG_FILE_MISSING_FILENAME' : '你需要选择一个文件或者输入一个文件名!', + 'DIALOG_FILE_MISSING_SELECTION': '你需要选择一个文件!', - 'DIALOG_INPUT_TITLE' : '输入', + 'DIALOG_FILEINFO_TITLE' : '文件信息', + 'DIALOG_FILEINFO_LOADING' : '从 {0} 加载文件信息', + 'DIALOG_FILEINFO_ERROR' : '读取文件信息错误', + 'DIALOG_FILEINFO_ERROR_LOOKUP' : '无法获取**{0}**的文件信息', + 'DIALOG_FILEINFO_ERROR_LOOKUP_FMT' : '无法获取文件信息: {0}', - 'DIALOG_FILEPROGRESS_TITLE' : '文件操作', - 'DIALOG_FILEPROGRESS_LOADING' : '加载中...', + 'DIALOG_INPUT_TITLE' : '输入', - 'DIALOG_UPLOAD_TITLE' : '上传', - 'DIALOG_UPLOAD_DESC' : '上传文件到**{0}**.
最大限制: {1} bytes', - 'DIALOG_UPLOAD_MSG_FMT' : '正在上传 \'{0}\' ({1} {2}) 到 {3}', - 'DIALOG_UPLOAD_MSG' : '上传文件...', - 'DIALOG_UPLOAD_FAILED' : '上传失败', - 'DIALOG_UPLOAD_FAILED_MSG' : '上传文件失败', - 'DIALOG_UPLOAD_FAILED_UNKNOWN' : '未知原因...', - 'DIALOG_UPLOAD_FAILED_CANCELLED': '用户取消...', - 'DIALOG_UPLOAD_TOO_BIG': '文件过大', - 'DIALOG_UPLOAD_TOO_BIG_FMT': '文件过大, 超过 {0}', + 'DIALOG_FILEPROGRESS_TITLE' : '文件操作', + 'DIALOG_FILEPROGRESS_LOADING' : '加载中...', - 'DIALOG_FONT_TITLE' : '字体', + 'DIALOG_UPLOAD_TITLE' : '上传', + 'DIALOG_UPLOAD_DESC' : '上传文件到**{0}**.
最大限制: {1} bytes', + 'DIALOG_UPLOAD_MSG_FMT' : '正在上传 \'{0}\' ({1} {2}) 到 {3}', + 'DIALOG_UPLOAD_MSG' : '上传文件...', + 'DIALOG_UPLOAD_FAILED' : '上传失败', + 'DIALOG_UPLOAD_FAILED_MSG' : '上传文件失败', + 'DIALOG_UPLOAD_FAILED_UNKNOWN' : '未知原因...', + 'DIALOG_UPLOAD_FAILED_CANCELLED': '用户取消...', + 'DIALOG_UPLOAD_TOO_BIG': '文件过大', + 'DIALOG_UPLOAD_TOO_BIG_FMT': '文件过大, 超过 {0}', - 'DIALOG_APPCHOOSER_TITLE' : '选择应用', - 'DIALOG_APPCHOOSER_MSG' : '选择一个应用打开', - 'DIALOG_APPCHOOSER_NO_SELECTION' : '你必须要选择一个应用', - 'DIALOG_APPCHOOSER_SET_DEFAULT' : '使用默认应用打开 {0}', + 'DIALOG_FONT_TITLE' : '字体', - // GoogleAPI - 'GAPI_DISABLED' : 'GoogleAPI 模块未配置或者未开启', - 'GAPI_SIGN_OUT' : '注销GoogleAPI', - 'GAPI_REVOKE' : '撤销权限并注销', - 'GAPI_AUTH_FAILURE' : 'GoogleAPI 认证失败或者未认证', - 'GAPI_AUTH_FAILURE_FMT' : '认证失败: {0}:{1}', - 'GAPI_LOAD_FAILURE' : '加载Google API失败', + 'DIALOG_APPCHOOSER_TITLE' : '选择应用', + 'DIALOG_APPCHOOSER_MSG' : '选择一个应用打开', + 'DIALOG_APPCHOOSER_NO_SELECTION' : '你必须要选择一个应用', + 'DIALOG_APPCHOOSER_SET_DEFAULT' : '使用默认应用打开 {0}', - // Windows Live API - 'WLAPI_DISABLED' : 'Windows Live API 模块未配置或者未开启', - 'WLAPI_SIGN_OUT' : '注销Window Live API', - 'WLAPI_LOAD_FAILURE' : '加载 Windows Live API失败', - 'WLAPI_LOGIN_FAILED' : '无法登录到Windows Live API', - 'WLAPI_LOGIN_FAILED_FMT' : '无法登录到Windows Live API: {0}', + // GoogleAPI + 'GAPI_DISABLED' : 'GoogleAPI 模块未配置或者未开启', + 'GAPI_SIGN_OUT' : '注销GoogleAPI', + 'GAPI_REVOKE' : '撤销权限并注销', + 'GAPI_AUTH_FAILURE' : 'GoogleAPI 认证失败或者未认证', + 'GAPI_AUTH_FAILURE_FMT' : '认证失败: {0}:{1}', + 'GAPI_LOAD_FAILURE' : '加载Google API失败', - // IndexedDB - 'IDB_MISSING_DBNAME' : '数据库名称未定义,无法创建数据库', - 'IDB_NO_SUCH_ITEM' : '没有项目', + // Windows Live API + 'WLAPI_DISABLED' : 'Windows Live API 模块未配置或者未开启', + 'WLAPI_SIGN_OUT' : '注销Window Live API', + 'WLAPI_LOAD_FAILURE' : '加载 Windows Live API失败', + 'WLAPI_LOGIN_FAILED' : '无法登录到Windows Live API', + 'WLAPI_LOGIN_FAILED_FMT' : '无法登录到Windows Live API: {0}', - // VFS - 'ERR_VFS_FATAL' : '致命的错误', - 'ERR_VFS_UNAVAILABLE' : '不可用', - 'ERR_VFS_FILE_ARGS' : '文件至少需要一个参数', - 'ERR_VFS_NUM_ARGS' : '参数不够', - 'ERR_VFS_EXPECT_FILE' : '需要一个文件对象', - 'ERR_VFS_EXPECT_SRC_FILE' : '需要一个文件内容对象', - 'ERR_VFS_EXPECT_DST_FILE' : '需要目标文件', - 'ERR_VFS_FILE_EXISTS' : '目标文件已存在', - 'ERR_VFS_TRANSFER_FMT' : '保存时发生错误: {0}', - 'ERR_VFS_UPLOAD_NO_DEST' : '没有指定目标文件路径,无法上传', - 'ERR_VFS_UPLOAD_NO_FILES' : '没有指定文件,无法上传。', - 'ERR_VFS_UPLOAD_FAIL_FMT' : '上传失败: {0}', - 'ERR_VFS_UPLOAD_CANCELLED': '文件上传取消', - 'ERR_VFS_DOWNLOAD_NO_FILE': '未指定文件路径无法下载', - 'ERR_VFS_DOWNLOAD_FAILED' : '文件下载时发生活错误: {0}', - 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': '下载文件', + // IndexedDB + 'IDB_MISSING_DBNAME' : '数据库名称未定义,无法创建数据库', + 'IDB_NO_SUCH_ITEM' : '没有项目', - 'ERR_VFSMODULE_XHR_ERROR' : 'XHR 错误', - 'ERR_VFSMODULE_ROOT_ID' : '找不到要根目录', - 'ERR_VFSMODULE_NOSUCH' : '文件不存在', - 'ERR_VFSMODULE_PARENT' : '上层目录不存在', - 'ERR_VFSMODULE_PARENT_FMT' : '无法浏览上层目录: {0}', - 'ERR_VFSMODULE_SCANDIR' : '搜索目录失败', - 'ERR_VFSMODULE_SCANDIR_FMT' : '搜索目录失败: {0}', - 'ERR_VFSMODULE_READ' : '读取文件失败', - 'ERR_VFSMODULE_READ_FMT' : '读取文件失败: {0}', - 'ERR_VFSMODULE_WRITE' : '写入文件失败', - 'ERR_VFSMODULE_WRITE_FMT' : '写入文件失败: {0}', - 'ERR_VFSMODULE_COPY' : '复制文件失败', - 'ERR_VFSMODULE_COPY_FMT' : '复制文件失败: {0}', - 'ERR_VFSMODULE_UNLINK' : '删除文件失败 file', - 'ERR_VFSMODULE_UNLINK_FMT' : '删除文件失败: {0}', - 'ERR_VFSMODULE_MOVE' : '移动文件失败', - 'ERR_VFSMODULE_MOVE_FMT' : '移动文件失败: {0}', - 'ERR_VFSMODULE_EXIST' : '检查文件是否存在失败', - 'ERR_VFSMODULE_EXIST_FMT' : '检查文件是否存在失败: {0}', - 'ERR_VFSMODULE_FILEINFO' : '获取文件信息失败', - 'ERR_VFSMODULE_FILEINFO_FMT' : '获取文件信息失败: {0}', - 'ERR_VFSMODULE_MKDIR' : '创建目录失败', - 'ERR_VFSMODULE_MKDIR_FMT' : '创建目录失败: {0}', - 'ERR_VFSMODULE_URL' : '获取远程文件失败', - 'ERR_VFSMODULE_URL_FMT' : '获取远程文件失败: {0}', - 'ERR_VFSMODULE_TRASH' : '将文件移动到回收站失败', - 'ERR_VFSMODULE_TRASH_FMT' : '将文件移动到回收站失败: {0}', - 'ERR_VFSMODULE_UNTRASH' : '将文件移出回收站失败', - 'ERR_VFSMODULE_UNTRASH_FMT' : '将文件移出回收站失败: {0}', - 'ERR_VFSMODULE_EMPTYTRASH' : '清空回收收失败', - 'ERR_VFSMODULE_EMPTYTRASH_FMT' : '清空回收收失败: {0}', + // VFS + 'ERR_VFS_FATAL' : '致命的错误', + 'ERR_VFS_UNAVAILABLE' : '不可用', + 'ERR_VFS_FILE_ARGS' : '文件至少需要一个参数', + 'ERR_VFS_NUM_ARGS' : '参数不够', + 'ERR_VFS_EXPECT_FILE' : '需要一个文件对象', + 'ERR_VFS_EXPECT_SRC_FILE' : '需要一个文件内容对象', + 'ERR_VFS_EXPECT_DST_FILE' : '需要目标文件', + 'ERR_VFS_FILE_EXISTS' : '目标文件已存在', + 'ERR_VFS_TRANSFER_FMT' : '保存时发生错误: {0}', + 'ERR_VFS_UPLOAD_NO_DEST' : '没有指定目标文件路径,无法上传', + 'ERR_VFS_UPLOAD_NO_FILES' : '没有指定文件,无法上传。', + 'ERR_VFS_UPLOAD_FAIL_FMT' : '上传失败: {0}', + 'ERR_VFS_UPLOAD_CANCELLED': '文件上传取消', + 'ERR_VFS_DOWNLOAD_NO_FILE': '未指定文件路径无法下载', + 'ERR_VFS_DOWNLOAD_FAILED' : '文件下载时发生活错误: {0}', + 'TOOLTIP_VFS_DOWNLOAD_NOTIFICATION': '下载文件', - // VFS -> Dropbox - 'DROPBOX_NOTIFICATION_TITLE' : '你正在登录到Dropbox API', - 'DROPBOX_SIGN_OUT' : '注销Google API 服务', + 'ERR_VFSMODULE_XHR_ERROR' : 'XHR 错误', + 'ERR_VFSMODULE_ROOT_ID' : '找不到要根目录', + 'ERR_VFSMODULE_NOSUCH' : '文件不存在', + 'ERR_VFSMODULE_PARENT' : '上层目录不存在', + 'ERR_VFSMODULE_PARENT_FMT' : '无法浏览上层目录: {0}', + 'ERR_VFSMODULE_SCANDIR' : '搜索目录失败', + 'ERR_VFSMODULE_SCANDIR_FMT' : '搜索目录失败: {0}', + 'ERR_VFSMODULE_READ' : '读取文件失败', + 'ERR_VFSMODULE_READ_FMT' : '读取文件失败: {0}', + 'ERR_VFSMODULE_WRITE' : '写入文件失败', + 'ERR_VFSMODULE_WRITE_FMT' : '写入文件失败: {0}', + 'ERR_VFSMODULE_COPY' : '复制文件失败', + 'ERR_VFSMODULE_COPY_FMT' : '复制文件失败: {0}', + 'ERR_VFSMODULE_UNLINK' : '删除文件失败 file', + 'ERR_VFSMODULE_UNLINK_FMT' : '删除文件失败: {0}', + 'ERR_VFSMODULE_MOVE' : '移动文件失败', + 'ERR_VFSMODULE_MOVE_FMT' : '移动文件失败: {0}', + 'ERR_VFSMODULE_EXIST' : '检查文件是否存在失败', + 'ERR_VFSMODULE_EXIST_FMT' : '检查文件是否存在失败: {0}', + 'ERR_VFSMODULE_FILEINFO' : '获取文件信息失败', + 'ERR_VFSMODULE_FILEINFO_FMT' : '获取文件信息失败: {0}', + 'ERR_VFSMODULE_MKDIR' : '创建目录失败', + 'ERR_VFSMODULE_MKDIR_FMT' : '创建目录失败: {0}', + 'ERR_VFSMODULE_URL' : '获取远程文件失败', + 'ERR_VFSMODULE_URL_FMT' : '获取远程文件失败: {0}', + 'ERR_VFSMODULE_TRASH' : '将文件移动到回收站失败', + 'ERR_VFSMODULE_TRASH_FMT' : '将文件移动到回收站失败: {0}', + 'ERR_VFSMODULE_UNTRASH' : '将文件移出回收站失败', + 'ERR_VFSMODULE_UNTRASH_FMT' : '将文件移出回收站失败: {0}', + 'ERR_VFSMODULE_EMPTYTRASH' : '清空回收收失败', + 'ERR_VFSMODULE_EMPTYTRASH_FMT' : '清空回收收失败: {0}', - // VFS -> OneDrive - 'ONEDRIVE_ERR_RESOLVE' : '找不到项目', + // VFS -> Dropbox + 'DROPBOX_NOTIFICATION_TITLE' : '你正在登录到Dropbox API', + 'DROPBOX_SIGN_OUT' : '注销Google API 服务', - // DefaultApplication - 'ERR_FILE_APP_OPEN' : '无法打开文件', - 'ERR_FILE_APP_OPEN_FMT' : '文件 {0} 的类型 {1} 不支持,无法打开', - 'ERR_FILE_APP_OPEN_ALT_FMT' : '文件 {0} 无法打开: {1}', - 'ERR_FILE_APP_SAVE_ALT_FMT' : '文件 {0} 无法保存: {1}', - 'ERR_GENERIC_APP_FMT' : '{0} 应用错误', - 'ERR_GENERIC_APP_ACTION_FMT': '无法执行此操作 \'{0}\'', - 'ERR_GENERIC_APP_UNKNOWN' : '未知错误', - 'ERR_GENERIC_APP_REQUEST' : '请求时发生错误', - 'ERR_GENERIC_APP_FATAL_FMT' : '致命错误: {0}', - 'MSG_GENERIC_APP_DISCARD' : '放弃更改?', - 'MSG_FILE_CHANGED' : '该文件已更改。确定重新载入?', - 'MSG_APPLICATION_WARNING' : '应用警告', - 'MSG_MIME_OVERRIDE' : '该文件 "{0}" 的类型不支持,用 "{1}" 替代.', + // VFS -> OneDrive + 'ONEDRIVE_ERR_RESOLVE' : '找不到项目', - // General + // DefaultApplication + 'ERR_FILE_APP_OPEN' : '无法打开文件', + 'ERR_FILE_APP_OPEN_FMT' : '文件 {0} 的类型 {1} 不支持,无法打开', + 'ERR_FILE_APP_OPEN_ALT_FMT' : '文件 {0} 无法打开: {1}', + 'ERR_FILE_APP_SAVE_ALT_FMT' : '文件 {0} 无法保存: {1}', + 'ERR_GENERIC_APP_FMT' : '{0} 应用错误', + 'ERR_GENERIC_APP_ACTION_FMT': '无法执行此操作 \'{0}\'', + 'ERR_GENERIC_APP_UNKNOWN' : '未知错误', + 'ERR_GENERIC_APP_REQUEST' : '请求时发生错误', + 'ERR_GENERIC_APP_FATAL_FMT' : '致命错误: {0}', + 'MSG_GENERIC_APP_DISCARD' : '放弃更改?', + 'MSG_FILE_CHANGED' : '该文件已更改。确定重新载入?', + 'MSG_APPLICATION_WARNING' : '应用警告', + 'MSG_MIME_OVERRIDE' : '该文件 "{0}" 的类型不支持,用 "{1}" 替代.', - 'LBL_UNKNOWN' : '未知', - 'LBL_APPEARANCE' : '外观', - 'LBL_USER' : '用户', - 'LBL_NAME' : '名称', - 'LBL_APPLY' : '应用', - 'LBL_FILENAME' : '文件名', - 'LBL_PATH' : '路径', - 'LBL_SIZE' : '大小', - 'LBL_TYPE' : '类似', - 'LBL_MIME' : '扩展类型', - 'LBL_LOADING' : '加载', - 'LBL_SETTINGS' : '设置', - 'LBL_ADD_FILE' : '添加文件', - 'LBL_COMMENT' : '评论', - 'LBL_ACCOUNT' : '账户', - 'LBL_CONNECT' : '联系', - 'LBL_ONLINE' : '在线', - 'LBL_OFFLINE' : '离线', - 'LBL_AWAY' : '离开', - 'LBL_BUSY' : '忙碌', - 'LBL_CHAT' : '聊天', - 'LBL_HELP' : '帮助', - 'LBL_ABOUT' : '关于', - 'LBL_PANELS' : '控制板', - 'LBL_LOCALES' : '本地化', - 'LBL_THEME' : '主题', - 'LBL_COLOR' : '颜色', - 'LBL_PID' : '句柄', - 'LBL_KILL' : '结束', - 'LBL_ALIVE' : '活动', - 'LBL_INDEX' : '索引', - 'LBL_ADD' : '添加', - 'LBL_FONT' : '字体', - 'LBL_YES' : '是', - 'LBL_NO' : '否', - 'LBL_CANCEL' : '取消', - 'LBL_TOP' : '上', - 'LBL_LEFT' : '左', - 'LBL_RIGHT' : '右', - 'LBL_BOTTOM' : '下', - 'LBL_CENTER' : '中', - 'LBL_FILE' : '文件', - 'LBL_NEW' : '新建', - 'LBL_OPEN' : '打开', - 'LBL_SAVE' : '保存', - 'LBL_SAVEAS' : '加存为...', - 'LBL_CLOSE' : '关闭', - 'LBL_MKDIR' : '创建目录', - 'LBL_UPLOAD' : '上传', - 'LBL_VIEW' : '查看', - 'LBL_EDIT' : '编辑', - 'LBL_RENAME' : '重命名', - 'LBL_DELETE' : '删除', - 'LBL_OPENWITH' : '打开方式...', - 'LBL_ICONVIEW' : '图标', - 'LBL_TREEVIEW' : '树型框', - 'LBL_LISTVIEW' : '列表', - 'LBL_REFRESH' : '刷新', - 'LBL_VIEWTYPE' : '视图类型', - 'LBL_BOLD' : '加粗', - 'LBL_ITALIC' : '斜体', - 'LBL_UNDERLINE' : '下划线', - 'LBL_REGULAR' : '对齐', - 'LBL_STRIKE' : '删除线', - 'LBL_INDENT' : '缩进', - 'LBL_OUTDENT' : '减少缩进', - 'LBL_UNDO' : '撤销', - 'LBL_REDO' : '重做', - 'LBL_CUT' : '剪切', - 'LBL_UNLINK' : '删除', - 'LBL_COPY' : '复制', - 'LBL_PASTE' : '粘贴', - 'LBL_INSERT' : '插入', - 'LBL_IMAGE' : '图片', - 'LBL_LINK' : '链接', - 'LBL_DISCONNECT' : '清除链接', - 'LBL_APPLICATIONS' : '应用', - 'LBL_ADD_FOLDER' : '添加目录', - 'LBL_INFORMATION' : '文件信息', - 'LBL_TEXT_COLOR' : '字体颜色', - 'LBL_BACK_COLOR' : '背景颜色', - 'LBL_RESET_DEFAULT' : '恢复默认设置', - 'LBL_DOWNLOAD_COMP' : '下载到电脑', - 'LBL_ORDERED_LIST' : '有序列表', - 'LBL_BACKGROUND_IMAGE' : '背景图片', - 'LBL_BACKGROUND_COLOR' : '背景颜色', - 'LBL_UNORDERED_LIST' : '无序列表', + // General - // - // NEW - // - 'LBL_STATUS' : '状态', - 'LBL_READONLY' : '只读' - }; + 'LBL_UNKNOWN' : '未知', + 'LBL_APPEARANCE' : '外观', + 'LBL_USER' : '用户', + 'LBL_NAME' : '名称', + 'LBL_APPLY' : '应用', + 'LBL_FILENAME' : '文件名', + 'LBL_PATH' : '路径', + 'LBL_SIZE' : '大小', + 'LBL_TYPE' : '类似', + 'LBL_MIME' : '扩展类型', + 'LBL_LOADING' : '加载', + 'LBL_SETTINGS' : '设置', + 'LBL_ADD_FILE' : '添加文件', + 'LBL_COMMENT' : '评论', + 'LBL_ACCOUNT' : '账户', + 'LBL_CONNECT' : '联系', + 'LBL_ONLINE' : '在线', + 'LBL_OFFLINE' : '离线', + 'LBL_AWAY' : '离开', + 'LBL_BUSY' : '忙碌', + 'LBL_CHAT' : '聊天', + 'LBL_HELP' : '帮助', + 'LBL_ABOUT' : '关于', + 'LBL_PANELS' : '控制板', + 'LBL_LOCALES' : '本地化', + 'LBL_THEME' : '主题', + 'LBL_COLOR' : '颜色', + 'LBL_PID' : '句柄', + 'LBL_KILL' : '结束', + 'LBL_ALIVE' : '活动', + 'LBL_INDEX' : '索引', + 'LBL_ADD' : '添加', + 'LBL_FONT' : '字体', + 'LBL_YES' : '是', + 'LBL_NO' : '否', + 'LBL_CANCEL' : '取消', + 'LBL_TOP' : '上', + 'LBL_LEFT' : '左', + 'LBL_RIGHT' : '右', + 'LBL_BOTTOM' : '下', + 'LBL_CENTER' : '中', + 'LBL_FILE' : '文件', + 'LBL_NEW' : '新建', + 'LBL_OPEN' : '打开', + 'LBL_SAVE' : '保存', + 'LBL_SAVEAS' : '加存为...', + 'LBL_CLOSE' : '关闭', + 'LBL_MKDIR' : '创建目录', + 'LBL_UPLOAD' : '上传', + 'LBL_VIEW' : '查看', + 'LBL_EDIT' : '编辑', + 'LBL_RENAME' : '重命名', + 'LBL_DELETE' : '删除', + 'LBL_OPENWITH' : '打开方式...', + 'LBL_ICONVIEW' : '图标', + 'LBL_TREEVIEW' : '树型框', + 'LBL_LISTVIEW' : '列表', + 'LBL_REFRESH' : '刷新', + 'LBL_VIEWTYPE' : '视图类型', + 'LBL_BOLD' : '加粗', + 'LBL_ITALIC' : '斜体', + 'LBL_UNDERLINE' : '下划线', + 'LBL_REGULAR' : '对齐', + 'LBL_STRIKE' : '删除线', + 'LBL_INDENT' : '缩进', + 'LBL_OUTDENT' : '减少缩进', + 'LBL_UNDO' : '撤销', + 'LBL_REDO' : '重做', + 'LBL_CUT' : '剪切', + 'LBL_UNLINK' : '删除', + 'LBL_COPY' : '复制', + 'LBL_PASTE' : '粘贴', + 'LBL_INSERT' : '插入', + 'LBL_IMAGE' : '图片', + 'LBL_LINK' : '链接', + 'LBL_DISCONNECT' : '清除链接', + 'LBL_APPLICATIONS' : '应用', + 'LBL_ADD_FOLDER' : '添加目录', + 'LBL_INFORMATION' : '文件信息', + 'LBL_TEXT_COLOR' : '字体颜色', + 'LBL_BACK_COLOR' : '背景颜色', + 'LBL_RESET_DEFAULT' : '恢复默认设置', + 'LBL_DOWNLOAD_COMP' : '下载到电脑', + 'LBL_ORDERED_LIST' : '有序列表', + 'LBL_BACKGROUND_IMAGE' : '背景图片', + 'LBL_BACKGROUND_COLOR' : '背景颜色', + 'LBL_UNORDERED_LIST' : '无序列表', -})(); + // + // NEW + // + 'LBL_STATUS' : '状态', + 'LBL_READONLY' : '只读' +}; diff --git a/src/client/javascript/polyfill.js b/src/client/javascript/polyfill.js index 718e423b85..ce31c943a2 100644 --- a/src/client/javascript/polyfill.js +++ b/src/client/javascript/polyfill.js @@ -27,72 +27,87 @@ * @author Anders Evenrud * @licence Simplified BSD License */ +import 'babel-polyfill'; + +// +// For browsers without "console" for some reason +// (function() { - 'use strict'; + 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; +})(); - // - // For browsers without "console" for some reason - // - (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; - })(); +// +// Add certain methods to global objects +// +(['forEach', 'every', 'map']).forEach(function(n) { + (['HTMLCollection', 'NodeList', 'FileList']).forEach(function(p) { + if ( window[p] ) { + window[p].prototype[n] = Array.prototype[n]; + } + }); +}); - // - // Add certain methods to global objects - // - (['forEach', 'every', 'map']).forEach(function(n) { - (['HTMLCollection', 'NodeList', 'FileList']).forEach(function(p) { - if ( window[p] ) { - window[p].prototype[n] = Array.prototype[n]; +// from:https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('remove')) { + return; + } + Object.defineProperty(item, 'remove', { + configurable: true, + enumerable: true, + writable: true, + value: function remove() { + this.parentNode.removeChild(this); } }); }); +})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); - // - // CustomEvent for IE - // - (function() { - function CustomEvent(event, params) { - params = params || {bubbles: false, cancelable: false, detail: window.undefined}; - - var evt = document.createEvent( 'CustomEvent' ); - evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); - return evt; - } +// +// CustomEvent for IE +// +(function() { + function CustomEvent(event, params) { + params = params || {bubbles: false, cancelable: false, detail: window.undefined}; - if ( window.navigator.userAgent.match(/MSIE|Edge|Trident/) ) { - CustomEvent.prototype = window.Event.prototype; - window.CustomEvent = CustomEvent; - } - })(); + var evt = document.createEvent( 'CustomEvent' ); + evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail); + return evt; + } - // - // MouseEvent - // - (function() { - /*eslint no-new: 0*/ - try { - new window.MouseEvent('test'); - return; - } catch (e) { - } + if ( window.navigator.userAgent.match(/MSIE|Edge|Trident/) ) { + CustomEvent.prototype = window.Event.prototype; + window.CustomEvent = CustomEvent; + } +})(); - function MouseEvent(eventType, params) { - params = params || {bubbles: false, cancelable: false}; +// +// MouseEvent +// +(function() { + /*eslint no-new: 0*/ + try { + new window.MouseEvent('test'); + return; + } catch (e) { + } - var mouseEvent = document.createEvent('MouseEvent'); - mouseEvent.initMouseEvent(eventType, params.bubbles, params.cancelable, window, 0, 0, 0, 0, 0, false, false, false, false, 0, params.relatedTarget); - return mouseEvent; - } + function MouseEvent(eventType, params) { + params = params || {bubbles: false, cancelable: false}; - MouseEvent.prototype = Event.prototype; - window.MouseEvent = MouseEvent; - })(); + var mouseEvent = document.createEvent('MouseEvent'); + mouseEvent.initMouseEvent(eventType, params.bubbles, params.cancelable, window, 0, 0, 0, 0, 0, false, false, false, false, 0, params.relatedTarget); + return mouseEvent; + } + MouseEvent.prototype = Event.prototype; + window.MouseEvent = MouseEvent; })(); + diff --git a/src/build/modules/example.js b/src/client/javascript/utils/clipboard.js similarity index 74% rename from src/build/modules/example.js rename to src/client/javascript/utils/clipboard.js index 586ace3644..93ae557452 100644 --- a/src/build/modules/example.js +++ b/src/client/javascript/utils/clipboard.js @@ -27,19 +27,27 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -/*eslint strict:["error", "global"]*/ -'use strict'; +let _CLIPBOARD; // Current 'clipboard' data -/* - * This method is called whenever the OS.js [CLI] build tool is initialized. +/** + * Set the "clipboard" data * - * Please note that this is synchronous and is only intended for loading externals - * or adding custom tasks. + * NOTE: This does not set the operating system clipboard (yet...) + * + * @param {Object|String|Numer} data What data to set + */ +export function setClipboard(data) { + console.debug('setClipboard()', data); + _CLIPBOARD = data; +} + +/** + * Get the "clipboard" data + * + * NOTE: This does not the operating system clipboard (yet...) + * + * @return {Object|String|Number} */ -module.exports.register = function(TASKS) { - /* You can for example add your own build task that will be run by default - TASKS.build.custom = function(cli, cfg) { - return Promise.resolve(); - }; - */ -}; +export function getClipboard() { + return _CLIPBOARD; +} diff --git a/src/client/javascript/utils/compability.js b/src/client/javascript/utils/compability.js index 22b2acc4be..bfd0d350d9 100644 --- a/src/client/javascript/utils/compability.js +++ b/src/client/javascript/utils/compability.js @@ -27,324 +27,270 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Gets browser compability flags - * - * @function getCompability - * @memberof OSjs.Utils - * - * @return {Object} List of compability - */ - 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; - } +const compability = (function() { + function _checkSupport(enabled, check, isSupported) { + const supported = {}; + + Object.keys(check).forEach((key) => { + let chk = check[key]; + let value = false; + + if ( chk instanceof Array ) { + chk.forEach((c) => { + value = isSupported(c); + return !value; + }); + } else { + value = isSupported(chk); + } + supported[key] = value; + }); - function canPlayCodec(support, check) { - return _checkSupport(support, check, function(codec) { - try { - return !!support.canPlayType(codec); - } catch ( e ) { - } - return false; - }); - } + return supported; + } - 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 getUpload() { + try { + const xhr = new XMLHttpRequest(); + return (!!(xhr && ('upload' in xhr) && ('onprogress' in xhr.upload))); + } catch ( e ) {} + return false; + } - function getAudioSupported() { - return document.createElement('audio').canPlayType ? document.createElement('audio') : null; - } + function getCanvasSupported() { + return document.createElement('canvas').getContext ? document.createElement('canvas') : null; + } - function getAudioTypesSupported() { - return canPlayCodec(getAudioSupported(), { - ogg: 'audio/ogg; codecs="vorbis', - mp3: 'audio/mpeg', - wav: 'audio/wav; codecs="1"' - }); - } + function getVideoSupported() { + return document.createElement('video').canPlayType ? document.createElement('video') : null; + } - function getAudioContext() { - if ( window.hasOwnProperty('AudioContext') || window.hasOwnProperty('webkitAudioContext') ) { - return true; + function canPlayCodec(support, check) { + return _checkSupport(support, check, (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"' + }); + } - 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 ) {} - }); - } - } + function getAudioSupported() { + return document.createElement('audio').canPlayType ? document.createElement('audio') : null; + } - return cache; - }; - })(); + function getAudioTypesSupported() { + return canPlayCodec(getAudioSupported(), { + ogg: 'audio/ogg; codecs="vorbis', + mp3: 'audio/mpeg', + wav: 'audio/wav; codecs="1"' + }); + } - 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 getAudioContext() { + if ( window.hasOwnProperty('AudioContext') || window.hasOwnProperty('webkitAudioContext') ) { + return true; } - - 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 ( typeof elm.style[domPrefixes[i] + featurenameCapital ] !== 'undefined' ) { - feature = true; - break; - } + return false; + } + + const getCanvasContexts = (() => { + const cache = []; + + return () => { + if ( !cache.length ) { + const canvas = getCanvasSupported(); + if ( canvas ) { + const test = ['2d', 'webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl']; + test.forEach((tst, i) => { + try { + if ( !!canvas.getContext(tst) ) { + cache.push(tst); + } + } catch ( eee ) {} + }); } } - 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; - } + return cache; + }; + })(); - function getTouch() { - // False positives in win 8+ - try { - if ( navigator.userAgent.match(/Windows NT 6\.(2|3)/) ) { - return false; + function getWebGL() { + let result = false; + let contexts = getCanvasContexts(); + try { + result = (contexts.length > 1); + if ( !result ) { + if ( 'WebGLRenderingContext' in window ) { + result = true; } - } catch ( e ) {} + } + } catch ( e ) {} + return result; + } - // We only want touch for mobile devices - try { - if ( navigator.userAgent.match(/iOS|Android|BlackBerry|IEMobile|iPad|iPhone|iPad/i) ) { - return true; - } - } catch ( e ) {} + function detectCSSFeature(featurename) { + let feature = false; + let domPrefixes = 'Webkit Moz ms O'.split(' '); + let elm = document.createElement('div'); + let featurenameCapital = null; - return false; - // This was the old method - //return ('ontouchstart' in window) || (window.DocumentTouch && (document instanceof window.DocumentTouch)); - //return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)); - } + featurename = featurename.toLowerCase(); - function getDnD() { - return !!('draggable' in document.createElement('span')); + if ( elm.style[featurename] ) { + feature = true; } - function getSVG() { - return (!!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect); + if ( feature === false ) { + featurenameCapital = featurename.charAt(0).toUpperCase() + featurename.substr(1); + for ( let i = 0; i < domPrefixes.length; i++ ) { + if ( typeof elm.style[domPrefixes[i] + featurenameCapital ] !== 'undefined' ) { + feature = true; + break; + } + } } - - function getFileSystem() { - return (('requestFileSystem' in window) || ('webkitRequestFileSystem' in window)); + return feature; + } + + function getUserMedia() { + let 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() { + // False positives in win 8+ + try { + if ( navigator.userAgent.match(/Windows NT 6\.(2|3)/) ) { + return false; + } + } catch ( e ) {} - 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; - }; - })(); - - /** - * Check if browser is IE - * - * @return boolean If IE - * - * @api OSjs.Utils.isIE() - */ - OSjs.Utils.isIE = function Utils_isIE() { - var dm = parseInt(document.documentMode, 10); - return dm <= 11 || !!navigator.userAgent.match(/(MSIE|Edge)/); + // We only want touch for mobile devices + try { + if ( navigator.userAgent.match(/iOS|Android|BlackBerry|IEMobile|iPad|iPhone|iPad/i) ) { + return true; + } + } catch ( e ) {} + + return false; + // This was the old method + //return ('ontouchstart' in window) || (window.DocumentTouch && (document instanceof window.DocumentTouch)); + //return (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)); + } + + 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)); + } + + const checkWindow = { + indexedDB: 'indexedDB', + localStorage: 'localStorage', + sessionStorage: 'sessionStorage', + globalStorage: 'globalStorage', + openDatabase: 'openDatabase', + socket: 'WebSocket', + worker: 'Worker', + file: 'File', + blob: 'Blob', + orientation: 'onorientationchange' }; - /** - * Gets the browser Locale - * - * For example 'en_EN' - * - * @function getUserLocale - * @memberof OSjs.Utils - * - * @return {String} Locale string - */ - OSjs.Utils.getUserLocale = function Utils_getUserLocale() { - var loc = ((window.navigator.userLanguage || window.navigator.language) || 'en-EN').replace('-', '_'); - - // Restricts to a certain type of language. - // Example: There are lots of variants of the English language, but currently we only - // provide locales for one of them, so we force to use the one available. - var map = { - 'nb': 'no_NO', - 'es': 'es_ES', - 'ru': 'ru_RU', - 'en': 'en_EN' - }; + const 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() + }; - var major = loc.split('_')[0] || 'en'; - var minor = loc.split('_')[1] || major.toUpperCase(); - if ( map[major] ) { - return map[major]; + Object.keys(checkWindow).forEach((key) => { + try { + compability[key] = (checkWindow[key] in window) && window[checkWindow[key]] !== null; + } catch ( e ) { + console.warn(e); } - return major + '_' + minor; - }; + }); - /** - * Gets the browser window rect (x, y, width, height) - * - * @function getRect - * @memberof OSjs.Utils - * - * @return {Object} - */ - OSjs.Utils.getRect = function Utils_getRect() { - var body = document.body || {}; - return { - top: 0, - left: 0, - width: body.offsetWidth || 0, - height: body.offsetHeight || 0 - }; + return () => { + return compability; }; - })(); + +/** + * Gets browser compability flags + * + * @return {Object} List of compability + */ +export function getCompability() { + return compability(); +} + +/** + * Check if browser is IE + * + * @return {Boolean} If IE + */ +export function isIE() { + const dm = parseInt(document.documentMode, 10); + return dm <= 11 || !!navigator.userAgent.match(/(MSIE|Edge)/); +} diff --git a/src/client/javascript/utils/dom.js b/src/client/javascript/utils/dom.js index 99903496b9..0b657c2773 100644 --- a/src/client/javascript/utils/dom.js +++ b/src/client/javascript/utils/dom.js @@ -27,550 +27,476 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // DOM - ///////////////////////////////////////////////////////////////////////////// - - /** - * Get element by ID - * - * @function $ - * @memberof OSjs.Utils - * - * @param {String} id DOM Element ID - * - * @return {Node} Found element or null - */ - OSjs.Utils.$ = function Utils_$(id) { - return document.getElementById(id); - }; - - /** - * Remove unwanted characters from ID or className - * - * @function $safeName - * @memberof OSjs.Utils - * - * @param {String} str The name - * - * @return {String} The new name - */ - OSjs.Utils.$safeName = function Utils_$safeName(str) { - return (str || '').replace(/[^a-zA-Z0-9]/g, '_'); - }; - - /** - * Remove given element from parent - * - * @function $remove - * @memberof OSjs.Utils - * - * @param {Node} node The DOM Element - */ - OSjs.Utils.$remove = function Utils_$remove(node) { - if ( node && node.parentNode ) { - node.parentNode.removeChild(node); - } - }; - - /** - * Empty this element (remove children) - * - * @function $empty - * @memberof OSjs.Utils - * - * @param {Node} myNode The DOM Element - * @param {Boolean|String} [removeEvents=false] Force removal of event handlers (on given elements) - */ - OSjs.Utils.$empty = function Utils_$empty(myNode, removeEvents) { - if ( myNode ) { - if ( removeEvents ) { - removeEvents = typeof removeEvents === 'string' ? removeEvents : '*'; - myNode.querySelectorAll(removeEvents).forEach(function(el) { - OSjs.Utils.$unbind(el); - }); - } - while ( myNode.firstChild ) { - myNode.removeChild(myNode.firstChild); - } - } - }; - - /** - * Get CSS style attribute - * - * @function $getStyle - * @memberof OSjs.Utils - * - * @param {Node} oElm The DOM Element - * @param {String} strCssRule The CSS rule to get - * - * @return {String} Style attribute - */ - OSjs.Utils.$getStyle = function Utils_$getStyle(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; - }; - - /** - * Get element absolute position - * - * Modern browsers will return getBoundingClientRect() - * See DOM documentation - * - * @function $position - * @memberof OSjs.Utils - * - * @param {Node} el The Element to find position of - * @param {Node} [parentEl] Parent to end loop in - * - * @return {Object} The bounding box - */ - OSjs.Utils.$position = function Utils_$position(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(); +/** + * Get element by ID + * + * @param {String} id DOM Element ID + * + * @return {Node} Found element or null + */ +export function $(id) { + return document.getElementById(id); +} + +/** + * Remove unwanted characters from ID or className + * + * @param {String} str The name + * + * @return {String} The new name + */ +export function $safeName(str) { + return (str || '').replace(/[^a-zA-Z0-9]/g, '_'); +} + +/** + * Remove given element from parent + * + * @param {Node} node The DOM Element + */ +export function $remove(node) { + if ( node && node.parentNode ) { + node.parentNode.removeChild(node); + } +} + +/** + * Empty this element (remove children) + * + * @param {Node} myNode The DOM Element + */ +export function $empty(myNode) { + if ( myNode ) { + while ( myNode.firstChild ) { + myNode.removeChild(myNode.firstChild); } - return null; - }; - - /** - * Traverses down to the parentnode validated by filter - * - * @function $parent - * @memberof OSjs.Utils - * - * @param {Node} el The Element to find position of - * @param {Function} cb The callback function => fn(node) return true/false here - * - * @return {Node} el The DOM element - */ - OSjs.Utils.$parent = function Utils_$parent(el, cb) { - var result = null; - - if ( el && cb ) { - var current = el; - while ( current.parentNode ) { - if ( cb(current) ) { - result = current; + } +} + +/** + * Get CSS style attribute + * + * @param {Node} oElm The DOM Element + * @param {String} strCssRule The CSS rule to get + * + * @return {String} Style attribute + */ +export function $getStyle(oElm, strCssRule) { + let strValue = ''; + if ( document.defaultView && document.defaultView.getComputedStyle ) { + strValue = document.defaultView.getComputedStyle(oElm, '').getPropertyValue(strCssRule); + } else if ( oElm.currentStyle ) { + strCssRule = strCssRule.replace(/\-(\w)/g, (strMatch, p1) => { + return p1.toUpperCase(); + }); + strValue = oElm.currentStyle[strCssRule]; + } + return strValue; +} + +/** + * Get element absolute position + * + * Modern browsers will return getBoundingClientRect() + * See DOM documentation + * + * @param {Node} el The Element to find position of + * @param {Node} [parentEl] Parent to end loop in + * + * @return {Object} The bounding box + */ +export function $position(el, parentEl) { + if ( el ) { + if ( parentEl ) { + const 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; } - current = current.parentNode; + el = el.offsetParent; } + return result; } + return el.getBoundingClientRect(); + } + return null; +} - return result; - }; - - /** - * Get the index of an element within a node - * - * @function $index - * @memberof OSjs.Utils - * - * @param {Node} el The Element to check - * @param {Node} [parentEl] Parent to end loop in - * - * @return {Number} The index - */ - OSjs.Utils.$index = function Utils_$index(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; +/** + * Traverses down to the parentnode validated by filter + * + * @param {Node} el The Element to find position of + * @param {Function} cb The callback function => fn(node) return true/false here + * + * @return {Node} el The DOM element + */ +export function $parent(el, cb) { + let result = null; + + if ( el && cb ) { + let current = el; + while ( current.parentNode ) { + if ( cb(current) ) { + result = current; + break; } + current = current.parentNode; } - return -1; - }; - - /** - * Selects range in a text field - * - * @function $selectRange - * @memberof OSjs.Utils - * - * @param {Node} field The DOM Element - * @param {Number} start Start position - * @param {Number} end End position - */ - OSjs.Utils.$selectRange = function Utils_$selectRange(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'); - } + return result; +} - 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(); - } - }; - - /** - * Add a className to a DOM Element - * - * @function $addClass - * @memberof OSjs.Utils - * - * @param {Node} el The dom Element - * @param {String} name The class name - */ - OSjs.Utils.$addClass = function Utils_$addClass(el, name) { - if ( el ) { - name.split(' ').forEach(function(n) { - el.classList.add(n); - }); - } - }; - - /** - * Remove a className from a DOM Element - * - * @function $removeClass - * @memberof OSjs.Utils - * - * @param {Node} el The dom Element - * @param {String} name The class name - */ - OSjs.Utils.$removeClass = function Utils_$removeClass(el, name) { - if ( el ) { - name.split(' ').forEach(function(n) { - el.classList.remove(n); - }); - } - }; - - /** - * Check if a DOM Element has given className - * - * @function $hasClass - * @memberof OSjs.Utils - * - * @param {Node} el The dom Element - * @param {String} name The class name - * - * @return {Boolean} - */ - OSjs.Utils.$hasClass = function Utils_$hasClass(el, name) { - if ( el && name ) { - return name.split(' ').every(function(n) { - return el.classList.contains(n); - }); - } - return false; - }; - - /** - * Escapes the given string for HTML - * - * works sort of like PHPs htmlspecialchars() - * - * @function $escape - * @memberof OSjs.Utils - * - * @param {String} str Input - * - * @return {String} Escaped HTML - */ - OSjs.Utils.$escape = function Utils_$escape(str) { - var div = document.createElement('div'); - div.appendChild(document.createTextNode(str)); - return div.innerHTML; - }; - - /** - * Creates a new DOM element - * - * @example - * Utils.$create('div', { - * className: 'foo', - * style: { - * width: '200px' - * }, - * data: { - * custom_attribute: 'bar' - * }, - * aria: { - * role: 'button' - * }, - * some_custom_attribute: 'baz' - * }) - * - * @function $create - * @memberof OSjs.Utils - * - * @param {String} tagName Tag Name - * @param {Object} properties Tag Properties - * - * @return {Node} - */ - OSjs.Utils.$create = function Utils_$create(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])); - }); +/** + * Get the index of an element within a node + * + * @param {Node} el The Element to check + * @param {Node} [parentEl] Parent to end loop in + * + * @return {Number} The index + */ +export function $index(el, parentEl) { + if ( el ) { + parentEl = parentEl || el.parentNode; + if ( parentEl ) { + const nodeList = Array.prototype.slice.call(parentEl.children); + const nodeIndex = nodeList.indexOf(el, parentEl); + return nodeIndex; } + } + return -1; +} - _foreach(properties.style, function(key, val) { - element.style[key] = val; +/** + * Selects range in a text field + * + * @param {Node} field The DOM Element + * @param {Number} start Start position + * @param {Number} end End position + */ +export function $selectRange(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 ) { + const 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(); + } +} + +/** + * Add a className to a DOM Element + * + * @param {Node} el The dom Element + * @param {String} name The class name + */ +export function $addClass(el, name) { + if ( el ) { + name.split(' ').forEach((n) => { + el.classList.add(n); }); + } +} - _foreach(properties.aria, function(key, val) { - if ( (['role']).indexOf(key) !== -1 ) { - key = 'aria-' + key; - } - element.setAttribute(key, val); +/** + * Remove a className from a DOM Element + * + * @param {Node} el The dom Element + * @param {String} name The class name + */ +export function $removeClass(el, name) { + if ( el ) { + name.split(' ').forEach((n) => { + el.classList.remove(n); }); + } +} - _foreach(properties.data, function(key, val) { - element.setAttribute('data-' + key, val); +/** + * Check if a DOM Element has given className + * + * @param {Node} el The dom Element + * @param {String} name The class name + * + * @return {Boolean} + */ +export function $hasClass(el, name) { + if ( el && name ) { + return name.split(' ').every((n) => { + return el.classList.contains(n); }); + } + return false; +} - _foreach(properties, function(key, val) { - if ( (['style', 'aria', 'data']).indexOf(key) === -1 ) { - element[key] = val; - } - }); +/** + * Escapes the given string for HTML + * + * works sort of like PHPs htmlspecialchars() + * + * @param {String} str Input + * + * @return {String} Escaped HTML + */ +export function $escape(str) { + const div = document.createElement('div'); + div.appendChild(document.createTextNode(str)); + return div.innerHTML; +} + +/** + * Creates a new DOM element + * + * @example + * $create('div', { + * className: 'foo', + * style: { + * width: '200px' + * }, + * data: { + * custom_attribute: 'bar' + * }, + * aria: { + * role: 'button' + * }, + * some_custom_attribute: 'baz' + * }) + * + * @param {String} tagName Tag Name + * @param {Object} properties Tag Properties + * + * @return {Node} + */ +export function $create(tagName, properties) { + const element = document.createElement(tagName); - return element; - }; - - /** - * Create a link stylesheet tag - * - * @function $createCSS - * @memberof OSjs.Utils - * - * @param {String} src The URL of resource - * @param {Function} onload onload callback - * @param {Function} onerror onerror callback - * - * @return {Node} The tag - */ - OSjs.Utils.$createCSS = function Utils_$createCSS(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; - }; - - /** - * Create a script tag - * - * @function $createJS - * @memberof OSjs.Utils - * - * @param {String} src The URL of resource - * @param {Function} onreadystatechange readystatechange callback - * @param {Function} onload onload callback - * @param {Function} onerror onerror callback - * @param {Object} [attrs] dict with optional arguments - * - * @return {Node} The tag - */ - OSjs.Utils.$createJS = function Utils_$createJS(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]); + function _foreach(dict, l) { + dict = dict || {}; + Object.keys(dict).forEach((name) => { + l(name.replace(/_/g, '-'), String(dict[name])); }); + } - document.getElementsByTagName('head')[0].appendChild(res); - - return res; - }; - - /** - * Check if event happened on a form element - * - * @function $isFormElement - * @memberof OSjs.Utils - * - * @param {Event|Element} input DOM Event or Element - * @param {Array} [types] Optional Array of types - * - * @return {Boolean} If is a form element - */ - OSjs.Utils.$isFormElement = function Utils_$isFormElement(input, types) { - types = types || ['TEXTAREA', 'INPUT', 'SELECT']; - - if ( input instanceof window.Event ) { - input = input.srcElement || input.target; - } + _foreach(properties.style, (key, val) => { + element.style[key] = val; + }); - if ( input instanceof window.Element ) { - if ( types.indexOf(input.tagName.toUpperCase()) >= 0 ) { - if ( !(input.readOnly || input.disabled) ) { - return true; - } - } + _foreach(properties.aria, (key, val) => { + if ( (['role']).indexOf(key) !== -1 ) { + key = 'aria-' + key; } + element.setAttribute(key, val); + }); + + _foreach(properties.data, (key, val) => { + element.setAttribute('data-' + key, val); + }); - return false; - }; - - /** - * Set or Get element CSS - * - * @param {Node} el DOM Node - * @param {(String|Object)} ink CSS attribute name to get/set, or full dict to set - * @param {(String|Number)} [inv] If previous argument was a string, this is the value that will be set - * - * @return {String} CSS attribute value - * - * @example - * Utils.$css(element, { - * backgroundColor: '#000', - * 'font-size': '14px' // You can also use CSS attributes like normal - * }); - * - * @example - * Utils.$css(element, 'font-family', 'Arial'); - * - * @example - * Utils.$css(element, 'font-family'); // -> 'Arial'. Same as $getStyle - * - * @function $css - * @memberof OSjs.Utils - */ - OSjs.Utils.$css = function Utils_$css(el, ink, inv) { - function rep(k) { - return k.replace(/\-(\w)/g, function(strMatch, p1) { - return p1.toUpperCase(); - }); + _foreach(properties, (key, val) => { + if ( (['style', 'aria', 'data']).indexOf(key) === -1 ) { + element[key] = val; } + }); + + return element; +} + +/** + * Create a link stylesheet tag + * + * @param {String} src The URL of resource + * @param {Function} onload onload callback + * @param {Function} onerror onerror callback + * + * @return {Node} The tag + */ +export function $createCSS(src, onload, onerror) { + const 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; +} + +/** + * Create a script tag + * + * @param {String} src The URL of resource + * @param {Function} onreadystatechange readystatechange callback + * @param {Function} onload onload callback + * @param {Function} onerror onerror callback + * @param {Object} [attrs] dict with optional arguments + * + * @return {Node} The tag + */ +export function $createJS(src, onreadystatechange, onload, onerror, attrs) { + const res = document.createElement('script'); + + res.onreadystatechange = onreadystatechange || function() {}; + res.onerror = onerror || function() {}; + res.onload = onload || function() {}; + + attrs = Object.assign({}, { + type: 'text/javascript', + charset: 'utf-8', + src: src + }, attrs || {}); + + Object.keys(attrs).forEach((k) => { + res[k] = String(attrs[k]); + }); + + document.getElementsByTagName('head')[0].appendChild(res); + + return res; +} + +/** + * Check if event happened on a form element + * + * @param {Event|Element} input DOM Event or Element + * @param {Array} [types] Optional Array of types + * + * @return {Boolean} If is a form element + */ +export function $isFormElement(input, types) { + types = types || ['TEXTAREA', 'INPUT', 'SELECT']; + + if ( input instanceof window.Event ) { + input = input.srcElement || input.target; + } - var obj = {}; - if ( arguments.length === 2 ) { - if ( typeof ink === 'string' ) { - return el.parentNode ? OSjs.Utils.$getStyle(el, ink) : el.style[rep(ink)]; + if ( input instanceof window.Element ) { + if ( types.indexOf(input.tagName.toUpperCase()) >= 0 ) { + if ( !(input.readOnly || input.disabled) ) { + return true; } - obj = ink; - } else if ( arguments.length === 3 ) { - obj[ink] = inv; } + } - Object.keys(obj).forEach(function(k) { - el.style[rep(k)] = String(obj[k]); + return false; +} + +/** + * Set or Get element CSS + * + * @param {Node} el DOM Node + * @param {(String|Object)} ink CSS attribute name to get/set, or full dict to set + * @param {(String|Number)} [inv] If previous argument was a string, this is the value that will be set + * + * @return {String} CSS attribute value + * + * @example + * $css(element, { + * backgroundColor: '#000', + * 'font-size': '14px' // You can also use CSS attributes like normal + * }); + * + * @example + * $css(element, 'font-family', 'Arial'); + * + * @example + * $css(element, 'font-family'); // -> 'Arial'. Same as $getStyle + */ +export function $css(el, ink, inv) { + function rep(k) { + return k.replace(/\-(\w)/g, (strMatch, p1) => { + return p1.toUpperCase(); }); - }; - - /** - * Gets the Xpath to a DOM Element - * - * @param {Node} el DOM Element - * @return {String} - * - * @function $path - * @memberof OSjs.Utils - */ - OSjs.Utils.$path = function Utils_$path(el) { - function _path(e) { - if ( e === document.body ) { - return e.tagName; - } else if ( e === window ) { - return 'WINDOW'; - } else if ( e === document ) { - return 'DOCUMENT'; - } + } - if ( e.id !== '' ) { - return 'id("' + e.id + '")'; - } + let obj = {}; + if ( arguments.length === 2 ) { + if ( typeof ink === 'string' ) { + return el.parentNode ? $getStyle(el, ink) : el.style[rep(ink)]; + } + obj = ink; + } else if ( arguments.length === 3 ) { + obj[ink] = inv; + } - var ix = 0; - var siblings = e.parentNode ? e.parentNode.childNodes : []; + Object.keys(obj).forEach((k) => { + el.style[rep(k)] = String(obj[k]); + }); - for ( var i = 0; i < siblings.length; i++ ) { - var sibling = siblings[i]; - if ( sibling === e ) { - return _path(e.parentNode) + '/' + e.tagName + '[' + (ix + 1) + ']'; - } + return null; +} - if ( sibling.nodeType === 1 && sibling.tagName === e.tagName ) { - ix++; - } +/** + * Gets the Xpath to a DOM Element + * + * @param {Node} el DOM Element + * @return {String} + */ +export function $path(el) { + function _path(e) { + if ( e === document.body ) { + return e.tagName; + } else if ( e === window ) { + return 'WINDOW'; + } else if ( e === document ) { + return 'DOCUMENT'; + } + + if ( e.id !== '' ) { + return 'id("' + e.id + '")'; + } + + let ix = 0; + + const siblings = e.parentNode ? e.parentNode.childNodes : []; + for ( let i = 0; i < siblings.length; i++ ) { + const sibling = siblings[i]; + if ( sibling === e ) { + return _path(e.parentNode) + '/' + e.tagName + '[' + (ix + 1) + ']'; } - return null; + if ( sibling.nodeType === 1 && sibling.tagName === e.tagName ) { + ix++; + } } - return _path(el); - }; - - /** - * Gets a DOM Element from Xpath - * - * @param {String} path The path - * @param {HTMLDocument} [doc] The document to resolve in - * @return {Node} - * - * @function $fromPath - * @memberof OSjs.Utils - */ - OSjs.Utils.$fromPath = function Uitls_$fromPath(path, doc) { - doc = doc || document; - - var evaluator = new XPathEvaluator(); - var result = evaluator.evaluate(path, doc.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); - return result.singleNodeValue; - }; - -})(); + return null; + } + + return _path(el); +} + +/** + * Gets a DOM Element from Xpath + * + * @param {String} path The path + * @param {HTMLDocument} [doc] The document to resolve in + * @return {Node} + */ +export function $fromPath(path, doc) { + doc = doc || document; + + const evaluator = new XPathEvaluator(); + const result = evaluator.evaluate(path, doc.documentElement, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null); + return result.singleNodeValue; +} diff --git a/src/client/javascript/utils/events.js b/src/client/javascript/utils/events.js index 0f56cb02d7..e0f1418ca9 100644 --- a/src/client/javascript/utils/events.js +++ b/src/client/javascript/utils/events.js @@ -27,598 +27,531 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - 'use strict'; - - /** - * The callback for browser events bound by OS.js - * @see OSjs.Utils.$bind - * @see OSjs.Utils.$unbind - * @callback CallbackEvent - * @param {Event} ev Browser event - * @param {Object} pos Event pointer position in form of x and y - */ - ///////////////////////////////////////////////////////////////////////////// - // MISC - ///////////////////////////////////////////////////////////////////////////// +import * as DOM from 'utils/dom'; +import * as Keycodes from 'utils/keycodes'; - /** - * A collection of keycode mappings - * - * @memberof OSjs.Utils - * @var - */ - 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 - }; +/** + * The callback for browser events bound by OS.js + * @callback CallbackEvent + * @param {Event} ev Browser event + * @param {Object} pos Event pointer position in form of x and y + */ + +///////////////////////////////////////////////////////////////////////////// +// MISC +///////////////////////////////////////////////////////////////////////////// - // Add all ASCII chacters to the map - for ( var n = 33; n <= 126; n++ ) { - list[String.fromCharCode(n)] = n; +/* + * Gets the event name considering compability with + * MSPointerEvent and PointerEvent interfaces. + */ +function getRealEventName(evName) { + let realName = evName; + if ( evName !== 'mousewheel' && evName.match(/^mouse/) ) { + if ( window.PointerEvent ) { + realName = evName.replace(/^mouse/, 'pointer'); + } else if ( window.MSPointerEvent ) { + const tmpName = evName.replace(/^mouse/, ''); + realName = 'MSPointer' + tmpName.charAt(0).toUpperCase() + tmpName.slice(1).toLowerCase(); } + } + return realName; +} - return Object.freeze(list); - })(); +/* + * Gets a list from string of event names + */ +function getEventList(str) { + return str.replace(/\s/g, '').split(','); +} - /* - * Gets the event name considering compability with - * MSPointerEvent and PointerEvent interfaces. - */ - function getRealEventName(evName) { - var realName = evName; - if ( evName !== 'mousewheel' && evName.match(/^mouse/) ) { - if ( window.PointerEvent ) { - realName = evName.replace(/^mouse/, 'pointer'); - } else if ( window.MSPointerEvent ) { - var tmpName = evName.replace(/^mouse/, ''); - realName = 'MSPointer' + tmpName.charAt(0).toUpperCase() + tmpName.slice(1).toLowerCase(); - } - } - return realName; +///////////////////////////////////////////////////////////////////////////// +// EVENTS +///////////////////////////////////////////////////////////////////////////// + +/** + * Gets mouse position in all cases (including touch) + * + * @example + * mousePosition(ev); // -> {x:1, y:1} + * + * @param {Event} ev DOM Event + * + * @return {(Event|Object)} ev DOM Event or an Object + * @return Object + */ +export function mousePosition(ev) { + // If this is a custom event containing position + if ( ev.detail && typeof ev.detail.x !== 'undefined' && typeof ev.detail.y !== 'undefined' ) { + return {x: ev.detail.x, y: ev.detail.y}; } - /* - * Gets a list from string of event names - */ - function getEventList(str) { - return str.replace(/\s/g, '').split(','); + // If this was a touch event + const touch = ev.touches || ev.changedTouches; + if ( touch && touch[0] ) { + return {x: touch[0].clientX, y: touch[0].clientY}; } - ///////////////////////////////////////////////////////////////////////////// - // EVENTS - ///////////////////////////////////////////////////////////////////////////// + return {x: ev.clientX, y: ev.clientY}; +} - /** - * Gets mouse position in all cases (including touch) - * - * @example - * Utils.mousePosition(ev); // -> {x:1, y:1} - * - * @param {Event} ev DOM Event - * - * @return {(Event|Object)} ev DOM Event or an Object - * @return Object - */ - OSjs.Utils.mousePosition = function Utils_mousePosition(ev) { - // If this is a custom event containing position - if ( ev.detail && typeof ev.detail.x !== 'undefined' && typeof ev.detail.y !== 'undefined' ) { - return {x: ev.detail.x, y: ev.detail.y}; +/** + * Get the mouse button pressed + * + * @param {Event} ev The DOM Event + * + * @return {String} The mouse button (left/middle/right) + */ +export function mouseButton(ev) { + if ( typeof ev.button !== 'undefined' ) { + if ( ev.button === 0 ) { + return 'left'; + } else if ( ev.button === 1 ) { + return 'middle'; } + return 'right'; + } - // If this was a touch event - var touch = ev.touches || ev.changedTouches; - if ( touch && touch[0] ) { - return {x: touch[0].clientX, y: touch[0].clientY}; - } + if ( ev.which === 2 || ev.which === 4 ) { + return 'middle'; + } else if ( ev.which === 1 ) { + return 'left'; + } + return 'right'; +} - return {x: ev.clientX, y: ev.clientY}; +/** + * Checks if the event currently has the given key comination. + * + * Example: 'CTRL+SHIFT+A' + * + * @param {Event} ev The DOM Event + * @param {String} checkFor The string of keystrokes to check + * + * @return {Boolean} + */ +export const keyCombination = (function() { + const modifiers = { + CTRL: (ev) => { + return ev.ctrlKey; + }, + SHIFT: (ev) => { + return ev.shiftKey; + }, + ALT: (ev) => { + return ev.altKey; + }, + META: (ev) => { + return ev.metaKey; + } }; - /** - * Get the mouse button pressed - * - * @function mouseButton - * @memberof OSjs.Utils - * - * @param {Event} ev The DOM Event - * - * @return {String} The mouse button (left/middle/right) - */ - OSjs.Utils.mouseButton = function Utils_mouseButton(ev) { - if ( typeof ev.button !== 'undefined' ) { - if ( ev.button === 0 ) { - return 'left'; - } else if ( ev.button === 1 ) { - return 'middle'; + function getKeyName(keyCode) { + let result = false; + Object.keys(Keycodes).forEach((k) => { + if ( !result && (keyCode === Keycodes[k]) ) { + result = k; } - return 'right'; - } + }); + return result; + } - if ( ev.which === 2 || ev.which === 4 ) { - return 'middle'; - } else if ( ev.which === 1 ) { - return 'left'; - } - return 'right'; - }; + return function(ev, checkFor) { + const checks = checkFor.toUpperCase().split('+'); + const checkMods = {CTRL: false, SHIFT: false, ALT: false}; + const checkKeys = []; - /** - * Checks if the event currently has the given key comination. - * - * Example: 'CTRL+SHIFT+A' - * - * @function keyCombination - * @memberof OSjs.Utils - * - * @param {Event} ev The DOM Event - * @param {String} checkFor The string of keystrokes to check - * - * @return {Boolean} - */ - 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; + checks.forEach((f) => { + if ( modifiers[f] ) { + checkMods[f] = true; + } else { + checkKeys.push(f); } - }; + }); - 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; - } + const hasmod = Object.keys(checkMods).every((f) => { + const fk = !!modifiers[f](ev); + return checkMods[f] === fk; + }); - return function(ev, checkFor) { - var checks = checkFor.toUpperCase().split('+'); - var checkMods = {CTRL: false, SHIFT: false, ALT: false}; - var checkKeys = []; + const haskey = checkKeys.every((f) => { + return getKeyName(ev.keyCode) === f; + }); - checks.forEach(function(f) { - if ( modifiers[f] ) { - checkMods[f] = true; - } else { - checkKeys.push(f); - } - }); + return hasmod && haskey; + }; +})(); - 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; - }); - }; - })(); +/** + * Wrapper for event-binding + * + *

+ * You can bind multiple events by separating types with a comma.
+ *
+ * This also automatically binds Touch events.
+ *
+ *   mousedown = touchstart
+ *   mouseup = touchend
+ *   mousemove = touchend
+ *   contextmenu = long-hold
+ *   dblclick = double-tap
+ *   click = tap
+ * 
+ * + * @example + * $bind(el, 'click', function(ev, pos, touch) { + * // A click event + * }); + * + * @example + * $bind(el, 'click:customname', function(ev, pos, touch) { + * // A click event with custom namespace. Useful + * // for when you want to separate events with same + * // type. + * }); + * + * @example + * $bind(el, 'click, mousedown, mouseup', function(ev, pos, touch) { + * // You can bind multiple events in one go + * }); + * + * @param {Node} el DOM Element to attach event to + * @param {String} ev DOM Event Name + * @param {CallbackEvent} callback Callback on event + * @param {Boolean} [useCapture] Use capture mode + */ +export const $bind = (function() { + // Default timeouts + const TOUCH_CONTEXTMENU = 1000; + const TOUCH_CLICK_MIN = 30; + const TOUCH_CLICK_MAX = 1000; + const TOUCH_DBLCLICK = 400; - /** - * Wrapper for event-binding - * - *

-   * You can bind multiple events by separating types with a comma.
-   *
-   * This also automatically binds Touch events.
-   *
-   *   mousedown = touchstart
-   *   mouseup = touchend
-   *   mousemove = touchend
-   *   contextmenu = long-hold
-   *   dblclick = double-tap
-   *   click = tap
-   * 
- * - * @example - * Utils.$bind(el, 'click', function(ev, pos, touch) { - * // A click event - * }); - * - * @example - * Utils.$bind(el, 'click:customname', function(ev, pos, touch) { - * // A click event with custom namespace. Useful - * // for when you want to separate events with same - * // type. - * }); - * - * @example - * Utils.$bind(el, 'click, mousedown, mouseup', function(ev, pos, touch) { - * // You can bind multiple events in one go - * }); - * - * @function $bind - * @memberof OSjs.Utils - * - * @param {Node} el DOM Element to attach event to - * @param {String} ev DOM Event Name - * @param {CallbackEvent} callback Callback on event - * @param {Boolean} [useCapture] Use capture mode + /* + * This is the wrapper for using addEventListener */ - OSjs.Utils.$bind = (function() { - // Default timeouts - var TOUCH_CONTEXTMENU = 1000; - var TOUCH_CLICK_MIN = 30; - var TOUCH_CLICK_MAX = 1000; - var TOUCH_DBLCLICK = 400; - - /* - * This is the wrapper for using addEventListener - */ - 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 addEventHandler(el, n, t, callback, handler, useCapture, realType) { + const args = [t, handler, useCapture]; - /* - * Creates mousewheel handler - */ - function createWheelHandler(el, n, t, callback, useCapture) { + el.addEventListener.apply(el, args); - function _wheel(ev) { - var pos = OSjs.Utils.mousePosition(ev); - var direction = (ev.detail < 0 || ev.wheelDelta > 0) ? 1 : -1; - pos.z = direction; + el._boundEvents[n].push({ + realType: realType, + args: args, + callback: callback + }); + } - return callback(ev, pos); - } + /* + * Creates mousewheel handler + */ + function createWheelHandler(el, n, t, callback, useCapture) { - addEventHandler(el, n, 'mousewheel', callback, _wheel, useCapture, 'mousewheel'); - addEventHandler(el, n, 'DOMMouseScroll', callback, _wheel, useCapture, 'DOMMouseScroll'); - } + function _wheel(ev) { + const pos = mousePosition(ev); + const direction = (ev.detail < 0 || ev.wheelDelta > 0) ? 1 : -1; + pos.z = direction; - /* - * Creates touch gestures for emulating mouse input - */ - function createGestureHandler(el, n, t, callback, useCapture) { - /*eslint no-use-before-define: "off"*/ - var started; - var contextTimeout; - var dblTimeout; - var moved = false; - var clicks = 0; - - // Wrapper for destroying` the event - function _done() { - contextTimeout = clearTimeout(contextTimeout); - started = null; - moved = false; - - el.removeEventListener('touchend', _touchend, false); - el.removeEventListener('touchmove', _touchmove, false); - el.removeEventListener('touchcancel', _touchcancel, false); - } + return callback(ev, pos); + } - // Figure out what kind of event we're supposed to handle on start - function _touchstart(ev) { - if ( ev.target === document.body ) { - ev.preventDefault(); - } + addEventHandler(el, n, 'mousewheel', callback, _wheel, useCapture, 'mousewheel'); + addEventHandler(el, n, 'DOMMouseScroll', callback, _wheel, useCapture, 'DOMMouseScroll'); + } - 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; - } - } + /* + * Creates touch gestures for emulating mouse input + */ + function createGestureHandler(el, n, t, callback, useCapture) { + /*eslint no-use-before-define: "off"*/ + let started; + let contextTimeout; + let dblTimeout; + let moved = false; + let clicks = 0; + + // Wrapper for destroying` the event + function _done() { + contextTimeout = clearTimeout(contextTimeout); + started = null; + moved = false; + + el.removeEventListener('touchend', _touchend, false); + el.removeEventListener('touchmove', _touchmove, false); + el.removeEventListener('touchcancel', _touchcancel, false); + } - el.addEventListener('touchend', _touchend, false); - el.addEventListener('touchmove', _touchmove, false); - el.addEventListener('touchcancel', _touchcancel, false); + // Figure out what kind of event we're supposed to handle on start + function _touchstart(ev) { + if ( ev.target === document.body ) { + ev.preventDefault(); } - // Tapping is registered when you let go of the screen - 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; + contextTimeout = clearTimeout(contextTimeout); + started = new Date(); + moved = false; + + if ( t === 'contextmenu' ) { + contextTimeout = setTimeout(() => { + emitTouchEvent(ev, t, {button: 2, which: 3, buttons: 2}); + _done(); + }, TOUCH_CONTEXTMENU); + } else if ( t === 'dblclick' ) { + if ( clicks === 0 ) { + dblTimeout = clearTimeout(dblTimeout); + dblTimeout = setTimeout(() => { + clicks = 0; + }, TOUCH_DBLCLICK); - if ( !moved && t === 'click' ) { - if ( (diff > TOUCH_CLICK_MIN) && (diff < TOUCH_CLICK_MAX) ) { - ev.stopPropagation(); + clicks++; + } else { + if ( !moved ) { emitTouchEvent(ev, t); } + clicks = 0; } - - return _done(); } - // Whenever a movement has occured make sure to avoid clicks - function _touchmove(ev) { - if ( ev.target === document.body || !moved ) { - ev.preventDefault(); - } + el.addEventListener('touchend', _touchend, false); + el.addEventListener('touchmove', _touchmove, false); + el.addEventListener('touchcancel', _touchcancel, false); + } - if ( !started ) { - return; - } + // Tapping is registered when you let go of the screen + function _touchend(ev) { + contextTimeout = clearTimeout(contextTimeout); + if ( !started ) { + return _done(); + } - contextTimeout = clearTimeout(contextTimeout); - dblTimeout = clearTimeout(dblTimeout); - clicks = 0; - moved = true; + if ( !DOM.$isFormElement(ev) ) { + ev.preventDefault(); } - // In case touch is canceled we reset our clickers - function _touchcancel(ev) { - dblTimeout = clearTimeout(dblTimeout); - clicks = 0; + const now = new Date(); + const diff = now - started; - _done(); + if ( !moved && t === 'click' ) { + if ( (diff > TOUCH_CLICK_MIN) && (diff < TOUCH_CLICK_MAX) ) { + ev.stopPropagation(); + emitTouchEvent(ev, t); + } } - addEventHandler(el, n, 'touchstart', callback, _touchstart, false, 'touchstart'); + return _done(); } - /* - * Emits a normal mouse event from touches - * - * This basically emulates mouse behaviour on touch events - */ - function emitTouchEvent(ev, type, combineWith) { - if ( ev.target === document.body ) { + // Whenever a movement has occured make sure to avoid clicks + function _touchmove(ev) { + if ( ev.target === document.body || !moved ) { ev.preventDefault(); } - if ( !ev.currentTarget || ev.changedTouches.length > 1 || (ev.type === 'touchend' && ev.changedTouches > 0) ) { + if ( !started ) { return; } - // Make sure we copy the keyboard attributes as well - 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]; - }); + contextTimeout = clearTimeout(contextTimeout); + dblTimeout = clearTimeout(dblTimeout); + clicks = 0; + moved = true; + } - if ( combineWith ) { - Object.keys(combineWith).forEach(function(k) { - evtArgs[k] = combineWith[k]; - }); - } + // In case touch is canceled we reset our clickers + function _touchcancel(ev) { + dblTimeout = clearTimeout(dblTimeout); + clicks = 0; + + _done(); + } + + addEventHandler(el, n, 'touchstart', callback, _touchstart, false, 'touchstart'); + } + + /* + * Emits a normal mouse event from touches + * + * This basically emulates mouse behaviour on touch events + */ + function emitTouchEvent(ev, type, combineWith) { + if ( ev.target === document.body ) { + ev.preventDefault(); + } - ev.currentTarget.dispatchEvent(new MouseEvent(type, evtArgs)); + if ( !ev.currentTarget || ev.changedTouches.length > 1 || (ev.type === 'touchend' && ev.changedTouches > 0) ) { + return; } - /* - * Map of touch events - */ - var customEvents = { - mousedown: 'touchstart', - mouseup: 'touchend', - mousemove: 'touchmove', - mousewheel: createWheelHandler, - contextmenu: createGestureHandler, - click: createGestureHandler, - dblclick: createGestureHandler + // Make sure we copy the keyboard attributes as well + const copy = ['ctrlKey', 'altKey', 'shiftKey', 'metaKey', 'screenX', 'screenY']; + const touch = ev.changedTouches[0]; + const evtArgs = { + clientX: touch.clientX, + clientY: touch.clientY, + relatedTarget: ev.target }; - return function Utils_$bind(el, evName, callback, useCapture, noBind) { - useCapture = (useCapture === true); + copy.forEach((k) => { + evtArgs[k] = ev[k]; + }); - 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'); - } + if ( combineWith ) { + Object.keys(combineWith).forEach((k) => { + evtArgs[k] = combineWith[k]; + }); + } - function addEvent(nsType, type) { - type = getRealEventName(type); + ev.currentTarget.dispatchEvent(new MouseEvent(type, evtArgs)); + } - addEventHandler(el, nsType, type, callback, function mouseEventHandler(ev) { - if ( !OSjs || !OSjs.Utils ) { // Probably shut down - return null; - } + /* + * Map of touch events + */ + const customEvents = { + mousedown: 'touchstart', + mouseup: 'touchend', + mousemove: 'touchmove', + mousewheel: createWheelHandler, + contextmenu: createGestureHandler, + click: createGestureHandler, + dblclick: createGestureHandler + }; - 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]); - } + return function Utils_$bind(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) { + type = getRealEventName(type); + + addEventHandler(el, nsType, type, callback, function mouseEventHandler(ev) { + if ( !window.OSjs ) { // Probably shut down + return null; } - } - function initNamespace(ns) { - if ( !el._boundEvents ) { - el._boundEvents = {}; + if ( noBind ) { + return callback(ev, mousePosition(ev)); } + return callback.call(el, ev, mousePosition(ev)); + }, useCapture); - if ( !el._boundEvents[ns] ) { - el._boundEvents[ns] = []; + 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]); } + } + } - var found = el._boundEvents[ns].filter(function(iter) { - return iter.callback === callback; - }); + function initNamespace(ns) { + if ( !el._boundEvents ) { + el._boundEvents = {}; + } - return found.length === 0; + if ( !el._boundEvents[ns] ) { + el._boundEvents[ns] = []; } - getEventList(evName).forEach(function(ns) { - var type = ns.split(':')[0]; + const found = el._boundEvents[ns].filter((iter) => { + return iter.callback === callback; + }); - if ( !initNamespace(ns) ) { - console.warn('Utils::$bind()', 'This event was already bound, skipping'); - return; - } + return found.length === 0; + } - addEvent(ns, type); - }); - }; - })(); + getEventList(evName).forEach((ns) => { + const type = ns.split(':')[0]; - /** - * Unbinds the given event - * - *

-   * If you don't give a callback it will unbind *all* events in this category.
-   *
-   * You can unbind multiple events by separating types with a comma
-   * 
- * - * @example - * Utils.$unbind(el, 'click', function() {...}); // Unbinds spesific function - * - * @example - * Utils.$unbind(el, 'click'); // Unbinds all click events - * - * @example - * Utils.$unbind(el); // Unbinds all events - * - * @function $unbind - * @memberof OSjs.Utils - * @see OSjs.Utils.$bind - * - * @param {Node} el DOM Element to attach event to - * @param {String} [evName] DOM Event Name - * @param {Function} [callback] Callback on event - * @param {Boolean} [useCapture] Use capture mode - */ - OSjs.Utils.$unbind = function Utils_$unbind(el, evName, callback, useCapture) { - - function unbindAll() { - if ( el._boundEvents ) { - Object.keys(el._boundEvents).forEach(function(type) { - unbindNamed(type); - }); - delete el._boundEvents; + if ( !initNamespace(ns) ) { + console.warn('Utils::$bind()', 'This event was already bound, skipping'); + return; } - } - function unbindNamed(type) { - if ( el._boundEvents ) { - var list = el._boundEvents || {}; + addEvent(ns, type); + }); + }; +})(); - if ( list[type] ) { - for ( var i = 0; i < list[type].length; i++ ) { - var iter = list[type][i]; +/** + * Unbinds the given event + * + *

+ * If you don't give a callback it will unbind *all* events in this category.
+ *
+ * You can unbind multiple events by separating types with a comma
+ * 
+ * + * @example + * $unbind(el, 'click', function() {...}); // Unbinds spesific function + * + * @example + * $unbind(el, 'click'); // Unbinds all click events + * + * @example + * $unbind(el); // Unbinds all events + * + * @see $bind + * + * @param {Node} el DOM Element to attach event to + * @param {String} [evName] DOM Event Name + * @param {Function} [callback] Callback on event + * @param {Boolean} [useCapture] Use capture mode + */ +export function $unbind(el, evName, callback, useCapture) { - // If a callback/handler was applied make sure we remove the correct one - if ( callback && iter.callback !== callback ) { - continue; - } + function unbindAll() { + if ( el._boundEvents ) { + Object.keys(el._boundEvents).forEach((type) => { + unbindNamed(type); + }); + delete el._boundEvents; + } + } + + function unbindNamed(type) { + if ( el._boundEvents ) { + const list = el._boundEvents || {}; - // We stored the event binding earlier - el.removeEventListener.apply(el, iter.args); + if ( list[type] ) { + for ( let i = 0; i < list[type].length; i++ ) { + let iter = list[type][i]; - list[type].splice(i, 1); - i--; + // If a callback/handler was applied make sure we remove the correct one + if ( callback && iter.callback !== callback ) { + continue; } + + // We stored the event binding earlier + el.removeEventListener.apply(el, iter.args); + + list[type].splice(i, 1); + i--; } } } + } - if ( el ) { - if ( evName ) { - getEventList(evName).forEach(function(type) { - unbindNamed(type); - }); - } else { - unbindAll(); - } + if ( el ) { + if ( evName ) { + getEventList(evName).forEach((type) => { + unbindNamed(type); + }); + } else { + unbindAll(); } - }; + } +} -})(); diff --git a/src/client/javascript/utils/fs.js b/src/client/javascript/utils/fs.js index 007b157d66..c3d657310e 100644 --- a/src/client/javascript/utils/fs.js +++ b/src/client/javascript/utils/fs.js @@ -27,376 +27,592 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // FS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Gets the path from a location - * - * @function getPathFromVirtual - * @memberof OSjs.Utils - * - * @param {String} str Path name - * - * @return {String} - */ - OSjs.Utils.getPathFromVirtual = function Utils_getPathFromVirtual(str) { - str = str || ''; - var res = str.split(/([A-z0-9\-_]+)\:\/\/(.*)/)[2] || ''; - return res.replace(/^\/?/, '/'); - }; - /** - * Gets the protocol from a location - * - * @function getPathProtocol - * @memberof OSjs.Utils - * - * @param {String} orig Path name - * - * @return {String} - */ - OSjs.Utils.getPathProtocol = function Utils_getPathProtocol(orig) { - //return orig.replace(/^([A-z0-9\-_]+)\:\/\//, ''); - var tmp = document.createElement('a'); - tmp.href = orig; - return tmp.protocol.replace(/:$/, ''); - }; +import * as Utils from 'utils/misc'; - /** - * Get file extension of filename/path - * - * @function filext - * @memberof OSjs.Utils - * - * @param {String} d filename/path - * - * @return {String} The file extension - */ - OSjs.Utils.filext = function Utils_filext(d) { - var ext = OSjs.Utils.filename(d).split('.').pop(); - return ext ? ext.toLowerCase() : null; - }; +///////////////////////////////////////////////////////////////////////////// +// FS +///////////////////////////////////////////////////////////////////////////// - /** - * Get directory from path - * - * If you use this on a directory path, you will - * get the parent - * - * @function dirname - * @memberof OSjs.Utils - * - * @param {String} f filename/path - * - * @return {String} The resulted path - */ - OSjs.Utils.dirname = function Utils_dirname(f) { - - function _parentDir(p) { - var pstr = p.split(/^(.*)\:\/\/(.*)/).filter(function(n) { - return n !== ''; - }); +/** + * Gets the path from a location + * + * @param {String} str Path name + * + * @return {String} + */ +export function getPathFromVirtual(str) { + str = str || ''; + const res = str.split(/([A-z0-9\-_]+)\:\/\/(.*)/)[2] || ''; + return res.replace(/^\/?/, '/'); +} + +/** + * Gets the protocol from a location + * + * @param {String} orig Path name + * + * @return {String} + */ +export function getPathProtocol(orig) { + //return orig.replace(/^([A-z0-9\-_]+)\:\/\//, ''); + const tmp = document.createElement('a'); + tmp.href = orig; + return tmp.protocol.replace(/:$/, ''); +} + +/** + * Get filename from path + * + * @param {String} p Path + * + * @return {String} The filename + */ +export function filename(p) { + return (p || '').replace(/\/$/, '').split('/').pop(); +} - var args = pstr.pop(); - var prot = pstr.pop(); - var result = ''; +/** + * Get file extension of filename/path + * + * @param {String} d filename/path + * + * @return {String} The file extension + */ +export function filext(d) { + const ext = filename(d).split('.').pop(); + return ext ? ext.toLowerCase() : null; +} - var tmp = args.split('/').filter(function(n) { - return n !== ''; - }); +/** + * Get directory from path + * + * If you use this on a directory path, you will + * get the parent + * + * @param {String} f filename/path + * + * @return {String} The resulted path + */ +export function dirname(f) { - if ( tmp.length ) { - tmp.pop(); - } - result = tmp.join('/'); + function _parentDir(p) { + const pstr = p.split(/^(.*)\:\/\/(.*)/).filter(function(n) { + return n !== ''; + }); - if ( !result.match(/^\//) ) { - result = '/' + result; - } + const args = pstr.pop(); + const prot = pstr.pop(); + let result = ''; - if ( prot ) { - result = prot + '://' + result; - } + const tmp = args.split('/').filter(function(n) { + return n !== ''; + }); - return result; + if ( tmp.length ) { + tmp.pop(); } + result = tmp.join('/'); - return f.match(/^((.*)\:\/\/)?\/$/) ? f : _parentDir(f.replace(/\/$/, '')); - }; - - /** - * Get filename from path - * - * @function filename - * @memberof OSjs.Utils - * - * @param {String} p Path - * - * @return {String} The filename - */ - OSjs.Utils.filename = function Utils_filename(p) { - return (p || '').replace(/\/$/, '').split('/').pop(); - }; - - /** - * Get human-readable size from integer - * - * Example return: '128 MB' - * - * @function humanFileSize - * @memberof OSjs.Utils - * @link http://stackoverflow.com/users/65387/mark - * - * @param {Number} bytes Size in bytes - * @param {String} si Use SI units ? - * - * @return {String} Size - */ - OSjs.Utils.humanFileSize = function Utils_humanFileSize(bytes, si) { - var thresh = si ? 1000 : 1024; - if (bytes < thresh) { - return bytes + ' B'; + if ( !result.match(/^\//) ) { + result = '/' + result; } - 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]; - }; + if ( prot ) { + result = prot + '://' + result; + } - /** - * Escape filename (removes invalid characters) - * - * @function escapeFilename - * @memberof OSjs.Utils - * - * @param {String} n Filename - * - * @return {String} Escaped filename - */ - OSjs.Utils.escapeFilename = function Utils_escapeFilename(n) { - return (n || '').replace(/[\|&;\$%@"<>\(\)\+,\*\/]/g, '').trim(); - }; + return result; + } - /** - * Replace file extension of filename - * - * @function replaceFileExtension - * @memberof OSjs.Utils - * - * @param {String} filename The filename - * @param {String} rep New file extension (without dot) - * - * @return {String} New filename - */ - OSjs.Utils.replaceFileExtension = function Utils_replaceFileExtension(filename, rep) { - var spl = filename.split('.'); - spl.pop(); - spl.push(rep); - return spl.join('.'); - }; + return f.match(/^((.*)\:\/\/)?\/$/) ? f : _parentDir(f.replace(/\/$/, '')); +} - /** - * Replace the filename of a path - * - * @function replaceFilename - * @memberof OSjs.Utils - * - * @param {String} orig The full path to file - * @param {String} newname Replace with this filename - * - * @return {String} The new path - */ - OSjs.Utils.replaceFilename = function Utils_replaceFilename(orig, newname) { - var spl = orig.split('/'); - spl.pop(); - spl.push(newname); - return spl.join('/'); - }; +/** + * Get human-readable size from integer + * + * Example return: '128 MB' + * @link http://stackoverflow.com/users/65387/mark + * + * @param {Number} bytes Size in bytes + * @param {String} si Use SI units ? + * + * @return {String} Size + */ +export function humanFileSize(bytes, si) { + const units = si ? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] : ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']; + const thresh = si ? 1000 : 1024; + + if (bytes < thresh) { + return bytes + ' B'; + } + + let u = -1; + do { + bytes /= thresh; + ++u; + } while (bytes >= thresh); + return bytes.toFixed(1) + ' ' + units[u]; +} + +/** + * Escape filename (removes invalid characters) + * + * @param {String} n Filename + * + * @return {String} Escaped filename + */ +export function escapeFilename(n) { + return (n || '').replace(/[\|&;\$%@"<>\(\)\+,\*\/]/g, '').trim(); +} - /** - * Joins arguments to a path (path.join) - * - * @function pathJoin - * @memberof OSjs.Utils - * - * @param {...String} s Input - * @return {String} - */ - OSjs.Utils.pathJoin = function Utils_pathJoin() { - var parts = []; - var prefix = ''; - - function getPart(s) { - if ( s.match(/^([A-z0-9\-_]+)\:\//) ) { - var spl = s.split(':/'); - if ( !prefix ) { - prefix = spl[0] + '://'; - } - s = spl[1] || ''; +/** + * Replace file extension of filename + * + * @param {String} filename The filename + * @param {String} rep New file extension (without dot) + * + * @return {String} New filename + */ +export function replaceFileExtension(filename, rep) { + const spl = filename.split('.'); + spl.pop(); + spl.push(rep); + return spl.join('.'); +} + +/** + * Replace the filename of a path + * + * @param {String} orig The full path to file + * @param {String} newname Replace with this filename + * + * @return {String} The new path + */ +export function replaceFilename(orig, newname) { + const spl = orig.split('/'); + spl.pop(); + spl.push(newname); + return spl.join('/'); +} + +/** + * Joins arguments to a path (path.join) + * + * @param {...String} s Input + * @return {String} + */ +export function pathJoin() { + let parts = []; + let prefix = ''; + + function getPart(s) { + if ( s.match(/^([A-z0-9\-_]+)\:\//) ) { + const spl = s.split(':/'); + if ( !prefix ) { + prefix = spl[0] + '://'; } + s = spl[1] || ''; + } - s = s.replace(/^\/+/, '').replace(/\/+$/, ''); + s = s.replace(/^\/+/, '').replace(/\/+$/, ''); - return s.split('/').filter(function(i) { - return ['', '.', '..'].indexOf(i) === -1; - }).join('/'); - } + return s.split('/').filter(function(i) { + return ['', '.', '..'].indexOf(i) === -1; + }).join('/'); + } - for ( var i = 0; i < arguments.length; i++ ) { - var str = getPart(String(arguments[i])); - if ( str ) { - parts.push(str); - } + for ( let i = 0; i < arguments.length; i++ ) { + const str = getPart(String(arguments[i])); + if ( str ) { + parts.push(str); } + } - return prefix + parts.join('/').replace(/^\/?/, '/'); - }; + return prefix + parts.join('/').replace(/^\/?/, '/'); +} - /** - * Gets the range of filename in a path (without extension) - * - * This is used for example in text boxes to highlight the filename - * - * @function getFilenameRange - * @memberof OSjs.Utils - * - * @param {String} val The path - * - * @return {Object} Range in form of min/max - */ - OSjs.Utils.getFilenameRange = function Utils_getFileNameRange(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; - } +/** + * Gets the range of filename in a path (without extension) + * + * This is used for example in text boxes to highlight the filename + * + * @param {String} val The path + * + * @return {Object} Range in form of min/max + */ +export function getFilenameRange(val) { + val = val || ''; + + const range = {min: 0, max: val.length}; + if ( val.match(/^\./) ) { + if ( val.length >= 2 ) { + range.min = 1; + } + } else { + if ( val.match(/\.(\w+)$/) ) { + const m = val.split(/\.(\w+)$/); + for ( let i = m.length - 1; i >= 0; i-- ) { + if ( m[i].length ) { + range.max = val.length - m[i].length - 1; + break; } } } - return range; - }; + } + return range; +} - /** - * (Encode) Convert URL-safe String to Base64 - * - * @function btoaUrlsafe - * @memberof OSjs.Utils - * - * @param {String} str String - * - * @return {String} Base64 String - */ - OSjs.Utils.btoaUrlsafe = function Utils_btoaUrlsafe(str) { - return (!str || !str.length) ? '' : btoa(str) - .replace(/\+/g, '-') - .replace(/\//g, '_') - .replace(/=+$/, ''); +/** + * (Encode) Convert URL-safe String to Base64 + * + * @param {String} str String + * + * @return {String} Base64 String + */ +export function btoaUrlsafe(str) { + return (!str || !str.length) ? '' : btoa(str) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); +} + +/** + * (Decode) Convert Base64 to URL-safe String + * + * @param {String} str Base64 String + * + * @return {String} String + */ +export function atobUrlsafe(str) { + if ( str && str.length ) { + str = (str + '===').slice(0, str.length + (str.length % 4)); + return atob(str.replace(/-/g, '+').replace(/_/g, '/')); + } + return ''; +} + +/** + * (Encode) Convert String to Base64 with UTF-8 + * + * @param {String} str String + * + * @return {String} Base64 String + */ +export function btoaUtf(str) { // Encode + const _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); +} - /** - * (Decode) Convert Base64 to URL-safe String - * - * @function atobUrlsafe - * @memberof OSjs.Utils - * - * @param {String} str Base64 String - * - * @return {String} String - */ - OSjs.Utils.atobUrlsafe = function Utils_atobUrlsafe(str) { - if ( str && str.length ) { - str = (str + '===').slice(0, str.length + (str.length % 4)); - return atob(str.replace(/-/g, '+').replace(/_/g, '/')); +/** + * (Decode) Convert Base64 with UTF-8 to String + * + * @param {String} str Base64 String + * + * @return {String} String + */ +export function atobUtf(str) { // Decode + const _escape = window.escape || function(s) { + function q(c) { + c = c.charCodeAt(); + return '%' + (c < 16 ? '0' : '') + c.toString(16).toUpperCase(); } - return ''; + return s.replace(/[\x00-),:-?[-^`{-\xFF]/g, q); }; - /** - * (Encode) Convert String to Base64 with UTF-8 - * - * @function btoaUtf - * @memberof OSjs.Utils - * - * @param {String} str String - * - * @return {String} Base64 String - */ - OSjs.Utils.btoaUtf = function Utils_btoaUtfh(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); - }; + const trans = _escape(atob(str)); + return decodeURIComponent(trans); +} - /** - * (Decode) Convert Base64 with UTF-8 to String - * - * @function atobUtf - * @memberof OSjs.Utils - * - * @param {String} str Base64 String - * - * @return {String} String - */ - OSjs.Utils.atobUtf = function Utils_atobUtf(str) { // Decode - var _escape = window.escape || function(s) { - function q(c) { - c = c.charCodeAt(); - return '%' + (c < 16 ? '0' : '') + c.toString(16).toUpperCase(); +/** + * Check if this MIME type is inside list + * This matches by regex + * + * @param {String} mime The mime string + * @param {Array} list Array of regex matches + * + * @return {Boolean} If found + */ +export function checkAcceptMime(mime, list) { + if ( mime && list.length ) { + let re; + for ( let i = 0; i < list.length; i++ ) { + re = new RegExp(list[i]); + if ( re.test(mime) === true ) { + return true; } - return s.replace(/[\x00-),:-?[-^`{-\xFF]/g, q); - }; + } + } + return false; +} - var trans = _escape(atob(str)); - return decodeURIComponent(trans); - }; +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// - /** - * Check if this MIME type is inside list - * This matches by regex - * - * @function checkAcceptMime - * @memberof OSjs.Utils - * - * @param {String} mime The mime string - * @param {Array} list Array of regex matches - * - * @return {Boolean} If found - */ - OSjs.Utils.checkAcceptMime = function Utils_checkAcceptMime(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 ) { +/** + * Filters a scandir() request + * + * @param {Array} list List of results from scandir() + * @param {Object} options Filter options + * @param {String} options.typeFilter `type` filter + * @param {Array} options.mimeFilter `mime` filter + * @param {Boolean} options.showHiddenFiles Show dotfiles + * @param {String} [options.sortBy=null] Sort by this key + * @param {String} [options.sortDir='asc'] Sort in this direction + * @param {Object} [defaultOptions] The default options (usually loaded from SettingsManager) + * + * @return {Boolean} + */ +export function filterScandir(list, options, defaultOptions) { + defaultOptions = Utils.cloneObject(defaultOptions || {}); + + const ioptions = Utils.cloneObject(options, true); + + let ooptions = Object.assign({}, defaultOptions.scandir || {}, ioptions); + ooptions = Object.assign({}, { + sortBy: null, + sortDir: 'asc', + typeFilter: null, + mimeFilter: [], + showHiddenFiles: true + }, ooptions); + + function filterFile(iter) { + if ( (ooptions.typeFilter && iter.type !== ooptions.typeFilter) || (!ooptions.showHiddenFiles && iter.filename.match(/^\.\w/)) ) { + return false; + } + return true; + } + + function validMime(iter) { + if ( ooptions.mimeFilter && ooptions.mimeFilter.length && iter.mime ) { + return ooptions.mimeFilter.some(function(miter) { + if ( iter.mime.match(miter) ) { return true; } - } + return false; + }); } - return false; + return true; + } + + const result = list.filter(function(iter) { + if ( iter.filename === '..' || !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; + }); + + const sb = ooptions.sortBy; + const types = { + mtime: 'date', + ctime: 'date' }; -})(); + if ( ['filename', 'size', 'mime', 'ctime', 'mtime'].indexOf(sb) !== -1 ) { + if ( types[sb] === 'date' ) { + result.sort(function(a, b) { + a = new Date(a[sb]); + b = new Date(b[sb]); + return (a > b) ? 1 : ((b > a) ? -1 : 0); + }); + } else { + if ( sb === 'size' || !String.prototype.localeCompare ) { + result.sort(function(a, b) { + return (a[sb] > b[sb]) ? 1 : ((b[sb] > a[sb]) ? -1 : 0); + }); + } else { + result.sort(function(a, b) { + return String(a[sb]).localeCompare(String(b[sb])); + }); + } + } + + if ( ooptions.sortDir === 'desc' ) { + result.reverse(); + } + } + + return result.filter(function(iter) { + return iter.type === 'dir'; + }).concat(result.filter(function(iter) { + return iter.type !== 'dir'; + })); +} + +/* + * Wrapper for converting data + */ +function _abToSomething(m, arrayBuffer, mime, callback) { + mime = mime || 'application/octet-stream'; + + try { + const blob = new Blob([arrayBuffer], {type: mime}); + const 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); + } +} + +///////////////////////////////////////////////////////////////////////////// +// CONVERSION HELPERS +///////////////////////////////////////////////////////////////////////////// + +/** + * This is a helper to add a File to FormData + * + * @param {FormData} fd FormData instance + * @param {String} key FormData entry name + * @param {(window.File|window.Blob)} data File Data (see supported types) + * @param {FileMetadata} file File Metadata + */ +export function addFormFile(fd, key, data, file) { + file = file || {mime: 'application/octet-stream', filename: 'filename'}; + + if ( data instanceof window.File ) { + fd.append(key, data); + } else 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); + } + } +} + +/** + * Convert DataSourceURL to ArrayBuffer + * + * @param {String} data The datasource string + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function dataSourceToAb(data, mime, callback) { + const byteString = atob(data.split(',')[1]); + //const mimeString = data.split(',')[0].split(':')[1].split(';')[0]; + + const ab = new ArrayBuffer(byteString.length); + const ia = new Uint8Array(ab); + for (let i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + callback(false, ab); +} + +/** + * Convert PlainText to ArrayBuffer + * + * @param {String} data The plaintext string + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function textToAb(data, mime, callback) { + _abToSomething('readAsArrayBuffer', data, mime, callback); +} + +/** + * Convert ArrayBuffer to DataSourceURL + * + * @param {ArrayBuffer} arrayBuffer The ArrayBuffer + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function abToDataSource(arrayBuffer, mime, callback) { + _abToSomething('readAsDataURL', arrayBuffer, mime, callback); +} + +/** + * Convert ArrayBuffer to PlainText + * + * @param {ArrayBuffer} arrayBuffer The ArrayBuffer + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function abToText(arrayBuffer, mime, callback) { + _abToSomething('readAsText', arrayBuffer, mime, callback); +} + +/** + * Convert ArrayBuffer to BinaryString + * + * @param {ArrayBuffer} arrayBuffer The ArrayBuffer + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function abToBinaryString(arrayBuffer, mime, callback) { + _abToSomething('readAsBinaryString', arrayBuffer, mime, callback); +} + +/** + * Convert ArrayBuffer to Blob + * + * @param {ArrayBuffer} arrayBuffer The ArrayBuffer + * @param {String} mime The mime type + * @param {Function} callback Callback function => fn(error, result) + */ +export function abToBlob(arrayBuffer, mime, callback) { + mime = mime || 'application/octet-stream'; + + try { + const blob = new Blob([arrayBuffer], {type: mime}); + callback(false, blob); + } catch ( e ) { + console.warn(e, e.stack); + callback(e); + } +} + +/** + * Convert Blob to ArrayBuffer + * + * @param {Blob} data The blob + * @param {Function} callback Callback function => fn(error, result) + */ +export function blobToAb(data, callback) { + try { + const 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); + } +} diff --git a/src/client/javascript/utils/gui.js b/src/client/javascript/utils/gui.js new file mode 100644 index 0000000000..bf6966bd99 --- /dev/null +++ b/src/client/javascript/utils/gui.js @@ -0,0 +1,779 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +import * as DOM from 'utils/dom'; +import * as Events from 'utils/events'; +import * as Compability from 'utils/compability'; +import PackageManager from 'core/package-manager'; +import Theme from 'core/theme'; +import GUIElement from 'gui/element'; + +///////////////////////////////////////////////////////////////////////////// +// HELPERS +///////////////////////////////////////////////////////////////////////////// + +/** + * Gets window id from upper parent element + * + * @param {Node} el Child element (can be anything) + * + * @return {Number} + */ +export function getWindowId(el) { + while ( el.parentNode ) { + const attr = el.getAttribute('data-window-id'); + if ( attr !== null ) { + return parseInt(attr, 10); + } + el = el.parentNode; + } + return null; +} + +/** + * Gets "label" from a node + * + * @param {Node} el The element + * + * @return {String} + */ +export function getLabel(el) { + const label = el.getAttribute('data-label'); + return label || ''; +} + +/** + * Gets "label" from a node (Where it can be innerHTML and parameter) + * + * @param {Node} el The element + * @param {Boolean} [attr=false] Get from attribute istead of node text + * + * @return {String} + */ +export function getValueLabel(el, attr) { + let 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; + DOM.$empty(el); + } + + return label || ''; +} + +/** + * Gets "value" from a node + * + * @param {Node} el The element + * + * @return {String} + */ +export function getViewNodeValue(el) { + let value = el.getAttribute('data-value'); + if ( typeof value === 'string' && value.match(/^\[|\{/) ) { + try { + value = JSON.parse(value); + } catch ( e ) { + value = null; + } + } + return value; +} + +/** + * Internal for getting + * + * @param {Node} el Element + * @param {Window} [win] Window Reference + * + * @return {String} + */ +export function getIcon(el, win) { + let image = el.getAttribute('data-icon'); + if ( image ) { + return win ? PackageManager.getPackageResource(win._app, image) : image; + } + + image = el.getAttribute('data-stock-icon'); + + if ( image && image !== 'undefined') { + let size = '16x16'; + try { + let spl = image.split('/'); + let tmp = spl.shift(); + let siz = tmp.match(/^\d+x\d+/); + if ( siz ) { + size = siz[0]; + image = spl.join('/'); + } + + image = Theme.getIcon(image, size); + } catch ( e ) {} + + return image; + } + + return null; +} + +/** + * Wrapper for getting custom dom element property value + * + * @param {Node} el Element + * @param {String} param Parameter name + * @param {String} [tagName] What tagname is in use? Automatic + * + * @return {Object|String} + */ +export function getProperty(el, param, tagName) { + tagName = tagName || el.tagName.toLowerCase(); + const 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 el.querySelector('input').value === 'on'; + } + return null; + } + + if ( (param === 'value' || param === 'selected') && isDataView ) { + return GUIElement.createFromNode(el).values(); + } + + return el.getAttribute('data-' + param); +} + +/** + * Creates a label for given input element + * + * @param {Node} el Element root + * @param {String} type Input element type + * @param {Node} input The input element + * @param {String} [label] Used when updating + */ +export function createInputLabel(el, type, input, label) { + label = label || getLabel(el); + + if ( label ) { + const lbl = document.createElement('label'); + const 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); + } +} + +/** + * Wrapper for setting custom dom element property value + * + * @param {Node} el Element + * @param {String} param Parameter name + * @param {String} value Parameter value + * @param {String} [tagName] What tagname is in use? Automatic + */ +export 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)); + } + + // Generics for input elements + const inner = el.children[0]; + + let accept = ['gui-slider', 'gui-text', 'gui-password', 'gui-textarea', 'gui-checkbox', 'gui-radio', 'gui-select', 'gui-select-list', 'gui-button']; + + (function() { + let firstChild; + + const 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); + DOM.$remove(el.querySelector('label')); + 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 || ''); + } + } + } + })(); + + // Other types of elements + accept = ['gui-image', 'gui-audio', 'gui-video']; + if ( (['src', 'controls', 'autoplay', 'alt']).indexOf(param) >= 0 && accept.indexOf(tagName) >= 0 ) { + inner[param] = value; + } + + // Normal DOM attributes + if ( (['_id', '_class', '_style']).indexOf(param) >= 0 ) { + inner.setAttribute(param.replace(/^_/, ''), value); + return; + } + + // Set the actual root element property value + if ( param !== 'value' ) { + _setValueAttribute(el, 'data-' + param, value); + } +} + +/** + * Create a new custom DOM element + * + * @param {String} tagName Tag Name + * @param {Object} params Dict with data-* properties + * @param {Array} [ignoreParams] List of arguments to ignore + * + * @return {Node} + */ +export function createElement(tagName, params, ignoreParams) { + ignoreParams = ignoreParams || []; + + const el = document.createElement(tagName); + + const classMap = { + textalign: function(v) { + DOM.$addClass(el, 'gui-align-' + v); + }, + className: function(v) { + DOM.$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; + } + + const value = params[k]; + if ( typeof value !== 'undefined' && typeof value !== 'function' ) { + if ( classMap[k] ) { + classMap[k](value); + return; + } + + const fvalue = getValue(k, value); + el.setAttribute('data-' + k, fvalue); + } + }); + } + + return el; +} + +/** + * Sets the flexbox CSS style properties for given container + * + * @param {Node} el The container + * @param {Number} grow Grow factor + * @param {Number} shrink Shrink factor + * @param {String} [basis=auto] Basis + * @param {Node} [checkel] Take defaults from this node + */ +export 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; + } + })(); + + const flex = [grow, shrink]; + if ( basis.length ) { + flex.push(basis); + } + + const 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; + + const align = el.getAttribute('data-align'); + DOM.$removeClass(el, 'gui-flex-align-start'); + DOM.$removeClass(el, 'gui-flex-align-end'); + if ( align ) { + DOM.$addClass(el, 'gui-flex-align-' + align); + } +} + +/** + * Wrapper for creating a draggable container + * + * @param {Node} el The container + * @param {Function} onDown On down action callback + * @param {Function} onMove On move action callback + * @param {Function} onUp On up action callback + */ +export function createDrag(el, onDown, onMove, onUp) { + onDown = onDown || function() {}; + onMove = onMove || function() {}; + onUp = onUp || function() {}; + + let startX, startY, currentX, currentY; + let dragging = false; + + function _onMouseMove(ev, pos, touchDevice) { + ev.preventDefault(); + + if ( dragging ) { + currentX = pos.x; + currentY = pos.y; + + const diffX = currentX - startX; + const 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; + + Events.$unbind(window, 'mouseup:guidrag'); + Events.$unbind(window, 'mousemove:guidrag'); + } + + function _onMouseDown(ev, pos, touchDevice) { + ev.preventDefault(); + + startX = pos.x; + startY = pos.y; + + onDown(ev, {x: startX, y: startY}); + dragging = true; + + Events.$bind(window, 'mouseup:guidrag', _onMouseUp, false); + Events.$bind(window, 'mousemove:guidrag', _onMouseMove, false); + } + + Events.$bind(el, 'mousedown', _onMouseDown, false); +} + +/** + * Method for getting the next (or previous) element in sequence + * + * If you don't supply a current element, the first one will be taken! + * + * @param {Boolean} prev Get previous element instead of next + * @param {Node} current The current element + * @param {Node} root The root container + * + * @return {Node} + */ +export function getNextElement(prev, current, root) { + function getElements() { + const ignore_roles = ['menu', 'menuitem', 'grid', 'gridcell', 'listitem']; + const list = []; + + root.querySelectorAll('.gui-element').forEach(function(e) { + // Ignore focused and disabled elements, and certain aria roles + if ( DOM.$hasClass(e, 'gui-focus-element') || ignore_roles.indexOf(e.getAttribute('role')) >= 0 || e.getAttribute('data-disabled') === 'true' ) { + return; + } + + // Elements without offsetParent are invisible + if ( e.offsetParent ) { + list.push(e); + } + }); + return list; + } + + function getCurrentIndex(els, m) { + let found = -1; + + // Simply get index from array, it seems indexOf is a bit iffy here ?! + if ( m ) { + els.every(function(e, idx) { + if ( e === m ) { + found = idx; + } + return found === -1; + }); + } + + return found; + } + + function getCurrentParent(els, m) { + if ( m ) { + let cur = m; + while ( cur.parentNode ) { + if ( DOM.$hasClass(cur, 'gui-element') ) { + return cur; + } + cur = cur.parentNode; + } + + return null; + } + + // When we dont have a initial element, take the first one + return els[0]; + } + + function getNextIndex(els, p, i) { + // This could probably be prettier, but it does the job + 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) { + let next = els[i]; + + // Get "real" elements from input wrappers + if ( next.tagName.match(/^GUI\-(BUTTON|TEXT|PASSWORD|SWITCH|CHECKBOX|RADIO|SELECT)/) ) { + next = next.querySelectorAll('input, textarea, button, select')[0]; + } + + // Special case for elements that wraps + if ( next.tagName === 'GUI-FILE-VIEW' ) { + next = next.children[0]; + } + + return next; + } + + if ( root ) { + const elements = getElements(); + if ( elements.length ) { + const currentParent = getCurrentParent(elements, current); + const currentIndex = getCurrentIndex(elements, currentParent); + + if ( currentIndex >= 0 ) { + const nextIndex = getNextIndex(elements, currentParent, currentIndex); + return getNext(elements, nextIndex); + } + } + } + + return null; +} + +/** + * Create a draggable DOM element + * + * @param {Node} el DOMElement + * @param {Object} args JSON of draggable params + * @param {Object} args.data The data (JSON by default) + * @param {String} [args.type] A custom drag event 'type' + * @param {String} [args.effect=move] The draggable effect (cursor) + * @param {String} [args.mime=application/json] The mime type of content + * @param {Function} args.onStart Callback when drag started => fn(ev, el, args) + * @param {Function} args.onEnd Callback when drag ended => fn(ev, el, args) + */ +export function createDraggable(el, args) { + /* eslint no-invalid-this: "off" */ + + args = Object.assign({}, { + type: null, + effect: 'move', + data: null, + mime: 'application/json', + dragImage: null, + onStart: function() { + return true; + }, + onEnd: function() { + return true; + } + }, args); + + if ( Compability.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 ) { + const dragImage = args.dragImage(ev, el); + if ( dragImage ) { + const dragEl = dragImage.element; + const 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'); + + Events.$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); + + Events.$bind(el, 'dragend', function(ev) { + this.setAttribute('aria-grabbed', 'false'); + this.style.opacity = '1.0'; + return args.onEnd(ev, this, args); + }, false); +} + +/** + * Create a droppable DOM element + * + * @param {Node} el DOMElement + * @param {Object} args JSON of droppable params + * @param {String} [args.accept] Accept given drag event 'type' + * @param {String} [args.effect=move] The draggable effect (cursor) + * @param {String} [args.mime=application/json] The mime type of content + * @param {Boolean} [args.files=true] Support file drops from OS + * @param {Function} args.onEnter Callback when drag entered => fn(ev, el) + * @param {Function} args.onOver Callback when drag over => fn(ev, el) + * @param {Function} args.onLeave Callback when drag leave => fn(ev, el) + * @param {Function} args.onDrop Callback when drag drop all => fn(ev, el) + * @param {Function} args.onFilesDropped Callback when drag drop file => fn(ev, el, files, args) + * @param {Function} args.onItemDropped Callback when drag drop internal object => fn(ev, el, item, args) + */ +export function createDroppable(el, args) { + /* eslint no-invalid-this: "off" */ + + args = Object.assign({}, { + 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; + } + }, args); + + if ( Compability.isIE() ) { + args.mime = 'text'; + } + + function getParent(start, matcher) { + if ( start === matcher ) { + return true; + } + + let i = 10; + + while ( start && i > 0 ) { + if ( start === matcher ) { + return true; + } + start = start.parentNode; + i--; + } + return false; + } + + function _doDrop(ev, el) { + if ( !ev.dataTransfer ) { + return true; + } + + if ( args.files ) { + const files = ev.dataTransfer.files; + if ( files && files.length ) { + return args.onFilesDropped(ev, el, files, args); + } + } + + try { + const data = ev.dataTransfer.getData(args.mime); + const item = JSON.parse(data); + if ( args.accept === null || args.accept === item.type ) { + return args.onItemDropped(ev, el, item, args); + } + } catch ( e ) { + console.warn('Failed to drop: ' + e); + } + + return false; + } + + function _onDrop(ev, el) { + ev.stopPropagation(); + ev.preventDefault(); + + const result = _doDrop(ev, el); + args.onDrop(ev, el); + return result; + } + + el.setAttribute('aria-dropeffect', args.effect); + + Events.$bind(el, 'drop', function(ev) { + //DOM.$removeClass(el, 'onDragEnter'); + return _onDrop(ev, this); + }, false); + + Events.$bind(el, 'dragenter', function(ev) { + //DOM.$addClass(el, 'onDragEnter'); + return args.onEnter.call(this, ev, this, args); + }, false); + + Events.$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); + + Events.$bind(el, 'dragleave', function(ev) { + //DOM.$removeClass(el, 'onDragEnter'); + return args.onLeave.call(this, ev, this, args); + }, false); +} diff --git a/src/client/javascript/utils/keycodes.js b/src/client/javascript/utils/keycodes.js new file mode 100644 index 0000000000..17326186c0 --- /dev/null +++ b/src/client/javascript/utils/keycodes.js @@ -0,0 +1,87 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ + +/** + * A collection of keycode mappings + * + * @var + */ +const Keycodes = (function() { + const 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 + }; + + // Add all ASCII chacters to the map + for ( let n = 33; n <= 126; n++ ) { + list[String.fromCharCode(n)] = n; + } + + return Object.freeze(list); +})(); + +export default Keycodes; diff --git a/src/client/javascript/utils/misc.js b/src/client/javascript/utils/misc.js index 1ab86ee094..df357f8f0e 100644 --- a/src/client/javascript/utils/misc.js +++ b/src/client/javascript/utils/misc.js @@ -27,481 +27,275 @@ * @author Anders Evenrud * @licence Simplified BSD License */ -(function() { - 'use strict'; - - ///////////////////////////////////////////////////////////////////////////// - // COOKIES - ///////////////////////////////////////////////////////////////////////////// - - /** - * Gets a cookie by key, or all cookies - * - * @function getCookie - * @memberof OSjs.Utils - * - * @param {String} [k] What key to get - * @return {String|Object} Depending on 'k' parameter - */ - OSjs.Utils.getCookie = function Utils_getCookie(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; - }; - - ///////////////////////////////////////////////////////////////////////////// - // STRING - ///////////////////////////////////////////////////////////////////////////// - - /** - * Format a string (almost like sprintf) - * - * @function format - * @memberof OSjs.Utils - * @link http://stackoverflow.com/a/4673436 - * - * @param {String} format String format - * @param {...String} s Insert into format - * - * @return {String} The formatted string - */ - OSjs.Utils.format = function Utils_format(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); - }; - /** - * Remove whitespaces and newlines from HTML document - * - * @function cleanHTML - * @memberof OSjs.Utils - * - * @param {String} html HTML string input - * - * @return {String} - */ - OSjs.Utils.cleanHTML = function Utils_cleanHTML(html) { - return html.replace(/\n/g, '') - .replace(/[\t ]+[\t ]+<') - .replace(/\>[\t ]+$/g, '>'); - }; +///////////////////////////////////////////////////////////////////////////// +// COOKIES +///////////////////////////////////////////////////////////////////////////// - /** - * Parses url into a dictionary (supports modification) - * - * @function parseurl - * @memberof OSjs.Utils - * - * @param {String} url Input URL - * @param {Object} [modify] Modify URL with these options - * - * @return {Object} Object with protocol, host, path - */ - OSjs.Utils.parseurl = function Utils_parseurl(url, modify) { - modify = modify || {}; - - if ( !url.match(/^(\w+\:)\/\//) ) { - url = '//' + url; - } +/** + * Gets a cookie by key, or all cookies + * + * @param {String} [k] What key to get + * @return {String|Object} Depending on 'k' parameter + */ +export function getCookie(k) { + const map = {}; + document.cookie.split(/;\s+?/g).forEach((i) => { + const idx = i.indexOf('='); + map[i.substr(i, idx)] = i.substr(idx + 1); + }); + return k ? map[k] : map; +} + +///////////////////////////////////////////////////////////////////////////// +// STRING +///////////////////////////////////////////////////////////////////////////// + +/** + * Format a string (almost like sprintf) + * + * @link http://stackoverflow.com/a/4673436 + * + * @param {String} format String format + * @param {...String} s Insert into format + * + * @return {String} The formatted string + */ +export function format(format) { + const args = Array.prototype.slice.call(arguments, 1); + const sprintfRegex = /\{(\d+)\}/g; - var protocol = url.split(/^(\w+\:)?\/\//); + function sprintf(match, number) { + return number in args ? args[number] : match; + } - 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('/') - }; - })(); + return format.replace(sprintfRegex, sprintf); +} - function _parts() { - var parts = [splitted.proto, '://']; +/** + * Remove whitespaces and newlines from HTML document + * + * @param {String} html HTML string input + * + * @return {String} + */ +export function cleanHTML(html) { + return html.replace(/\n/g, '') + .replace(/[\t ]+[\t ]+<') + .replace(/\>[\t ]+$/g, '>'); +} + +/** + * Parses url into a dictionary (supports modification) + * + * @param {String} url Input URL + * @param {Object} [modify] Modify URL with these options + * + * @return {Object} Object with protocol, host, path + */ +export function parseurl(url, modify) { + modify = modify || {}; - if ( modify.username ) { - var authstr = String(modify.username) + ':' + String(modify.password); - parts.push(authstr); - parts.push('@'); - } + if ( !url.match(/^(\w+\:)\/\//) ) { + url = '//' + url; + } - parts.push(splitted.host); - parts.push(splitted.path); - return parts.join(''); - } + const protocol = url.split(/^(\w+\:)?\/\//); + const splitted = (() => { + const tmp = protocol[2].replace(/^\/\//, '').split('/'); return { - protocol: splitted.proto, - host: splitted.host, - path: splitted.path, - url: _parts() + proto: (modify.protocol || protocol[1] || window.location.protocol || '').replace(/\:$/, ''), + host: modify.host || tmp.shift(), + path: modify.path || '/' + tmp.join('/') }; - }; + })(); - ///////////////////////////////////////////////////////////////////////////// - // OBJECT HELPERS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Wrapper for merging function argument dictionaries - * - * @function argumentDefaults - * @memberof OSjs.Utils - * - * @param {Object} args Given function Dictionary - * @param {Object} defaults Defaults Dictionary - * @param {Boolean} undef Check with 'undefined' - * @return {Object} - */ - OSjs.Utils.argumentDefaults = function Utils_argumentDefaults(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; - }; - - /** - * Deep-merge to objects - * - * @function mergeObject - * @memberof OSjs.Utils - * - * @param {Object} obj1 Object to merge to - * @param {Object} obj2 Object to merge with - * @param {Object} [opts] Options - * @param {Bollean} [opts.overwrite=true] Overwrite existing - * - * @return {Object} The merged object - */ - OSjs.Utils.mergeObject = function Utils_mergeObject(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; - }; + function _parts() { + const parts = [splitted.proto, '://']; - /** - * Clone a object - * - * @function cloneObject - * @memberof OSjs.Utils - * - * @param {Object} o The object to clone - * @param {Boolean} [alternative=false] Do a programatic deep clone approach - * - * @return {Object} An identical object - */ - OSjs.Utils.cloneObject = function Utils_cloneObject(o, alternative) { - function _clone(i) { - if ( typeof i !== 'object' || i === null ) { - return i; - } else if ( i instanceof Array ) { - return i.map(_clone); - } - - var iter = {}; - Object.keys(i).forEach(function(k) { - iter[k] = _clone(i[k]); - }); - return iter; + if ( modify.username ) { + const authstr = String(modify.username) + ':' + String(modify.password); + parts.push(authstr); + parts.push('@'); } - if ( alternative ) { - return _clone(o); - } + parts.push(splitted.host); + parts.push(splitted.path); + return parts.join(''); + } - return JSON.parse(JSON.stringify(o, function(key, value) { - if ( value && typeof value === 'object' && value.tagName ) { - return window.undefined; - } - return value; - })); - }; - - /** - * Extends the given object - * - *
-   * If you give a `parentObj` and a prototype method exists
-   * in that target, the child object method will be wrapped
-   * to make sure the super object method is called.
-   * 
- * - * @example - * Utils.extend({ - * a: 'foo' - * }, { - * b: 'bar' - * }); // -> {a: 'foo', b: 'bar'} - * - * @function extend - * @memberof OSjs.Utils - * - * @param {Object} obj The destination - * @param {Object} methods The source - */ - OSjs.Utils.extend = function Utils_extend(obj, methods) { - if ( obj && methods ) { - Object.keys(methods).forEach(function(k) { - obj[k] = methods[k]; - }); - } + return { + protocol: splitted.proto, + host: splitted.host, + path: splitted.path, + url: _parts() }; +} - /** - * Extends the given object by prototype chain - * - * @example - * var MyApp = Utils.inherit(OSjs.Core.Application, function(name, args, metadata) { - * Application.apply(this, arguments); - * }, { - * init: function() { - * // then do your stuff here - * } - * }); - * - * @function inherit - * @memberof OSjs.Utils - * @see OSjs.Utils.extend - * - * @param {Object} to The class to inherit - * @param {Object} from The child class - * @param {Object} [extend] Extend the class with these methods - * @return {Object} - */ - OSjs.Utils.inherit = function Utils_inherit(to, from, extend) { - from = from || function() { - /* eslint no-invalid-this: "off" */ - to.apply(this, arguments); - }; - - from.prototype = Object.create(to.prototype); - from.constructor = to; +///////////////////////////////////////////////////////////////////////////// +// OBJECT HELPERS +///////////////////////////////////////////////////////////////////////////// - if ( extend ) { - OSjs.Utils.extend(from.prototype, extend); +/** + * Wrapper for merging function argument dictionaries + * + * @param {Object} args Given function Dictionary + * @param {Object} defaults Defaults Dictionary + * @param {Boolean} undef Check with 'undefined' + * @return {Object} + */ +export function argumentDefaults(args, defaults, undef) { + args = args || {}; + Object.keys(defaults).forEach((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; +} - return from; - }; +/** + * Deep-merge to objects + * + * @param {Object} obj1 Object to merge to + * @param {Object} obj2 Object to merge with + * @param {Object} [opts] Options + * @param {Bollean} [opts.overwrite=true] Overwrite existing + * + * @return {Object} The merged object + */ +export function mergeObject(obj1, obj2, opts) { + opts = opts || {}; - ///////////////////////////////////////////////////////////////////////////// - // COLORS - ///////////////////////////////////////////////////////////////////////////// - - /** - * Convert HEX to RGB - * - * @function convertToRGB - * @memberof OSjs.Utils - * - * @param {String} hex The hex string (with #) - * - * @return {Object} RGB in form of r, g, b - */ - OSjs.Utils.convertToRGB = function Utils_convertToRGB(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; - }; + for ( let p in obj2 ) { + if ( obj2.hasOwnProperty(p) ) { + try { + if (opts.overwrite === false && obj1.hasOwnProperty(p)) { + continue; + } - /** - * Convert RGB to HEX - * - * @function convertToHEX - * @memberof OSjs.Utils - * - * @param {Number|Object} r Red value or RGB object - * @param {Number|undefined} [g] Green value - * @param {Number|undefined} [b] Blue value - * - * @return {String} Hex string (with #) - */ - OSjs.Utils.convertToHEX = function Utils_convertToHEX(r, g, b) { - if ( typeof r === 'object' ) { - g = r.g; - b = r.b; - r = r.r; + if ( obj2[p].constructor === Object ) { + obj1[p] = mergeObject(obj1[p], obj2[p]); + } else { + obj1[p] = obj2[p]; + } + } catch (e) { + obj1[p] = obj2[p]; + } } + } + return obj1; +} - if ( typeof r === 'undefined' || typeof g === 'undefined' || typeof b === 'undefined' ) { - throw new Error('Invalid RGB supplied to convertToHEX()'); +/** + * Clone a object + * + * @param {Object} o The object to clone + * @param {Boolean} [alternative=false] Do a programatic deep clone approach + * + * @return {Object} An identical object + */ +export function cloneObject(o, alternative) { + function _clone(i) { + if ( typeof i !== 'object' || i === null ) { + return i; + } else if ( i instanceof Array ) { + return i.map(_clone); } - 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]; - } + const iter = {}; + Object.keys(i).forEach((k) => { + iter[k] = _clone(i[k]); }); + return iter; + } - return '#' + hex.join('').toUpperCase(); - }; - - /** - * Ivert HEX color - * - * @function invertHEX - * @memberof OSjs.Utils - * @link http://stackoverflow.com/a/9601429/1236086 - * - * @param {String} hex Hex string (With #) - * - * @return {String} Inverted hex (With #) - * - */ - OSjs.Utils.invertHEX = function Utils_invertHEX(hex) { - var color = parseInt(hex.replace('#', ''), 16); - color = 0xFFFFFF ^ color; - color = color.toString(16); - color = ('000000' + color).slice(-6); - return '#' + color; - }; - - ///////////////////////////////////////////////////////////////////////////// - // ASYNC - ///////////////////////////////////////////////////////////////////////////// - - /** - * Run an async queue in series - * - * @function asyncs - * @memberof OSjs.Utils - * - * @param {Array} queue The queue - * @param {Function} onentry Callback on step => fn(entry, index, fnNext) - * @param {Function} ondone Callback on done => fn() - */ - OSjs.Utils.asyncs = function Utils_asyncs(queue, onentry, ondone) { - onentry = onentry || function(e, i, n) { - return n(); - }; - ondone = ondone || function() {}; - - var finished = []; - var isdone = false; - - (function next(i) { - // Ensure that the given index is not run again! - // This might occur if something is out of time - if ( isdone || finished.indexOf(i) !== -1 ) { - return; - } - finished.push(i); - - if ( i >= queue.length ) { - isdone = true; - ondone(); - return; - } + if ( alternative ) { + return _clone(o); + } - try { - onentry(queue[i], i, function onAsyncIter() { - next(i + 1); - }); - } catch ( e ) { - console.warn('Utils::asyncs()', 'Exception while stepping', e.stack, e); - next(i + 1); - } - })(0); - }; - - /** - * Run an async queue in parallel - * - * @function asyncp - * @memberof OSjs.Utils - * - * @param {Array} queue The queue - * @param {Object} [opts] Options - * @param {Number} [opts.max=3] Maximum number of running entries - * @param {Function} onentry Callback on step => fn(entry, index, fnNext) - * @param {Function} ondone Callback on done => fn() - */ - OSjs.Utils.asyncp = function Utils_asyncp(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(); - } + return JSON.parse(JSON.stringify(o, (key, value) => { + if ( value && typeof value === 'object' && value.tagName ) { + return window.undefined; + } + return value; + })); +} - if ( finished.indexOf(i) !== -1 ) { - return; - } - finished.push(i); +///////////////////////////////////////////////////////////////////////////// +// COLORS +///////////////////////////////////////////////////////////////////////////// - running++; - try { - onentry(queue[i], i, _done); - } catch ( e ) { - console.warn('Utils::asyncp()', 'Exception while stepping', e.stack, e); - _done(); - } +/** + * Convert HEX to RGB + * + * @param {String} hex The hex string (with #) + * + * @return {Object} RGB in form of r, g, b + */ +export function convertToRGB(hex) { + const rgb = parseInt(hex.replace('#', ''), 16); + const val = {}; + val.r = (rgb & (255 << 16)) >> 16; + val.g = (rgb & (255 << 8)) >> 8; + val.b = (rgb & 255); + return val; +} + +/** + * Convert RGB to HEX + * + * @param {Number|Object} r Red value or RGB object + * @param {Number|undefined} [g] Green value + * @param {Number|undefined} [b] Blue value + * + * @return {String} Hex string (with #) + */ +export function convertToHEX(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()'); + } + + const hex = [ + parseInt(r, 10).toString( 16 ), + parseInt(g, 10).toString( 16 ), + parseInt(b, 10).toString( 16 ) + ]; + + Object.keys(hex).forEach((i) => { + if ( hex[i].length === 1 ) { + hex[i] = '0' + hex[i]; } + }); - (function check() { - if ( !qleft.length ) { - if ( running || isdone ) { - return; - } - isdone = true; - ondone(); - return; - } + return '#' + hex.join('').toUpperCase(); +} - var d = Math.min(qleft.length, max - running); - for ( var i = 0; i < d; i++ ) { - spawn(qleft.shift(), check); - } - })(); - }; - -})(); +/** + * Ivert HEX color + * @link http://stackoverflow.com/a/9601429/1236086 + * + * @param {String} hex Hex string (With #) + * + * @return {String} Inverted hex (With #) + * + */ +export function invertHEX(hex) { + let color = parseInt(hex.replace('#', ''), 16); + color = 0xFFFFFF ^ color; + color = color.toString(16); + color = ('000000' + color).slice(-6); + return '#' + color; +} diff --git a/src/client/javascript/utils/preloader.js b/src/client/javascript/utils/preloader.js new file mode 100644 index 0000000000..948a519bc7 --- /dev/null +++ b/src/client/javascript/utils/preloader.js @@ -0,0 +1,230 @@ +import Promise from 'bluebird'; +import promiseLimit from 'promise-limit'; +import {getBrowserPath} from 'core/config'; +import axios from 'axios'; + +/* + * Gets file type + * @return {String} + */ +const getFileType = (src) => { + if ( src.match(/\.js$/i) ) { + return 'javascript'; + } else if ( src.match(/\.css$/i) ) { + return 'stylesheet'; + }/* else if ( src.match(/\.html?$/i) ) { + return 'html'; + }*/ + return 'unknown'; +}; + +/* + * Ensures correct base uris + * @return {String} + */ +const getSource = (src) => { + if ( src && !src.match(/^(\/|file|https?)/) ) { + return getBrowserPath(src); + } + return src; +}; + +/* + * Check if CSS has been loaded + * @return {Boolean} + */ +const checkCss = (path) => { + let result = false; + (document.styleSheet || []).forEach((iter, i) => { + if ( iter.href.indexOf(path) !== -1 ) { + result = true; + return false; + } + return true; + }); + return result; +}; + +/* + * Preload File Type Handlers + */ +const handlers = { + javascript: (src) => new Promise((resolve, reject) => { + const el = document.createElement('script'); + el.onreadystatechange = function() { + if ( (this.readyState === 'complete' || this.readyState === 'loaded') ) { + resolve(); + } + }; + el.onerror = (err) => { + let error = new Error(); + error.name = ' -%SCRIPTS% +<% htmlWebpackPlugin.options.osjs.styles.forEach(function(path) { %> + +<% }); %> -%SPLASH% - -%LOGIN% - +<% htmlWebpackPlugin.options.osjs.scripts.forEach(function(path) { %> + +<% }); %> diff --git a/src/templates/dist/login/default.html b/src/templates/dist/default/login.html similarity index 100% rename from src/templates/dist/login/default.html rename to src/templates/dist/default/login.html diff --git a/src/templates/dist/default/splash.html b/src/templates/dist/default/splash.html new file mode 100644 index 0000000000..6e2af4e6e5 --- /dev/null +++ b/src/templates/dist/default/splash.html @@ -0,0 +1,48 @@ + +
+ +
+
+
+
+ + diff --git a/src/templates/dist/default/test.html b/src/templates/dist/default/test.html deleted file mode 100644 index 7d5319d616..0000000000 --- a/src/templates/dist/default/test.html +++ /dev/null @@ -1,65 +0,0 @@ - - - - - - - Mocha - OS.js - - - -%STYLES% - - -%SCRIPTS% - - - - - - -%SPLASH% - -%LOGIN% - - - - - - - diff --git a/dist/vendor/dropboxOauthReceiver.html b/src/templates/dist/dropbox-oauth.html similarity index 80% rename from dist/vendor/dropboxOauthReceiver.html rename to src/templates/dist/dropbox-oauth.html index 459a09cb4d..07f089cf6c 100644 --- a/dist/vendor/dropboxOauthReceiver.html +++ b/src/templates/dist/dropbox-oauth.html @@ -1,7 +1,7 @@ - + diff --git a/src/templates/dist/header.css b/src/templates/dist/header.css deleted file mode 100644 index 5d771173f5..0000000000 --- a/src/templates/dist/header.css +++ /dev/null @@ -1,31 +0,0 @@ -@charset "UTF-8"; -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2015, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - diff --git a/src/templates/dist/header.js b/src/templates/dist/header.js deleted file mode 100644 index 4eecd5600e..0000000000 --- a/src/templates/dist/header.js +++ /dev/null @@ -1,32 +0,0 @@ -/**! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -window.OSjs = window.OSjs || {}; - diff --git a/src/templates/dist/packages.js b/src/templates/dist/packages.js index 179bfae043..ab30c7759b 100644 --- a/src/templates/dist/packages.js +++ b/src/templates/dist/packages.js @@ -1,7 +1,6 @@ (function() { window.OSjs = window.OSjs || {} - OSjs.Core = OSjs.Core || {} - OSjs.Core.getMetadata = function() { + OSjs.getManifest = function() { return Object.freeze(%PACKAGES%); }; })(); diff --git a/src/templates/dist/settings.js b/src/templates/dist/settings.js index d72f7e06ab..a353526eca 100644 --- a/src/templates/dist/settings.js +++ b/src/templates/dist/settings.js @@ -4,7 +4,7 @@ /** * Generated by OS.js build system */ - var SETTINGS = Object.freeze((function() { + var SETTINGS = (function() { var c = %CONFIG%; var rootURI = window.location.pathname || '/'; @@ -33,16 +33,15 @@ }); } - return Object.freeze(c); - }())); + return c; + }()); /** * Exports */ window.OSjs = window.OSjs || {}; - OSjs.Core = OSjs.Core || {} - OSjs.Core.getConfig = function() { - return SETTINGS; + OSjs.getConfig = function() { + return Object.assign({}, SETTINGS); }; })(); diff --git a/src/templates/dist/splash/default.html b/src/templates/dist/splash/default.html deleted file mode 100644 index 52b1e899bd..0000000000 --- a/src/templates/dist/splash/default.html +++ /dev/null @@ -1,61 +0,0 @@ - -
- -
- - diff --git a/dist/vendor/wlOauthReceiver.html b/src/templates/dist/windows-live-oauth.html similarity index 100% rename from dist/vendor/wlOauthReceiver.html rename to src/templates/dist/windows-live-oauth.html diff --git a/src/templates/misc/authstorage.sql b/src/templates/misc/authstorage.sql index 5e2c2718b5..02f80d6839 100644 --- a/src/templates/misc/authstorage.sql +++ b/src/templates/misc/authstorage.sql @@ -1,9 +1,27 @@ -CREATE TABLE IF NOT EXISTS `users` ( - `id` int(11) NOT NULL AUTO_INCREMENT, - `username` varchar(255) NOT NULL, - `password` varchar(255) NOT NULL, - `name` varchar(255) NOT NULL, - `groups` text, - `settings` text, - PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1; + +CREATE TABLE `groups` ( + `user_id` int(11) NOT NULL, + `group_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE `settings` ( + `user_id` int(11) NOT NULL, + `settings` text COLLATE utf8mb4_unicode_ci NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +CREATE TABLE `users` ( + `id` int(11) NOT NULL, + `username` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `password` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + `name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +ALTER TABLE `groups` + ADD KEY `user_id` (`user_id`); + +ALTER TABLE `settings` + ADD PRIMARY KEY (`user_id`); + +ALTER TABLE `users` + ADD PRIMARY KEY (`id`); + diff --git a/src/templates/misc/authstorage.sqlite b/src/templates/misc/authstorage.sqlite index 76bc9ad534fb7eb8a548c67953cca08067e6a642..707fb03184b47fd55d438b8ff6fc984f836a09b1 100644 GIT binary patch literal 20480 zcmeI#O;5rw7{Kw37fDD2ZVLyJo(v192fu)57DMDs9EqG5$|Os8?}!Ia_#OPTUhD=l zfEurc{F`)Z*LHpS+b+-jUCr}d@jP9O`@Xo)a+BSzSaJ% z8Q0EoAIEAmkukOGd-f#rsu~mo5I_I{1Q0*~0R#|00D=E2&`KN`rIOzD`;Q}6&POV1 z>`8aNbSF>y-Q;!Ks@RsWD_1p3?9DAs`eV1OR+_6~JY^V${&pU|b1B`03@?eD^-lQA z5yi9+jyG^bwP9N~R$H{%)q17f6}MJbR62IE+EDB2R>Lj_GlNyZR*tZ(2U|3ns&;C% zaBS9>@@2YE@A^LW!~$3;+NC delta 332 zcmZozz}S#5L0XWJfq{V;h+%+nqK+|8P>(T+m;VO?6W7z~TUf)*=A`My}0_0{{5|E0 + * Copyright (c) 2011-2017, Anders Evenrud * All rights reserved. * * Redistribution and use in source and binary forms, with or without diff --git a/src/templates/package/application/main.js b/src/templates/package/application/main.js index 77075fbf8f..cb0ac11f98 100644 --- a/src/templates/package/application/main.js +++ b/src/templates/package/application/main.js @@ -27,84 +27,49 @@ * @author Anders Evenrud * @licence Simplified BSD License */ +const Application = OSjs.require('core/application'); +const Window = OSjs.require('core/window'); -/*eslint valid-jsdoc: "off"*/ -(function(Application, Window, Utils, API, VFS, GUI) { - 'use strict'; +class ApplicationEXAMPLEWindow extends Window { - ///////////////////////////////////////////////////////////////////////////// - // WINDOWS - ///////////////////////////////////////////////////////////////////////////// - - function ApplicationEXAMPLEWindow(app, metadata, scheme) { - Window.apply(this, ['ApplicationEXAMPLEWindow', { + constructor(app, metadata) { + super('ApplicationEXAMPLEWindow', { icon: metadata.icon, title: metadata.name, width: 400, height: 200 - }, app, scheme]); + }, app); } - ApplicationEXAMPLEWindow.prototype = Object.create(Window.prototype); - ApplicationEXAMPLEWindow.constructor = Window.prototype; - - ApplicationEXAMPLEWindow.prototype.init = function(wmRef, app, scheme) { - var root = Window.prototype.init.apply(this, arguments); - var self = this; + init(wmRef, app) { + const root = super.init(...arguments); // Render our Scheme file fragment into this Window - this._render('EXAMPLEWindow'); + this._render('EXAMPLEWindow', require('osjs-scheme-loader!./scheme.html')); // Put your GUI code here (or make a new prototype function and call it): return root; - }; + } - ApplicationEXAMPLEWindow.prototype.destroy = function() { - // This is where you remove objects, dom elements etc attached to your - // instance. You can remove this if not used. - if ( Window.prototype.destroy.apply(this, arguments) ) { - return true; - } - return false; - }; +} - ///////////////////////////////////////////////////////////////////////////// - // APPLICATION - ///////////////////////////////////////////////////////////////////////////// +class ApplicationEXAMPLE extends Application { - function ApplicationEXAMPLE(args, metadata) { - Application.apply(this, ['ApplicationEXAMPLE', args, metadata]); + constructor(args, metadata) { + super('ApplicationEXAMPLE', args, metadata); } - ApplicationEXAMPLE.prototype = Object.create(Application.prototype); - ApplicationEXAMPLE.constructor = Application; + init(settings, metadata) { + super.init(...arguments); - ApplicationEXAMPLE.prototype.destroy = function() { - // This is where you remove objects, dom elements etc attached to your - // instance. You can remove this if not used. - if ( Application.prototype.destroy.apply(this, arguments) ) { - return true; - } - return false; - }; - - ApplicationEXAMPLE.prototype.init = function(settings, metadata, scheme) { - Application.prototype.init.apply(this, arguments); - this._addWindow(new ApplicationEXAMPLEWindow(this, metadata, scheme)); + this._addWindow(new ApplicationEXAMPLEWindow(this, metadata)); // Example on how to call `api.js` methods - this._api('test', {}, function(err, res) { - console.log('Result from your server API method', err, res); + this._api('test', {}).then((res) => { + console.log('Result from your server API method', res); }); }; +} - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Applications = OSjs.Applications || {}; - OSjs.Applications.ApplicationEXAMPLE = OSjs.Applications.ApplicationEXAMPLE || {}; - OSjs.Applications.ApplicationEXAMPLE.Class = Object.seal(ApplicationEXAMPLE); - -})(OSjs.Core.Application, OSjs.Core.Window, OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.GUI); +OSjs.Applications.ApplicationEXAMPLE = ApplicationEXAMPLE; diff --git a/src/templates/package/application/metadata.json b/src/templates/package/application/metadata.json index f1f91868c7..0da695ee3f 100644 --- a/src/templates/package/application/metadata.json +++ b/src/templates/package/application/metadata.json @@ -4,12 +4,9 @@ "mime": null, "icon": "categories/applications-system.png", "main": { + "webpack": ["main.js", "main.css"], "node": "server/main.js", "php": "server/main.php" }, - "preload": [ - {"src": "main.js", "type": "javascript"}, - {"src": "main.css", "type": "stylesheet"}, - {"src": "scheme.html", "type": "scheme"} - ] + "preload": ["main.js", "main.css"] } diff --git a/src/templates/package/application/server/main.js b/src/templates/package/application/server/main.js index 29f58c24c9..08ef961ecf 100644 --- a/src/templates/package/application/server/main.js +++ b/src/templates/package/application/server/main.js @@ -28,28 +28,19 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function() { - 'use strict'; - - /* - * See http://os.js.org/doc/tutorials/application-with-server-api.html - */ - - /** - * Registers your package when OS.js server starts. - */ - module.exports.register = function(env, metadata, servers) { - }; - - /** - * Registers your Application API methods - */ - module.exports.api = { - test: function(env, http, resolve, reject, args) { - resolve('This is a response from your application'); - } - }; +/** + * Registers your package when OS.js server starts. + */ +module.exports.register = function(env, metadata, servers) { + return Promise.resolve(true); +}; -})(); +/** + * Registers your Application API methods + */ +module.exports.api = { + test: function(env, http, args) { + return Promise.resolve('This is a response from your application'); + } +}; diff --git a/src/templates/package/application/webpack.config.js b/src/templates/package/application/webpack.config.js new file mode 100644 index 0000000000..ae5675a3ef --- /dev/null +++ b/src/templates/package/application/webpack.config.js @@ -0,0 +1,10 @@ +const path = require('path'); +const osjs = require('osjs-build'); + +module.exports = new Promise((resolve, reject) => { + const metadataFile = path.join(__dirname, 'metadata.json'); + + osjs.webpack.createPackageConfiguration(metadataFile).then((result) => { + resolve(result.config); + }).catch(reject); +}); diff --git a/src/templates/package/dummy/metadata.json b/src/templates/package/dummy/metadata.json deleted file mode 100644 index a322bda8cf..0000000000 --- a/src/templates/package/dummy/metadata.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "className": "ApplicationEXAMPLE", - "name": "EXAMPLE", - "icon": "categories/applications-system.png", - "preload": [ - {"src": "main.js", "type": "javascript"} - ] -} - - - diff --git a/src/templates/package/extension/main.js b/src/templates/package/extension/main.js index 1fa6cd6ed3..c6aa1fec78 100644 --- a/src/templates/package/extension/main.js +++ b/src/templates/package/extension/main.js @@ -29,37 +29,34 @@ */ /*eslint valid-jsdoc: "off"*/ -(function(Utils, VFS, API) { - 'use strict'; +'use strict'; - ///////////////////////////////////////////////////////////////////////////// - // MODULE API - ///////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////////////////////////////////////////// +// MODULE API +///////////////////////////////////////////////////////////////////////////// - /** - * Extension modules requires an init() method - */ - var EXAMPLE = { - init: function(metadata, done) { - done(); - }, - - test: function(done) { - API.call('test', {}, function(err, res) { - console.log('Result from your server API method', err, res); - }); - } - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - /** - * This is an example using the internal Extension system. - * You can use any namespace you want and override already defined internal methods - */ - OSjs.Extensions.EXAMPLE = EXAMPLE; - -})(OSjs.Utils, OSjs.VFS, OSjs.API); +/** + * Extension modules requires an init() method + */ +const EXAMPLE = { + init: function(metadata, done) { + done(); + }, + + test: function(done) { + API.call('test', {}, function(err, res) { + console.log('Result from your server API method', err, res); + }); + } +}; + +///////////////////////////////////////////////////////////////////////////// +// EXPORTS +///////////////////////////////////////////////////////////////////////////// + +/** + * This is an example using the internal Extension system. + * You can use any namespace you want and override already defined internal methods + */ +OSjs.Extensions.EXAMPLE = EXAMPLE; diff --git a/src/templates/package/extension/metadata.json b/src/templates/package/extension/metadata.json index b07c1b54f6..3df66bab2c 100644 --- a/src/templates/package/extension/metadata.json +++ b/src/templates/package/extension/metadata.json @@ -1,15 +1,14 @@ { - "className": "EXAMPLEExtension", - "type": "extension", + "className": "EXAMPLEExtension", + "type": "extension", "conf": [ ], "main": { + "webpack": ["main.js"], "node": "server/main.js", "php": "server/main.php" }, - "preload": [ - {"src": "main.js", "type": "javascript"} - ] + "preload": ["main.js"] } diff --git a/src/templates/package/extension/server/main.js b/src/templates/package/extension/server/main.js index aa95060f49..c0125fa41b 100644 --- a/src/templates/package/extension/server/main.js +++ b/src/templates/package/extension/server/main.js @@ -28,17 +28,12 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function() { - 'use strict'; - - /** - * Registers your Extension API methods - */ - module.exports.api = { - test: function(http, data) { - return Promise.resolve('This is a response from your extension'); - } - }; +/** + * Registers your Extension API methods + */ +module.exports.api = { + test: function(http, data) { + return Promise.resolve('This is a response from your extension'); + } +}; -})(); diff --git a/src/templates/package/extension/webpack.config.js b/src/templates/package/extension/webpack.config.js new file mode 100644 index 0000000000..ae5675a3ef --- /dev/null +++ b/src/templates/package/extension/webpack.config.js @@ -0,0 +1,10 @@ +const path = require('path'); +const osjs = require('osjs-build'); + +module.exports = new Promise((resolve, reject) => { + const metadataFile = path.join(__dirname, 'metadata.json'); + + osjs.webpack.createPackageConfiguration(metadataFile).then((result) => { + resolve(result.config); + }).catch(reject); +}); diff --git a/src/templates/package/iframe-application/data/index.html b/src/templates/package/iframe-application/data/index.html new file mode 100644 index 0000000000..36be453292 --- /dev/null +++ b/src/templates/package/iframe-application/data/index.html @@ -0,0 +1,27 @@ + + + +

Hello World

+ + + + + + diff --git a/src/templates/package/iframe-application/data/osjs.js b/src/templates/package/iframe-application/data/osjs.js new file mode 100644 index 0000000000..109a03297d --- /dev/null +++ b/src/templates/package/iframe-application/data/osjs.js @@ -0,0 +1,140 @@ +/*! + * OS.js - JavaScript Cloud/Web Desktop Platform + * + * Copyright (c) 2011-2017, Anders Evenrud + * 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 + * @licence Simplified BSD License + */ +(function() { + 'use strict'; + + var COUNT = 0; + + window.OSjs = (function() { + + var origin = {}; // Data that connects your iframe wirh OS.js app + var listeners = {}; // The list of event listeners + var callbacks = {}; + + ////////////////////////////////////////////////////////////////////////// + // Private methods + ////////////////////////////////////////////////////////////////////////// + + /** + * onload window event handler + */ + function _onload(ev) { + _emit('load', [ev]); + } + + /** + * Parse a recieved event + */ + function _onmessage(ev) { + if ( ev && ev.data ) { + var data = Object.assign({}, ev.data); + + if ( data.message === 'Window::init' ) { + origin.wid = data.wid; + origin.pid = data.pid; + Object.freeze(origin); + + _emit('init', [origin]); + } else if ( data.message === 'Window::destroy' ) { + _emit('destroy'); + } else if ( data.message ) { + _emit('data', [data.message]); + } + } + } + + /** + * Emits a bound event + */ + function _emit(type, args) { + if ( listeners[type] ) { + listeners[type].forEach(function(listener) { + listener.apply(null, args || []); + }); + } + } + + ////////////////////////////////////////////////////////////////////////// + // Main + ////////////////////////////////////////////////////////////////////////// + + window.addEventListener('load', _onload); + window.addEventListener('message', _onmessage, false); + + ////////////////////////////////////////////////////////////////////////// + // Public methods + ////////////////////////////////////////////////////////////////////////// + + var exports = { + /** + * Bind an event + */ + on: function(type, cb) { + if ( !listeners[type] ) { + listeners[type] = []; + } + listeners[type].push(cb); + }, + + /** + * Make a callback-type request to your OS.js app. + */ + request: function(method, args, cb) { + callbacks[COUNT] = cb; + + exports.send({ + id: COUNT, + method: method, + args: args + }); + + COUNT++; + }, + + /** + * Send a message to OS.js app. + * Is recieved by `Application.onPostMessage` + */ + send: function(data) { + if ( origin.pid ) { + top.postMessage({ + wid: origin.wid, + pid: origin.pid, + message: data + }, '*'); + } + } + }; + + return exports; + + })(); + +})(); diff --git a/src/templates/package/iframe-application/main.js b/src/templates/package/iframe-application/main.js index bf7e39ddc3..90d69ba0fc 100644 --- a/src/templates/package/iframe-application/main.js +++ b/src/templates/package/iframe-application/main.js @@ -28,16 +28,11 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function(Application, GUI, Dialogs, Utils, API, VFS) { - 'use strict'; +const IFrameApplication = OSjs.require('helpers/iframe-application'); - ///////////////////////////////////////////////////////////////////////////// - // APPLICATION - ///////////////////////////////////////////////////////////////////////////// - - function ApplicationEXAMPLE(args, metadata) { - Application.apply(this, ['ApplicationEXAMPLE', args, metadata, { +class ApplicationEXAMPLE extends IFrameApplication { + constructor(args, metadata) { + super('ApplicationEXAMPLE', args, metadata, { src: 'data/index.html', title: metadata.name, icon: metadata.icon, @@ -46,17 +41,16 @@ allow_resize: false, allow_restore: false, allow_maximize: false - }]); + }); } - ApplicationEXAMPLE.prototype = Object.create(Application.prototype); - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Applications = OSjs.Applications || {}; - OSjs.Applications.ApplicationEXAMPLE = OSjs.Applications.ApplicationEXAMPLE || {}; - OSjs.Applications.ApplicationEXAMPLE.Class = Object.seal(ApplicationEXAMPLE); + onPostMessage(message, ev) { + console.log('Application got message', message); + if ( message === 'ping' ) { + // Send a message back + this.postMessage({foo: 'bar'}); + } + } +} -})(OSjs.Helpers.IFrameApplication, OSjs.GUI, OSjs.Dialogs, OSjs.Utils, OSjs.API, OSjs.VFS); +OSjs.Applications.ApplicationEXAMPLE = ApplicationEXAMPLE; diff --git a/src/templates/package/iframe-application/metadata.json b/src/templates/package/iframe-application/metadata.json index 392657d46f..233ece901f 100644 --- a/src/templates/package/iframe-application/metadata.json +++ b/src/templates/package/iframe-application/metadata.json @@ -1,11 +1,15 @@ { - "className": "ApplicationEXAMPLE", - "name": "EXAMPLE", - "mime": null, - "icon": "categories/applications-system.png", - "preload": [ - {"src": "main.js", "type": "javascript"} - ] + "className": "ApplicationEXAMPLE", + "name": "EXAMPLE", + "mime": null, + "icon": "categories/applications-system.png", + "preload": ["main.js"], + "main": { + "webpack": ["main.js"] + }, + "build": { + "copy": ["data"] + } } diff --git a/src/templates/package/iframe-application/webpack.config.js b/src/templates/package/iframe-application/webpack.config.js new file mode 100644 index 0000000000..bf92937841 --- /dev/null +++ b/src/templates/package/iframe-application/webpack.config.js @@ -0,0 +1,12 @@ +const path = require('path'); +const osjs = require('osjs-build'); + +module.exports = new Promise((resolve, reject) => { + const metadataFile = path.join(__dirname, 'metadata.json'); + + osjs.webpack.createPackageConfiguration(metadataFile).then((result) => { + const configuration = result.config; + + resolve(configuration); + }).catch(reject); +}); diff --git a/src/templates/package/service/main.js b/src/templates/package/service/main.js index 7ae131b550..1d1a5b3acb 100644 --- a/src/templates/package/service/main.js +++ b/src/templates/package/service/main.js @@ -28,42 +28,18 @@ * @licence Simplified BSD License */ -/*eslint valid-jsdoc: "off"*/ -(function(Service, Window, Utils, API, VFS, GUI) { - 'use strict'; +const Service = OSjs.require('core/service'); - ///////////////////////////////////////////////////////////////////////////// - // SERVICE - ///////////////////////////////////////////////////////////////////////////// - - function EXAMPLEService(args, metadata) { - Service.apply(this, ['EXAMPLEService', args, metadata]); +class EXAMPLEService extends Service { + constructor(args, metadata) { + super('EXAMPLEService', args, metadata); } - EXAMPLEService.prototype = Object.create(Service.prototype); - EXAMPLEService.constructor = Service; - - EXAMPLEService.prototype.destroy = function() { - // This is where you remove objects, dom elements etc attached to your - // instance. You can remove this if not used. - if ( Service.prototype.destroy.apply(this, arguments) ) { - return true; - } - return false; - }; - - EXAMPLEService.prototype.init = function(settings, metadata) { - Service.prototype.init.apply(this, arguments); + init(settings, metadata) { + super.init(...arguments); // Put your stuff here - }; - - ///////////////////////////////////////////////////////////////////////////// - // EXPORTS - ///////////////////////////////////////////////////////////////////////////// - - OSjs.Applications = OSjs.Applications || {}; - OSjs.Applications.EXAMPLEService = OSjs.Applications.EXAMPLEService || {}; - OSjs.Applications.EXAMPLEService.Class = Object.seal(EXAMPLEService); + } +} -})(OSjs.Core.Service, OSjs.Core.Window, OSjs.Utils, OSjs.API, OSjs.VFS, OSjs.GUI); +OSjs.Applications.EXAMPLEService = EXAMPLEService; diff --git a/src/templates/package/service/metadata.json b/src/templates/package/service/metadata.json index 8a1af09f78..d89d1789cc 100644 --- a/src/templates/package/service/metadata.json +++ b/src/templates/package/service/metadata.json @@ -4,13 +4,9 @@ "name": "EXAMPLEService", "icon": "categories/applications-system.png", "main": { + "webpack": ["main.js"], "node": "server/main.js", "php": "server/main.php" }, - "preload": [ - { - "src": "main.js", - "type": "javascript" - } - ] + "preload": ["main.js"] } diff --git a/src/templates/package/service/server/main.js b/src/templates/package/service/server/main.js index 947e4f7377..f3626f11dc 100644 --- a/src/templates/package/service/server/main.js +++ b/src/templates/package/service/server/main.js @@ -36,14 +36,15 @@ * Registers your package when OS.js server starts. */ module.exports.register = function(env, metadata, servers) { + return Promise.resolve(true); }; /** * Registers your Application API methods */ module.exports.api = { - test: function(env, http, resolve, reject, args) { - resolve('This is a response from your application'); + test: function(env, http, args) { + return Promise.resolve('This is a response from your application'); } }; diff --git a/src/templates/package/service/webpack.config.js b/src/templates/package/service/webpack.config.js new file mode 100644 index 0000000000..ae5675a3ef --- /dev/null +++ b/src/templates/package/service/webpack.config.js @@ -0,0 +1,10 @@ +const path = require('path'); +const osjs = require('osjs-build'); + +module.exports = new Promise((resolve, reject) => { + const metadataFile = path.join(__dirname, 'metadata.json'); + + osjs.webpack.createPackageConfiguration(metadataFile).then((result) => { + resolve(result.config); + }).catch(reject); +}); diff --git a/src/templates/package/simple-application/main.css b/src/templates/package/simple-application/main.css deleted file mode 100644 index e46307b5aa..0000000000 --- a/src/templates/package/simple-application/main.css +++ /dev/null @@ -1,33 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2015, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -.ApplicationEXAMPLEWindow application-window-content { -} - diff --git a/src/templates/package/simple-application/metadata.json b/src/templates/package/simple-application/metadata.json deleted file mode 100644 index d780c5c1bc..0000000000 --- a/src/templates/package/simple-application/metadata.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "className": "ApplicationEXAMPLE", - "classType": "simple", - "name": "EXAMPLE", - "mime": null, - "icon": "categories/applications-system.png", - "main": { - "node": "server/main.js", - "php": "server/main.php" - }, - "preload": [ - {"src": "main.js", "type": "javascript"}, - {"src": "main.css", "type": "stylesheet"}, - {"src": "scheme.html", "type": "scheme"} - ] -} - - - diff --git a/src/templates/package/simple-application/scheme.html b/src/templates/package/simple-application/scheme.html deleted file mode 100644 index c0c504f7a4..0000000000 --- a/src/templates/package/simple-application/scheme.html +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/templates/package/simple-application/server/main.php b/src/templates/package/simple-application/server/main.php deleted file mode 100644 index 0d488a9cc8..0000000000 --- a/src/templates/package/simple-application/server/main.php +++ /dev/null @@ -1,17 +0,0 @@ - .application-window-button-entry::before { + background-color : #bababa; + background : linear-gradient(to bottom, #bababa 0%,#d9d9d9 100%); + z-index : 1; + } + + application-window-top > .application-window-button-entry::after { + border : 1px solid rgba(102, 102, 102, 0.5); + z-index : 2; + } + + application-window-top > .application-window-button-entry:active::after { + box-shadow: inset 0 0 .2em rgba(0, 0, 0, .2); + } + + application-window[data-focused="true"] > application-window-top > application-window-button-maximize.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-maximize.application-window-button-entry::before { + background: #8dd22b; + background: -moz-linear-gradient(top, #8dd22b 0%, #b1ec70 100%); + background: -webkit-linear-gradient(top, #8dd22b 0%,#b1ec70 100%); + background: linear-gradient(to bottom, #8dd22b 0%,#b1ec70 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-minimize.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-minimize.application-window-button-entry::before { + background: #f9c435; + background: -moz-linear-gradient(top, #f9c435 0%, #fdd675 100%); + background: -webkit-linear-gradient(top, #f9c435 0%,#fdd675 100%); + background: linear-gradient(to bottom, #f9c435 0%,#fdd675 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-close.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-close.application-window-button-entry::before { + background: #e56c5c; + background: -moz-linear-gradient(top, #e56c5c 0%, #f09c8d 100%); + background: -webkit-linear-gradient(top, #e56c5c 0%,#f09c8d 100%); + background: linear-gradient(to bottom, #e56c5c 0%,#f09c8d 100%); + } + + application-window[data-focused="true"] > application-window-top > application-window-button-maximize:hover::before { + background: #b1ec70; + background: -moz-linear-gradient(top, #b1ec70 0%, #8dd22b 100%); + background: -webkit-linear-gradient(top, #b1ec70 0%,#8dd22b 100%); + background: linear-gradient(to bottom, #b1ec70 0%,#8dd22b 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-minimize:hover::before { + background: #fdd675; + background: -moz-linear-gradient(top, #fdd675 0%, #f9c435 100%); + background: -webkit-linear-gradient(top, #fdd675 0%,#f9c435 100%); + background: linear-gradient(to bottom, #fdd675 0%,#f9c435 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-close:hover::before { + background: #f09c8d; + background: -moz-linear-gradient(top, #f09c8d 0%, #e56c5c 100%); + background: -webkit-linear-gradient(top, #f09c8d 0%,#e56c5c 100%); + background: linear-gradient(to bottom, #f09c8d 0%,#e56c5c 100%); + } + +} diff --git a/src/themes/styles/dark/theme.js b/src/themes/styles/dark/theme.js new file mode 100644 index 0000000000..5261b168c4 --- /dev/null +++ b/src/themes/styles/dark/theme.js @@ -0,0 +1,9 @@ +(function() { + window.OSjs = window.OSjs || {}; + OSjs.Themes = window.OSjs.Themes || {}; + OSjs.Themes.dark = { + init: function() {}, + destroy: function() {}, + event: function() {} + }; +})(); diff --git a/src/client/themes/styles/dark/wm/wm.png b/src/themes/styles/dark/wm/wm.png similarity index 100% rename from src/client/themes/styles/dark/wm/wm.png rename to src/themes/styles/dark/wm/wm.png diff --git a/src/client/themes/styles/default/gui/progressbar.png b/src/themes/styles/default/gui/progressbar.png similarity index 100% rename from src/client/themes/styles/default/gui/progressbar.png rename to src/themes/styles/default/gui/progressbar.png diff --git a/src/client/themes/styles/default/metadata.json b/src/themes/styles/default/metadata.json similarity index 100% rename from src/client/themes/styles/default/metadata.json rename to src/themes/styles/default/metadata.json diff --git a/src/themes/styles/default/style.less b/src/themes/styles/default/style.less new file mode 100644 index 0000000000..24ba434b6b --- /dev/null +++ b/src/themes/styles/default/style.less @@ -0,0 +1,83 @@ +@import 'animations.less'; + +body[data-style-theme="default"] { + @import 'theme.less'; + + @gui_progress_bar_background : @gui_selected_background_color url('./gui/progressbar.png') repeat-x center; + + application-window:before { + .theme_border_top(3px); + } + + .application-window-button-entry::after, + .application-window-button-entry::before { + content : ''; + position : absolute; + top : 50%; + left : 50%; + margin-top : -.5em; + margin-left : -.5em; + display : block; + width : 1em; + height : 1em; + border-radius : 100%; + box-sizing : border-box; + } + + application-window-top > .application-window-button-entry::before { + background-color : #bababa; + background : linear-gradient(to bottom, #bababa 0%,#d9d9d9 100%); + z-index : 1; + } + + application-window-top > .application-window-button-entry::after { + border : 1px solid rgba(102, 102, 102, 0.5); + z-index : 2; + } + + application-window-top > .application-window-button-entry:active::after { + box-shadow: inset 0 0 .2em rgba(0, 0, 0, .2); + } + + application-window[data-focused="true"] > application-window-top > application-window-button-maximize.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-maximize.application-window-button-entry::before { + background: #8dd22b; + background: -moz-linear-gradient(top, #8dd22b 0%, #b1ec70 100%); + background: -webkit-linear-gradient(top, #8dd22b 0%,#b1ec70 100%); + background: linear-gradient(to bottom, #8dd22b 0%,#b1ec70 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-minimize.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-minimize.application-window-button-entry::before { + background: #f9c435; + background: -moz-linear-gradient(top, #f9c435 0%, #fdd675 100%); + background: -webkit-linear-gradient(top, #f9c435 0%,#fdd675 100%); + background: linear-gradient(to bottom, #f9c435 0%,#fdd675 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-close.application-window-button-entry:active::before, + application-window[data-focused="true"] > application-window-top > application-window-button-close.application-window-button-entry::before { + background: #e56c5c; + background: -moz-linear-gradient(top, #e56c5c 0%, #f09c8d 100%); + background: -webkit-linear-gradient(top, #e56c5c 0%,#f09c8d 100%); + background: linear-gradient(to bottom, #e56c5c 0%,#f09c8d 100%); + } + + application-window[data-focused="true"] > application-window-top > application-window-button-maximize:hover::before { + background: #b1ec70; + background: -moz-linear-gradient(top, #b1ec70 0%, #8dd22b 100%); + background: -webkit-linear-gradient(top, #b1ec70 0%,#8dd22b 100%); + background: linear-gradient(to bottom, #b1ec70 0%,#8dd22b 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-minimize:hover::before { + background: #fdd675; + background: -moz-linear-gradient(top, #fdd675 0%, #f9c435 100%); + background: -webkit-linear-gradient(top, #fdd675 0%,#f9c435 100%); + background: linear-gradient(to bottom, #fdd675 0%,#f9c435 100%); + } + application-window[data-focused="true"] > application-window-top > application-window-button-close:hover::before { + background: #f09c8d; + background: -moz-linear-gradient(top, #f09c8d 0%, #e56c5c 100%); + background: -webkit-linear-gradient(top, #f09c8d 0%,#e56c5c 100%); + background: linear-gradient(to bottom, #f09c8d 0%,#e56c5c 100%); + } + +} diff --git a/src/themes/styles/default/theme.js b/src/themes/styles/default/theme.js new file mode 100644 index 0000000000..2fed42e34a --- /dev/null +++ b/src/themes/styles/default/theme.js @@ -0,0 +1,9 @@ +(function() { + window.OSjs = window.OSjs || {}; + OSjs.Themes = window.OSjs.Themes || {}; + OSjs.Themes.default = { + init: function() {}, + destroy: function() {}, + event: function() {} + }; +})(); diff --git a/src/client/themes/styles/default/wm/close.png b/src/themes/styles/default/wm/close.png similarity index 100% rename from src/client/themes/styles/default/wm/close.png rename to src/themes/styles/default/wm/close.png diff --git a/src/client/themes/styles/default/wm/close_focused_normal.png b/src/themes/styles/default/wm/close_focused_normal.png similarity index 100% rename from src/client/themes/styles/default/wm/close_focused_normal.png rename to src/themes/styles/default/wm/close_focused_normal.png diff --git a/src/client/themes/styles/default/wm/close_focused_prelight.png b/src/themes/styles/default/wm/close_focused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/close_focused_prelight.png rename to src/themes/styles/default/wm/close_focused_prelight.png diff --git a/src/client/themes/styles/default/wm/close_focused_pressed.png b/src/themes/styles/default/wm/close_focused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/close_focused_pressed.png rename to src/themes/styles/default/wm/close_focused_pressed.png diff --git a/src/client/themes/styles/default/wm/close_unfocused.png b/src/themes/styles/default/wm/close_unfocused.png similarity index 100% rename from src/client/themes/styles/default/wm/close_unfocused.png rename to src/themes/styles/default/wm/close_unfocused.png diff --git a/src/client/themes/styles/default/wm/close_unfocused_prelight.png b/src/themes/styles/default/wm/close_unfocused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/close_unfocused_prelight.png rename to src/themes/styles/default/wm/close_unfocused_prelight.png diff --git a/src/client/themes/styles/default/wm/close_unfocused_pressed.png b/src/themes/styles/default/wm/close_unfocused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/close_unfocused_pressed.png rename to src/themes/styles/default/wm/close_unfocused_pressed.png diff --git a/src/client/themes/styles/default/wm/maximize.png b/src/themes/styles/default/wm/maximize.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize.png rename to src/themes/styles/default/wm/maximize.png diff --git a/src/client/themes/styles/default/wm/maximize_focused_normal.png b/src/themes/styles/default/wm/maximize_focused_normal.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_focused_normal.png rename to src/themes/styles/default/wm/maximize_focused_normal.png diff --git a/src/client/themes/styles/default/wm/maximize_focused_prelight.png b/src/themes/styles/default/wm/maximize_focused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_focused_prelight.png rename to src/themes/styles/default/wm/maximize_focused_prelight.png diff --git a/src/client/themes/styles/default/wm/maximize_focused_pressed.png b/src/themes/styles/default/wm/maximize_focused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_focused_pressed.png rename to src/themes/styles/default/wm/maximize_focused_pressed.png diff --git a/src/client/themes/styles/default/wm/maximize_unfocused.png b/src/themes/styles/default/wm/maximize_unfocused.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_unfocused.png rename to src/themes/styles/default/wm/maximize_unfocused.png diff --git a/src/client/themes/styles/default/wm/maximize_unfocused_prelight.png b/src/themes/styles/default/wm/maximize_unfocused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_unfocused_prelight.png rename to src/themes/styles/default/wm/maximize_unfocused_prelight.png diff --git a/src/client/themes/styles/default/wm/maximize_unfocused_pressed.png b/src/themes/styles/default/wm/maximize_unfocused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/maximize_unfocused_pressed.png rename to src/themes/styles/default/wm/maximize_unfocused_pressed.png diff --git a/src/client/themes/styles/default/wm/minimize.png b/src/themes/styles/default/wm/minimize.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize.png rename to src/themes/styles/default/wm/minimize.png diff --git a/src/client/themes/styles/default/wm/minimize_focused_normal.png b/src/themes/styles/default/wm/minimize_focused_normal.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_focused_normal.png rename to src/themes/styles/default/wm/minimize_focused_normal.png diff --git a/src/client/themes/styles/default/wm/minimize_focused_prelight.png b/src/themes/styles/default/wm/minimize_focused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_focused_prelight.png rename to src/themes/styles/default/wm/minimize_focused_prelight.png diff --git a/src/client/themes/styles/default/wm/minimize_focused_pressed.png b/src/themes/styles/default/wm/minimize_focused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_focused_pressed.png rename to src/themes/styles/default/wm/minimize_focused_pressed.png diff --git a/src/client/themes/styles/default/wm/minimize_unfocused.png b/src/themes/styles/default/wm/minimize_unfocused.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_unfocused.png rename to src/themes/styles/default/wm/minimize_unfocused.png diff --git a/src/client/themes/styles/default/wm/minimize_unfocused_prelight.png b/src/themes/styles/default/wm/minimize_unfocused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_unfocused_prelight.png rename to src/themes/styles/default/wm/minimize_unfocused_prelight.png diff --git a/src/client/themes/styles/default/wm/minimize_unfocused_pressed.png b/src/themes/styles/default/wm/minimize_unfocused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/minimize_unfocused_pressed.png rename to src/themes/styles/default/wm/minimize_unfocused_pressed.png diff --git a/src/client/themes/styles/default/wm/unmaximize.png b/src/themes/styles/default/wm/unmaximize.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize.png rename to src/themes/styles/default/wm/unmaximize.png diff --git a/src/client/themes/styles/default/wm/unmaximize_focused_normal.png b/src/themes/styles/default/wm/unmaximize_focused_normal.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_focused_normal.png rename to src/themes/styles/default/wm/unmaximize_focused_normal.png diff --git a/src/client/themes/styles/default/wm/unmaximize_focused_prelight.png b/src/themes/styles/default/wm/unmaximize_focused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_focused_prelight.png rename to src/themes/styles/default/wm/unmaximize_focused_prelight.png diff --git a/src/client/themes/styles/default/wm/unmaximize_focused_pressed.png b/src/themes/styles/default/wm/unmaximize_focused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_focused_pressed.png rename to src/themes/styles/default/wm/unmaximize_focused_pressed.png diff --git a/src/client/themes/styles/default/wm/unmaximize_unfocused.png b/src/themes/styles/default/wm/unmaximize_unfocused.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_unfocused.png rename to src/themes/styles/default/wm/unmaximize_unfocused.png diff --git a/src/client/themes/styles/default/wm/unmaximize_unfocused_prelight.png b/src/themes/styles/default/wm/unmaximize_unfocused_prelight.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_unfocused_prelight.png rename to src/themes/styles/default/wm/unmaximize_unfocused_prelight.png diff --git a/src/client/themes/styles/default/wm/unmaximize_unfocused_pressed.png b/src/themes/styles/default/wm/unmaximize_unfocused_pressed.png similarity index 100% rename from src/client/themes/styles/default/wm/unmaximize_unfocused_pressed.png rename to src/themes/styles/default/wm/unmaximize_unfocused_pressed.png diff --git a/src/client/themes/styles/default/wm/wm.png b/src/themes/styles/default/wm/wm.png similarity index 100% rename from src/client/themes/styles/default/wm/wm.png rename to src/themes/styles/default/wm/wm.png diff --git a/src/client/themes/styles/default/wm/wm/wm.png b/src/themes/styles/default/wm/wm/wm.png similarity index 100% rename from src/client/themes/styles/default/wm/wm/wm.png rename to src/themes/styles/default/wm/wm/wm.png diff --git a/src/client/themes/styles/glass/gui/progressbar.png b/src/themes/styles/glass/gui/progressbar.png similarity index 100% rename from src/client/themes/styles/glass/gui/progressbar.png rename to src/themes/styles/glass/gui/progressbar.png diff --git a/src/client/themes/styles/glass/metadata.json b/src/themes/styles/glass/metadata.json similarity index 100% rename from src/client/themes/styles/glass/metadata.json rename to src/themes/styles/glass/metadata.json diff --git a/src/themes/styles/glass/style.less b/src/themes/styles/glass/style.less new file mode 100644 index 0000000000..324e8e2b5e --- /dev/null +++ b/src/themes/styles/glass/style.less @@ -0,0 +1,70 @@ +@import 'animations.less'; + +body[data-style-theme="glass"] { + @import 'theme.less'; + + @base_background_color : #fefefe; + @base_foreground_color : #656565; + @gui_border_color : #c3c3c3; + @gui_selected_background_color : rgb(51, 165, 80); + @gui_selected_blur_background_color : rgba(51, 165, 80, .8); + + @gui_input_border_color : #c3c3c3; + + @window_top_height : 3em; + @window_border_size : .4em; + + @gui_progress_bar_background : @gui_selected_background_color url('./gui/progressbar.png') repeat-x center; + + + .application-window-button-entry { + width : 20px; + } + application-window-top { + height : 2.6em; + line-height : 2.6em; + } + application-window-title { + line-height : 2.6em; + } + + application-window-content { + background : @base_background_color; + } + + application-window:before { + opacity : .7; + border : 1px solid @base_background_color; + } + + /* Max */ + application-window-button-maximize, + application-window-button-maximize:hover, + application-window-button-maximize:active, + application-window[data-focused="true"] application-window-button-maximize, + application-window[data-focused="true"] application-window-button-maximize:hover, + application-window[data-focused="true"] application-window-button-maximize:active { + background : url('wm/maximize.png') no-repeat center center; + } + + /* Min */ + application-window-button-minimize, + application-window-button-minimize:hover, + application-window-button-minimize:active, + application-window[data-focused="true"] application-window-button-minimize, + application-window[data-focused="true"] application-window-button-minimize:hover, + application-window[data-focused="true"] application-window-button-minimize:active { + background : url('wm/minimize.png') no-repeat center 70%; + } + + /* Close */ + application-window-button-close, + application-window-button-close:hover, + application-window-button-close:active, + application-window[data-focused="true"] application-window-button-close, + application-window[data-focused="true"] application-window-button-close:hover, + application-window[data-focused="true"] application-window-button-close:active { + background : url('wm/close.png') no-repeat center center; + } + +} diff --git a/src/themes/styles/glass/theme.js b/src/themes/styles/glass/theme.js new file mode 100644 index 0000000000..c3945d30f3 --- /dev/null +++ b/src/themes/styles/glass/theme.js @@ -0,0 +1,9 @@ +(function() { + window.OSjs = window.OSjs || {}; + OSjs.Themes = window.OSjs.Themes || {}; + OSjs.Themes.glass = { + init: function() {}, + destroy: function() {}, + event: function() {} + }; +})(); diff --git a/src/client/themes/styles/glass/wm/close.png b/src/themes/styles/glass/wm/close.png similarity index 100% rename from src/client/themes/styles/glass/wm/close.png rename to src/themes/styles/glass/wm/close.png diff --git a/src/client/themes/styles/glass/wm/maximize.png b/src/themes/styles/glass/wm/maximize.png similarity index 100% rename from src/client/themes/styles/glass/wm/maximize.png rename to src/themes/styles/glass/wm/maximize.png diff --git a/src/client/themes/styles/glass/wm/minimize.png b/src/themes/styles/glass/wm/minimize.png similarity index 100% rename from src/client/themes/styles/glass/wm/minimize.png rename to src/themes/styles/glass/wm/minimize.png diff --git a/src/client/themes/styles/glass/wm/wm.png b/src/themes/styles/glass/wm/wm.png similarity index 100% rename from src/client/themes/styles/glass/wm/wm.png rename to src/themes/styles/glass/wm/wm.png diff --git a/src/client/themes/styles/material/materialColors.less b/src/themes/styles/material/materialColors.less similarity index 100% rename from src/client/themes/styles/material/materialColors.less rename to src/themes/styles/material/materialColors.less diff --git a/src/client/themes/styles/material/metadata.json b/src/themes/styles/material/metadata.json similarity index 100% rename from src/client/themes/styles/material/metadata.json rename to src/themes/styles/material/metadata.json diff --git a/src/themes/styles/material/style.less b/src/themes/styles/material/style.less new file mode 100644 index 0000000000..597a046350 --- /dev/null +++ b/src/themes/styles/material/style.less @@ -0,0 +1,370 @@ +@import 'animations.less'; + +/* +* Material Theme +*/ + + +body[data-style-theme="material"] { + @import 'theme.less'; + @fadedWhite: rgba(255, 255, 255, 0.7); + + @import './materialColors.less'; + + @base_background_color : @clr-blue-700; + @base_foreground_color : #242424; + @base_shadow_unfocused : 0px 0px 10px 1px rgba(0, 0, 0, .3); + @base_shadow_focused : 0px 0px 10px 1px rgba(0, 0, 0, .6); + + @scrollbar_button_background : #cdcdcd; + @scrollbar_button_foreground : #f0f0f0; + @scrollbar_track_background : #f0f0f0; + + @window_top_height : 2.833em; + @window_border_size : 0; + + @menu_background_color : #fff; + + @gui_selected_background_color : rgb(45, 115, 210); + @gui_selected_blur_background_color : rgba(45, 115, 210, .8); + @gui_selected_foreground_color : #ffffff; + + @gui_border_color : #dbdbdb; + @gui_background_color : #f5f6f8; + + @gui_input_border_color : #dbdbdb; + @gui_input_background_color : #ffffff; + @gui_input_foreground_color : @base_foreground_color; + + @gui_input_disabled_border_color : #d9d9d9; + @gui_input_disabled_background_color : #e6e6e6; + @gui_input_disabled_foreground_color : #727272; + + @gui_button_border_color : #ababab; + @gui_button_background_color : #f8f8f8; + @gui_button_foreground_color : @base_foreground_color; + @gui_button_background : linear-gradient(to bottom, #f1f1f1 0%, #e5e5e5 100%); + + @gui_button_active_border_color : #242424; + @gui_button_active_background_color : @gui_button_background_color; + @gui_button_active_foreground_color : @base_foreground_color; + @gui_button_active_background : linear-gradient(to bottom, #f8f8f8 0%, #f4f4f4 100%); + + @gui_button_disabled_border_color : @gui_input_disabled_border_color; + @gui_button_disabled_background_color: @gui_input_disabled_background_color; + @gui_button_disabled_foreground_color: @base_foreground_color; + @gui_button_disabled_background : @gui_input_disabled_background_color; + + gui-progress-bar{ + > div { + background: #fff; + } + > span { + color: #000; + } + } + application-window{ + &:before { + background: @clr-blue-700; + } + application-window-content { + background: #fff; + padding-top: 0; + + &[data-focused="false"] { + border: 1px solid @clr-blue-500; + } + &[data-focused="true"] { + border: 1px solid #dadada; + } + gui-menu-bar { + background: @clr-blue-600; + color: #fff; + + gui-menu-bar-entry{ + padding: .666em .5em; + } + gui-menu-bar-entry:hover, + .gui-active { + background: @clr-blue-700; + } + gui-menu { + min-width: 100px; + background: @clr-blue-600; + + gui-menu-entry{ + &:hover { + background-color: @clr-blue-700; + } + > * { + color: #fff; + } + label{ + padding: .5em; + } + &[data-disabled="true"] > * { + color: rgba(255, 255, 255, 0.5) !important; + } + } + } + } + } + application-window-top{ + application-window-icon { + width: 30px; + } + application-window-title { + font-size: 1.2em; + font-weight: 300; + color: rgba(255, 255, 255, 0.9); + } + + .application-window-button-entry { + height: 100%; + width: 30px; + line-height: 20px; + text-align: center; + font-family: Arial; + font-size: .833em; + z-index: 0; + + &:hover { + background-color: rgba(255, 255, 255, 0.2); + } + &:after, + &:before { + z-index: 1; + content: ''; + position: absolute; + top: 50%; + left: 50%; + } + } + application-window-button-close:before, + application-window-button-close:after { + width: 15px; + height: 2px; + background-color: @fadedWhite; + transition: background-color 0.2s; + } + application-window-button-close{ + &:before { + transform: translate(-50%, -50%) rotate(45deg); + } + &:after { + transform: translate(-50%, -50%) rotate(-45deg); + } + &:hover{ + &:after, + &:before { + background-color: #fff; + } + } + } + application-window-button-maximize{ + &:before, + &:after { + width: 11px; + height: 9px; + background: @clr-blue-700; + border: 1px solid @fadedWhite; + border-top-width: 2px; + transform: translate(-50%, -50%); + transition: border-color 0.2s; + } + &:before{ + opacity: 0; + margin: -3px 0 0 3px; + transition: margin 0.3s, opacity 0.3s; + } + &:hover{ + &:before, + &:after{ + border-color: #fff; + background: #468FD8; + } + } + } + application-window-button-minimize{ + &:after { + width: 11px; + height: 9px; + border-bottom: 2px solid @fadedWhite; + transform: translate(-50%, -50%); + transition: border-color 0.2s; + } + &:hover:after{ + border-color: #fff; + } + } + } + &[data-maximized="true"]{ + application-window-button-maximize:before{ + opacity: 1; + } + } + } + application-splash{ + > span { + color: #fff; + } + } + gui-menu { + background: @clr-blue-500; + + gui-menu-entry { + &:after{ + color: #fff; + } + > div, + > label { + color: #fff; + } + &:hover { + background-color: @clr-blue-700; + } + } + } + gui-tabs > ul { + height : 2.666em; + } + gui-tabs > ul > li { + padding: 0.25em .5em; + } + gui-tabs .gui-active:after { + border: 1px solid @clr-pink-500 !important; + } + gui-list-view gui-list-view-row.gui-active { + background-color: @clr-blue-700 !important; + } + gui-icon-view-entry.gui-active { + background-color: @clr-blue-700 !important; + > div > span { + background: rgba(0, 0, 0, 0) !important; + } + } + gui-switch > div { + width : 5.333em; + } + gui-switch button.gui-active { + margin-left: calc(50% - 1px); + } + + gui-select, + gui-password, + gui-text { + height: 3em; + } + + gui-input-modal, + gui-switch, + gui-button { + height: 3em; + + button { + position: relative; + font-size: 1.333em; + padding: 0.416em 1.333em; + color: rgba(0, 0, 0, 0.9); + border-radius: 3px; + border: 0; + background: #fff; + overflow: hidden; + outline: 0 !important; + text-decoration: none !important; + cursor: pointer; + transition: background 0.3s; + + img{ + pointer-events: none; + } + .drop{ + background: rgba(0, 0, 0, 0.16); + } + &[disabled="disabled"]{ + background: #fff; + color: rgba(0, 0, 0, 0.26); + &:active { + color: rgba(0, 0, 0, 0.26); + } + } + &:hover { + background: rgba(153, 153, 153, 0.1); + } + &:active { + background: rgba(153, 153, 153, 0.2); + } + } + } + + gui-tabs > div { + height : ~"calc(100% - 32px)"; + } + + gui-select:after { + top : 10px; + } + + corewm-notification-entry:before { + background: @clr-blue-700 !important; + } + corewm-panel{ + &:before { + background: @clr-blue-700 !important; + } + .PanelItemWindowList li { + opacity: 1 !important; + + span { + color: @fadedWhite; + } + img { + opacity: 0.7; + } + &.Focused { + span { + color: #fff; + } + img { + opacity: 1; + } + } + } + } + + .drop { + display: block; + position: absolute; + background: #CCC; + border-radius: 100%; + transform: scale(0); + pointer-events: none; + width: 100%; + height: 100%; + + &.animate { + animation: drop 1s ease-out; + } + } + + @keyframes drop { + 100% { + opacity: 0; + transform: scale(2.5); + } + } + a{ + color: rgba(0, 0, 0, 0.9); + padding: 5px; + } + application-window-loading{ + background: rgba(0, 0, 0, 0); + } + + /* Application styles */ + .ApplicationCalculatorWindow{ + button{ + padding: 0; + } + } +} diff --git a/src/themes/styles/material/theme.js b/src/themes/styles/material/theme.js new file mode 100644 index 0000000000..37c1cef98d --- /dev/null +++ b/src/themes/styles/material/theme.js @@ -0,0 +1,38 @@ +(function() { + window.OSjs = window.OSjs || {}; + OSjs.Themes = window.OSjs.Themes || {}; + OSjs.Themes.material = { + init: function() {}, + destroy: function() {}, + event: function(e) { + if ( e.target && e.target.nodeName.toLowerCase() === 'button' ) { + var parent = e.target; + if ( parseFloat(window.getComputedStyle(parent).getPropertyValue('opacity')) > 0 ) { + var drop; + var maxWidthHeight = Math.max(parent.clientWidth, parent.clientHeight); + var drops = Array.prototype.slice.call(parent.childNodes).filter(function(e) { + return (e.className === 'drop animate'); + }); + var freeDrops = drops.slice().filter(function(e) { + // .drop opacity is 1 when it's hidden... css animations + return parseFloat(window.getComputedStyle(e).getPropertyValue('opacity')) === 1; + }); + if ( drops.length === 0 || freeDrops.length === 0 ) { + drop = document.createElement('b'); + drop.className = 'drop'; + drop.style.width = maxWidthHeight + 'px'; + drop.style.height = maxWidthHeight + 'px'; + drop = parent.appendChild(drop); + } else { + drop = freeDrops[0]; + drop.className = 'drop'; + } + var rect = parent.getBoundingClientRect(); + drop.style.top = (e.pageY - rect.top - maxWidthHeight / 2) + 'px'; + drop.style.left = (e.pageX - rect.left - maxWidthHeight / 2) + 'px'; + drop.className = 'drop animate'; + } + } + } + }; +})(); diff --git a/src/client/themes/styles/windows8/metadata.json b/src/themes/styles/windows8/metadata.json similarity index 100% rename from src/client/themes/styles/windows8/metadata.json rename to src/themes/styles/windows8/metadata.json diff --git a/src/themes/styles/windows8/style.less b/src/themes/styles/windows8/style.less new file mode 100644 index 0000000000..62caf49ecb --- /dev/null +++ b/src/themes/styles/windows8/style.less @@ -0,0 +1,113 @@ +@import 'animations.less'; + +/** + * Windows 8 Theme + */ + +body[data-style-theme="windows8"] { + @import 'theme.less'; + + @base_background_color : #6dabf4; + @base_foreground_color : #242424; + @base_shadow_unfocused : 0px 0px 10px 1px rgba(0, 0, 0, .3); + @base_shadow_focused : 0px 0px 10px 1px rgba(0, 0, 0, .6); + + @scrollbar_button_background : #cdcdcd; + @scrollbar_button_foreground : #f0f0f0; + @scrollbar_track_background : #f0f0f0; + + @window_top_height : 2.5em; + @window_border_size : 0.41666em; + + @menu_background_color : #fff; + + @gui_selected_background_color : rgb(45, 115, 210); + @gui_selected_blur_background_color : rgba(45, 115, 210, .8); + @gui_selected_foreground_color : #ffffff; + + @gui_border_color : #dbdbdb; + @gui_background_color : #f5f6f8; + + @gui_input_border_color : #dbdbdb; + @gui_input_background_color : #ffffff; + @gui_input_foreground_color : @base_foreground_color; + + @gui_input_disabled_border_color : #d9d9d9; + @gui_input_disabled_background_color : #e6e6e6; + @gui_input_disabled_foreground_color : #727272; + + @gui_button_border_color : #ababab; + @gui_button_background_color : #f8f8f8; + @gui_button_foreground_color : @base_foreground_color; + @gui_button_background : linear-gradient(to bottom, #f1f1f1 0%, #e5e5e5 100%); + + @gui_button_active_border_color : #242424; + @gui_button_active_background_color : @gui_button_background_color; + @gui_button_active_foreground_color : @base_foreground_color; + @gui_button_active_background : linear-gradient(to bottom, #f8f8f8 0%, #f4f4f4 100%); + + @gui_button_disabled_border_color : @gui_input_disabled_border_color; + @gui_button_disabled_background_color: @gui_input_disabled_background_color; + @gui_button_disabled_foreground_color: @base_foreground_color; + @gui_button_disabled_background : @gui_input_disabled_background_color; + gui-tabs > ul > li.gui-active:after { + border-bottom: 1px solid #fff; + } + gui-progress-bar > div { + background: #6dabf4; + } + + application-window-top { + height : 2.08333em; + } + application-window-title { + line-height : 2.08333em; + } + + application-window[data-focused="false"]:before { + background : #ebebeb; + border : 1px solid #d3d3d3; + } + application-window[data-focused="true"]:before { + background : @base_background_color; + border : 1px solid #5185be; + } + application-window-content { + background : #ffffff; + padding-top : 0.1666em; + } + application-window-content[data-focused="false"] { + border : 1px solid #5d93d1; + } + application-window-content[data-focused="true"] { + border : 1px solid #dadada; + } + + .application-window-button-entry { + width : 2.1666em; + line-height : 1.666em; + text-align : center; + font-family : Arial; + font-size : .8333em; + margin-top : -0.5em; + } + application-window-button-maximize { + background : url('wm/maximize.png') no-repeat center center; + } + application-window-button-minimize { + background : url('wm/minimize.png') no-repeat center center; + } + application-window-button-close { + background : #c74f51 url('wm/close.png') no-repeat 49% center; + } + application-window-button-maximize:hover, + application-window-button-minimize:hover { + background-color : #5185be; + } + application-window-button-close:hover { + background-color : #de1e19; + } + application-window-button-close { + width : 45px !important; + } +} diff --git a/src/themes/styles/windows8/theme.js b/src/themes/styles/windows8/theme.js new file mode 100644 index 0000000000..9b7615d59d --- /dev/null +++ b/src/themes/styles/windows8/theme.js @@ -0,0 +1,9 @@ +(function() { + window.OSjs = window.OSjs || {}; + OSjs.Themes = window.OSjs.Themes || {}; + OSjs.Themes.windows8 = { + init: function() {}, + destroy: function() {}, + event: function() {} + }; +})(); diff --git a/src/client/themes/styles/windows8/wm/close.png b/src/themes/styles/windows8/wm/close.png similarity index 100% rename from src/client/themes/styles/windows8/wm/close.png rename to src/themes/styles/windows8/wm/close.png diff --git a/src/client/themes/styles/windows8/wm/maximize.png b/src/themes/styles/windows8/wm/maximize.png similarity index 100% rename from src/client/themes/styles/windows8/wm/maximize.png rename to src/themes/styles/windows8/wm/maximize.png diff --git a/src/client/themes/styles/windows8/wm/minimize.png b/src/themes/styles/windows8/wm/minimize.png similarity index 100% rename from src/client/themes/styles/windows8/wm/minimize.png rename to src/themes/styles/windows8/wm/minimize.png diff --git a/src/client/themes/styles/windows8/wm/wm.png b/src/themes/styles/windows8/wm/wm.png similarity index 100% rename from src/client/themes/styles/windows8/wm/wm.png rename to src/themes/styles/windows8/wm/wm.png diff --git a/src/client/themes/wallpapers/wallpaper.png b/src/themes/wallpapers/wallpaper.png similarity index 100% rename from src/client/themes/wallpapers/wallpaper.png rename to src/themes/wallpapers/wallpaper.png diff --git a/src/themes/webpack.config.js b/src/themes/webpack.config.js new file mode 100644 index 0000000000..c40ed4e3f9 --- /dev/null +++ b/src/themes/webpack.config.js @@ -0,0 +1,8 @@ +const osjs = require('osjs-build'); + +module.exports = new Promise((resolve, reject) => { + osjs.webpack.createThemeConfiguration().then((result) => { + resolve(result.config); + }).catch(reject); +}); + diff --git a/src/x11-launcher/Makefile b/src/x11-launcher/Makefile deleted file mode 100644 index 54b4aed690..0000000000 --- a/src/x11-launcher/Makefile +++ /dev/null @@ -1,55 +0,0 @@ -# -# OS.js - JavaScript Cloud/Web Desktop Platform -# -# Copyright (c) 2011-2017, Anders Evenrud -# 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 -# @licence Simplified BSD License -# - -# -# This is the X11 launcher build script for OS.js -# - -CC = gcc -LCFLAGS = -I. -CFLAGS = $(shell pkg-config --cflags gtk+-3.0 webkitgtk-3.0 glib-2.0) -LIBS = $(shell pkg-config --libs gtk+-3.0 webkitgtk-3.0 glib-2.0) -LIBS += -lX11 -OUT = session-launch -SRC = main.c - -all: - $(CC) -Wall $(SRC) $(CFLAGS) $(LCFLAGS) -o $(OUT) $(LIBS) - -clean: - rm -f session-launch - rm -f *.o - rm -f Makefile.bak - -install: - cp -f session-launch /usr/local/bin/osjs-launcher - -uninstall: - rm -rm /usr/local/bin/osjs-launcher diff --git a/src/x11-launcher/main.c b/src/x11-launcher/main.c deleted file mode 100644 index 90b88f633d..0000000000 --- a/src/x11-launcher/main.c +++ /dev/null @@ -1,138 +0,0 @@ -/*! - * OS.js - JavaScript Cloud/Web Desktop Platform - * - * Copyright (c) 2011-2017, Anders Evenrud - * 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 - * @licence Simplified BSD License - */ - -// -// This is the X11 Launcher executable for OS.js -// - -#include -#include -#include -#include -#include -#include -#include - -/////////////////////////////////////////////////////////////////////////////// -// X11 -/////////////////////////////////////////////////////////////////////////////// - -#ifndef NOX11 -Display *d; - -void -initialize_x11() -{ - d = XOpenDisplay(NULL); - if (d == NULL) { - fprintf(stderr, "Cannot open display\n"); - exit(1); - } -} -#endif - -/////////////////////////////////////////////////////////////////////////////// -// CALLBACKS -/////////////////////////////////////////////////////////////////////////////// - -static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window) -{ - gtk_widget_destroy(window); - return TRUE; -} - - -/////////////////////////////////////////////////////////////////////////////// -// MAIN -/////////////////////////////////////////////////////////////////////////////// - -char *uri = "http://localhost:8000"; -GtkWidget *window; - -/** - * - * - */ -int main (int argc, gchar *argv[]) -{ -#ifndef NOX11 - initialize_x11(); -#endif - - - // Init GTK+ - if ( !g_thread_supported() ) - g_thread_init(NULL); - - gtk_init_check(&argc, &argv); - - GdkDisplay *display = gdk_display_get_default(); - GdkScreen *screen = gdk_display_get_screen(display, 0); - gint swidth = gdk_screen_get_width(screen); - gint sheight = gdk_screen_get_height(screen); - - // GtkWindow - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - g_signal_connect(GTK_WINDOW(window), "destroy", G_CALLBACK(gtk_main_quit), NULL); - - // WebKit - WebKitWebSettings *settings = webkit_web_settings_new (); - g_object_set (G_OBJECT(settings), "enable-scripts", TRUE, NULL); - g_object_set (G_OBJECT(settings), "enable-webgl", TRUE, NULL); - g_object_set (G_OBJECT(settings), "enable-fullscreen", TRUE, NULL); - g_object_set (G_OBJECT(settings), "enable-webaudio", TRUE, NULL); - g_object_set (G_OBJECT(settings), "enable-html5-local-storage", TRUE, NULL); - g_object_set (G_OBJECT(settings), "enable-html5-database", TRUE, NULL); - - WebKitWebView *web_view; - web_view = WEBKIT_WEB_VIEW(webkit_web_view_new ()); - webkit_web_view_set_settings(WEBKIT_WEB_VIEW(web_view), settings); - webkit_web_view_load_uri(WEBKIT_WEB_VIEW(web_view), uri); - - g_signal_connect(web_view, "close-web-view", G_CALLBACK(closeWebViewCb), GTK_CONTAINER(window)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(web_view)); - - // Fullscreen stuff - gtk_window_set_default_size(GTK_WINDOW(window), swidth, sheight); - gtk_window_move(GTK_WINDOW(window), 0, 0); - gtk_window_resize(GTK_WINDOW(window), swidth, sheight); - gtk_window_fullscreen(GTK_WINDOW(window)); - - // Run - gtk_widget_show_all(GTK_WIDGET(window)); - gtk_window_set_resizable(GTK_WINDOW(window), false); - gtk_main(); - -#ifndef NOX11 - XCloseDisplay(d); -#endif - - return 0; -}