diff --git a/.es5/.eslintrc b/.es5/.eslintrc deleted file mode 100644 index 672de656..00000000 --- a/.es5/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "env": { - "node": true, - "browser": true - }, - "parserOptions": { - "ecmaVersion": 5, - "sourceType": "module" - }, - "rules": { - "indent": ["error", 4], - "semi": "error" - }, - "extends": ["eslint:recommended"] -} diff --git a/.es5/.jshintrc b/.es5/.jshintrc deleted file mode 100644 index 90470891..00000000 --- a/.es5/.jshintrc +++ /dev/null @@ -1,19 +0,0 @@ -{ - "unused" : true, - "bitwise" : false, - "browser" : true, - "devel" : true, - "eqeqeq" : true, - "jquery" : false, - "newcap" : false, - "noarg" : true, - "node" : true, - "noempty" : true, - "nonew" : true, - "strict" : true, - "undef" : true, - "evil" : true, - "expr" : true, - "quotmark": "single", - "validthis": true -} diff --git a/.gitignore b/.gitignore index ae081cf2..ad83d7ab 100644 --- a/.gitignore +++ b/.gitignore @@ -12,8 +12,6 @@ modules/fancybox/lib/ modules/fancybox/demo modules/fancybox/sprite.psd -modules/currify/dist/currify.js - legacy server_ @@ -21,3 +19,6 @@ server_ *.swp +dist +dist-debug + diff --git a/.npmignore b/.npmignore index 0d915e6a..dd5f9ee1 100644 --- a/.npmignore +++ b/.npmignore @@ -13,8 +13,10 @@ circle.yml bin/release.js bin/legacy.js -.es5 +client legacy/bin/release.js legacy/bin/legacy.js +webpack.config.js + diff --git a/bower.json b/bower.json index 8ffa3b5e..57a65ab5 100644 --- a/bower.json +++ b/bower.json @@ -30,19 +30,13 @@ "dependencies": { "domtokenlist-shim": "~1.1.0", "fancybox": "~2.1.5", - "format-io": "~0.9.6", - "rendy": "~1.1.0", - "execon": "~1.2.8", "emitify": "~2.1.1", "findit": "^1.1.5", "menu": "~1.0.2", "olark": "^1.0.0", "philip": "^1.3.3", - "jonny": "1.0.1", "promise-polyfill": "6.0.2", "smalltalk": "2.1.3", - "jquery": "3.1.1", - "currify": "2.0.3", - "itype": "2.0.3" + "jquery": "3.1.1" } } diff --git a/client/client.js b/client/client.js index 73b76dad..bf39a0cd 100644 --- a/client/client.js +++ b/client/client.js @@ -1,577 +1,578 @@ -/* global itype */ -/* global rendy */ +'use strict'; -var Util, DOM, CloudFunc, join; +const itype = require('itype/legacy'); +const rendy = require('rendy'); -(function(scope, Util, DOM, CloudFunc) { - 'use strict'; +/* global Util, DOM, CloudFunc, join */ + +module.exports = new CloudCmdProto(Util, DOM, CloudFunc); + +function CloudCmdProto(Util, DOM, CloudFunc) { + let Key; + let Debug; + let Listeners; - scope.CloudCmd = new CloudCmdProto(Util, DOM, CloudFunc); + const log = (str) => { + if (!Debug) + return; + + console.log(str); + }; - function CloudCmdProto(Util, DOM, CloudFunc) { - var Key, - Debug, - log = function(str) { - if (Debug) - console.log(str); - }, - - TITLE, - Listeners, - Files = DOM.Files, - Images = DOM.Images, - Info = DOM.CurrentInfo, - CloudCmd = this, - Storage = DOM.Storage; + const CloudCmd = this; + const Images = DOM.Images; + const Info = DOM.CurrentInfo; + const Storage = DOM.Storage; + const Files = DOM.Files; + + this.log = log; + this.PREFIX = ''; + this.PREFIX_URL = ''; + this.DIRCLIENT = '/dist/'; + this.MIN_ONE_PANEL_WIDTH = 1155; + this.HOST = location.origin || + location.protocol + '//' + location.host; + + const TITLE = 'Cloud Commander'; + this.TITLE = TITLE; + + this.sort = { + left: 'name', + right: 'name', + }; + + this.order = { + left: 'asc', + right: 'asc', + }; + + log.enable = function() { + Debug = true; + }; + + log.disable = function() { + Debug = false; + }; + + var getStrBigFirst = Util.getStrBigFirst; + var kebabToCamelCase = Util.kebabToCamelCase; + + /** + * Функция привязываеться ко всем ссылкам и + * загружает содержимое каталогов + * + * @param params - { + * paramLink - ссылка + * needRefresh - необходимость обязательной загрузки данных с сервера + * panel + * } + * @param callback + */ + this.loadDir = function(params, callback) { + var imgPosition; + var panelChanged; + var p = params; - this.log = log; - this.PREFIX = ''; - this.PREFIX_URL = ''; - this.DIRCLIENT = '/client/'; - this.MIN_ONE_PANEL_WIDTH = 1155; - this.HOST = location.origin || - location.protocol + '//' + location.host; + var isRefresh = p.isRefresh; + var panel = p.panel; + var history = p.history; + var noCurrent = p.noCurrent; - this.TITLE = 'Cloud Commander'; - - this.sort = { - left: 'name', - right: 'name', - }; - - this.order = { - left: 'asc', - right: 'asc', - }; - - TITLE = this.TITLE; - - log.enable = function() { - Debug = true; - }; - - log.disable = function() { - Debug = false; - }; - - var getStrBigFirst = Util.getStrBigFirst; - var kebabToCamelCase = Util.kebabToCamelCase; - - /** - * Функция привязываеться ко всем ссылкам и - * загружает содержимое каталогов - * - * @param params - { - * paramLink - ссылка - * needRefresh - необходимость обязательной загрузки данных с сервера - * panel - * } - * @param callback - */ - this.loadDir = function(params, callback) { - var imgPosition; - var panelChanged; - var p = params; - - var isRefresh = p.isRefresh; - var panel = p.panel; - var history = p.history; - var noCurrent = p.noCurrent; - - if (!noCurrent) - if (panel && panel !== Info.panel) { - DOM.changePanel(); - panelChanged = true; - } - - if (panelChanged || isRefresh || !history) - imgPosition = 'top'; - - Images.show.load(imgPosition, panel); - - /* загружаем содержимое каталога */ - ajaxLoad(p.path, { - refresh: isRefresh, - history: history, - noCurrent: noCurrent - }, panel, callback); - }; - - /** - * function load modules - * @pParams = {name, path, func, dobefore, arg} - */ - function loadModule(params) { - var name, path, func, doBefore, - funcName, isContain; - - if (params) { - name = params.name, - path = params.path, - func = params.func, - funcName = params.funcName, - doBefore = params.dobefore; - - if (path && !name) - name = kebabToCamelCase(path); - - isContain = /\.js/.test(path); - - if (!isContain) - path += '.js'; - - if (!CloudCmd[name]) { - CloudCmd[name] = function() { - var prefix = CloudCmd.PREFIX, - pathFull = prefix + CloudCmd.DIRCLIENT + path, - args = arguments; - - Util.exec(doBefore); - - return DOM.load.js(pathFull, func || - function(error) { - var Proto = CloudCmd[name]; - - if (!error && itype.function(Proto)) - CloudCmd[name] = applyConstructor(Proto, args); - }); - }; - - CloudCmd[name][funcName] = CloudCmd[name]; - } + if (!noCurrent) + if (panel && panel !== Info.panel) { + DOM.changePanel(); + panelChanged = true; } - } - /* - * apply arguemnts to constructor - * - * @param constructor - * @param args - */ - function applyConstructor(constructor, args) { - var F = function () { - return constructor.apply(this, args); - }; - - F.prototype = constructor.prototype; - return new F(); - } + if (panelChanged || isRefresh || !history) + imgPosition = 'top'; - /** - * Конструктор CloudClient, который - * выполняет весь функционал по - * инициализации - */ - this.init = function(prefix, config) { - var func = function() { - Util.exec.series([ - initModules, - baseInit, - loadPlugins, - function() { - CloudCmd.route(location.hash); - } - ]); - }; - - var funcBefore = function(callback) { - var src = prefix + '/join:' + [ - CloudCmd.DIRCLIENT + 'polyfill.js', - '/modules/domtokenlist-shim/dist/domtokenlist.min.js', - ].join(':'); - - DOM.loadJquery(function() { - DOM.load.js(src, callback); - }); - }; - - CloudCmd.PREFIX = prefix; - CloudCmd.PREFIX_URL = prefix + CloudFunc.apiURL; - - CloudCmd.config = function(key) { - return config[key]; - }; - - CloudCmd._config = function(key, value) { - /* - * should be called from config.js only - * after successful update on server - */ - config[key] = value; - }; - - if (config.onePanelMode) - CloudCmd.MIN_ONE_PANEL_WIDTH = Infinity; - - DOM.Dialog = new DOM.Dialog(prefix, { - htmlDialogs: config.htmlDialogs - }); - - Util.exec.if(document.body.scrollIntoViewIfNeeded, func, funcBefore); - }; + Images.show.load(imgPosition, panel); - function loadPlugins(callback) { - var prefix = CloudCmd.PREFIX; - var plugins = prefix + '/plugins.js'; - - DOM.load.js(plugins, callback); - } + /* загружаем содержимое каталога */ + ajaxLoad(p.path, { + refresh: isRefresh, + history: history, + noCurrent: noCurrent + }, panel, callback); + }; + + /** + * function load modules + * @params = {name, path, func, dobefore, arg} + */ + function loadModule(params) { + var name, path, func, doBefore, + funcName, isContain; - this.join = function(urls) { - var prefix = CloudCmd.PREFIX; + if (params) { + name = params.name, + path = params.path, + func = params.func, + funcName = params.funcName, + doBefore = params.dobefore; - if (!Array.isArray(urls)) - throw Error('urls should be array!'); + if (path && !name) + name = kebabToCamelCase(path); - var noPrefixUrls = urls.map(function(url) { - return url.replace(prefix, ''); - }); + isContain = /\.js/.test(path); - return prefix + join(noPrefixUrls); - }; - - this.route = function(path) { - var module, file, current, msg, - query = path.split('/'); + if (!isContain) + path += '.js'; - if (path) { - module = query[0]; - module = module.slice(1); - module = getStrBigFirst(module); - - file = query[1]; - current = DOM.getCurrentByName(file); - - if (file && !current) { - msg = CloudFunc.formatMsg('set current file', file, 'error'); - CloudCmd.log(msg); - } else { - DOM.setCurrentFile(current); - CloudCmd.execFromModule(module, 'show'); - } - } - }; - - this.logOut = function() { - DOM.load.ajax({ - url: CloudCmd.PREFIX + '/logout', - error: function() { - document.location.reload(); - } - }); - }; - - function initModules(callback) { - Util.exec.if(CloudCmd.Key, function() { - Key = new CloudCmd.Key(); - CloudCmd.Key = Key; - Key.bind(); - }, function(callback) { - loadModule({ - /* привязываем клавиши к функциям */ - path : 'key.js', - func : callback - }); - }); - - Files.get('modules', function(error, modules) { - var storageObj, mod, path, - STORAGE = 'storage', - showLoad = Images.show.load, + if (!CloudCmd[name]) { + CloudCmd[name] = (...args) => { + const prefix = CloudCmd.PREFIX; + const pathFull = prefix + CloudCmd.DIRCLIENT + path; - doBefore = { - 'edit' : showLoad, - 'menu' : showLoad, - 'storage/_filepicker' : showLoad - }, + Util.exec(doBefore); - load = function(name, path, func) { - var isTmpl = path === 'template'; - - loadModule({ - name : name, - funcName : isTmpl ? 'get' : 'show', - path : path, - dobefore : func + return DOM.load.js(pathFull, func || + function(error) { + var Proto = CloudCmd[name]; + + if (!error && itype.function(Proto)) + CloudCmd[name] = applyConstructor(Proto, args); }); - }; + }; - if (!modules) - modules = []; - - modules.forEach(function(module) { - var isStr = itype.string(module); - - if (isStr) - load(null, module, doBefore[module]); - }); - - storageObj = Util.findObjByNameInArr(modules, STORAGE); - mod = Util.getNamesFromObjArray(storageObj); - - mod.forEach(function(name) { - path = STORAGE + '/_' + name.toLowerCase(); - - load(name, path, doBefore[path]); - }); - - callback(); + CloudCmd[name][funcName] = CloudCmd[name]; + } + } + } + + /* + * apply arguemnts to constructor + * + * @param constructor + * @param args + */ + function applyConstructor(constructor, args) { + var F = function () { + return constructor.apply(this, args); + }; + + F.prototype = constructor.prototype; + return new F(); + } + + /** + * Конструктор CloudClient, который + * выполняет весь функционал по + * инициализации + */ + this.init = (prefix, config) => { + const func = () => { + Util.exec.series([ + initModules, + baseInit, + loadPlugins, + () => { + CloudCmd.route(location.hash); + } + ]); + }; + + const funcBefore = (callback) => { + const src = prefix + '/join:' + [ + CloudCmd.DIRCLIENT + 'polyfill.js', + '/modules/domtokenlist-shim/dist/domtokenlist.min.js', + ].join(':'); + + DOM.loadJquery(() => { + DOM.load.js(src, callback); }); + }; + + CloudCmd.PREFIX = prefix; + CloudCmd.PREFIX_URL = prefix + CloudFunc.apiURL; + + CloudCmd.config = (key) => config[key]; + CloudCmd._config = (key, value) => { + /* + * should be called from config.js only + * after successful update on server + */ + config[key] = value; + }; + + if (config.onePanelMode) + CloudCmd.MIN_ONE_PANEL_WIDTH = Infinity; + + const {htmlDialogs} = config; + + DOM.Dialog = new DOM.Dialog(prefix, { + htmlDialogs + }); + + Util.exec.if(document.body.scrollIntoViewIfNeeded, func, funcBefore); + }; + + function loadPlugins(callback) { + const prefix = CloudCmd.PREFIX; + const plugins = prefix + '/plugins.js'; + + DOM.load.js(plugins, callback); + } + + this.join = (urls) => { + const prefix = CloudCmd.PREFIX; + + if (!Array.isArray(urls)) + throw Error('urls should be array!'); + + const noPrefixUrls = urls.map((url) => { + return url.replace(prefix, ''); + }); + + return prefix + join(noPrefixUrls); + }; + + this.route = (path) => { + const query = path.split('/'); + + if (!path) + return; + + let [module] = query; + + module = module.slice(1); + module = getStrBigFirst(module); + + const file = query[1]; + const current = DOM.getCurrentByName(file); + + if (file && !current) { + const msg = CloudFunc.formatMsg('set current file', file, 'error'); + CloudCmd.log(msg); + return; } - function baseInit(callback) { - var dirPath = '', - files = DOM.getFiles(); - - /* выделяем строку с первым файлом */ - if (files) - DOM.setCurrentFile(files[0], { - // when hash is present - // it should be handled with this.route - // overwre otherwise - history: !location.hash + DOM.setCurrentFile(current); + CloudCmd.execFromModule(module, 'show'); + }; + + this.logOut = () => { + const url = CloudCmd.PREFIX + '/logout'; + const error = () => document.location.reload(); + + DOM.load.ajax({url, error}); + }; + + function initModules(callback) { + Util.exec.if(CloudCmd.Key, () => { + Key = new CloudCmd.Key(); + CloudCmd.Key = Key; + Key.bind(); + }, (func) => { + /* привязываем клавиши к функциям */ + const path = 'key.js'; + + loadModule({ + path, + func + }); + }); + + Files.get('modules', (error, modules) => { + const STORAGE = 'storage'; + const showLoad = Images.show.load; + + const doBefore = { + 'edit' : showLoad, + 'menu' : showLoad, + 'storage/_filepicker' : showLoad + }; + + const load = (name, path, dobefore) => { + const isTmpl = path === 'template'; + const funcName = isTmpl ? 'get' : 'show'; + + loadModule({ + name, + path, + dobefore, + funcName, }); + }; - dirPath = DOM.getCurrentDirPath(), - Listeners = CloudCmd.Listeners; - Listeners.init(); + if (!modules) + modules = []; - Listeners.setOnPanel('left'); - Listeners.setOnPanel('right'); + modules.forEach((module) => { + const isStr = itype.string(module); + + if (!isStr) + return; + + load(null, module, doBefore[module]); + }); - Listeners.initKeysPanel(); + const storageObj = Util.findObjByNameInArr(modules, STORAGE); + const mod = Util.getNamesFromObjArray(storageObj); - Storage.get(dirPath, function(error, data) { - if (!data) { - data = getJSONfromFileTable(); - Storage.set(dirPath, data); - } + mod.forEach((name) => { + const path = STORAGE + '/_' + name.toLowerCase(); + + load(name, path, doBefore[path]); }); callback(); + }); + } + + function baseInit(callback) { + var dirPath = '', + files = DOM.getFiles(); + + /* выделяем строку с первым файлом */ + if (files) + DOM.setCurrentFile(files[0], { + // when hash is present + // it should be handled with this.route + // overwre otherwise + history: !location.hash + }); + + dirPath = DOM.getCurrentDirPath(), + Listeners = CloudCmd.Listeners; + Listeners.init(); + + Listeners.setOnPanel('left'); + Listeners.setOnPanel('right'); + + Listeners.initKeysPanel(); + + Storage.get(dirPath, function(error, data) { + if (!data) { + data = getJSONfromFileTable(); + Storage.set(dirPath, data); + } + }); + + callback(); + } + + this.execFromModule = function(moduleName, funcName) { + var args = [].slice.call(arguments, 2), + obj = CloudCmd[moduleName], + isObj = itype.object(obj); + + Util.exec.if(isObj, + function() { + var obj = CloudCmd[moduleName], + func = obj[funcName]; + + func.apply(null, args); + }, obj); + }; + + this.refresh = function(panelParam, options, callback) { + var panel = panelParam || Info.panel; + var NEEDREFRESH = true; + var path = DOM.getCurrentDirPath(panel); + var noCurrent; + + if (options) + noCurrent = options.noCurrent; + + if (!callback && typeof options === 'function') { + callback = options; + options = {}; } - this.execFromModule = function(moduleName, funcName) { - var args = [].slice.call(arguments, 2), - obj = CloudCmd[moduleName], - isObj = itype.object(obj); + CloudCmd.loadDir({ + path : path, + isRefresh : NEEDREFRESH, + history : false, + panel : panel, + noCurrent : noCurrent + }, callback); + }; + + /** + * Функция загружает json-данные о Файловой Системе + * через ajax-запрос. + * @param path - каталог для чтения + * @param options + * { refresh, history } - необходимость обновить данные о каталоге + * @param panel + * @param callback + * + */ + function ajaxLoad(path, options, panel, callback) { + var create = function(error, json) { + var RESTful = DOM.RESTful, + name = Info.name, + obj = Util.json.parse(json), + isRefresh = options.refresh, + noCurrent = options.noCurrent; - Util.exec.if(isObj, - function() { - var obj = CloudCmd[moduleName], - func = obj[funcName]; + if (!isRefresh && json) + return createFileTable(obj, panel, options, callback); + + var position = DOM.getPanelPosition(panel); + var sort = CloudCmd.sort[position]; + var order = CloudCmd.order[position]; + + var query = rendy('?sort={{ sort }}&order={{ order }}', { + sort: sort, + order: order, + }); + + RESTful.read(path + query, 'json', function(error, obj) { + if (error) + return; + + Storage.set(path, obj); + + options.sort = sort; + options.order = order; + + createFileTable(obj, panel, options, function() { + if (isRefresh && !noCurrent) { + DOM.setCurrentByName(name); + } - func.apply(null, args); - }, obj); + Util.exec(callback); + }); + }); }; - this.refresh = function(panelParam, options, callback) { - var panel = panelParam || Info.panel; - var NEEDREFRESH = true; - var path = DOM.getCurrentDirPath(panel); - var noCurrent; + if (!options) + options = {}; + + CloudCmd.log('reading dir: "' + path + '";'); + + var dirStorage = CloudCmd.config(dirStorage); + + if (!dirStorage) + return create(); + + Storage.get(path, create); + } + + /** + * Функция строит файловую таблицу + * @param json - данные о файлах + * @param panelParam + * @param history + * @param callback + */ + function createFileTable(json, panelParam, options, callback) { + var history = options.history, + noCurrent = options.noCurrent, + names = ['file', 'path', 'link', 'pathLink']; + + Files.get(names, function(error, templFile, templPath, templLink, templPathLink) { + var childNodes, i, + Dialog = DOM.Dialog, + current, + panel = panelParam || DOM.getPanel(), + + dir = Info.dir, + name = Info.name; - if (options) - noCurrent = options.noCurrent; + if (error) + return Dialog.alert(TITLE, error.responseText); + + childNodes = panel.childNodes; + i = childNodes.length; - if (!callback && typeof options === 'function') { - callback = options; - options = {}; + while (i--) + panel.removeChild(panel.lastChild); + + panel.innerHTML = CloudFunc.buildFromJSON({ + sort : options.sort, + order : options.order, + data : json, + id : panel.id, + prefix : CloudCmd.PREFIX, + template : { + file : templFile, + path : templPath, + pathLink : templPathLink, + link : templLink + } + }); + + Listeners.setOnPanel(panel); + + if (!noCurrent) { + if (name === '..' && dir !== '/') + current = DOM.getCurrentByName(dir); + + if (!current) + current = DOM.getFiles(panel)[0]; + + DOM.setCurrentFile(current, { + history: history + }); } + Util.exec(callback); + }); + } + + /** + * Функция генерирует JSON из html-таблицы файлов и + * используеться при первом заходе в корень + */ + function getJSONfromFileTable() { + var name, size, owner, mode, ret, + path = DOM.getCurrentDirPath(), + infoFiles = Info.files || [], + + fileTable = { + path : path, + files : [] + }, + + files = fileTable.files; + + [].forEach.call(infoFiles, function(current) { + name = DOM.getCurrentName(current); + size = DOM.getCurrentSize(current); + owner = DOM.getCurrentOwner(current); + mode = DOM.getCurrentMode(current); + + if (name !== '..') + files.push({ + name : name, + size : size, + mode : mode, + owner : owner + }); + }); + + ret = Util.json.stringify(fileTable); + + return ret; + } + + this.goToParentDir = function() { + var path = Info.dirPath, + dir = Info.dir, + parentPath = Info.parentDirPath; + + if (path !== parentPath) { + path = parentPath; + CloudCmd.loadDir({ - path : path, - isRefresh : NEEDREFRESH, - history : false, - panel : panel, - noCurrent : noCurrent - }, callback); - }; - - /** - * Функция загружает json-данные о Файловой Системе - * через ajax-запрос. - * @param path - каталог для чтения - * @param options - * { refresh, history } - необходимость обновить данные о каталоге - * @param panel - * @param callback - * - */ - function ajaxLoad(path, options, panel, callback) { - var create = function(error, json) { - var RESTful = DOM.RESTful, - name = Info.name, - obj = Util.json.parse(json), - isRefresh = options.refresh, - noCurrent = options.noCurrent; + path: path, + }, function() { + var current, + panel = Info.panel; - if (!isRefresh && json) - return createFileTable(obj, panel, options, callback); + current = DOM.getCurrentByName(dir); - var position = DOM.getPanelPosition(panel); - var sort = CloudCmd.sort[position]; - var order = CloudCmd.order[position]; - - var query = rendy('?sort={{ sort }}&order={{ order }}', { - sort: sort, - order: order, + if (!current) + current = DOM.getFiles(panel)[0]; + + DOM.setCurrentFile(current, { + history: history }); - - RESTful.read(path + query, 'json', function(error, obj) { - if (error) - return; - - Storage.set(path, obj); - - options.sort = sort; - options.order = order; - - createFileTable(obj, panel, options, function() { - if (isRefresh && !noCurrent) { - DOM.setCurrentByName(name); - } - - Util.exec(callback); - }); - }); - }; - - if (!options) - options = {}; - - CloudCmd.log('reading dir: "' + path + '";'); - - var dirStorage = CloudCmd.config(dirStorage); - - if (!dirStorage) - return create(); - - Storage.get(path, create); - } - - /** - * Функция строит файловую таблицу - * @param json - данные о файлах - * @param panelParam - * @param history - * @param callback - */ - function createFileTable(json, panelParam, options, callback) { - var history = options.history, - noCurrent = options.noCurrent, - names = ['file', 'path', 'link', 'pathLink']; - - Files.get(names, function(error, templFile, templPath, templLink, templPathLink) { - var childNodes, i, - Dialog = DOM.Dialog, - current, - panel = panelParam || DOM.getPanel(), - - dir = Info.dir, - name = Info.name; - - if (error) - return Dialog.alert(TITLE, error.responseText); - - childNodes = panel.childNodes; - i = childNodes.length; - - while (i--) - panel.removeChild(panel.lastChild); - - panel.innerHTML = CloudFunc.buildFromJSON({ - sort : options.sort, - order : options.order, - data : json, - id : panel.id, - prefix : CloudCmd.PREFIX, - template : { - file : templFile, - path : templPath, - pathLink : templPathLink, - link : templLink - } - }); - - Listeners.setOnPanel(panel); - - if (!noCurrent) { - if (name === '..' && dir !== '/') - current = DOM.getCurrentByName(dir); - - if (!current) - current = DOM.getFiles(panel)[0]; - - DOM.setCurrentFile(current, { - history: history - }); - } - - Util.exec(callback); }); } - - /** - * Функция генерирует JSON из html-таблицы файлов и - * используеться при первом заходе в корень - */ - function getJSONfromFileTable() { - var name, size, owner, mode, ret, - path = DOM.getCurrentDirPath(), - infoFiles = Info.files || [], - - fileTable = { - path : path, - files : [] - }, - - files = fileTable.files; - - [].forEach.call(infoFiles, function(current) { - name = DOM.getCurrentName(current); - size = DOM.getCurrentSize(current); - owner = DOM.getCurrentOwner(current); - mode = DOM.getCurrentMode(current); - - if (name !== '..') - files.push({ - name : name, - size : size, - mode : mode, - owner : owner - }); - }); - - ret = Util.json.stringify(fileTable); - - return ret; - } - - this.goToParentDir = function() { - var path = Info.dirPath, - dir = Info.dir, - parentPath = Info.parentDirPath; - - if (path !== parentPath) { - path = parentPath; - - CloudCmd.loadDir({ - path: path, - }, function() { - var current, - panel = Info.panel; - - current = DOM.getCurrentByName(dir); - - if (!current) - current = DOM.getFiles(panel)[0]; - - DOM.setCurrentFile(current, { - history: history - }); - }); - } - }; - } -})(this, Util, DOM, CloudFunc); + }; +} diff --git a/client/cloud.js b/client/cloud.js index 6bf6ff64..c0199017 100644 --- a/client/cloud.js +++ b/client/cloud.js @@ -1,63 +1,61 @@ /* global CloudCmd, Util, DOM, filepicker */ -(function(CloudCmd, Util, DOM) { - 'use strict'; - - CloudCmd.Cloud = CloudProto; - - function CloudProto(callback) { - function init(callback) { - Util.exec.series([ - load, - callback, - ]); - } - - this.uploadFile = function(name, data) { - var log = CloudCmd.log; - - filepicker.store(data, { - mimetype: '', - filename: name - }, - function(fpFile) { - log(fpFile); - filepicker.exportFile(fpFile, log, log); - }); - }; - - this.saveFile = function(callback) { - filepicker.pick(function(fpFile) { - console.log(fpFile); - - DOM.load.ajax({ - url : fpFile.url, - responseType : 'arraybuffer', - success : function(data) { - Util.exec(callback, fpFile.filename, data); - } - }); - }); - }; - - function load(callback) { - Util.time('filepicker load'); - - DOM.load.js('//api.filepicker.io/v1/filepicker.js', function() { - DOM.Files.get('modules', function(error, modules) { - var storage = Util.findObjByNameInArr(modules, 'storage'), - picker = Util.findObjByNameInArr(storage, 'FilePicker'), - key = picker && picker.key; - - filepicker.setKey(key); - - DOM.Images.hide(); - Util.timeEnd('filepicker loaded'); - Util.exec(callback); - }); - }); - } - - init(callback); +'use strict'; + +CloudCmd.Cloud = CloudProto; + +function CloudProto(callback) { + function init(callback) { + Util.exec.series([ + load, + callback, + ]); } -})(CloudCmd, Util, DOM); + + this.uploadFile = function(name, data) { + var log = CloudCmd.log; + + filepicker.store(data, { + mimetype: '', + filename: name + }, + function(fpFile) { + log(fpFile); + filepicker.exportFile(fpFile, log, log); + }); + }; + + this.saveFile = function(callback) { + filepicker.pick(function(fpFile) { + console.log(fpFile); + + DOM.load.ajax({ + url : fpFile.url, + responseType : 'arraybuffer', + success : function(data) { + Util.exec(callback, fpFile.filename, data); + } + }); + }); + }; + + function load(callback) { + Util.time('filepicker load'); + + DOM.load.js('//api.filepicker.io/v1/filepicker.js', function() { + DOM.Files.get('modules', function(error, modules) { + var storage = Util.findObjByNameInArr(modules, 'storage'), + picker = Util.findObjByNameInArr(storage, 'FilePicker'), + key = picker && picker.key; + + filepicker.setKey(key); + + DOM.Images.hide(); + Util.timeEnd('filepicker loaded'); + Util.exec(callback); + }); + }); + } + + init(callback); +} diff --git a/client/cloudcmd.js b/client/cloudcmd.js index 52893bc4..432c3044 100644 --- a/client/cloudcmd.js +++ b/client/cloudcmd.js @@ -1,104 +1,80 @@ -var CloudCmd; +'use strict'; -(function() { - 'use strict'; +window.CloudCmd = (config) => { + window.Util = require('../common/util'); + window.CloudFunc = require('../common/cloudfunc'); + window.DOM = require('./dom'); - CloudCmd = load; + require('./events'); + require('./storage'); + require('./files'); + require('./rest'); + require('./load'); + require('./notify'); + require('./dialog'); - function load(config) { - var prefix = getPrefix(config.prefix); - var modules = '/modules/'; - var client = 'client/'; - var files = [ - 'common/util', - 'common/cloudfunc', - client + 'dom', - client + 'events', - client + 'rest', - client + 'load', - client + 'notify', - client + 'storage', - client + 'files', - client + 'dialog', - 'client/client', - client + 'buffer', - client + 'listeners', - client + 'key', - client + 'directory', - client + 'sort' - ]; - - var moduleFiles = [ - window.Promise ? '' : 'promise-polyfill/promise.min', - libDir('format', 'format-io'), - libDir('rendy'), - libDir('exec', 'execon'), - libDir('jonny'), - libDist('emitify'), - libDist('currify'), - libDist('itype'), - ].filter(function(name) { - return name; - }).map(function(name) { - return modules + name; - }); - - var allFiles = moduleFiles - .concat(files) - .concat('/join/join') - .map(function(name) { - return name + '.js'; - }); - - var urlFiles = getJoinURL(allFiles); - - createScript(prefix + urlFiles, function() { - CloudCmd.init(prefix, config); - }); - } + window.CloudCmd = require('./client'); - function libDir(name, dir) { - var lib = '/lib/'; - - if (!dir) - dir = name; - - return dir + lib + name; - } + require('./buffer'); + require('./listeners'); + require('./key'); + require('./directory'); + require('./sort'); - function libDist(name) { - return name + '/dist/' + name + '.min'; - } + window.exec = require('execon'); + window.rendy = require('rendy'); - function getPrefix(prefix) { - if (!prefix) - return ''; - - if (!prefix.indexOf('/')) - return prefix; - - return '/' + prefix; - } + const modules = '/modules/'; - function createScript(url, callback) { - var script = document.createElement('script'); - - script.src = url; - script.async = true; - - script.addEventListener('load', function load(event) { - callback(event); - script.removeEventListener('load', load); - }); - - document.body.appendChild(script); - } - - function getJoinURL(names) { - var prefix = '/join:'; - var url = prefix + names.join(':'); - - return url; - } -})(); + var moduleFiles = [ + window.Promise ? '' : 'promise-polyfill/promise.min', + ].filter((name) => { + return name; + }).map((name) => { + return modules + name; + }); + + const allFiles = moduleFiles + .concat('/join/join') + .map((name) => `${name}.js`); + + const urlFiles = getJoinURL(allFiles); + + const prefix = getPrefix(config.prefix); + + createScript(prefix + urlFiles, () => { + window.CloudCmd.init(prefix, config); + }); +}; + +function getPrefix(prefix) { + if (!prefix) + return ''; + + if (!prefix.indexOf('/')) + return prefix; + + return '/' + prefix; +} + +function createScript(url, callback) { + var script = document.createElement('script'); + + script.src = url; + script.async = true; + + script.addEventListener('load', function load(event) { + callback(event); + script.removeEventListener('load', load); + }); + + document.body.appendChild(script); +} + +function getJoinURL(names) { + const prefix = '/join:'; + const url = prefix + names.join(':'); + + return url; +} diff --git a/client/config.js b/client/config.js index 3a899677..ec68e4ac 100644 --- a/client/config.js +++ b/client/config.js @@ -1,305 +1,300 @@ -var CloudCmd, Util, DOM, io; +'use strict'; -(function(CloudCmd, Util, DOM) { - 'use strict'; +/* global CloudCmd, DOM, io */ + +const rendy = require('rendy'); +const exec = require('execon'); +const input = require('./input'); + +CloudCmd.Config = ConfigProto; + +function ConfigProto() { + const config = CloudCmd.config; + const Key = CloudCmd.Key; + const Dialog = DOM.Dialog; + const Images = DOM.Images; + const Events = DOM.Events; + const Files = DOM.Files; - /* global rendy */ - /* global input */ + const showLoad = () => { + Images.show.load('top'); + }; - CloudCmd.Config = ConfigProto; + const TITLE = 'Config'; + const Notify = DOM.Notify; + const Config = this; + + let Loading = true; + let Element; + let Template; + + function init() { + Loading = true; - function ConfigProto() { - var config = CloudCmd.config; - var Loading = true, - Key = CloudCmd.Key, - Dialog = DOM.Dialog, - Images = DOM.Images, - Events = DOM.Events, - Files = DOM.Files, - - showLoad = function() { - Images.show.load('top'); + showLoad(); + exec.series([ + CloudCmd.View, + function(callback) { + Loading = false; + exec(callback); + DOM.loadSocket(initSocket); }, + Config.show + ]); + } + + function getHost() { + var l = location, + href = l.origin || l.protocol + '//' + l.host; + + return href; + } + + function initSocket(error) { + var href = getHost(); + var prefix = CloudCmd.PREFIX, + FIVE_SECONDS = 5000, + save = function(data) { + onSave(data); + socket.send(data); + }; - Element, - Template, - - TITLE = 'Config', - - Notify = DOM.Notify, - Config = this; - - function init() { - Loading = true; - + if (error) + return; + + var socket = io.connect(href + prefix + '/config', { + 'max reconnection attempts' : Math.pow(2, 32), + 'reconnection limit' : FIVE_SECONDS, + path: prefix + '/socket.io' + }); + + authCheck(socket); + + socket.on('connect', function() { + Config.save = save; + }); + + socket.on('config', function(config) { + DOM.Storage.setAllowed(config.localStorage); + }); + + socket.on('message', function(data) { + onSave(data); + }); + + socket.on('log', function(msg) { + CloudCmd.log(msg); + }); + + socket.on('disconnect', function() { + Config.save = saveHttp; + }); + + socket.on('err', function(error) { + Dialog.alert(TITLE, error); + }); + } + + function authCheck(socket) { + if (!config('auth')) + return; + + socket.emit('auth', config('username'), config('password')); + + socket.on('reject', function() { + Dialog.alert(TITLE, 'Wrong credentials!'); + }); + } + + Config.save = saveHttp; + + this.show = function() { + var prefix = CloudCmd.PREFIX, + funcs = [ + exec.with(Files.get, 'config-tmpl'), + exec.with(DOM.load.parallel, [ + prefix + '/css/config.css' + ]) + ]; + + if (!Loading) { showLoad(); - Util.exec.series([ - CloudCmd.View, - function(callback) { - Loading = false; - Util.exec(callback); - DOM.loadSocket(initSocket); - }, - Config.show - ]); + exec.parallel(funcs, fillTemplate); } + }; + + function fillTemplate(error, template) { + if (!Template) + Template = template; - function getHost() { - var l = location, - href = l.origin || l.protocol + '//' + l.host; + Files.get('config', (error, config) => { + if (error) + return Dialog.alert(TITLE, 'Could not load config!'); - return href; + const obj = input.convert(config); + + obj[obj.editor + '-selected'] = 'selected'; + delete obj.editor; + + obj[obj.packer + '-selected'] = 'selected'; + delete obj.packer; + + const inner = rendy(Template, obj); + + Element = DOM.load({ + name : 'div', + className : 'config', + inner, + attribute : { + 'data-name': 'js-config' + } + }); + + const inputs = document.querySelectorAll('input, select', Element); + const inputFirst = inputs[0]; + + let focus; + if (inputFirst) { + onAuthChange(inputFirst.checked); + + focus = () => { + inputFirst.focus(); + }; + } + + [].forEach.call(inputs, (input) => { + Events.addKey(input, onKey) + .add('change', input, ({target}) => { + onChange(target); + }); + }); + + CloudCmd.View.show(Element, { + autoSize: true, + afterShow: focus + }); + }); + } + + this.hide = () => { + CloudCmd.View.hide(); + }; + + function onChange(el) { + var obj = {}, + name = input.getName(el), + data = input.getValue(name, Element), + type = el.type; + + if (type === 'checkbox') + if (/^(diff|buffer|dirStorage)$/.test(name)) + onLSChange(name, data); + else if (name === 'localStorage') + onLocalStorageChange(); + else if (name === 'auth') + onAuthChange(data); + + if (name === 'notifications') { + if (data && !Notify.check()) + Notify.request(); } - function initSocket(error) { - var href = getHost(); - var prefix = CloudCmd.PREFIX, - FIVE_SECONDS = 5000, - save = function(data) { - onSave(data); - socket.send(data); - }; - + obj[name] = data; + + Config.save(obj); + } + + function onSave(obj) { + Object.keys(obj).forEach((name) => { + const data = obj[name]; + + CloudCmd._config(name, data); + input.setValue(name, data, Element); + }); + + DOM.Storage.setAllowed(obj.localStorage); + } + + function saveHttp(obj) { + const {RESTful} = DOM; + + RESTful.Config.write(obj, (error) => { if (error) return; - var socket = io.connect(href + prefix + '/config', { - 'max reconnection attempts' : Math.pow(2, 32), - 'reconnection limit' : FIVE_SECONDS, - path: prefix + '/socket.io' - }); - - authCheck(socket); - - socket.on('connect', function() { - Config.save = save; - }); - - socket.on('config', function(config) { - DOM.Storage.setAllowed(config.localStorage); - }); - - socket.on('message', function(data) { - onSave(data); - }); - - socket.on('log', function(msg) { - CloudCmd.log(msg); - }); - - socket.on('disconnect', function() { - Config.save = saveHttp; - }); - - socket.on('err', function(error) { - Dialog.alert(TITLE, error); - }); - } - - function authCheck(socket) { - if (!config('auth')) - return; - - socket.emit('auth', config('username'), config('password')); - - socket.on('reject', function() { - Dialog.alert(TITLE, 'Wrong credentials!'); - }); - } - - Config.save = saveHttp; - - this.show = function() { - var prefix = CloudCmd.PREFIX, - exec = Util.exec, - funcs = [ - exec.with(Files.get, 'config-tmpl'), - exec.with(DOM.load.parallel, [ - prefix + '/css/config.css', - prefix + CloudCmd.DIRCLIENT + 'input.js' - ]) - ]; - - if (!Loading) { - showLoad(); - exec.parallel(funcs, fillTemplate); - } - }; - - function fillTemplate(error, template) { - if (!Template) - Template = template; - - Files.get('config', function(error, config) { - var data, inputs, inputFirst, - focus, obj; - - if (error) - return Dialog.alert(TITLE, 'Could not load config!'); - - obj = input.convert(config); - - obj[obj.editor + '-selected'] = 'selected'; - delete obj.editor; - - obj[obj.packer + '-selected'] = 'selected'; - delete obj.packer; - - data = rendy(Template, obj); - Element = DOM.load({ - name : 'div', - className : 'config', - inner : data, - attribute : { - 'data-name': 'js-config' - } - }); - - inputs = document.querySelectorAll('input, select', Element); - inputFirst = inputs[0]; - - if (inputFirst) { - onAuthChange(inputFirst.checked); - - focus = function() { - inputFirst.focus(); - }; - } - - [].forEach.call(inputs, function(input) { - Events.addKey(input, onKey) - .add('change', input, function(event) { - onChange(event.target); - }); - }); - - CloudCmd.View.show(Element, { - autoSize: true, - afterShow: focus - }); - }); - } - - this.hide = function() { - CloudCmd.View.hide(); - }; - - function onChange(el) { - var obj = {}, - name = input.getName(el), - data = input.getValue(name, Element), - type = el.type; - - if (type === 'checkbox') - if (/^(diff|buffer|dirStorage)$/.test(name)) - onLSChange(name, data); - else if (name === 'localStorage') - onLocalStorageChange(); - else if (name === 'auth') - onAuthChange(data); - - if (name === 'notifications') { - if (data && !Notify.check()) - Notify.request(); - } - - obj[name] = data; - - Config.save(obj); - } - - function onSave(obj) { - Object.keys(obj).forEach(function(name) { - var data = obj[name]; - - CloudCmd._config(name, data); - input.setValue(name, data, Element); - }); - - DOM.Storage.setAllowed(obj.localStorage); - } - - function saveHttp(obj) { - var RESTful = DOM.RESTful; - - RESTful.Config.write(obj, function(error) { - if (!error) - onSave(obj); - }); - } - - function onLocalStorageChange() { - var names = ['diff', 'buffer', 'dirStorage', 'localStorage'], - elements = names.map(function(name) { - return input.getElementByName(name, Element); - }), - - el = {}, - msg = 'Diff, Buffer and Directory Storage do not work without localStorage', - isChecked; - - elements.forEach(function(element) { - var name = input.getName(element); - - el[name] = element; - - if (element.checked) - isChecked = true; - }); - - if (isChecked && !el.localStorage.checked) { - Dialog.alert(TITLE, msg); - - elements.forEach(function(element) { - if (element.checked) { - element.checked = false; - - onChange(element); - } - - return element; - }); - } - } - - function onLSChange(name, data) { - var elLocalStorage = input.getElementByName('localStorage', Element), - - msg = name + ' depends on localStorage'; - - if (data && !elLocalStorage.checked) { - Dialog.alert(TITLE, msg); - elLocalStorage.checked = true; - } - } - - function onAuthChange(checked) { - var elUsername = input.getElementByName('username', Element), - elPassword = input.getElementByName('password', Element); - - elUsername.disabled = - elPassword.disabled = !checked; - } - - function onKey(event) { - var keyCode = event.keyCode; - - switch (keyCode) { - case Key.ESC: - Config.hide(); - break; - - case Key.ENTER: - onChange(event.target); - break; - } - } - - if (!CloudCmd.config('configDialog')) - return; - - init(); + onSave(obj); + }); } -})(CloudCmd, Util, DOM); + function onLocalStorageChange() { + var names = ['diff', 'buffer', 'dirStorage', 'localStorage'], + elements = names.map(function(name) { + return input.getElementByName(name, Element); + }), + + el = {}, + msg = 'Diff, Buffer and Directory Storage do not work without localStorage', + isChecked; + + elements.forEach((element) => { + const name = input.getName(element); + + el[name] = element; + + if (element.checked) + isChecked = true; + }); + + if (!isChecked || el.localStorage.checked) + return; + + Dialog.alert(TITLE, msg); + + elements.forEach((element) => { + if (element.checked) { + element.checked = false; + + onChange(element); + } + + return element; + }); + } + + function onLSChange(name, data) { + const elLocalStorage = input.getElementByName('localStorage', Element); + const msg = name + ' depends on localStorage'; + + if (!data || elLocalStorage.checked) + return; + + Dialog.alert(TITLE, msg); + elLocalStorage.checked = true; + } + + function onAuthChange(checked) { + const elUsername = input.getElementByName('username', Element); + const elPassword = input.getElementByName('password', Element); + + elUsername.disabled = + elPassword.disabled = !checked; + } + + function onKey({keyCode, target}) { + switch (keyCode) { + case Key.ESC: + Config.hide(); + break; + + case Key.ENTER: + onChange(target); + break; + } + } + + if (!CloudCmd.config('configDialog')) + return; + + init(); +} diff --git a/client/directory.js b/client/directory.js index a388259b..44828679 100644 --- a/client/directory.js +++ b/client/directory.js @@ -2,124 +2,109 @@ /* global CloudFunc */ /* global DOM */ -(function() { - 'use strict'; +'use strict'; + +module.exports = uploadDirectory; + +function uploadDirectory(items) { + const Images = DOM.Images; + const Info = DOM.CurrentInfo; + const load = DOM.load; + const Dialog = DOM.Dialog; - if (typeof module !== 'undefined' && module.exports) - module.exports = uploadDirectory; - else - DOM.uploadDirectory = uploadDirectory; + let array = [ + 'findit', + 'philip' + ]; - function uploadDirectory(items) { - var entries, - Images = DOM.Images, - Info = DOM.CurrentInfo, - load = DOM.load, - Dialog = DOM.Dialog, - url = '', - array = [ - 'findit', - 'philip' - ]; - - if (items.length) - Images.show('top'); - - entries = [].map.call(items, function(item) { - return item.webkitGetAsEntry(); - }); - - array = array.map(function(name) { - var result = [ - '/modules/' + name, - '/lib/' + name, - '.js' - ].join(''); - - return result; - }); - - if (!window.Emitify) - array.unshift('/modules/emitify/dist/emitify.js'); - - if (!window.exec) - array.unshift('/modules/execon/lib/exec.js'); - - url = CloudCmd.join(array); - - load.js(url, function() { - var path = Info.dirPath - .replace(/\/$/, ''), - - uploader; - - uploader = window.philip(entries, function(type, name, data, i, n, callback) { - var upload, - prefixURL = CloudCmd.PREFIX_URL, - FS = CloudFunc.FS, - full = prefixURL + FS + path + name; - - switch(type) { - case 'file': - upload = uploadFile(full, data); - break; - - case 'directory': - upload = uploadDir(full); - break; - } - - upload.on('end', callback); - - upload.on('progress', function(count) { - var current = percent(i, n), - next = percent(i + 1, n), - max = next - current, - value = current + percent(count, 100, max); - - setProgress(value); - }); - }); - - uploader.on('error', function(error) { - Dialog.alert(error); - uploader.abort(); - }); - - uploader.on('progress', function(count) { - setProgress(count); - }); - - uploader.on('end', function() { - CloudCmd.refresh(); - }); - }); - } - - function percent(i, n, per) { - var value; - - if (typeof per === 'undefined') - per = 100; - - value = Math.round(i * per / n); - - return value; - } - - function setProgress(count) { - var Images = DOM.Images; - - Images.setProgress(count); + if (items.length) Images.show('top'); - } - function uploadFile(url, data) { - return DOM.load.put(url, data); - } + const entries = [].map.call(items, (item) => { + return item.webkitGetAsEntry(); + }); - function uploadDir(url) { - return DOM.load.put(url + '?dir'); - } + array = array.map(function(name) { + const result = [ + '/modules/' + name, + '/lib/' + name, + '.js' + ].join(''); + + return result; + }); -})(); + if (!window.Emitify) + window.Emitify = require('emitify'); + + if (!window.exec) + window.exec = require('execon'); + + const url = CloudCmd.join(array); + + load.js(url, () => { + const path = Info.dirPath + .replace(/\/$/, ''); + + const uploader = window.philip(entries, (type, name, data, i, n, callback) => { + const prefixURL = CloudCmd.PREFIX_URL; + const FS = CloudFunc.FS; + const full = prefixURL + FS + path + name; + + let upload; + switch(type) { + case 'file': + upload = uploadFile(full, data); + break; + + case 'directory': + upload = uploadDir(full); + break; + } + + upload.on('end', callback); + + upload.on('progress', (count) => { + const current = percent(i, n); + const next = percent(i + 1, n); + const max = next - current; + const value = current + percent(count, 100, max); + + setProgress(value); + }); + }); + + uploader.on('error', (error) => { + Dialog.alert(error); + uploader.abort(); + }); + + uploader.on('progress', setProgress); + + uploader.on('end', () => { + CloudCmd.refresh(); + }); + }); +} + +function percent(i, n, per) { + if (typeof per === 'undefined') + per = 100; + + return Math.round(i * per / n); +} + +function setProgress(count) { + DOM.Images + .setProgress(count) + .show('top'); +} + +function uploadFile(url, data) { + return DOM.load.put(url, data); +} + +function uploadDir(url) { + return DOM.load.put(url + '?dir'); +} + diff --git a/client/dom.js b/client/dom.js index 58d0e834..ec541da2 100644 --- a/client/dom.js +++ b/client/dom.js @@ -1,1647 +1,1650 @@ -var CloudCmd, Util, DOM, CloudFunc; +/* global CloudCmd */ +/* global CloudFunc */ +/* global Util */ -(function(Util, window) { - 'use strict'; - - /* global rendy */ - /* global itype */ - /* global exec */ - - var DOMFunc = function() {}; - var DOMTree = Util.extendProto(DOMTreeProto); - var Images = Util.extendProto(ImagesProto); - - var DOMProto = DOMFunc.prototype = new CmdProto(); - - Util.extend(DOMProto, [ - DOMTree, { - Images : Images - } - ]); - - window.DOM = new DOMFunc(); - - function ImagesProto() { - var Images = new ImageElementProto(); - - function ImageElementProto () { - var LOADING = 'loading'; - var LoadingImage; - var HIDDEN = 'hidden'; - var ERROR = 'error'; - - function getLoadingType() { - return DOM.isSVG() ? '-svg' : '-gif'; - } - - function init() { - if (LoadingImage) - return; - - LoadingImage = LOADING + getLoadingType(); - } - - function getElement() { - init(); - - return DOM.load({ - name : 'span', - id : 'js-status-image', - className : 'icon', - attribute : 'data-progress', - notAppend : true - }); - } - - this.get = getElement; - - /* Функция создаёт картинку загрузки */ - this.loading = function() { - var element = getElement(); - var classList = element.classList; - - classList.add(LOADING, LoadingImage); - classList.remove(ERROR, HIDDEN); - - return element; - }; - - /* Функция создаёт картинку ошибки загрузки */ - this.error = function() { - var element = getElement(); - var classList = element.classList; - - classList.add(ERROR); - classList.remove(HIDDEN, LOADING, LoadingImage); - - return element; - }; - } - - this.show = load; - this.show.load = load; - this.show.error = error; - - /** - * Function shows loading spinner - * position = {top: true}; - */ - function load(position, panel) { - var current, - image = Images.loading(), - parent = image.parentElement, - refreshButton = DOM.getRefreshButton(panel); - - if (position === 'top') { - current = refreshButton.parentElement; - } else { - current = DOM.getCurrentFile(); - - if (current) - current = DOM.getByDataName('js-name', current); - else - current = refreshButton.parentElement; - } - - if (!parent || (parent && parent !== current)) - current.appendChild(image); - - DOM.show(image); - - return image; - } - - function error(text) { - var image = Images.error(); - - DOM.show(image); - image.title = text; - - CloudCmd.log(text); - - return image; - } - - /** - * hide load image - */ - this.hide = function() { - var element = Images.get(); - DOM.hide(element); - - return this; - }; - - this.setProgress = function(value, title) { - var DATA = 'data-progress', - element = Images.get(); - - if (element) { - element.setAttribute(DATA, value + '%'); - - if (title) - element.title = title; - } - - return this; - }; - - this.clearProgress = function() { - var DATA = 'data-progress', - element = Images.get(); - - if (element) { - element.setAttribute(DATA, ''); - element.title = ''; - } - - return this; - }; - } - - function DOMTreeProto() { - var DOM = this; - - /** - * check class of element - * - * @param element - * @param pClass - */ - this.isContainClass = function(element, className) { - var ret, classList; - - if (!element) - throw Error('element could not be empty!'); - - if (!className) - throw Error('className could not be empty!'); - - classList = element.classList; - ret = classList.contains(className); - - return ret; - }; - - /** - * Function search element by tag - * @param pTag - className - * @param element - element - */ - this.getByTag = function(pTag, element) { - return (element || document).getElementsByTagName(pTag); - }; - - /** - * Function search element by id - * @param Id - id - */ - this.getById = function(id, element) { - return (element || document).querySelector('#' + id); - }; - - /** - * Function search first element by class name - * @param pClass - className - * @param element - element - */ - this.getByClass = function(pClass, elementParam) { - var element = elementParam || document, - ret = this.getByClassAll(pClass, element)[0]; - - return ret; - }; - - this.getByDataName = function(attribute, element) { - var ret, - selector = '[' + 'data-name="' + attribute + '"]'; - - if (!element) - element = document; - - ret = element.querySelector(selector); - - return ret; - }; - - /** - * Function search element by class name - * @param pClass - className - * @param element - element - */ - this.getByClassAll = function(pClass, element) { - return (element || document).getElementsByClassName(pClass); - }; - - /** - * check SVG SMIL animation support - */ - this.isSVG = function() { - var ret, svgNode, name, - create = document.createElementNS, - SVG_URL = 'http://www.w3.org/2000/svg'; - - if (create) { - create = create.bind(document); - svgNode = create(SVG_URL, 'animate'); - name = svgNode.toString(); - ret = /SVGAnimate/.test(name); - } - - return ret; - }; - - /** - * add class=hidden to element - * - * @param element - */ - this.hide = function(element) { - element.classList.add('hidden'); - return DOM; - }; - - this.show = function(element) { - element.classList.remove('hidden'); - return DOM; - }; +'use strict'; + +const itype = require('itype/legacy'); +const rendy = require('rendy'); +const exec = require('execon'); + +const DOMFunc = function() {}; +const DOMTree = Util.extendProto(DOMTreeProto); +const Images = Util.extendProto(ImagesProto); + +const DOMProto = DOMFunc.prototype = new CmdProto(); + +Util.extend(DOMProto, [ + DOMTree, { + Images : Images } +]); + +const DOM = new DOMFunc(); +module.exports = DOM; + +DOM.uploadDirectory = require('./directory'); + +function ImagesProto() { + var Images = new ImageElementProto(); - function CmdProto() { - var Cmd = this; - var CurrentInfo = {}; - var CURRENT_FILE = 'current-file'; - var SELECTED_FILE = 'selected-file'; - var SelectType = '*.*'; - var TITLE = 'Cloud Commander'; - var Title; - var TabPanel = { - 'js-left' : null, - 'js-right' : null - }; + function ImageElementProto () { + var LOADING = 'loading'; + var LoadingImage; + var HIDDEN = 'hidden'; + var ERROR = 'error'; - /** - * private function thet unset currentfile - * - * @currentFile - */ - function unsetCurrentFile(currentFile) { - var ret = DOM.isCurrentFile(currentFile); - - if (ret) - currentFile.classList.remove(CURRENT_FILE); - - return ret; + function getLoadingType() { + return DOM.isSVG() ? '-svg' : '-gif'; } - this.loadRemote = function(name, options, callback) { - var o = options; - var Files = DOM.Files; + function init() { + if (LoadingImage) + return; - if (!callback) - callback = options; - - if (o.name && window[o.name]) - callback(); - else - Files.get('modules', function(error, modules) { - var remoteTmpls, local, remote, - load = DOM.load, - prefix = CloudCmd.PREFIX, - online = CloudCmd.config('online') && navigator.onLine, - - remoteObj = Util.findObjByNameInArr(modules, 'remote'), - module = Util.findObjByNameInArr(remoteObj, name), - - isArray = itype.array(module.local), - version = module.version, - - funcON = function() { - load.parallel(remote, function(error) { - if (error) - funcOFF(); - else - callback(); - }); - }, - - funcOFF = function() { - load.parallel(local, callback); - }; - - if (isArray) { - remoteTmpls = module.remote; - local = module.local; - } else { - remoteTmpls = [module.remote]; - local = [module.local]; - } - - local = local.map(function(url) { - return prefix + url; - }); - - remote = remoteTmpls.map(function(tmpl) { - return rendy(tmpl, { - version: version - }); - }); - - Util.exec.if(online, funcON, funcOFF); - }); - - return DOM; - }; + LoadingImage = LOADING + getLoadingType(); + } - /** - * load jquery from google cdn or local copy - * @param callback - */ - this.loadJquery = function(callback) { - DOM.loadRemote('jquery', { - name : '$' - }, callback); + function getElement() { + init(); - return DOM; - }; - - this.loadSocket = function(callback) { - DOM.loadRemote('socket', { - name : 'io' - }, callback); - - return DOM; - }; - - /** function loads css and js of Menu - * @param callback - */ - this.loadMenu = function(callback) { - return DOM.loadRemote('menu', callback); - }; - - this.uploadFiles = function(dir, files) { - var array, - slice = [].slice, - i = 0, - n = 0, - func = function(name) { - return function() { - CloudCmd.refresh(null, function() { - DOM.setCurrentByName(name); - }); - }; - }, - - percent = function(i, n, per) { - var value; - - if (!per) - per = 100; - - value = Math.round(i * per / n); - - return value; - }, - - step = function(n) { - return 100 / n; - }, - - load = function(file, callback) { - var uploader, - Images = DOM.Images, - name = file.name, - path = dir + name, - prefixURL = CloudCmd.PREFIX_URL, - FS = CloudFunc.FS, - api = prefixURL + FS; - - ++i; - - uploader = DOM.load.put(api + path, file); - uploader.on('progress', function(count) { - var max = step(n), - value = (i - 1) * max + percent(count, 100, max); - - Images.show.load('top'); - Images.setProgress(Math.round(value)); - }); - - uploader.on('end', callback); - }; - - if (!files) { - files = dir; - dir = CurrentInfo.dirPath; - } - - n = files.length; - array = slice.call(files); - - if (n) { - Util.exec.eachSeries(array, load, func(files[0].name)); - } - }; - - /** - * create new folder - * - */ - this.promptNewDir = function() { - promptNew('directory', '?dir'); - }; - - /** - * create new file - * - * @typeName - * @type - */ - this.promptNewFile = function() { - promptNew('file'); - }; - - function promptNew(typeName, type) { - var RESTful = DOM.RESTful, - Dialog = DOM.Dialog, - path = '', - name = Cmd.getCurrentName(), - dir = Cmd.getCurrentDirPath(), - msg = 'New ' + typeName || 'File'; - - if (name === '..') - name = ''; - - Dialog.prompt(TITLE, msg, name, {cancel: false}).then(function(name) { - path = dir + name; - - if (type) - path += type; - - if (name) - RESTful.write(path, function(error) { - !error && CloudCmd.refresh(null, function() { - DOM.setCurrentByName(name); - }); - }); + return DOM.load({ + name : 'span', + id : 'js-status-image', + className : 'icon', + attribute : 'data-progress', + notAppend : true }); } - /** - * get current direcotory name - */ - this.getCurrentDirName = function() { - var ret, - substr, - /* получаем имя каталога в котором находимся */ - href = this.getCurrentDirPath(); - - href = href.replace(/\/$/, ''); - substr = href.substr(href, href.lastIndexOf('/')); - ret = href.replace(substr + '/', '') || '/'; - - return ret; - }; + this.get = getElement; - /** - * get current direcotory path - */ - this.getCurrentDirPath = function(panel) { - var ret, path; + /* Функция создаёт картинку загрузки */ + this.loading = function() { + var element = getElement(); + var classList = element.classList; - if (!panel) - panel = this.getPanel(); - - path = this.getByDataName('js-path', panel); - ret = path && path.textContent; - - return ret; - }; - - /** - * get current direcotory path - */ - this.getParentDirPath = function(panel) { - var path = DOM.getCurrentDirPath(panel), - dirName = DOM.getCurrentDirName() + '/'; - - if (path !== '/') - path = path.replace(RegExp(dirName + '$'), ''); - - return path; - }; - - /** - * get not current direcotory path - */ - this.getNotCurrentDirPath = function() { - var panel = this.getPanel({active: false}), - path = this.getCurrentDirPath(panel); - - return path; - }; - - /** - * unified way to get current file - * - * @currentFile - */ - this.getCurrentFile = function() { - var ret = this.getByClass(CURRENT_FILE); - - return ret; - }; - - /** - * get current file by name - */ - this.getCurrentByName = function(name, panelParam) { - var element, - panel = panelParam || CurrentInfo.panel; - - name = 'js-file-' + name; - element = DOM.getByDataName(name, panel); + classList.add(LOADING, LoadingImage); + classList.remove(ERROR, HIDDEN); return element; }; - /** - * unified way to get current file - * - * @currentFile - */ - this.getSelectedFiles = function() { - var panel = DOM.getPanel(), - selected = this.getByClassAll(SELECTED_FILE, panel), - ret = [].slice.call(selected); + /* Функция создаёт картинку ошибки загрузки */ + this.error = function() { + var element = getElement(); + var classList = element.classList; - return ret; - }; - - - /* - * unselect all files - */ - this.unselectFiles = function(files) { - var array, - isArray = Array.isArray(files); - - if (!files) { - array = DOM.getSelectedFiles(); - } else if (!isArray) - array = [].slice.call(files); - - array.forEach(DOM.toggleSelectedFile); - }; - - /** - * get all selected files or current when none selected - * - * @currentFile - */ - this.getActiveFiles = function() { - var current = DOM.getCurrentFile(); - var files = DOM.getSelectedFiles(); - var name = DOM.getCurrentName(current); - - if (!files.length && name !== '..') - return [current]; - - return files; - }; - - /** - * get size - * @currentFile - */ - this.getCurrentSize = function(currentFile) { - var current = currentFile || Cmd.getCurrentFile(), - size = this.getByDataName('js-size', current); - - /* если это папка - возвращаем слово dir вместо размера*/ - size = size - .textContent - .replace(/^<|>$/g, ''); - - return size; - }; - - /** - * get size - * @currentFile - */ - this.loadCurrentSize = function(callback, currentFile) { - var RESTful = DOM.RESTful, - Images = DOM.Images, - current = currentFile || this.getCurrentFile(), - query = '?size', - link = this.getCurrentPath(current); - - Images.show.load(); - - if (name !== '..') - RESTful.read(link + query, function(error, size) { - if (!error) { - DOM.setCurrentSize(size, current); - Util.exec(callback, current); - Images.hide(); - } - }); - }; - - /** - * load hash - * @callback - * @currentFile - */ - this.loadCurrentHash = function(callback, currentFile) { - var RESTful = DOM.RESTful, - current = currentFile || DOM.getCurrentFile(), - query = '?hash', - link = DOM.getCurrentPath(current); - - RESTful.read(link + query, callback); - }; - - /** - * load current modification time of file - * @callback - * @currentFile - */ - this.loadCurrentTime = function(callback, currentFile) { - var RESTful = DOM.RESTful, - current = currentFile || this.getCurrentFile(), - query = '?time', - link = this.getCurrentPath(current); - - RESTful.read(link + query, callback); - }; - - /** - * set size - * @currentFile - */ - this.setCurrentSize = function(size, currentFile) { - var current = currentFile || this.getCurrentFile(), - sizeElement = this.getByDataName('js-size', current); - - sizeElement.textContent = size; - - }; - - /** - * @currentFile - */ - this.getCurrentMode = function(currentFile) { - var ret, - current = currentFile || this.getCurrentFile(), - lMode = this.getByDataName('js-mode', current); - ret = lMode.textContent; - - return ret; - }; - - /** - * @currentFile - */ - this.getCurrentOwner = function(currentFile) { - var ret, - current = currentFile || this.getCurrentFile(), - owner = this.getByDataName('js-owner', current); - - ret = owner.textContent; - - return ret; - }; - - /** - * unified way to get current file content - * - * @param callback - * @param currentFile - */ - this.getCurrentData = function(callback, currentFile) { - var hash, - RESTful = DOM.RESTful, - Dialog = DOM.Dialog, - Info = DOM.CurrentInfo, - current = currentFile || DOM.getCurrentFile(), - path = DOM.getCurrentPath(current), - isDir = DOM.isCurrentIsDir(current), - - func = function(error, data) { - var length, - ONE_MEGABYTE = 1024 * 1024 * 1024; - - if (!error) { - if (itype.object(data)) - data = Util.json.stringify(data); - - length = data.length; - - if (hash && length < ONE_MEGABYTE) - DOM.saveDataToStorage(path, data, hash); - } - - callback(error, data); - }; - - if (Info.name === '..') { - Dialog.alert.noFiles(TITLE); - return callback(Error('No files selected!')); - } - - if (isDir) - return RESTful.read(path, func); - - DOM.checkStorageHash(path, function(error, equal, hashNew) { - if (error) { - callback(error); - } else if (equal) { - DOM.getDataFromStorage(path, callback); - } else { - hash = hashNew; - RESTful.read(path, func); - } - }); - }; - - /** - * unified way to save current file content - * - * @callback - function({data, name}) {} - * @currentFile - */ - this.saveCurrentData = function(url, data, callback, query) { - if (!query) - query = ''; - - DOM.RESTful.write(url + query, data, function(error) { - !error && DOM.saveDataToStorage(url, data); - }); - }; - - /** - * unified way to get RefreshButton - */ - this.getRefreshButton = function(panel) { - var currentPanel = panel || this.getPanel(), - refresh = this.getByDataName('js-refresh', currentPanel); - - return refresh; - }; - - this.setCurrentByName = function(name) { - var current = this.getCurrentByName(name); - return this.setCurrentFile(current); - }; - - /** - * unified way to set current file - */ - this.setCurrentFile = function(currentFile, options) { - var path, pathWas, title, - o = options, - FS = CloudFunc.FS, - CENTER = true, - currentFileWas = this.getCurrentFile(); - - if (currentFile) { - if (currentFileWas) { - pathWas = DOM.getCurrentDirPath(); - unsetCurrentFile(currentFileWas); - } - - currentFile.classList.add(CURRENT_FILE); - - path = DOM.getCurrentDirPath(); - - if (path !== pathWas) { - title = CloudFunc.getTitle(path); - this.setTitle(title); - - /* history could be present - * but it should be false - * to prevent default behavior - */ - if (!o || o.history !== false) { - if (path !== '/') - path = FS + path; - - DOM.setHistory(path, null, path); - } - } - - /* scrolling to current file */ - this.scrollIntoViewIfNeeded(currentFile, CENTER); - - Cmd.updateCurrentInfo(); - } - - return this; - }; - - /* - * set current file by position - * - * @param layer - element - * @param - position {x, y} - */ - this.getCurrentByPosition = function(position) { - var element, tag, isChild, - x = position.x, - y = position.y; - - element = document.elementFromPoint(x, y), - tag = element.tagName; - - isChild = /A|SPAN|LI/.test(tag); - - if (!isChild) { - element = null; - } else { - switch (tag) { - case 'A': - element = element.parentElement.parentElement; - break; - - case 'SPAN': - element = element.parentElement; - break; - } - } - - if (element && element.tagName !== 'LI') - element = null; + classList.add(ERROR); + classList.remove(HIDDEN, LOADING, LoadingImage); return element; }; + } + + this.show = load; + this.show.load = load; + this.show.error = error; + + /** + * Function shows loading spinner + * position = {top: true}; + */ + function load(position, panel) { + var current, + image = Images.loading(), + parent = image.parentElement, + refreshButton = DOM.getRefreshButton(panel); - /** - * select current file - * @param currentFile - */ - this.selectFile = function(currentFile) { - var current = currentFile || DOM.getCurrentFile(); - - current.classList.add(SELECTED_FILE); - - return Cmd; - }; - - this.toggleSelectedFile = function(currentFile) { - var current = currentFile || this.getCurrentFile(); - - current.classList.toggle(SELECTED_FILE); - - return Cmd; - }; - - this.toggleAllSelectedFiles = function() { - DOM.getAllFiles().map(DOM.toggleSelectedFile); - - return Cmd; - }; - - this.selectAllFiles = function() { - DOM.getAllFiles().map(DOM.selectFile); - - return Cmd; - }; - - this.getAllFiles = function() { - var i, - panel = DOM.getPanel(), - files = DOM.getFiles(panel), - name = DOM.getCurrentName(files[0]); - - if (name === '..') - i = 1; - else - i = 0; - - return [].slice.call(files, i); - }; - - function selectByPattern(msg, files) { - var n, regExp, - Dialog = DOM.Dialog, - allMsg = 'Specify file type for ' + msg + ' selection', - i = 0, - matches = 0, - name, - shouldSel = msg === 'expand', - isSelected, isMatch, - current; - - Dialog.prompt(TITLE, allMsg, SelectType, {cancel: false}).then(function(type) { - SelectType = type; - - regExp = Util.getRegExp(type); - - n = files && files.length; - for (i = 0; i < n; i++) { - current = files[i]; - name = DOM.getCurrentName(current); - - if (name !== '..') { - isMatch = regExp.test(name); - - if (isMatch) { - ++matches; - - isSelected = DOM.isSelected(current); - - if (shouldSel) - isSelected = !isSelected; - - if (isSelected) - DOM.toggleSelectedFile(current); - } - } - } - - if (!matches) - Dialog.alert('Select Files', 'No matches found!'); - }); - } - - /** - * open dialog with expand selection - */ - this.expandSelection = function() { - var msg = 'expand', - files = CurrentInfo.files; - - selectByPattern(msg, files); - }; - - /** - * open dialog with shrink selection - */ - this.shrinkSelection = function() { - var msg = 'shrink', - files = DOM.getSelectedFiles(); - - selectByPattern(msg, files); - }; - - /** - * setting history wrapper - */ - this.setHistory = function(data, title, url) { - var ret = window.history; - - url = CloudCmd.PREFIX + url; - - if (ret) - history.pushState(data, title, url); - - return ret; - }; - - /** - * set title or create title element - * - * @param name - */ - - this.setTitle = function(name) { - if (!Title) - Title = DOM.getByTag('title')[0] || - DOM.load({ - name : 'title', - innerHTML : name, - parentElement : document.head - }); - - Title.textContent = name; - - return this; - }; - - /** - * current file check - * - * @param currentFile - */ - this.isCurrentFile = function(currentFile) { - var ret; - - if (currentFile) - ret = this.isContainClass(currentFile, CURRENT_FILE); - - return ret; - }; - - /** - * selected file check - * - * @param currentFile - */ - this.isSelected = function(pSelected) { - var ret; - - if (pSelected) - ret = this.isContainClass(pSelected, SELECTED_FILE); - - return ret; - }; - - /** - * check is current file is a directory - * - * @param currentFile - */ - this.isCurrentIsDir = function(currentFile) { - var current = currentFile || this.getCurrentFile(), - fileType = this.getByDataName('js-type', current), - ret = this.isContainClass(fileType, 'directory'); - - return ret; - }; - - /** - * get link from current (or param) file - * - * @param currentFile - current file by default - */ - this.getCurrentLink = function(currentFile) { - var current = currentFile || this.getCurrentFile(), - link = this.getByTag('a', current); - - return link[0]; - }; - - /** - * get link from current (or param) file - * - * @param currentFile - current file by default - */ - this.getCurrentPath = function(currentFile) { - var current = currentFile || DOM.getCurrentFile(), - element = DOM.getByTag('a', current)[0], - path = element.getAttribute('href'), - prefix = CloudCmd.PREFIX, - fs = CloudFunc.FS; - - path = path.replace(RegExp('^' + prefix + fs), ''); - - return path; - }; - - /** - * get name from current (or param) file - * - * @param currentFile - */ - this.getCurrentName = function(currentFile) { - var link, - name = '', - current = currentFile || this.getCurrentFile(); + if (position === 'top') { + current = refreshButton.parentElement; + } else { + current = DOM.getCurrentFile(); if (current) - link = this.getCurrentLink(current); - - if (link) { - name = link.title; - } - - return name; - }; - - this.getFilenames = function(allFiles) { - var first, name, - files, - slice = Array.prototype.slice, - names = []; - - if (!allFiles) - throw Error('AllFiles could not be empty'); - - files = slice.call(allFiles); - first = files[0]; - - if (first) { - name = this.getCurrentName(first); - } else { - first = this.getCurrentFile(); - name = this.getCurrentName(first); - } - - if (name === '..') - files.shift(); - - names = files.map(function(current) { - return DOM.getCurrentName(current); - }); - - return names; - }; - - /** - * set name from current (or param) file - * - * @param name - * @param current - */ - this.setCurrentName = function(name, current) { - var Info = CurrentInfo, - link = Info.link, - FS = CloudFunc.FS, - PREFIX = CloudCmd.PREFIX, - dir = PREFIX + FS + Info.dirPath; - - link.title = name; - link.innerHTML = CloudFunc.Entity.encode(name); - link.href = dir + name; - - current.setAttribute('data-name', 'js-file-' + name); - - return link; - }; - - /** - * check storage hash - */ - this.checkStorageHash = function(name, callback) { - var Storage = DOM.Storage; - var parallel = Util.exec.parallel; - var loadHash = DOM.loadCurrentHash; - var nameHash = name + '-hash'; - var getStoreHash = Util.exec.with(Storage.get, nameHash); - - if (typeof name !== 'string') - throw Error('name should be a string!'); - - if (typeof callback !== 'function') - throw Error('callback should be a function!'); - - parallel([loadHash, getStoreHash], function(error, loadHash, storeHash) { - var equal; - var isContain = /error/.test(loadHash); - - if (isContain) - error = loadHash; - else if (loadHash === storeHash) - equal = true; - - callback(error, equal, loadHash); - }); - }; - - /** - * save data to storage - * - * @param name - * @param data - * @param hash - * @param callback - */ - this.saveDataToStorage = function(name, data, hash, callback) { - var allowed = CloudCmd.config('localStorage'); - var isDir = DOM.isCurrentIsDir(); - var nameHash = name + '-hash'; - var nameData = name + '-data'; - - if (!allowed || isDir) - return Util.exec(callback); - - Util.exec.if(hash, function() { - var Storage = DOM.Storage; - - Storage.set(nameHash, hash); - Storage.set(nameData, data); - - Util.exec(callback, hash); - }, function(callback) { - DOM.loadCurrentHash(function(error, loadHash) { - hash = loadHash; - callback(); - }); - }); - }; - - /** - * save data to storage - * - * @param name - * @param data - * @param callback - */ - this.getDataFromStorage = function(name, callback) { - var Storage = DOM.Storage; - var nameHash = name + '-hash'; - var nameData = name + '-data'; - var allowed = CloudCmd.config('localStorage'); - var isDir = DOM.isCurrentIsDir(); - - if (!allowed || isDir) - return Util.exec(callback); - - Util.exec.parallel([ - exec.with(Storage.get, nameData), - exec.with(Storage.get, nameHash), - ], callback); - }; - - this.getFM = function() { - return this.getPanel().parentElement; - }; - - this.getPanelPosition = function(panel) { - panel = panel || DOM.getPanel(); - - return panel.dataset.name.replace('js-', ''); - }; - - /** function getting panel active, or passive - * @param options = {active: true} - */ - this.getPanel = function(options) { - var files, panel, isLeft, - dataName = 'js-', - current = this.getCurrentFile(); - - if (!current) { - panel = this.getByDataName('js-left'); - } else { - files = current.parentElement, - panel = files.parentElement, - isLeft = panel.getAttribute('data-name') === 'js-left'; - } - - /* if {active : false} getting passive panel */ - if (options && !options.active) { - dataName += isLeft ? 'right' : 'left'; - panel = this.getByDataName(dataName); - } - - /* if two panels showed - * then always work with passive - * panel - */ - if (window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH) - panel = this.getByDataName('js-left'); - - - if (!panel) - throw Error('can not find Active Panel!'); - - return panel; - }; - - this.getFiles = function(element) { - var files = DOM.getByDataName('js-files', element), - ret = files.children || []; - - return ret; - }; - - /** - * shows panel right or left (or active) - */ - this.showPanel = function(active) { - var ret = true, - panel = this.getPanel({active: active}); - - if (panel) - this.show(panel); + current = DOM.getByDataName('js-name', current); else - ret = false; - - return ret; - }; + current = refreshButton.parentElement; + } - /** - * hides panel right or left (or active) - */ - this.hidePanel = function(active) { - var ret = false, - panel = this.getPanel({active: active}); - - if (panel) - ret = this.hide(panel); - - return ret; - }; - - /** - * open window with URL - * @param url - */ - this.openWindow = function(url) { - var left = 140, - top = 187, - width = 1000, - height = 650, - - options = 'left=' + left + - ',top=' + top + - ',width=' + width + - ',height=' + height + - ',personalbar=0,toolbar=0' + - ',scrollbars=1,resizable=1', - - wnd = window.open(url, 'Cloud Commander Auth', options); - - if (!wnd) - DOM.Dialog.alert(TITLE, 'Please disable your popup blocker and try again.'); - - return wnd; - }; + if (!parent || (parent && parent !== current)) + current.appendChild(image); - /** - * remove child of element - * @param pChild - * @param element - */ - this.remove = function(child, element) { - var parent = element || document.body; - - parent.removeChild(child); - - return DOM; - }; + DOM.show(image); - /** - * remove current file from file table - * @param current - * - */ - this.deleteCurrent = function(current) { - var next, prev, currentNew; + return image; + } + + function error(text) { + var image = Images.error(); + + DOM.show(image); + image.title = text; + + CloudCmd.log(text); + + return image; + } + + /** + * hide load image + */ + this.hide = function() { + var element = Images.get(); + DOM.hide(element); + + return this; + }; + + this.setProgress = function(value, title) { + var DATA = 'data-progress', + element = Images.get(); - if (!current) - Cmd.getCurrentFile(); + if (element) { + element.setAttribute(DATA, value + '%'); - var parent = current && current.parentElement; - var name = Cmd.getCurrentName(current); + if (title) + element.title = title; + } + + return this; + }; + + this.clearProgress = function() { + var DATA = 'data-progress', + element = Images.get(); - if (current && name !== '..') { - next = current.nextSibling, - prev = current.previousSibling; + if (element) { + element.setAttribute(DATA, ''); + element.title = ''; + } + + return this; + }; +} + +function DOMTreeProto() { + var DOM = this; + + /** + * check class of element + * + * @param element + * @param pClass + */ + this.isContainClass = function(element, className) { + var ret, classList; + + if (!element) + throw Error('element could not be empty!'); + + if (!className) + throw Error('className could not be empty!'); + + classList = element.classList; + ret = classList.contains(className); + + return ret; + }; + + /** + * Function search element by tag + * @param pTag - className + * @param element - element + */ + this.getByTag = function(pTag, element) { + return (element || document).getElementsByTagName(pTag); + }; + + /** + * Function search element by id + * @param Id - id + */ + this.getById = function(id, element) { + return (element || document).querySelector('#' + id); + }; + + /** + * Function search first element by class name + * @param pClass - className + * @param element - element + */ + this.getByClass = function(pClass, elementParam) { + var element = elementParam || document, + ret = this.getByClassAll(pClass, element)[0]; + + return ret; + }; + + this.getByDataName = function(attribute, element) { + var ret, + selector = '[' + 'data-name="' + attribute + '"]'; + + if (!element) + element = document; + + ret = element.querySelector(selector); + + return ret; + }; + + /** + * Function search element by class name + * @param pClass - className + * @param element - element + */ + this.getByClassAll = function(pClass, element) { + return (element || document).getElementsByClassName(pClass); + }; + + /** + * check SVG SMIL animation support + */ + this.isSVG = function() { + var ret, svgNode, name, + create = document.createElementNS, + SVG_URL = 'http://www.w3.org/2000/svg'; + + if (create) { + create = create.bind(document); + svgNode = create(SVG_URL, 'animate'); + name = svgNode.toString(); + ret = /SVGAnimate/.test(name); + } + + return ret; + }; + + /** + * add class=hidden to element + * + * @param element + */ + this.hide = function(element) { + element.classList.add('hidden'); + return DOM; + }; + + this.show = function(element) { + element.classList.remove('hidden'); + return DOM; + }; +} + +function CmdProto() { + var Cmd = this; + var CurrentInfo = {}; + var CURRENT_FILE = 'current-file'; + var SELECTED_FILE = 'selected-file'; + var SelectType = '*.*'; + var TITLE = 'Cloud Commander'; + var Title; + var TabPanel = { + 'js-left' : null, + 'js-right' : null + }; + + /** + * private function thet unset currentfile + * + * @currentFile + */ + function unsetCurrentFile(currentFile) { + var ret = DOM.isCurrentFile(currentFile); + + if (ret) + currentFile.classList.remove(CURRENT_FILE); + + return ret; + } + + this.loadRemote = function(name, options, callback) { + var o = options; + var Files = DOM.Files; + + if (!callback) + callback = options; + + if (o.name && window[o.name]) + callback(); + else + Files.get('modules', function(error, modules) { + var remoteTmpls, local, remote, + load = DOM.load, + prefix = CloudCmd.PREFIX, + online = CloudCmd.config('online') && navigator.onLine, - if (next) - currentNew = next; - else if (prev) - currentNew = prev; + remoteObj = Util.findObjByNameInArr(modules, 'remote'), + module = Util.findObjByNameInArr(remoteObj, name), + + isArray = itype.array(module.local), + version = module.version, + + funcON = function() { + load.parallel(remote, function(error) { + if (error) + funcOFF(); + else + callback(); + }); + }, + + funcOFF = function() { + load.parallel(local, callback); + }; + + if (isArray) { + remoteTmpls = module.remote; + local = module.local; + } else { + remoteTmpls = [module.remote]; + local = [module.local]; + } - DOM.setCurrentFile(currentNew); + local = local.map(function(url) { + return prefix + url; + }); - parent.removeChild(current); + remote = remoteTmpls.map(function(tmpl) { + return rendy(tmpl, { + version: version + }); + }); + + Util.exec.if(online, funcON, funcOFF); + }); + + return DOM; + }; + + /** + * load jquery from google cdn or local copy + * @param callback + */ + this.loadJquery = function(callback) { + DOM.loadRemote('jquery', { + name : '$' + }, callback); + + return DOM; + }; + + this.loadSocket = function(callback) { + DOM.loadRemote('socket', { + name : 'io' + }, callback); + + return DOM; + }; + + /** function loads css and js of Menu + * @param callback + */ + this.loadMenu = function(callback) { + return DOM.loadRemote('menu', callback); + }; + + this.uploadFiles = function(dir, files) { + var array, + slice = [].slice, + i = 0, + n = 0, + func = function(name) { + return function() { + CloudCmd.refresh(null, function() { + DOM.setCurrentByName(name); + }); + }; + }, + + percent = function(i, n, per) { + var value; + + if (!per) + per = 100; + + value = Math.round(i * per / n); + + return value; + }, + + step = function(n) { + return 100 / n; + }, + + load = function(file, callback) { + var uploader, + Images = DOM.Images, + name = file.name, + path = dir + name, + prefixURL = CloudCmd.PREFIX_URL, + FS = CloudFunc.FS, + api = prefixURL + FS; + + ++i; + + uploader = DOM.load.put(api + path, file); + uploader.on('progress', function(count) { + var max = step(n), + value = (i - 1) * max + percent(count, 100, max); + + Images.show.load('top'); + Images.setProgress(Math.round(value)); + }); + + uploader.on('end', callback); + }; + + if (!files) { + files = dir; + dir = CurrentInfo.dirPath; + } + + n = files.length; + array = slice.call(files); + + if (n) { + Util.exec.eachSeries(array, load, func(files[0].name)); + } + }; + + /** + * create new folder + * + */ + this.promptNewDir = function() { + promptNew('directory', '?dir'); + }; + + /** + * create new file + * + * @typeName + * @type + */ + this.promptNewFile = function() { + promptNew('file'); + }; + + function promptNew(typeName, type) { + var RESTful = DOM.RESTful, + Dialog = DOM.Dialog, + path = '', + name = Cmd.getCurrentName(), + dir = Cmd.getCurrentDirPath(), + msg = 'New ' + typeName || 'File'; + + if (name === '..') + name = ''; + + Dialog.prompt(TITLE, msg, name, {cancel: false}).then(function(name) { + path = dir + name; + + if (type) + path += type; + + if (name) + RESTful.write(path, function(error) { + !error && CloudCmd.refresh(null, function() { + DOM.setCurrentByName(name); + }); + }); + }); + } + + /** + * get current direcotory name + */ + this.getCurrentDirName = function() { + var ret, + substr, + /* получаем имя каталога в котором находимся */ + href = this.getCurrentDirPath(); + + href = href.replace(/\/$/, ''); + substr = href.substr(href, href.lastIndexOf('/')); + ret = href.replace(substr + '/', '') || '/'; + + return ret; + }; + + /** + * get current direcotory path + */ + this.getCurrentDirPath = function(panel) { + var ret, path; + + if (!panel) + panel = this.getPanel(); + + path = this.getByDataName('js-path', panel); + ret = path && path.textContent; + + return ret; + }; + + /** + * get current direcotory path + */ + this.getParentDirPath = function(panel) { + var path = DOM.getCurrentDirPath(panel), + dirName = DOM.getCurrentDirName() + '/'; + + if (path !== '/') + path = path.replace(RegExp(dirName + '$'), ''); + + return path; + }; + + /** + * get not current direcotory path + */ + this.getNotCurrentDirPath = function() { + var panel = this.getPanel({active: false}), + path = this.getCurrentDirPath(panel); + + return path; + }; + + /** + * unified way to get current file + * + * @currentFile + */ + this.getCurrentFile = function() { + var ret = this.getByClass(CURRENT_FILE); + + return ret; + }; + + /** + * get current file by name + */ + this.getCurrentByName = function(name, panelParam) { + var element, + panel = panelParam || CurrentInfo.panel; + + name = 'js-file-' + name; + element = DOM.getByDataName(name, panel); + + return element; + }; + + /** + * unified way to get current file + * + * @currentFile + */ + this.getSelectedFiles = function() { + var panel = DOM.getPanel(), + selected = this.getByClassAll(SELECTED_FILE, panel), + ret = [].slice.call(selected); + + return ret; + }; + + + /* + * unselect all files + */ + this.unselectFiles = function(files) { + var array, + isArray = Array.isArray(files); + + if (!files) { + array = DOM.getSelectedFiles(); + } else if (!isArray) + array = [].slice.call(files); + + array.forEach(DOM.toggleSelectedFile); + }; + + /** + * get all selected files or current when none selected + * + * @currentFile + */ + this.getActiveFiles = function() { + var current = DOM.getCurrentFile(); + var files = DOM.getSelectedFiles(); + var name = DOM.getCurrentName(current); + + if (!files.length && name !== '..') + return [current]; + + return files; + }; + + /** + * get size + * @currentFile + */ + this.getCurrentSize = function(currentFile) { + var current = currentFile || Cmd.getCurrentFile(), + size = this.getByDataName('js-size', current); + + /* если это папка - возвращаем слово dir вместо размера*/ + size = size + .textContent + .replace(/^<|>$/g, ''); + + return size; + }; + + /** + * get size + * @currentFile + */ + this.loadCurrentSize = function(callback, currentFile) { + var RESTful = DOM.RESTful, + Images = DOM.Images, + current = currentFile || this.getCurrentFile(), + query = '?size', + link = this.getCurrentPath(current); + + Images.show.load(); + + if (name !== '..') + RESTful.read(link + query, function(error, size) { + if (!error) { + DOM.setCurrentSize(size, current); + Util.exec(callback, current); + Images.hide(); + } + }); + }; + + /** + * load hash + * @callback + * @currentFile + */ + this.loadCurrentHash = function(callback, currentFile) { + var RESTful = DOM.RESTful, + current = currentFile || DOM.getCurrentFile(), + query = '?hash', + link = DOM.getCurrentPath(current); + + RESTful.read(link + query, callback); + }; + + /** + * load current modification time of file + * @callback + * @currentFile + */ + this.loadCurrentTime = function(callback, currentFile) { + var RESTful = DOM.RESTful, + current = currentFile || this.getCurrentFile(), + query = '?time', + link = this.getCurrentPath(current); + + RESTful.read(link + query, callback); + }; + + /** + * set size + * @currentFile + */ + this.setCurrentSize = function(size, currentFile) { + var current = currentFile || this.getCurrentFile(), + sizeElement = this.getByDataName('js-size', current); + + sizeElement.textContent = size; + + }; + + /** + * @currentFile + */ + this.getCurrentMode = function(currentFile) { + var ret, + current = currentFile || this.getCurrentFile(), + lMode = this.getByDataName('js-mode', current); + ret = lMode.textContent; + + return ret; + }; + + /** + * @currentFile + */ + this.getCurrentOwner = function(currentFile) { + var ret, + current = currentFile || this.getCurrentFile(), + owner = this.getByDataName('js-owner', current); + + ret = owner.textContent; + + return ret; + }; + + /** + * unified way to get current file content + * + * @param callback + * @param currentFile + */ + this.getCurrentData = function(callback, currentFile) { + var hash, + RESTful = DOM.RESTful, + Dialog = DOM.Dialog, + Info = DOM.CurrentInfo, + current = currentFile || DOM.getCurrentFile(), + path = DOM.getCurrentPath(current), + isDir = DOM.isCurrentIsDir(current), + + func = function(error, data) { + var length, + ONE_MEGABYTE = 1024 * 1024 * 1024; + + if (!error) { + if (itype.object(data)) + data = Util.json.stringify(data); + + length = data.length; + + if (hash && length < ONE_MEGABYTE) + DOM.saveDataToStorage(path, data, hash); + } + + callback(error, data); + }; + + if (Info.name === '..') { + Dialog.alert.noFiles(TITLE); + return callback(Error('No files selected!')); + } + + if (isDir) + return RESTful.read(path, func); + + DOM.checkStorageHash(path, function(error, equal, hashNew) { + if (error) { + callback(error); + } else if (equal) { + DOM.getDataFromStorage(path, callback); + } else { + hash = hashNew; + RESTful.read(path, func); + } + }); + }; + + /** + * unified way to save current file content + * + * @callback - function({data, name}) {} + * @currentFile + */ + this.saveCurrentData = function(url, data, callback, query) { + if (!query) + query = ''; + + DOM.RESTful.write(url + query, data, function(error) { + !error && DOM.saveDataToStorage(url, data); + }); + }; + + /** + * unified way to get RefreshButton + */ + this.getRefreshButton = function(panel) { + var currentPanel = panel || this.getPanel(), + refresh = this.getByDataName('js-refresh', currentPanel); + + return refresh; + }; + + this.setCurrentByName = function(name) { + var current = this.getCurrentByName(name); + return this.setCurrentFile(current); + }; + + /** + * unified way to set current file + */ + this.setCurrentFile = function(currentFile, options) { + var path, pathWas, title, + o = options, + FS = CloudFunc.FS, + CENTER = true, + currentFileWas = this.getCurrentFile(); + + if (currentFile) { + if (currentFileWas) { + pathWas = DOM.getCurrentDirPath(); + unsetCurrentFile(currentFileWas); } - return currentNew; - }; - - /** - * remove selected files from file table - * @Selected - */ - this.deleteSelected = function(selected) { - var i, n, current; + currentFile.classList.add(CURRENT_FILE); - if (!selected) - selected = this.getSelectedFiles(); + path = DOM.getCurrentDirPath(); - if (selected) { - n = selected.length; + if (path !== pathWas) { + title = CloudFunc.getTitle(path); + this.setTitle(title); - for (i = 0; i < n; i++) { - current = selected[i]; - DOM.deleteCurrent(current); + /* history could be present + * but it should be false + * to prevent default behavior + */ + if (!o || o.history !== false) { + if (path !== '/') + path = FS + path; + + DOM.setHistory(path, null, path); } } - return selected; - }; + /* scrolling to current file */ + this.scrollIntoViewIfNeeded(currentFile, CENTER); + + Cmd.updateCurrentInfo(); + } - /** - * rename current file - * - * @currentFile - */ - this.renameCurrent = function(current) { - var from, dirPath, files, isExist, - RESTful = DOM.RESTful, - Dialog = DOM.Dialog; + return this; + }; + + /* + * set current file by position + * + * @param layer - element + * @param - position {x, y} + */ + this.getCurrentByPosition = function(position) { + var element, tag, isChild, + x = position.x, + y = position.y; + + element = document.elementFromPoint(x, y), + tag = element.tagName; + + isChild = /A|SPAN|LI/.test(tag); + + if (!isChild) { + element = null; + } else { + switch (tag) { + case 'A': + element = element.parentElement.parentElement; + break; - if (!Cmd.isCurrentFile(current)) - current = Cmd.getCurrentFile(); + case 'SPAN': + element = element.parentElement; + break; + } + } + + if (element && element.tagName !== 'LI') + element = null; + + return element; + }; + + /** + * select current file + * @param currentFile + */ + this.selectFile = function(currentFile) { + var current = currentFile || DOM.getCurrentFile(); + + current.classList.add(SELECTED_FILE); + + return Cmd; + }; + + this.toggleSelectedFile = function(currentFile) { + var current = currentFile || this.getCurrentFile(); + + current.classList.toggle(SELECTED_FILE); + + return Cmd; + }; + + this.toggleAllSelectedFiles = function() { + DOM.getAllFiles().map(DOM.toggleSelectedFile); + + return Cmd; + }; + + this.selectAllFiles = function() { + DOM.getAllFiles().map(DOM.selectFile); + + return Cmd; + }; + + this.getAllFiles = function() { + var i, + panel = DOM.getPanel(), + files = DOM.getFiles(panel), + name = DOM.getCurrentName(files[0]); + + if (name === '..') + i = 1; + else + i = 0; + + return [].slice.call(files, i); + }; + + function selectByPattern(msg, files) { + var n, regExp, + Dialog = DOM.Dialog, + allMsg = 'Specify file type for ' + msg + ' selection', + i = 0, + matches = 0, + name, + shouldSel = msg === 'expand', + isSelected, isMatch, + current; + + Dialog.prompt(TITLE, allMsg, SelectType, {cancel: false}).then(function(type) { + SelectType = type; - from = Cmd.getCurrentName(current); + regExp = Util.getRegExp(type); - if (from === '..') - Dialog.alert.noFiles(TITLE); - else - Dialog.prompt(TITLE, 'Rename', from, {cancel: false}).then(function(to) { - isExist = !!DOM.getCurrentByName(to); - dirPath = Cmd.getCurrentDirPath(); + n = files && files.length; + for (i = 0; i < n; i++) { + current = files[i]; + name = DOM.getCurrentName(current); - if (from !== to) { - files = { - from : dirPath + from, - to : dirPath + to - }; + if (name !== '..') { + isMatch = regExp.test(name); + + if (isMatch) { + ++matches; - RESTful.mv(files, function(error) { - var Storage = DOM.Storage; - - if (!error) { - DOM.setCurrentName(to, current); - Cmd.updateCurrentInfo(); - Storage.remove(dirPath); - - if (isExist) - CloudCmd.refresh(); - } - }); + isSelected = DOM.isSelected(current); + + if (shouldSel) + isSelected = !isSelected; + + if (isSelected) + DOM.toggleSelectedFile(current); } - }); - }; - - /** - * unified way to scrollIntoViewIfNeeded - * (native suporte by webkit only) - * @param element - * @param pCenter - */ - this.scrollIntoViewIfNeeded = function(element, center) { - var ret = element && element.scrollIntoViewIfNeeded; - - /* for scroll as small as possible - * param should be false - */ - if (arguments.length === 1) - center = false; - - if (ret) - element.scrollIntoViewIfNeeded(center); - - return ret; - }; - - /* scroll on one page*/ - this.scrollByPages = function(element, pPages) { - var ret = element && element.scrollByPages && pPages; - - if (ret) - element.scrollByPages(pPages); - - return ret; - }; - - this.changePanel = function() { - var dataName, files, current, - - panel = DOM.getPanel(), - panelPassive = DOM.getPanel({ - active: false - }), - - name = DOM.getCurrentName(), - - filesPassive = DOM.getFiles(panelPassive); - - dataName = panel.getAttribute('data-name'); - TabPanel[dataName] = name; - - panel = panelPassive; - dataName = panel.getAttribute('data-name'); - - name = TabPanel[dataName]; - - if (name) { - current = DOM.getCurrentByName(name, panel); - - if (current) - files = current.parentElement; + } } - if (!files || !files.parentElement) { - current = DOM.getCurrentByName(name, panel); - - if (!current) - current = filesPassive[0]; - } - - DOM.setCurrentFile(current, { - history: true - }); - - return this; - }; - - this.getPackerExt = function(type) { - if (type === 'zip') - return '.zip'; - - return '.tar.gz'; - }; - - this.goToDirectory = function() { - var msg = 'Go to directory:', - path = CurrentInfo.dirPath, - Dialog = DOM.Dialog; - - Dialog.prompt(TITLE, msg, path, {cancel: false}).then(function(path) { - CloudCmd.loadDir({ - path: path - }); - }); - }, - - this.duplicatePanel = function() { - var isDir = CurrentInfo.isDir; - var path = CurrentInfo.dirPath; - var panel = CurrentInfo.panelPassive; - var noCurrent = !CurrentInfo.isOnePanel; - - if (isDir) - path = CurrentInfo.path; - - CloudCmd.loadDir({ - path: path, - panel: panel, - noCurrent: noCurrent, - }); - }; - - this.swapPanels = function() { - var Info = CurrentInfo, - panel = Info.panel, - panelPassive = Info.panelPassive, - - currentIndex = [].indexOf.call(Info.files, Info.element), - - dirPath = DOM.getCurrentDirPath(), - dirPathPassive = DOM.getNotCurrentDirPath(); - - CloudCmd.loadDir({ - path: dirPath, - panel: panelPassive, - noCurrent: true - }); - - CloudCmd.loadDir({ - path: dirPathPassive, - panel: panel - }, function() { - var el, - files = Info.files, - length = files.length - 1; - - if (currentIndex > length) - currentIndex = length; - - el = files[currentIndex]; - - DOM.setCurrentFile(el); - }); - }; - - this.CurrentInfo = CurrentInfo, - - this.updateCurrentInfo = function(currentFile) { - var info = Cmd.CurrentInfo, - current = currentFile || Cmd.getCurrentFile(), - files = current.parentElement, - panel = files.parentElement, - - panelPassive = Cmd.getPanel({ - active: false - }), - - filesPassive = DOM.getFiles(panelPassive), - - name = Cmd.getCurrentName(current); - - info.dir = Cmd.getCurrentDirName(); - info.dirPath = Cmd.getCurrentDirPath(); - info.parentDirPath = Cmd.getParentDirPath(); - info.element = current; - info.ext = Util.getExt(name); - info.files = [].slice.call(files.children), - info.filesPassive = [].slice.call(filesPassive), - info.first = files.firstChild; - info.getData = Cmd.getCurrentData; - info.last = files.lastChild; - info.link = Cmd.getCurrentLink(current); - info.mode = Cmd.getCurrentMode(current); - info.name = name; - info.path = Cmd.getCurrentPath(current); - info.panel = panel; - info.panelPassive = panelPassive; - info.size = Cmd.getCurrentSize(current); - info.isDir = Cmd.isCurrentIsDir(); - info.isSelected = Cmd.isSelected(current); - info.panelPosition = Cmd.getPanel().dataset.name.replace('js-', ''); - info.isOnePanel = - info.panel.getAttribute('data-name') === - info.panelPassive.getAttribute('data-name'); - }; + if (!matches) + Dialog.alert('Select Files', 'No matches found!'); + }); } -})(Util, window); + + /** + * open dialog with expand selection + */ + this.expandSelection = function() { + var msg = 'expand', + files = CurrentInfo.files; + + selectByPattern(msg, files); + }; + + /** + * open dialog with shrink selection + */ + this.shrinkSelection = function() { + var msg = 'shrink', + files = DOM.getSelectedFiles(); + + selectByPattern(msg, files); + }; + + /** + * setting history wrapper + */ + this.setHistory = function(data, title, url) { + var ret = window.history; + + url = CloudCmd.PREFIX + url; + + if (ret) + history.pushState(data, title, url); + + return ret; + }; + + /** + * set title or create title element + * + * @param name + */ + + this.setTitle = function(name) { + if (!Title) + Title = DOM.getByTag('title')[0] || + DOM.load({ + name : 'title', + innerHTML : name, + parentElement : document.head + }); + + Title.textContent = name; + + return this; + }; + + /** + * current file check + * + * @param currentFile + */ + this.isCurrentFile = function(currentFile) { + var ret; + + if (currentFile) + ret = this.isContainClass(currentFile, CURRENT_FILE); + + return ret; + }; + + /** + * selected file check + * + * @param currentFile + */ + this.isSelected = function(pSelected) { + var ret; + + if (pSelected) + ret = this.isContainClass(pSelected, SELECTED_FILE); + + return ret; + }; + + /** + * check is current file is a directory + * + * @param currentFile + */ + this.isCurrentIsDir = function(currentFile) { + var current = currentFile || this.getCurrentFile(), + fileType = this.getByDataName('js-type', current), + ret = this.isContainClass(fileType, 'directory'); + + return ret; + }; + + /** + * get link from current (or param) file + * + * @param currentFile - current file by default + */ + this.getCurrentLink = function(currentFile) { + var current = currentFile || this.getCurrentFile(), + link = this.getByTag('a', current); + + return link[0]; + }; + + /** + * get link from current (or param) file + * + * @param currentFile - current file by default + */ + this.getCurrentPath = function(currentFile) { + var current = currentFile || DOM.getCurrentFile(), + element = DOM.getByTag('a', current)[0], + path = element.getAttribute('href'), + prefix = CloudCmd.PREFIX, + fs = CloudFunc.FS; + + path = path.replace(RegExp('^' + prefix + fs), ''); + + return path; + }; + + /** + * get name from current (or param) file + * + * @param currentFile + */ + this.getCurrentName = function(currentFile) { + var link, + name = '', + current = currentFile || this.getCurrentFile(); + + if (current) + link = this.getCurrentLink(current); + + if (link) { + name = link.title; + } + + return name; + }; + + this.getFilenames = function(allFiles) { + var first, name, + files, + slice = Array.prototype.slice, + names = []; + + if (!allFiles) + throw Error('AllFiles could not be empty'); + + files = slice.call(allFiles); + first = files[0]; + + if (first) { + name = this.getCurrentName(first); + } else { + first = this.getCurrentFile(); + name = this.getCurrentName(first); + } + + if (name === '..') + files.shift(); + + names = files.map(function(current) { + return DOM.getCurrentName(current); + }); + + return names; + }; + + /** + * set name from current (or param) file + * + * @param name + * @param current + */ + this.setCurrentName = function(name, current) { + var Info = CurrentInfo, + link = Info.link, + FS = CloudFunc.FS, + PREFIX = CloudCmd.PREFIX, + dir = PREFIX + FS + Info.dirPath; + + link.title = name; + link.innerHTML = CloudFunc.Entity.encode(name); + link.href = dir + name; + + current.setAttribute('data-name', 'js-file-' + name); + + return link; + }; + + /** + * check storage hash + */ + this.checkStorageHash = function(name, callback) { + var Storage = DOM.Storage; + var parallel = Util.exec.parallel; + var loadHash = DOM.loadCurrentHash; + var nameHash = name + '-hash'; + var getStoreHash = Util.exec.with(Storage.get, nameHash); + + if (typeof name !== 'string') + throw Error('name should be a string!'); + + if (typeof callback !== 'function') + throw Error('callback should be a function!'); + + parallel([loadHash, getStoreHash], function(error, loadHash, storeHash) { + var equal; + var isContain = /error/.test(loadHash); + + if (isContain) + error = loadHash; + else if (loadHash === storeHash) + equal = true; + + callback(error, equal, loadHash); + }); + }; + + /** + * save data to storage + * + * @param name + * @param data + * @param hash + * @param callback + */ + this.saveDataToStorage = function(name, data, hash, callback) { + var allowed = CloudCmd.config('localStorage'); + var isDir = DOM.isCurrentIsDir(); + var nameHash = name + '-hash'; + var nameData = name + '-data'; + + if (!allowed || isDir) + return Util.exec(callback); + + Util.exec.if(hash, function() { + var Storage = DOM.Storage; + + Storage.set(nameHash, hash); + Storage.set(nameData, data); + + Util.exec(callback, hash); + }, function(callback) { + DOM.loadCurrentHash(function(error, loadHash) { + hash = loadHash; + callback(); + }); + }); + }; + + /** + * save data to storage + * + * @param name + * @param data + * @param callback + */ + this.getDataFromStorage = function(name, callback) { + var Storage = DOM.Storage; + var nameHash = name + '-hash'; + var nameData = name + '-data'; + var allowed = CloudCmd.config('localStorage'); + var isDir = DOM.isCurrentIsDir(); + + if (!allowed || isDir) + return Util.exec(callback); + + Util.exec.parallel([ + exec.with(Storage.get, nameData), + exec.with(Storage.get, nameHash), + ], callback); + }; + + this.getFM = function() { + return this.getPanel().parentElement; + }; + + this.getPanelPosition = function(panel) { + panel = panel || DOM.getPanel(); + + return panel.dataset.name.replace('js-', ''); + }; + + /** function getting panel active, or passive + * @param options = {active: true} + */ + this.getPanel = function(options) { + var files, panel, isLeft, + dataName = 'js-', + current = this.getCurrentFile(); + + if (!current) { + panel = this.getByDataName('js-left'); + } else { + files = current.parentElement, + panel = files.parentElement, + isLeft = panel.getAttribute('data-name') === 'js-left'; + } + + /* if {active : false} getting passive panel */ + if (options && !options.active) { + dataName += isLeft ? 'right' : 'left'; + panel = this.getByDataName(dataName); + } + + /* if two panels showed + * then always work with passive + * panel + */ + if (window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH) + panel = this.getByDataName('js-left'); + + + if (!panel) + throw Error('can not find Active Panel!'); + + return panel; + }; + + this.getFiles = function(element) { + var files = DOM.getByDataName('js-files', element), + ret = files.children || []; + + return ret; + }; + + /** + * shows panel right or left (or active) + */ + this.showPanel = function(active) { + var ret = true, + panel = this.getPanel({active: active}); + + if (panel) + this.show(panel); + else + ret = false; + + return ret; + }; + + /** + * hides panel right or left (or active) + */ + this.hidePanel = function(active) { + var ret = false, + panel = this.getPanel({active: active}); + + if (panel) + ret = this.hide(panel); + + return ret; + }; + + /** + * open window with URL + * @param url + */ + this.openWindow = function(url) { + var left = 140, + top = 187, + width = 1000, + height = 650, + + options = 'left=' + left + + ',top=' + top + + ',width=' + width + + ',height=' + height + + ',personalbar=0,toolbar=0' + + ',scrollbars=1,resizable=1', + + wnd = window.open(url, 'Cloud Commander Auth', options); + + if (!wnd) + DOM.Dialog.alert(TITLE, 'Please disable your popup blocker and try again.'); + + return wnd; + }; + + /** + * remove child of element + * @param pChild + * @param element + */ + this.remove = function(child, element) { + var parent = element || document.body; + + parent.removeChild(child); + + return DOM; + }; + + /** + * remove current file from file table + * @param current + * + */ + this.deleteCurrent = function(current) { + var next, prev, currentNew; + + if (!current) + Cmd.getCurrentFile(); + + var parent = current && current.parentElement; + var name = Cmd.getCurrentName(current); + + if (current && name !== '..') { + next = current.nextSibling, + prev = current.previousSibling; + + if (next) + currentNew = next; + else if (prev) + currentNew = prev; + + DOM.setCurrentFile(currentNew); + + parent.removeChild(current); + } + + return currentNew; + }; + + /** + * remove selected files from file table + * @Selected + */ + this.deleteSelected = function(selected) { + var i, n, current; + + if (!selected) + selected = this.getSelectedFiles(); + + if (selected) { + n = selected.length; + + for (i = 0; i < n; i++) { + current = selected[i]; + DOM.deleteCurrent(current); + } + } + + return selected; + }; + + /** + * rename current file + * + * @currentFile + */ + this.renameCurrent = function(current) { + var from, dirPath, files, isExist, + RESTful = DOM.RESTful, + Dialog = DOM.Dialog; + + if (!Cmd.isCurrentFile(current)) + current = Cmd.getCurrentFile(); + + from = Cmd.getCurrentName(current); + + if (from === '..') + Dialog.alert.noFiles(TITLE); + else + Dialog.prompt(TITLE, 'Rename', from, {cancel: false}).then(function(to) { + isExist = !!DOM.getCurrentByName(to); + dirPath = Cmd.getCurrentDirPath(); + + if (from !== to) { + files = { + from : dirPath + from, + to : dirPath + to + }; + + RESTful.mv(files, function(error) { + var Storage = DOM.Storage; + + if (!error) { + DOM.setCurrentName(to, current); + Cmd.updateCurrentInfo(); + Storage.remove(dirPath); + + if (isExist) + CloudCmd.refresh(); + } + }); + } + }); + }; + + /** + * unified way to scrollIntoViewIfNeeded + * (native suporte by webkit only) + * @param element + * @param pCenter + */ + this.scrollIntoViewIfNeeded = function(element, center) { + var ret = element && element.scrollIntoViewIfNeeded; + + /* for scroll as small as possible + * param should be false + */ + if (arguments.length === 1) + center = false; + + if (ret) + element.scrollIntoViewIfNeeded(center); + + return ret; + }; + + /* scroll on one page*/ + this.scrollByPages = function(element, pPages) { + var ret = element && element.scrollByPages && pPages; + + if (ret) + element.scrollByPages(pPages); + + return ret; + }; + + this.changePanel = function() { + var dataName, files, current, + + panel = DOM.getPanel(), + panelPassive = DOM.getPanel({ + active: false + }), + + name = DOM.getCurrentName(), + + filesPassive = DOM.getFiles(panelPassive); + + dataName = panel.getAttribute('data-name'); + TabPanel[dataName] = name; + + panel = panelPassive; + dataName = panel.getAttribute('data-name'); + + name = TabPanel[dataName]; + + if (name) { + current = DOM.getCurrentByName(name, panel); + + if (current) + files = current.parentElement; + } + + if (!files || !files.parentElement) { + current = DOM.getCurrentByName(name, panel); + + if (!current) + current = filesPassive[0]; + } + + DOM.setCurrentFile(current, { + history: true + }); + + return this; + }; + + this.getPackerExt = function(type) { + if (type === 'zip') + return '.zip'; + + return '.tar.gz'; + }; + + this.goToDirectory = function() { + var msg = 'Go to directory:', + path = CurrentInfo.dirPath, + Dialog = DOM.Dialog; + + Dialog.prompt(TITLE, msg, path, {cancel: false}).then(function(path) { + CloudCmd.loadDir({ + path: path + }); + }); + }, + + this.duplicatePanel = function() { + var isDir = CurrentInfo.isDir; + var path = CurrentInfo.dirPath; + var panel = CurrentInfo.panelPassive; + var noCurrent = !CurrentInfo.isOnePanel; + + if (isDir) + path = CurrentInfo.path; + + CloudCmd.loadDir({ + path: path, + panel: panel, + noCurrent: noCurrent, + }); + }; + + this.swapPanels = function() { + var Info = CurrentInfo, + panel = Info.panel, + panelPassive = Info.panelPassive, + + currentIndex = [].indexOf.call(Info.files, Info.element), + + dirPath = DOM.getCurrentDirPath(), + dirPathPassive = DOM.getNotCurrentDirPath(); + + CloudCmd.loadDir({ + path: dirPath, + panel: panelPassive, + noCurrent: true + }); + + CloudCmd.loadDir({ + path: dirPathPassive, + panel: panel + }, function() { + var el, + files = Info.files, + length = files.length - 1; + + if (currentIndex > length) + currentIndex = length; + + el = files[currentIndex]; + + DOM.setCurrentFile(el); + }); + }; + + this.CurrentInfo = CurrentInfo, + + this.updateCurrentInfo = function(currentFile) { + var info = Cmd.CurrentInfo, + current = currentFile || Cmd.getCurrentFile(), + files = current.parentElement, + panel = files.parentElement, + + panelPassive = Cmd.getPanel({ + active: false + }), + + filesPassive = DOM.getFiles(panelPassive), + + name = Cmd.getCurrentName(current); + + info.dir = Cmd.getCurrentDirName(); + info.dirPath = Cmd.getCurrentDirPath(); + info.parentDirPath = Cmd.getParentDirPath(); + info.element = current; + info.ext = Util.getExt(name); + info.files = [].slice.call(files.children), + info.filesPassive = [].slice.call(filesPassive), + info.first = files.firstChild; + info.getData = Cmd.getCurrentData; + info.last = files.lastChild; + info.link = Cmd.getCurrentLink(current); + info.mode = Cmd.getCurrentMode(current); + info.name = name; + info.path = Cmd.getCurrentPath(current); + info.panel = panel; + info.panelPassive = panelPassive; + info.size = Cmd.getCurrentSize(current); + info.isDir = Cmd.isCurrentIsDir(); + info.isSelected = Cmd.isSelected(current); + info.panelPosition = Cmd.getPanel().dataset.name.replace('js-', ''); + info.isOnePanel = + info.panel.getAttribute('data-name') === + info.panelPassive.getAttribute('data-name'); + }; +} diff --git a/client/edit-file.js b/client/edit-file.js index cc7f43e6..dcd2819d 100644 --- a/client/edit-file.js +++ b/client/edit-file.js @@ -1,189 +1,190 @@ -var CloudCmd, Util, DOM, CloudFunc, MenuIO, Format; +'use strict'; -(function(CloudCmd, Util, DOM) { - 'use strict'; +/* global CloudCmd, DOM, MenuIO, Format */ - CloudCmd.EditFile = function EditFileProto(callback) { - var Info = DOM.CurrentInfo; - var Dialog = DOM.Dialog; - var exec = Util.exec; - var EditFile = this; - var config = CloudCmd.config; - - var Menu, - - TITLE = 'Edit', - - Images = DOM.Images, - MSG_CHANGED, - ConfigView = { - beforeClose: function() { - exec.ifExist(Menu, 'hide'); - isChanged(); - } - }; - - function init(callback) { - var editor; - - exec.series([ - CloudCmd.Edit, - function(callback) { - editor = CloudCmd.Edit.getEditor(); - callback(); - }, - function(callback) { - authCheck(editor); - callback(); - }, - - function(callback) { - setListeners(editor); - callback(); - }, - function(callback) { - EditFile.show(callback); - }, - ], callback); +CloudCmd.EditFile = function EditFileProto(callback) { + var Info = DOM.CurrentInfo; + var Dialog = DOM.Dialog; + var EditFile = this; + var config = CloudCmd.config; + + let Menu; + + const exec = require('execon'); + const TITLE = 'Edit'; + const Images = DOM.Images; + + let MSG_CHANGED; + const ConfigView = { + beforeClose: () => { + exec.ifExist(Menu, 'hide'); + isChanged(); } - - this.show = function() { - Images.show.load(); - - Info.getData(function(error, data) { - var path = Info.path; - var isDir = Info.isDir; - var name = Info.name; - - if (isDir) - name += '.json'; - - if (error) - return Images.hide(); - - setMsgChanged(name); - - CloudCmd.Edit - .getEditor() - .setValueFirst(path, data) - .setModeForPath(name) - .setOption('fontSize', 16) - .enableKey(); - - CloudCmd.Edit.show(ConfigView); - }); - }; - - this.hide = function() { - CloudCmd.Edit.hide(); - }; - - function setListeners(editor) { - var element = CloudCmd.Edit.getElement(); - - DOM.Events.addOnce('contextmenu', element, setMenu); - - editor.on('save', function(value) { - DOM.setCurrentSize(Format.size(value)); - }); - } - - function authCheck(spawn) { - if (!config('auth')) - return; - - spawn.emit('auth', config('username'), config('password')); - spawn.on('reject', function() { - Dialog.alert(TITLE, 'Wrong credentials!'); - }); - } - - function setMenu(event) { - var position = { - x: event.clientX, - y: event.clientY - }; - - event.preventDefault(); - - !Menu && DOM.loadRemote('menu', function(error) { - var noFocus; - var options = { - beforeShow: function(params) { - params.x -= 18; - params.y -= 27; - }, - - afterClick: function() { - !noFocus && editor.focus(); - } - }; - - var editor = CloudCmd.Edit.getEditor(); - - var menuData = { - 'Save Ctrl+S' : function() { - editor.save(); - }, - 'Go To Line Ctrl+G' : function() { - noFocus = true; - editor.goToLine(); - }, - 'Cut Ctrl+X' : function() { - editor.cutToClipboard(); - }, - 'Copy Ctrl+C' : function() { - editor.copyToClipboard(); - }, - 'Paste Ctrl+V' : function() { - editor.pasteFromClipboard(); - }, - 'Delete Del' : function() { - editor.remove('right'); - }, - 'Select All Ctrl+A' : function() { - editor.selectAll(); - }, - 'Beautify Ctrl+B' : function() { - editor.beautify(); - }, - 'Minify Ctrl+M' : function() { - editor.minify(); - }, - 'Close Esc' : function() { - EditFile.hide(); - } - }; - - if (error) - return Dialog.alert(TITLE, error); - - if (Menu || !MenuIO) - return; - - var element = CloudCmd.Edit.getElement(); - - Menu = new MenuIO(element, options, menuData); - Menu.show(position.x, position.y); - }); - } - - function setMsgChanged(name) { - MSG_CHANGED = 'Do you want to save changes to ' + name + '?'; - } - - function isChanged() { - var editor = CloudCmd.Edit.getEditor(); - var is = editor.isChanged(); - - is && Dialog.confirm(TITLE, MSG_CHANGED, {cancel: false}) - .then(function() { - editor.save(); - }); - } - - init(callback); }; -})(CloudCmd, Util, DOM, CloudFunc); + function init(callback) { + var editor; + + exec.series([ + CloudCmd.Edit, + function(callback) { + editor = CloudCmd.Edit.getEditor(); + callback(); + }, + function(callback) { + authCheck(editor); + callback(); + }, + + function(callback) { + setListeners(editor); + callback(); + }, + function(callback) { + EditFile.show(callback); + }, + ], callback); + } + + this.show = function() { + Images.show.load(); + + Info.getData(function(error, data) { + var path = Info.path; + var isDir = Info.isDir; + var name = Info.name; + + if (isDir) + name += '.json'; + + if (error) + return Images.hide(); + + setMsgChanged(name); + + CloudCmd.Edit + .getEditor() + .setValueFirst(path, data) + .setModeForPath(name) + .setOption('fontSize', 16) + .enableKey(); + + CloudCmd.Edit.show(ConfigView); + }); + }; + + this.hide = function() { + CloudCmd.Edit.hide(); + }; + + function setListeners(editor) { + var element = CloudCmd.Edit.getElement(); + + DOM.Events.addOnce('contextmenu', element, setMenu); + + editor.on('save', function(value) { + DOM.setCurrentSize(Format.size(value)); + }); + } + + function authCheck(spawn) { + if (!config('auth')) + return; + + spawn.emit('auth', config('username'), config('password')); + spawn.on('reject', function() { + Dialog.alert(TITLE, 'Wrong credentials!'); + }); + } + + function setMenu(event) { + var position = { + x: event.clientX, + y: event.clientY + }; + + event.preventDefault(); + + !Menu && DOM.loadRemote('menu', function(error) { + var noFocus; + var options = { + beforeShow: function(params) { + params.x -= 18; + params.y -= 27; + }, + + afterClick: function() { + !noFocus && editor.focus(); + } + }; + + var editor = CloudCmd.Edit.getEditor(); + + var menuData = { + 'Save Ctrl+S' : function() { + editor.save(); + }, + 'Go To Line Ctrl+G' : function() { + noFocus = true; + editor.goToLine(); + }, + 'Cut Ctrl+X' : function() { + editor.cutToClipboard(); + }, + 'Copy Ctrl+C' : function() { + editor.copyToClipboard(); + }, + 'Paste Ctrl+V' : function() { + editor.pasteFromClipboard(); + }, + 'Delete Del' : function() { + editor.remove('right'); + }, + 'Select All Ctrl+A' : function() { + editor.selectAll(); + }, + 'Beautify Ctrl+B' : function() { + editor.beautify(); + }, + 'Minify Ctrl+M' : function() { + editor.minify(); + }, + 'Close Esc' : function() { + EditFile.hide(); + } + }; + + if (error) + return Dialog.alert(TITLE, error); + + if (Menu || !MenuIO) + return; + + var element = CloudCmd.Edit.getElement(); + + Menu = new MenuIO(element, options, menuData); + Menu.show(position.x, position.y); + }); + } + + function setMsgChanged(name) { + MSG_CHANGED = 'Do you want to save changes to ' + name + '?'; + } + + function isChanged() { + const editor = CloudCmd.Edit.getEditor(); + const is = editor.isChanged(); + + if (!is) + return; + + const cancel = false; + Dialog.confirm(TITLE, MSG_CHANGED, {cancel}) + .then(() => { + editor.save(); + }); + } + + init(callback); +}; diff --git a/client/edit-names.js b/client/edit-names.js index be6828a5..1f0eee41 100644 --- a/client/edit-names.js +++ b/client/edit-names.js @@ -1,219 +1,216 @@ +'use strict'; + /* global Promise */ +/* global CloudCmd, Util, DOM, MenuIO */ -var CloudCmd, Util, DOM, CloudFunc, MenuIO; - -(function(CloudCmd, Util, DOM) { - 'use strict'; - - CloudCmd.EditNames = function EditNamesProto(callback) { - var Info = DOM.CurrentInfo; - var Dialog = DOM.Dialog; - var exec = Util.exec; - var EditNames = this; - var Menu; - var TITLE = 'Edit Names'; - var ConfigView = { - beforeClose: function() { - exec.ifExist(Menu, 'hide'); - isChanged(); - DOM.Events.remove('keydown', keyListener); - } - }; - - function init(callback) { - var editor; - - exec.series([ - CloudCmd.Edit, - - function(callback) { - editor = CloudCmd.Edit.getEditor(); - callback(); - }, - - function(callback) { - setListeners(editor); - callback(); - }, - - function(callback) { - EditNames.show(); - callback(); - }, - ], callback); +CloudCmd.EditNames = function EditNamesProto(callback) { + var Info = DOM.CurrentInfo; + var Dialog = DOM.Dialog; + var exec = Util.exec; + var EditNames = this; + var Menu; + var TITLE = 'Edit Names'; + var ConfigView = { + beforeClose: () => { + exec.ifExist(Menu, 'hide'); + isChanged(); + DOM.Events.remove('keydown', keyListener); } - - this.show = function() { - var names = getActiveNames().join('\n'); - - if (Info.name === '..' && names.length === 1) - return Dialog.alert.noFiles(TITLE); - - CloudCmd.Edit - .getEditor() - .setValueFirst('edit-names', names) - .setOption('fontSize', 16) - .disableKey(); - - DOM.Events.addKey(keyListener); - CloudCmd.Edit.show(ConfigView); - }; - - function keyListener(event) { - var ctrl = event.ctrlKey; - var meta = event.metaKey; - var ctrlMeta = ctrl || meta; - var Key = CloudCmd.Key; - - if (!ctrlMeta || event.keyCode !== Key.S) - return; - - EditNames.hide(); - } - - function getActiveNames() { - return DOM.getFilenames(DOM.getActiveFiles()); - } - - this.hide = function() { - CloudCmd.Edit.hide(); - }; - - function setListeners() { - var element = CloudCmd.Edit.getElement(); - - DOM.Events.addOnce('contextmenu', element, setMenu); - } - - function applyNames() { - var dir = Info.dirPath; - var from = getActiveNames(); - var nameIndex = from.indexOf(Info.name); - - var editor = CloudCmd.Edit.getEditor(); - var to = editor - .getValue() - .split('\n'); - - var reject = Promise.reject.bind(Promise); - var root = CloudCmd.config('root'); - - Promise.resolve(root) - .then(rename(dir, from, to)) - .then(function(res) { - if (res.status === 404) - return res.text().then(reject); - - CloudCmd.refresh(null, function() { - var name = to[nameIndex]; - DOM.setCurrentByName(name); - }); - }).catch(function(message) { - Dialog.alert(TITLE, message); - }); - } - - function getDir(root, dir) { - if (root === '/') - return dir; - - return root + dir; - } - - function rename(dir, from, to) { - return function(root) { - return fetch(CloudCmd.PREFIX + '/rename', { - method: 'put', - credentials: 'include', - body: JSON.stringify({ - from: from, - to: to, - dir: getDir(root, dir) - }) - }); - }; - } - - function setMenu(event) { - var position = { - x: event.clientX, - y: event.clientY - }; - - event.preventDefault(); - - !Menu && DOM.loadRemote('menu', function(error) { - var noFocus; - var options = { - beforeShow: function(params) { - params.x -= 18; - params.y -= 27; - }, - - afterClick: function() { - !noFocus && editor.focus(); - } - }; - - var editor = CloudCmd.Edit.getEditor(); - - var menuData = { - 'Save Ctrl+S' : function() { - editor.save(); - EditNames.hide(); - }, - 'Go To Line Ctrl+G' : function() { - noFocus = true; - editor.goToLine(); - }, - 'Cut Ctrl+X' : function() { - editor.cutToClipboard(); - }, - 'Copy Ctrl+C' : function() { - editor.copyToClipboard(); - }, - 'Paste Ctrl+V' : function() { - editor.pasteFromClipboard(); - }, - 'Delete Del' : function() { - editor.remove('right'); - }, - 'Select All Ctrl+A' : function() { - editor.selectAll(); - }, - 'Close Esc' : function() { - EditNames.hide(); - } - }; - - if (error) - return Dialog.alert(TITLE, error); - - if (Menu || !MenuIO) - return; - - var element = CloudCmd.Edit.getElement(); - - Menu = new MenuIO(element, options, menuData); - Menu.show(position.x, position.y); - }); - } - - function isChanged() { - var editor = CloudCmd.Edit.getEditor(); - var msg = 'Apply new names?'; - - if (!editor.isChanged()) - return; - - Dialog.confirm(TITLE, msg) - .then(EditNames.hide) - .then(applyNames) - .catch(EditNames.hide); - } - - init(callback); }; -})(CloudCmd, Util, DOM, CloudFunc); + function init(callback) { + var editor; + + exec.series([ + CloudCmd.Edit, + + function(callback) { + editor = CloudCmd.Edit.getEditor(); + callback(); + }, + + function(callback) { + setListeners(editor); + callback(); + }, + + function(callback) { + EditNames.show(); + callback(); + }, + ], callback); + } + + this.show = function() { + var names = getActiveNames().join('\n'); + + if (Info.name === '..' && names.length === 1) + return Dialog.alert.noFiles(TITLE); + + CloudCmd.Edit + .getEditor() + .setValueFirst('edit-names', names) + .setOption('fontSize', 16) + .disableKey(); + + DOM.Events.addKey(keyListener); + CloudCmd.Edit.show(ConfigView); + }; + + function keyListener(event) { + var ctrl = event.ctrlKey; + var meta = event.metaKey; + var ctrlMeta = ctrl || meta; + var Key = CloudCmd.Key; + + if (!ctrlMeta || event.keyCode !== Key.S) + return; + + EditNames.hide(); + } + + function getActiveNames() { + return DOM.getFilenames(DOM.getActiveFiles()); + } + + this.hide = function() { + CloudCmd.Edit.hide(); + }; + + function setListeners() { + var element = CloudCmd.Edit.getElement(); + + DOM.Events.addOnce('contextmenu', element, setMenu); + } + + function applyNames() { + var dir = Info.dirPath; + var from = getActiveNames(); + var nameIndex = from.indexOf(Info.name); + + var editor = CloudCmd.Edit.getEditor(); + var to = editor + .getValue() + .split('\n'); + + var reject = Promise.reject.bind(Promise); + var root = CloudCmd.config('root'); + + Promise.resolve(root) + .then(rename(dir, from, to)) + .then(function(res) { + if (res.status === 404) + return res.text().then(reject); + + CloudCmd.refresh(null, function() { + var name = to[nameIndex]; + DOM.setCurrentByName(name); + }); + }).catch(function(message) { + Dialog.alert(TITLE, message); + }); + } + + function getDir(root, dir) { + if (root === '/') + return dir; + + return root + dir; + } + + function rename(dir, from, to) { + return function(root) { + return fetch(CloudCmd.PREFIX + '/rename', { + method: 'put', + credentials: 'include', + body: JSON.stringify({ + from: from, + to: to, + dir: getDir(root, dir) + }) + }); + }; + } + + function setMenu(event) { + var position = { + x: event.clientX, + y: event.clientY + }; + + event.preventDefault(); + + !Menu && DOM.loadRemote('menu', function(error) { + var noFocus; + var options = { + beforeShow: function(params) { + params.x -= 18; + params.y -= 27; + }, + + afterClick: function() { + !noFocus && editor.focus(); + } + }; + + var editor = CloudCmd.Edit.getEditor(); + + var menuData = { + 'Save Ctrl+S' : function() { + editor.save(); + EditNames.hide(); + }, + 'Go To Line Ctrl+G' : function() { + noFocus = true; + editor.goToLine(); + }, + 'Cut Ctrl+X' : function() { + editor.cutToClipboard(); + }, + 'Copy Ctrl+C' : function() { + editor.copyToClipboard(); + }, + 'Paste Ctrl+V' : function() { + editor.pasteFromClipboard(); + }, + 'Delete Del' : function() { + editor.remove('right'); + }, + 'Select All Ctrl+A' : function() { + editor.selectAll(); + }, + 'Close Esc' : function() { + EditNames.hide(); + } + }; + + if (error) + return Dialog.alert(TITLE, error); + + if (Menu || !MenuIO) + return; + + var element = CloudCmd.Edit.getElement(); + + Menu = new MenuIO(element, options, menuData); + Menu.show(position.x, position.y); + }); + } + + function isChanged() { + var editor = CloudCmd.Edit.getEditor(); + var msg = 'Apply new names?'; + + if (!editor.isChanged()) + return; + + Dialog.confirm(TITLE, msg) + .then(EditNames.hide) + .then(applyNames) + .catch(EditNames.hide); + } + + init(callback); +}; + diff --git a/client/edit.js b/client/edit.js index c5b71e72..70a9837c 100644 --- a/client/edit.js +++ b/client/edit.js @@ -1,136 +1,133 @@ -/* global itype */ +/* global CloudCmd, Util, DOM, CloudFunc */ -var CloudCmd, Util, DOM, CloudFunc; +'use strict'; -(function(CloudCmd, Util, DOM) { - 'use strict'; +const itype = require('itype/legacy'); + +CloudCmd.Edit = EditProto; + +function EditProto(callback) { + var Name = 'Edit'; + var Loading = true; + var EditorName = CloudCmd.config('editor'); - CloudCmd.Edit = EditProto; - - function EditProto(callback) { - var Name = 'Edit'; - var Loading = true; - var EditorName = CloudCmd.config('editor'); + var exec = Util.exec; + var Element, + editor, - var exec = Util.exec; - var Element, - editor, - - ConfigView = { - afterShow: function() { - editor - .moveCursorTo(0, 0) - .focus(); - } - }; - - var Edit = function(fn) { - if (!itype.function(fn)) - return; - - fn(); - }; - - function init(callback) { - var element = createElement(); - - exec.series([ - CloudCmd.View, - function(callback) { - loadFiles(element, callback); - }, - ], callback); - } - - function createElement() { - var element = DOM.load({ - name: 'div', - style: - 'width : 100%;' + - 'height : 100%;' + - 'font-family: "Droid Sans Mono";' + - 'position : absolute;', - notAppend: true - }); - - Element = element; - - return element; - } - - function checkFn(name, fn) { - if (typeof fn !== 'function') - throw Error(name + ' should be a function!'); - } - - function initConfig(config, options) { - Util.copyObj(config, ConfigView); - - if (!options) - return config; - - if (options.afterShow) { - checkFn('options.afterShow', options.afterShow); - - var afterShow = config.afterShow; - - config.afterShow = function() { - afterShow(); - options.afterShow(); - }; + ConfigView = { + afterShow: function() { + editor + .moveCursorTo(0, 0) + .focus(); } - - return config; - } - - Edit.show = function(options) { - if (Loading) - return; - - CloudCmd.View.show(Element, initConfig(options)); }; + + var Edit = function(fn) { + if (!itype.function(fn)) + return; - Edit.getEditor = function() { - return editor; - }; + fn(); + }; + + function init(callback) { + var element = createElement(); - Edit.getElement = function() { - return Element; - }; - - Edit.hide = function() { - CloudCmd.View.hide(); - }; - - function loadFiles(element, callback) { - var prefix = CloudCmd.PREFIX; - var prefixName = prefix + '/' + EditorName; - var url = prefixName + '/' + EditorName + '.js'; - - Util.time(Name + ' load'); - - DOM.load.js(url, function() { - var word = window[EditorName]; - var options = { - maxSize : CloudFunc.MAX_FILE_SIZE, - prefix : prefixName, - socketPath : prefix - }; - - word(element, options, function(ed) { - Util.timeEnd(Name + ' load'); - editor = ed; - Loading = false; - - exec(callback); - }); - }); - } - - init(callback); - - return Edit; + exec.series([ + CloudCmd.View, + function(callback) { + loadFiles(element, callback); + }, + ], callback); } -})(CloudCmd, Util, DOM, CloudFunc); + function createElement() { + var element = DOM.load({ + name: 'div', + style: + 'width : 100%;' + + 'height : 100%;' + + 'font-family: "Droid Sans Mono";' + + 'position : absolute;', + notAppend: true + }); + + Element = element; + + return element; + } + + function checkFn(name, fn) { + if (typeof fn !== 'function') + throw Error(name + ' should be a function!'); + } + + function initConfig(config, options) { + Util.copyObj(config, ConfigView); + + if (!options) + return config; + + if (options.afterShow) { + checkFn('options.afterShow', options.afterShow); + + var afterShow = config.afterShow; + + config.afterShow = function() { + afterShow(); + options.afterShow(); + }; + } + + return config; + } + + Edit.show = function(options) { + if (Loading) + return; + + CloudCmd.View.show(Element, initConfig(options)); + }; + + Edit.getEditor = function() { + return editor; + }; + + Edit.getElement = function() { + return Element; + }; + + Edit.hide = function() { + CloudCmd.View.hide(); + }; + + function loadFiles(element, callback) { + var prefix = CloudCmd.PREFIX; + var prefixName = prefix + '/' + EditorName; + var url = prefixName + '/' + EditorName + '.js'; + + Util.time(Name + ' load'); + + DOM.load.js(url, function() { + var word = window[EditorName]; + var options = { + maxSize : CloudFunc.MAX_FILE_SIZE, + prefix : prefixName, + socketPath : prefix + }; + + word(element, options, function(ed) { + Util.timeEnd(Name + ' load'); + editor = ed; + Loading = false; + + exec(callback); + }); + }); + } + + init(callback); + + return Edit; +} diff --git a/client/events.js b/client/events.js index ff24ca3a..b8abf568 100644 --- a/client/events.js +++ b/client/events.js @@ -1,337 +1,318 @@ -var Util, DOM; +'use strict'; -/* global itype */ +const DOM = require('./dom'); +const itype = require('itype/legacy'); -(function(Util, DOM) { - 'use strict'; +var DOMProto = Object.getPrototypeOf(DOM); + +DOMProto.Events = new EventsProto(); + +function EventsProto() { + const Events = this; - var DOMProto = Object.getPrototypeOf(DOM); - - DOMProto.Events = new EventsProto(); - - function EventsProto() { - var Events = this; - var Type = itype; + function parseArgs(eventName, element, listener, callback) { + var isFunc, isElement, error, + EVENT_NAME = 0, + ELEMENT = 1, + type = itype(eventName); + + switch(type) { + default: + isElement = type.match('element'); - function parseArgs(eventName, element, listener, callback) { - var isFunc, isElement, error, - EVENT_NAME = 0, - ELEMENT = 1, - type = Type(eventName); - - switch(type) { - default: - isElement = type.match('element'); + if (!isElement) { + error = new Error('unknown eventName: ' + type); + throw(error); + } else { + eventName = arguments[ELEMENT]; + element = arguments[EVENT_NAME]; - if (!isElement) { - error = new Error('unknown eventName: ' + type); - throw(error); - } else { - eventName = arguments[ELEMENT]; - element = arguments[EVENT_NAME]; - - parseArgs( - eventName, - element, - listener, - callback - ); - } - break; - - case 'string': - isFunc = Type.function(element); - - if (isFunc) { - listener = element; - element = null; - } - - if (!element) - element = window; - - callback(element, [ + parseArgs( eventName, + element, listener, - false - ]); - break; - - case 'array': - eventName.forEach(function(eventName) { - parseArgs( - eventName, - element, - listener, - callback - ); - }); - break; - - case 'object': - Object.keys(eventName).forEach(function(name) { - var eventListener = eventName[name]; - - parseArgs( - name, - element, - eventListener, - callback - ); - }); - - break; + callback + ); } - } + break; - /** - * safe add event listener - * - * @param type - * @param element {document by default} - * @param listener - */ - this.add = function(type, element, listener) { - checkType(type); + case 'string': + isFunc = itype.function(element); - parseArgs(type, element, listener, function(element, args) { - element.addEventListener.apply(element, args); - }); - - return Events; - }; - - /** - * safe add event listener - * - * @param type - * @param listener - * @param element {document by default} - */ - this.addOnce = function(type, element, listener) { - var once = function (event) { - Events.remove(type, element, once); - listener(event); - }; - - if (!listener) { - listener = element; - element = null; + if (isFunc) { + listener = element; + element = null; } - this.add(type, element, once); + if (!element) + element = window; - return Events; - }; + callback(element, [ + eventName, + listener, + false + ]); + break; - /** - * safe remove event listener - * - * @param type - * @param listener - * @param element {document by default} - */ - this.remove = function(type, element, listener) { - checkType(type); - - parseArgs(type, element, listener, function(element, args) { - element.removeEventListener.apply(element, args); + case 'array': + eventName.forEach(function(eventName) { + parseArgs( + eventName, + element, + listener, + callback + ); }); - - return Events; - }; + break; - /** - * safe add event keydown listener - * - * @param listener - */ - this.addKey = function() { - var name = 'keydown', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.add.apply(this, args); - }; - - /** - * safe remove event click listener - * - * @param listener - */ - this.rmKey = function() { - var name = 'keydown', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.remove.apply(this, args); - }; - - /** - * safe add event click listener - * - * @param listener - */ - this.addClick = function() { - var name = 'click', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.add.apply(this, args); - }; - - /** - * safe remove event click listener - * - * @param listener - */ - this.rmClick = function() { - var name = 'click', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.remove.apply(this, args); - }; - - this.addContextMenu = function() { - var name = 'contextmenu', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.add.apply(this, args); - }; - - /** - * safe add event click listener - * - * @param listener - */ - this.addError = function() { - var name = 'error', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.add.apply(this, args); - }; - - /** - * safe add load click listener - * - * @param listener - */ - this.addLoad = function() { - var name = 'load', - argsArr = [].slice.call(arguments), - args = [name].concat(argsArr); - - return this.add.apply(this, args); - }; - - /** - * crossbrowser create event - * - * @param eventName - * @param keyCode - not necessarily - */ - this.create = function(eventName, keyCode) { - var event = document.createEvent('Event'); - - event.initEvent(eventName, true, true); - - if (keyCode) - event.keyCode = keyCode; - - event.isDefaultPrevented = function() { - return this.defaultPrevented; - }; - - return event; - }; - - /** - * create keydown event - * - * @param keyCode - */ - this.createKey = function(keyCode) { - return this.create('keydown', keyCode); - }; - - /** - * create click event - * - * @param pKeyCode - */ - this.createClick = function() { - return this.create('click'); - }; - - /** - * create click event - * - * @param pKeyCode - */ - this.createDblClick = function() { - return this.create('dblclick'); - }; - - /** - * dispatch event - * - * @param event - */ - this.dispatch = function(event, element) { - var customEvent; - var isStr = Type.string(event); - - if (isStr) - customEvent = Events.create(event); - else - customEvent = event; - - return (element || window).dispatchEvent(customEvent); - }; - - /** - * dispatch keydown event - * - * @param pKeyCode - * @param element - */ - this.dispatchKey = function(keyCode, element) { - var event = this.createKey(keyCode), - ret = this.dispatch(event, element); - - return ret; - }; - - /** - * dispatch click event - * - * @param element - */ - this.dispatchClick = function(element) { - var event = this.createClick(), - ret = this.dispatch(event, element); - - return ret; - }; - - /** - * dispatch dblclick event - * - * @param element - */ - this.dispatchDblClick = function(element) { - var event = this.createDblClick(), - ret = this.dispatch(event, element); - - return ret; - }; - - function checkType(type) { - if (!type) - throw Error('type could not be empty!'); + case 'object': + Object.keys(eventName).forEach(function(name) { + var eventListener = eventName[name]; + + parseArgs( + name, + element, + eventListener, + callback + ); + }); + + break; } } -})(Util, DOM); + + /** + * safe add event listener + * + * @param type + * @param element {document by default} + * @param listener + */ + this.add = function(type, element, listener) { + checkType(type); + + parseArgs(type, element, listener, function(element, args) { + element.addEventListener.apply(element, args); + }); + + return Events; + }; + + /** + * safe add event listener + * + * @param type + * @param listener + * @param element {document by default} + */ + this.addOnce = function(type, element, listener) { + var once = function (event) { + Events.remove(type, element, once); + listener(event); + }; + + if (!listener) { + listener = element; + element = null; + } + + this.add(type, element, once); + + return Events; + }; + + /** + * safe remove event listener + * + * @param type + * @param listener + * @param element {document by default} + */ + this.remove = function(type, element, listener) { + checkType(type); + + parseArgs(type, element, listener, function(element, args) { + element.removeEventListener.apply(element, args); + }); + + return Events; + }; + + /** + * safe add event keydown listener + * + * @param listener + */ + this.addKey = function(...argsArr) { + const name = 'keydown'; + const args = [name].concat(argsArr); + + return this.add(...args); + }; + + /** + * safe remove event click listener + * + * @param listener + */ + this.rmKey = function(...argsArr) { + const name = 'keydown'; + const args = [name].concat(argsArr); + + return this.remove(...args); + }; + + /** + * safe add event click listener + * + * @param listener + */ + this.addClick = function(...argsArr) { + const name = 'click'; + const args = [name].concat(argsArr); + + return this.add(...args); + }; + + /** + * safe remove event click listener + * + * @param listener + */ + this.rmClick = function(...argsArr) { + const name = 'click'; + const args = [name].concat(argsArr); + + return this.remove(...args); + }; + + this.addContextMenu = function(...argsArr) { + const name = 'contextmenu'; + const args = [name].concat(argsArr); + + return this.add(...args); + }; + + /** + * safe add event click listener + * + * @param listener + */ + this.addError = function(...argsArr) { + const name = 'error'; + const args = [name].concat(argsArr); + + return this.add(...args); + }; + + /** + * safe add load click listener + * + * @param listener + */ + this.addLoad = function(...argsArr) { + const name = 'load'; + const args = [name].concat(argsArr); + + return this.add(...args); + }; + + /** + * crossbrowser create event + * + * @param eventName + * @param keyCode - not necessarily + */ + this.create = function(eventName, keyCode) { + var event = document.createEvent('Event'); + + event.initEvent(eventName, true, true); + + if (keyCode) + event.keyCode = keyCode; + + event.isDefaultPrevented = function() { + return this.defaultPrevented; + }; + + return event; + }; + + /** + * create keydown event + * + * @param keyCode + */ + this.createKey = function(keyCode) { + return this.create('keydown', keyCode); + }; + + /** + * create click event + */ + this.createClick = function() { + return this.create('click'); + }; + + /** + * create click event + */ + this.createDblClick = function() { + return this.create('dblclick'); + }; + + /** + * dispatch event + * + * @param event + */ + this.dispatch = function(event, element) { + var customEvent; + var isStr = itype.string(event); + + if (isStr) + customEvent = Events.create(event); + else + customEvent = event; + + return (element || window).dispatchEvent(customEvent); + }; + + /** + * dispatch keydown event + * + * @param keyCode + * @param element + */ + this.dispatchKey = function(keyCode, element) { + const event = this.createKey(keyCode); + return this.dispatch(event, element); + }; + + /** + * dispatch click event + * + * @param element + */ + this.dispatchClick = function(element) { + const event = this.createClick(); + return this.dispatch(event, element); + }; + + /** + * dispatch dblclick event + * + * @param element + */ + this.dispatchDblClick = function(element) { + const event = this.createDblClick(); + + return this.dispatch(event, element); + }; + + function checkType(type) { + if (!type) + throw Error('type could not be empty!'); + } +} + diff --git a/client/files.js b/client/files.js index 02983525..1389ae28 100644 --- a/client/files.js +++ b/client/files.js @@ -1,171 +1,171 @@ /* global Promise */ -/* global itype */ -/* global Util, DOM, CloudCmd */ +/* global Util, CloudCmd */ -(function(Util, DOM) { - 'use strict'; +'use strict'; + +const DOM = require('./dom'); + +var DOMProto = Object.getPrototypeOf(DOM); +DOMProto.Files = new FilesProto(Util, DOM); + +const itype = require('itype/legacy'); + +function FilesProto(Util, DOM) { + var Promises = {}, + Storage = DOM.Storage, + Files = this, + FILES_JSON = 'config|modules', + FILES_HTML = 'file|path|link|pathLink|media', + FILES_HTML_ROOT = 'view/media-tmpl|config-tmpl|upload', + funcs = [], + DIR_HTML = '/tmpl/', + DIR_HTML_FS = DIR_HTML + 'fs/', + DIR_JSON = '/json/', + timeout = getTimeoutOnce(2000); - var DOMProto = Object.getPrototypeOf(DOM); - - DOMProto.Files = new FilesProto(Util, DOM); - - function FilesProto(Util, DOM) { - var Promises = {}, - Storage = DOM.Storage, - Files = this, - FILES_JSON = 'config|modules', - FILES_HTML = 'file|path|link|pathLink|media', - FILES_HTML_ROOT = 'view/media-tmpl|config-tmpl|upload', - funcs = [], - DIR_HTML = '/tmpl/', - DIR_HTML_FS = DIR_HTML + 'fs/', - DIR_JSON = '/json/', - timeout = getTimeoutOnce(2000); + this.get = function(name, callback) { + var type = itype(name); - this.get = function(name, callback) { - var type = itype(name); - - check(name, callback); - - switch(type) { - case 'string': - getModule(name, callback); - break; - - case 'array': - funcs = name.map(function(name) { - return function(callback) { - Files.get(name, callback); - }; - }); - - Util.exec.parallel(funcs, callback); - break; - } - - return Files; - }; + check(name, callback); - function check(name, callback) { - if (!name) - throw Error('name could not be empty!'); - - if (typeof callback !== 'function') - throw Error('callback should be a function'); - } + switch(type) { + case 'string': + getModule(name, callback); + break; - function getModule(name, callback) { - var path, - - regExpHTML = new RegExp(FILES_HTML + '|' + FILES_HTML_ROOT), - regExpJSON = new RegExp(FILES_JSON), - - isHTML = regExpHTML.test(name), - isJSON = regExpJSON.test(name); - - if (!isHTML && !isJSON) { - showError(name); - } else if (name === 'config') { - getConfig(callback); - } else { - path = getPath(name, isHTML, isJSON); - - getSystemFile(path, callback); - } - - } - - function getPath(name, isHTML, isJSON) { - var path, - regExp = new RegExp(FILES_HTML_ROOT), - isRoot = regExp.test(name); - - if (isHTML) { - if (isRoot) - path = DIR_HTML + name.replace('-tmpl', ''); - else - path = DIR_HTML_FS + name; - - path += '.hbs'; - } else if (isJSON) { - path = DIR_JSON + name + '.json'; - } - - return path; - } - - function showError(name) { - var str = 'Wrong file name: ' + name, - error = new Error(str); - - throw(error); - } - - function getSystemFile(url, callback) { - var prefix = CloudCmd.PREFIX; - - if (!Promises[url]) - Promises[url] = new Promise(function(resolve, reject) { - DOM.load.ajax({ - url : prefix + url, - success : resolve, - error : reject - }); - }); - - Promises[url].then(function(data) { - callback(null, data); - }, function(error) { - Promises[url] = null; - callback(error); + case 'array': + funcs = name.map(function(name) { + return function(callback) { + Files.get(name, callback); + }; }); + + Util.exec.parallel(funcs, callback); + break; } - function getConfig(callback) { - var is, - RESTful = DOM.RESTful; + return Files; + }; + + function check(name, callback) { + if (!name) + throw Error('name could not be empty!'); + + if (typeof callback !== 'function') + throw Error('callback should be a function'); + } + + function getModule(name, callback) { + var path, - if (!Promises.config) - Promises.config = new Promise(function(resolve, reject) { - is = true; - RESTful.Config.read(function(error, data) { - if (error) - reject(error); - else - resolve(data); - }); - }); + regExpHTML = new RegExp(FILES_HTML + '|' + FILES_HTML_ROOT), + regExpJSON = new RegExp(FILES_JSON), - Promises.config.then(function(data) { - is = false; - Storage.setAllowed(data.localStorage); - - callback(null, data); - - timeout(function() { - if (!is) - Promises.config = null; + isHTML = regExpHTML.test(name), + isJSON = regExpJSON.test(name); + + if (!isHTML && !isJSON) { + showError(name); + } else if (name === 'config') { + getConfig(callback); + } else { + path = getPath(name, isHTML, isJSON); + + getSystemFile(path, callback); + } + + } + + function getPath(name, isHTML, isJSON) { + var path, + regExp = new RegExp(FILES_HTML_ROOT), + isRoot = regExp.test(name); + + if (isHTML) { + if (isRoot) + path = DIR_HTML + name.replace('-tmpl', ''); + else + path = DIR_HTML_FS + name; + + path += '.hbs'; + } else if (isJSON) { + path = DIR_JSON + name + '.json'; + } + + return path; + } + + function showError(name) { + var str = 'Wrong file name: ' + name, + error = new Error(str); + + throw(error); + } + + function getSystemFile(url, callback) { + var prefix = CloudCmd.PREFIX; + + if (!Promises[url]) + Promises[url] = new Promise(function(resolve, reject) { + DOM.load.ajax({ + url : prefix + url, + success : resolve, + error : reject }); - }, function() { + }); + + Promises[url].then(function(data) { + callback(null, data); + }, function(error) { + Promises[url] = null; + callback(error); + }); + } + + function getConfig(callback) { + var is, + RESTful = DOM.RESTful; + + if (!Promises.config) + Promises.config = new Promise(function(resolve, reject) { + is = true; + RESTful.Config.read(function(error, data) { + if (error) + reject(error); + else + resolve(data); + }); + }); + + Promises.config.then(function(data) { + is = false; + Storage.setAllowed(data.localStorage); + + callback(null, data); + + timeout(function() { if (!is) Promises.config = null; }); - } - - function getTimeoutOnce(time) { - var is, - fn = function(callback) { - if (!is) { - is = true; - - setTimeout(function() { - is = false; - callback(); - }, time); - } - }; - - return fn; - } + }, function() { + if (!is) + Promises.config = null; + }); } -})(Util, DOM); + + function getTimeoutOnce(time) { + var is, + fn = function(callback) { + if (!is) { + is = true; + + setTimeout(function() { + is = false; + callback(); + }, time); + } + }; + + return fn; + } +} diff --git a/client/help.js b/client/help.js index ad66def7..1d8a3e6b 100644 --- a/client/help.js +++ b/client/help.js @@ -1,33 +1,31 @@ -var CloudCmd, Util, DOM; +'use strict'; -(function(CloudCmd, Util, DOM) { - 'use strict'; +/* global DOM, CloudCmd */ + +window.CloudCmd.Help = HelpProto; + +function HelpProto() { + const Images = DOM.Images; + const Help = this; - CloudCmd.Help = HelpProto; - - function HelpProto() { - var Images = DOM.Images, - Help = this; - - function init() { - Images.show.load('top'); - Help.show(); - } - - this.show = function() { - CloudCmd - .Markdown - .show('/HELP.md', { - positionLoad : 'top', - relative : true - }); - }; - - this.hide = function() { - CloudCmd.View.hide(); - }; - - init(); + function init() { + Images.show.load('top'); + Help.show(); } -})(CloudCmd, Util, DOM); + this.show = () => { + CloudCmd + .Markdown + .show('/HELP.md', { + positionLoad : 'top', + relative : true + }); + }; + + this.hide = () => { + CloudCmd.View.hide(); + }; + + init(); +} + diff --git a/client/input.js b/client/input.js index 16e18260..b651e15f 100644 --- a/client/input.js +++ b/client/input.js @@ -1,125 +1,120 @@ -(function(global) { - 'use strict'; +'use strict'; + +module.exports = InputProto(); + +function InputProto() { + if (!(this instanceof InputProto)) + return new InputProto(); - if (typeof module !== 'undefined' && module.exports) - module.exports = InputProto(); - else - global.input = InputProto(); + this.setValue = setValue; + this.getValue = getValue; + this.convert = convert; + this.getName = getName; + this.getElementByName = getElementByName; + + function getElementByName(selector, element) { + var el = element.querySelector('[data-name="js-' + selector + '"]'); - function InputProto() { - if (!(this instanceof InputProto)) - return new InputProto(); + return el; + } - this.setValue = setValue; - this.getValue = getValue; - this.convert = convert; - this.getName = getName; - this.getElementByName = getElementByName; + function getName(element) { + var name = element + .getAttribute('data-name') + .replace(/^js-/, ''); - function getElementByName(selector, element) { - var el = element.querySelector('[data-name="js-' + selector + '"]'); - - return el; - } - - function getName(element) { - var name = element - .getAttribute('data-name') - .replace(/^js-/, ''); - - return name; - } - - function convert(config) { - var result = clone(config), - array = Object.keys(result), - isBool = partial(isType, result, 'boolean'); - - array - .filter(isBool) - .forEach(function(name) { - var item = result[name]; - - result[name] = setState(item); - }); - - return result; - } - - function clone(object) { - var result = {}; - - Object.keys(object).forEach(function(name) { - result[name] = object[name]; - }); - - return result; - } - - function partial(fn) { - var i, - bind = Function.prototype.bind, - n = arguments.length, - args = Array(n - 1); - - args[0] = null; - - for (i = 1; i < n; i++) - args[i] = arguments[i]; - - return bind.apply(fn, args); - } - - function isType(object, type, name) { - var current = typeof object[name], - is = current === type; - - return is; - } - - function setState(state) { - var ret = ''; - - if (state) - ret = ' checked'; - - return ret; - } - - function getValue(name, element) { - var data, - el = getElementByName(name, element), - type = el.type; - - switch(type) { - case 'checkbox': - data = el.checked; - break; - case 'number': - data = Number(el.value); - break; - default: - data = el.value; - break; - } - - return data; - } - - function setValue(name, value, element) { - var el = getElementByName(name, element), - type = el.type; - - switch(type) { - case 'checkbox': - el.checked = value; - break; - - default: - el.value = value; - break; - } - } + return name; } -})(window); + function convert(config) { + var result = clone(config), + array = Object.keys(result), + isBool = partial(isType, result, 'boolean'); + + array + .filter(isBool) + .forEach(function(name) { + var item = result[name]; + + result[name] = setState(item); + }); + + return result; + } + + function clone(object) { + var result = {}; + + Object.keys(object).forEach(function(name) { + result[name] = object[name]; + }); + + return result; + } + + function partial(fn) { + var i, + bind = Function.prototype.bind, + n = arguments.length, + args = Array(n - 1); + + args[0] = null; + + for (i = 1; i < n; i++) + args[i] = arguments[i]; + + return bind.apply(fn, args); + } + + function isType(object, type, name) { + var current = typeof object[name], + is = current === type; + + return is; + } + + function setState(state) { + var ret = ''; + + if (state) + ret = ' checked'; + + return ret; + } + + function getValue(name, element) { + var data, + el = getElementByName(name, element), + type = el.type; + + switch(type) { + case 'checkbox': + data = el.checked; + break; + case 'number': + data = Number(el.value); + break; + default: + data = el.value; + break; + } + + return data; + } + + function setValue(name, value, element) { + var el = getElementByName(name, element), + type = el.type; + + switch(type) { + case 'checkbox': + el.checked = value; + break; + + default: + el.value = value; + break; + } + } +} + diff --git a/client/key.js b/client/key.js index 13e88d06..09f370c0 100644 --- a/client/key.js +++ b/client/key.js @@ -1,566 +1,564 @@ -var CloudCmd, Util, DOM; +/* global CloudCmd, Util, DOM */ -(function(CloudCmd, Util, DOM) { - 'use strict'; +'use strict'; + +var Info = DOM.CurrentInfo, + Events = DOM.Events, + Buffer = DOM.Buffer, - var Info = DOM.CurrentInfo, - Events = DOM.Events, - Buffer = DOM.Buffer, + Chars = [], + KEY = { + BACKSPACE : 8, + TAB : 9, + ENTER : 13, + ESC : 27, - Chars = [], - KEY = { - BACKSPACE : 8, - TAB : 9, - ENTER : 13, - ESC : 27, - - SPACE : 32, - PAGE_UP : 33, - PAGE_DOWN : 34, - END : 35, - HOME : 36, - - LEFT : 37, - UP : 38, - RIGHT : 39, - DOWN : 40, - - INSERT : 45, - DELETE : 46, - - ZERO : 48, - - A : 65, - - C : 67, - D : 68, - - G : 71, - - M : 77, - - O : 79, - Q : 81, - R : 82, - S : 83, - T : 84, - U : 85, - - V : 86, - - X : 88, - - Z : 90, - - INSERT_MAC : 96, - - ASTERISK : 106, - PLUS : 107, - MINUS : 109, - - F1 : 112, - F2 : 113, - F3 : 114, - F4 : 115, - F5 : 116, - F6 : 117, - F7 : 118, - F8 : 119, - F9 : 120, - F10 : 121, - - EQUAL : 187, - HYPHEN : 189, - DOT : 190, - SLASH : 191, - TRA : 192, /* Typewritten Reverse Apostrophe (`) */ - BACKSLASH : 220, - - BRACKET_CLOSE: 221 - }; + SPACE : 32, + PAGE_UP : 33, + PAGE_DOWN : 34, + END : 35, + HOME : 36, + + LEFT : 37, + UP : 38, + RIGHT : 39, + DOWN : 40, + + INSERT : 45, + DELETE : 46, + + ZERO : 48, + + A : 65, + + C : 67, + D : 68, + + G : 71, + + M : 77, + + O : 79, + Q : 81, + R : 82, + S : 83, + T : 84, + U : 85, + + V : 86, + + X : 88, + + Z : 90, + + INSERT_MAC : 96, + + ASTERISK : 106, + PLUS : 107, + MINUS : 109, + + F1 : 112, + F2 : 113, + F3 : 114, + F4 : 115, + F5 : 116, + F6 : 117, + F7 : 118, + F8 : 119, + F9 : 120, + F10 : 121, + + EQUAL : 187, + HYPHEN : 189, + DOT : 190, + SLASH : 191, + TRA : 192, /* Typewritten Reverse Apostrophe (`) */ + BACKSLASH : 220, + + BRACKET_CLOSE: 221 + }; + +KeyProto.prototype = KEY; +CloudCmd.Key = KeyProto; + +function KeyProto() { + var Key = this, + Binded; - KeyProto.prototype = KEY; - CloudCmd.Key = KeyProto; + this.isBind = function() { + return Binded; + }; - function KeyProto() { - var Key = this, - Binded; + this.setBind = function() { + Binded = true; + }; + + this.unsetBind = function() { + Binded = false; + }; + + this.bind = function() { + Events.addKey(listener); + Binded = true; + }; + + function listener(event) { + /* get selected file */ + var keyCode = event.keyCode, + alt = event.altKey, + ctrl = event.ctrlKey, + shift = event.shiftKey, + meta = event.metaKey, + isBetween = keyCode >= KEY.ZERO && keyCode <= KEY.Z, + isNumpad = /Numpad/.test(event.code), + isSymbol, + char = ''; - this.isBind = function() { - return Binded; - }; + /* + * event.keyIdentifier deprecated in chrome v51 + * but event.key is absent in chrome <= v51 + */ - this.setBind = function() { - Binded = true; - }; + if (event.key) + char = event.key; + else + char = fromCharCode(event.keyIdentifier); - this.unsetBind = function() { - Binded = false; - }; + isSymbol = ~['.', '_', '-', '+', '='].indexOf(char); - this.bind = function() { - Events.addKey(listener); - Binded = true; - }; - - function listener(event) { - /* get selected file */ - var keyCode = event.keyCode, - alt = event.altKey, - ctrl = event.ctrlKey, - shift = event.shiftKey, - meta = event.metaKey, - isBetween = keyCode >= KEY.ZERO && keyCode <= KEY.Z, - isNumpad = /Numpad/.test(event.code), - isSymbol, - char = ''; + if (!isSymbol) { + isSymbol = getSymbol(shift, keyCode); - /* - * event.keyIdentifier deprecated in chrome v51 - * but event.key is absent in chrome <= v51 - */ + if (isSymbol) + char = isSymbol; + } + + /* in case buttons can be processed */ + if (Key.isBind()) + if (!isNumpad && !alt && !ctrl && !meta && (isBetween || isSymbol)) + setCurrentByChar(char); + else { + Chars = []; + switchKey(event); + } + } + + function getSymbol(shift, keyCode) { + var char; + + switch (keyCode) { + case KEY.DOT: + char = '.'; + break; + + case KEY.HYPHEN: + char = shift ? '_' : '-'; + break; + + case KEY.EQUAL: + char = shift ? '+' : '='; + break; + } + + return char; + } + + function fromCharCode(keyIdentifier) { + var code = keyIdentifier.substring(2), + hex = parseInt(code, 16), + char = String.fromCharCode(hex); - if (event.key) - char = event.key; + return char; + } + + function setCurrentByChar(char) { + var firstByName, + skipCount = 0, + skipN = 0, + setted = false, + files = Info.files, + escapeChar = Util.escapeRegExp(char), + regExp = new RegExp('^' + escapeChar + '.*$', 'i'), + i = 0, + n = Chars.length; + + while(i < n && char === Chars[i]) { + i++; + } + + if (!i) + Chars = []; + + skipN = skipCount = i; + Chars.push(char); + + var names = DOM.getFilenames(files); + + names.filter(function(name) { + var isMatch = name.match(regExp); + + if (isMatch && name !== '..') + return true; + }).some(function(name) { + var byName = DOM.getCurrentByName(name); + + if (!skipCount) { + setted = true; + DOM.setCurrentFile(byName); + return true; + } else { + if (skipN === skipCount) + firstByName = byName; + + --skipCount; + } + }); + + if (!setted) { + DOM.setCurrentFile(firstByName); + Chars = [char]; + } + } + + function switchKey(event) { + var i, name, isSelected, isDir, prev, next, + Operation = CloudCmd.Operation, + current = Info.element, + panel = Info.panel, + path = Info.path, + keyCode = event.keyCode, + alt = event.altKey, + shift = event.shiftKey, + ctrl = event.ctrlKey, + meta = event.metaKey, + ctrlMeta = ctrl || meta; + + if (current) { + prev = current.previousSibling; + next = current.nextSibling; + } + + switch (keyCode) { + case Key.TAB: + DOM.changePanel(); + event.preventDefault(); + break; + + case Key.INSERT: + DOM .toggleSelectedFile(current) + .setCurrentFile(next); + break; + + case Key.INSERT_MAC: + DOM .toggleSelectedFile(current) + .setCurrentFile(next); + break; + + case Key.DELETE: + if (shift) + Operation.show('delete:silent'); else - char = fromCharCode(event.keyIdentifier); - - isSymbol = ~['.', '_', '-', '+', '='].indexOf(char); - - if (!isSymbol) { - isSymbol = getSymbol(shift, keyCode); - - if (isSymbol) - char = isSymbol; - } - - /* in case buttons can be processed */ - if (Key.isBind()) - if (!isNumpad && !alt && !ctrl && !meta && (isBetween || isSymbol)) - setCurrentByChar(char); - else { - Chars = []; - switchKey(event); - } - } + Operation.show('delete'); + break; - function getSymbol(shift, keyCode) { - var char; - - switch (keyCode) { - case KEY.DOT: - char = '.'; - break; - - case KEY.HYPHEN: - char = shift ? '_' : '-'; - break; - - case KEY.EQUAL: - char = shift ? '+' : '='; - break; - } - - return char; - } + case Key.ASTERISK: + DOM.toggleAllSelectedFiles(current); + break; - function fromCharCode(keyIdentifier) { - var code = keyIdentifier.substring(2), - hex = parseInt(code, 16), - char = String.fromCharCode(hex); - - return char; - } + case Key.PLUS: + DOM.expandSelection(); + event.preventDefault(); + break; - function setCurrentByChar(char) { - var firstByName, - skipCount = 0, - skipN = 0, - setted = false, - files = Info.files, - escapeChar = Util.escapeRegExp(char), - regExp = new RegExp('^' + escapeChar + '.*$', 'i'), - i = 0, - n = Chars.length; + case Key.MINUS: + DOM.shrinkSelection(); + event.preventDefault(); + break; + + case Key.F1: + CloudCmd.Help.show(); + event.preventDefault(); + break; + + case Key.F2: + DOM.renameCurrent(current); + break; - while(i < n && char === Chars[i]) { - i++; - } + case Key.F3: + if (shift) + CloudCmd.Markdown.show(path); + else if (ctrlMeta) + CloudCmd.sortPanel('name'); + else + CloudCmd.View.show(); - if (!i) - Chars = []; + event.preventDefault(); + break; + + case Key.F4: + CloudCmd.EditFile.show(); + event.preventDefault(); + break; + + case Key.F5: + if (ctrlMeta) + CloudCmd.sortPanel('date'); + else + Operation.show('copy'); - skipN = skipCount = i; - Chars.push(char); + event.preventDefault(); + break; + + case Key.F6: + if (ctrlMeta) + CloudCmd.sortPanel('size'); + else + Operation.show('move'); - var names = DOM.getFilenames(files); + event.preventDefault(); + break; + + case Key.F7: + if (shift) + DOM.promptNewFile(); + else + DOM.promptNewDir(); - names.filter(function(name) { - var isMatch = name.match(regExp); + event.preventDefault(); + break; + + case Key.F8: + Operation.show('delete'); + event.preventDefault(); + break; + + case Key.F9: + CloudCmd.Menu.show(); + event.preventDefault(); + break; + + case Key.F10: + CloudCmd.Config.show(); + event.preventDefault(); + break; + + case Key.TRA: + CloudCmd.Konsole.show(); + event.preventDefault(); + break; + + case KEY.BRACKET_CLOSE: + CloudCmd.Konsole.show(); + event.preventDefault(); + break; + + case Key.SPACE: + isDir = Info.isDir, + name = Info.name; + + if (!isDir || name === '..') + isSelected = true; + else + isSelected = DOM.isSelected(current); - if (isMatch && name !== '..') - return true; - }).some(function(name) { - var byName = DOM.getCurrentByName(name); - - if (!skipCount) { - setted = true; - DOM.setCurrentFile(byName); - return true; - } else { - if (skipN === skipCount) - firstByName = byName; - - --skipCount; - } + Util.exec.if(isSelected, function() { + DOM.toggleSelectedFile(current); + }, function(callback) { + DOM.loadCurrentSize(callback, current); }); - if (!setted) { - DOM.setCurrentFile(firstByName); - Chars = [char]; - } - } + event.preventDefault(); + break; - function switchKey(event) { - var i, name, isSelected, isDir, prev, next, - Operation = CloudCmd.Operation, - current = Info.element, - panel = Info.panel, - path = Info.path, - keyCode = event.keyCode, - alt = event.altKey, - shift = event.shiftKey, - ctrl = event.ctrlKey, - meta = event.metaKey, - ctrlMeta = ctrl || meta; + case Key.U: + if (ctrlMeta) { + DOM.swapPanels(); + event.preventDefault(); + } + break; + + /* navigation on file table: * + * in case of pressing button 'up', * + * select previous row */ + case Key.UP: + if (shift) + DOM.toggleSelectedFile(current); - if (current) { - prev = current.previousSibling; - next = current.nextSibling; + DOM.setCurrentFile(prev); + event.preventDefault(); + break; + + /* in case of pressing button 'down', * + * select next row */ + case Key.DOWN: + if (shift) + DOM.toggleSelectedFile(current); + + DOM.setCurrentFile(next); + event.preventDefault(); + break; + + case Key.LEFT: + if (!alt) + return; + + event.preventDefault(); + + name = Info.panel.getAttribute('data-name'); + + if (name === 'js-right') + DOM.duplicatePanel(); + + break; + + case Key.RIGHT: + if (!alt) + return; + + event.preventDefault(); + + name = Info.panel.getAttribute('data-name'); + + if (name === 'js-left') + DOM.duplicatePanel(); + + break; + + /* in case of pressing button 'Home', * + * go to top element */ + case Key.HOME: + DOM.setCurrentFile(Info.first); + event.preventDefault(); + break; + + /* in case of pressing button 'End', select last element */ + case Key.END: + DOM.setCurrentFile(Info.last); + event.preventDefault(); + break; + + /* если нажали клавишу page down проматываем экран */ + case Key.PAGE_DOWN: + DOM.scrollByPages(panel, 1); + + for (i = 0; i < 30; i++) { + if (!current.nextSibling) + break; + + current = current.nextSibling; } - switch (keyCode) { - case Key.TAB: - DOM.changePanel(); - event.preventDefault(); - break; + DOM.setCurrentFile(current); + event.preventDefault(); + break; + + /* если нажали клавишу page up проматываем экран */ + case Key.PAGE_UP: + DOM.scrollByPages(panel, -1); - case Key.INSERT: - DOM .toggleSelectedFile(current) - .setCurrentFile(next); - break; - - case Key.INSERT_MAC: - DOM .toggleSelectedFile(current) - .setCurrentFile(next); - break; - - case Key.DELETE: - if (shift) - Operation.show('delete:silent'); - else - Operation.show('delete'); - break; - - case Key.ASTERISK: - DOM.toggleAllSelectedFiles(current); - break; - - case Key.PLUS: - DOM.expandSelection(); - event.preventDefault(); - break; - - case Key.MINUS: - DOM.shrinkSelection(); - event.preventDefault(); - break; - - case Key.F1: - CloudCmd.Help.show(); - event.preventDefault(); - break; - - case Key.F2: - DOM.renameCurrent(current); - break; + for (i = 0; i < 30; i++) { + if (!current.previousSibling) + break; - case Key.F3: - if (shift) - CloudCmd.Markdown.show(path); - else if (ctrlMeta) - CloudCmd.sortPanel('name'); - else - CloudCmd.View.show(); + current = current.previousSibling; + } + + DOM.setCurrentFile(current); + event.preventDefault(); + break; + + /* open directory */ + case Key.ENTER: + if (Info.isDir) + CloudCmd.loadDir({ + path: path === '/' ? '/' : path + '/' + }); + break; + + case Key.BACKSPACE: + CloudCmd.goToParentDir(); + event.preventDefault(); + break; + + case Key.BACKSLASH: + if (ctrlMeta) + CloudCmd.loadDir({ + path: '/' + }); + break; + + case Key.A: + if (ctrlMeta) { + DOM.selectAllFiles(); + event.preventDefault(); + } + + break; + + case Key.G: + if (alt) { + DOM.goToDirectory(); + event.preventDefault(); + } + + break; + + case Key.M: + if (ctrlMeta) { + CloudCmd.EditNames.show(); + event.preventDefault(); + } + + break; + + /** + * обновляем страницу, + * загружаем содержимое каталога + * при этом данные берём всегда с + * сервера, а не из кэша + * (обновляем кэш) + */ + case Key.R: + if (ctrlMeta) { + CloudCmd.log('reloading page...\n'); + CloudCmd.refresh(); + event.preventDefault(); + } + break; + + case Key.C: + if (ctrlMeta) + Buffer.copy(); + break; + + case Key.X: + if (ctrlMeta) + Buffer.cut(); + break; + + case Key.V: + if (ctrlMeta) + Buffer.paste(); + break; + + case Key.Z: + if (ctrlMeta) + Buffer.clear(); + break; + + /* чистим хранилище */ + case Key.D: + if (ctrlMeta) { + CloudCmd.log('clearing storage...'); - event.preventDefault(); - break; - - case Key.F4: - CloudCmd.EditFile.show(); - event.preventDefault(); - break; - - case Key.F5: - if (ctrlMeta) - CloudCmd.sortPanel('date'); - else - Operation.show('copy'); - - event.preventDefault(); - break; - - case Key.F6: - if (ctrlMeta) - CloudCmd.sortPanel('size'); - else - Operation.show('move'); - - event.preventDefault(); - break; - - case Key.F7: - if (shift) - DOM.promptNewFile(); - else - DOM.promptNewDir(); - - event.preventDefault(); - break; - - case Key.F8: - Operation.show('delete'); - event.preventDefault(); - break; - - case Key.F9: - CloudCmd.Menu.show(); - event.preventDefault(); - break; - - case Key.F10: - CloudCmd.Config.show(); - event.preventDefault(); - break; - - case Key.TRA: - CloudCmd.Konsole.show(); - event.preventDefault(); - break; - - case KEY.BRACKET_CLOSE: - CloudCmd.Konsole.show(); - event.preventDefault(); - break; - - case Key.SPACE: - isDir = Info.isDir, - name = Info.name; - - if (!isDir || name === '..') - isSelected = true; - else - isSelected = DOM.isSelected(current); - - Util.exec.if(isSelected, function() { - DOM.toggleSelectedFile(current); - }, function(callback) { - DOM.loadCurrentSize(callback, current); + DOM.Storage.clear(function() { + CloudCmd.log('storage cleared'); }); event.preventDefault(); - break; - - case Key.U: - if (ctrlMeta) { - DOM.swapPanels(); - event.preventDefault(); - } - break; - - /* navigation on file table: * - * in case of pressing button 'up', * - * select previous row */ - case Key.UP: - if (shift) - DOM.toggleSelectedFile(current); - - DOM.setCurrentFile(prev); - event.preventDefault(); - break; - - /* in case of pressing button 'down', * - * select next row */ - case Key.DOWN: - if (shift) - DOM.toggleSelectedFile(current); - - DOM.setCurrentFile(next); - event.preventDefault(); - break; - - case Key.LEFT: - if (!alt) - return; - - event.preventDefault(); - - name = Info.panel.getAttribute('data-name'); - - if (name === 'js-right') - DOM.duplicatePanel(); - - break; - - case Key.RIGHT: - if (!alt) - return; - - event.preventDefault(); - - name = Info.panel.getAttribute('data-name'); - - if (name === 'js-left') - DOM.duplicatePanel(); - - break; - - /* in case of pressing button 'Home', * - * go to top element */ - case Key.HOME: - DOM.setCurrentFile(Info.first); - event.preventDefault(); - break; - - /* in case of pressing button 'End', select last element */ - case Key.END: - DOM.setCurrentFile(Info.last); - event.preventDefault(); - break; - - /* если нажали клавишу page down проматываем экран */ - case Key.PAGE_DOWN: - DOM.scrollByPages(panel, 1); - - for (i = 0; i < 30; i++) { - if (!current.nextSibling) - break; - - current = current.nextSibling; - } - - DOM.setCurrentFile(current); - event.preventDefault(); - break; - - /* если нажали клавишу page up проматываем экран */ - case Key.PAGE_UP: - DOM.scrollByPages(panel, -1); - - for (i = 0; i < 30; i++) { - if (!current.previousSibling) - break; - - current = current.previousSibling; - } - - DOM.setCurrentFile(current); - event.preventDefault(); - break; - - /* open directory */ - case Key.ENTER: - if (Info.isDir) - CloudCmd.loadDir({ - path: path === '/' ? '/' : path + '/' - }); - break; - - case Key.BACKSPACE: - CloudCmd.goToParentDir(); - event.preventDefault(); - break; - - case Key.BACKSLASH: - if (ctrlMeta) - CloudCmd.loadDir({ - path: '/' - }); - break; - - case Key.A: - if (ctrlMeta) { - DOM.selectAllFiles(); - event.preventDefault(); - } - - break; - - case Key.G: - if (alt) { - DOM.goToDirectory(); - event.preventDefault(); - } - - break; - - case Key.M: - if (ctrlMeta) { - CloudCmd.EditNames.show(); - event.preventDefault(); - } - - break; - - /** - * обновляем страницу, - * загружаем содержимое каталога - * при этом данные берём всегда с - * сервера, а не из кэша - * (обновляем кэш) - */ - case Key.R: - if (ctrlMeta) { - CloudCmd.log('reloading page...\n'); - CloudCmd.refresh(); - event.preventDefault(); - } - break; - - case Key.C: - if (ctrlMeta) - Buffer.copy(); - break; - - case Key.X: - if (ctrlMeta) - Buffer.cut(); - break; - - case Key.V: - if (ctrlMeta) - Buffer.paste(); - break; - - case Key.Z: - if (ctrlMeta) - Buffer.clear(); - break; - - /* чистим хранилище */ - case Key.D: - if (ctrlMeta) { - CloudCmd.log('clearing storage...'); - - DOM.Storage.clear(function() { - CloudCmd.log('storage cleared'); - }); - - event.preventDefault(); - } - break; } + break; } } +} -})(CloudCmd, Util, DOM); diff --git a/client/listeners.js b/client/listeners.js index 891ea906..8562eec3 100644 --- a/client/listeners.js +++ b/client/listeners.js @@ -1,497 +1,495 @@ -var Util, DOM, CloudFunc, CloudCmd; +/* global Util, DOM, CloudFunc, CloudCmd */ -(function (Util, DOM, CloudFunc, CloudCmd) { - 'use strict'; +'use strict'; + +CloudCmd.Listeners = new ListenersProto(Util, DOM, CloudFunc, CloudCmd); + +function ListenersProto(Util, DOM, CloudFunc, CloudCmd) { + var Info = DOM.CurrentInfo, + Storage = DOM.Storage, + Events = DOM.Events, + EventsFiles = { + 'mousedown' : Util.exec.with(execIfNotUL, setCurrentFileByEvent), + 'click' : onClick, + 'dragstart' : Util.exec.with(execIfNotUL, onDragStart), + 'dblclick' : Util.exec.with(execIfNotUL, onDblClick), + 'touchstart': Util.exec.with(execIfNotUL, onTouch) + }; - CloudCmd.Listeners = new ListenersProto(Util, DOM, CloudFunc, CloudCmd); - - function ListenersProto(Util, DOM, CloudFunc, CloudCmd) { - var Info = DOM.CurrentInfo, - Storage = DOM.Storage, - Events = DOM.Events, - EventsFiles = { - 'mousedown' : Util.exec.with(execIfNotUL, setCurrentFileByEvent), - 'click' : onClick, - 'dragstart' : Util.exec.with(execIfNotUL, onDragStart), - 'dblclick' : Util.exec.with(execIfNotUL, onDblClick), - 'touchstart': Util.exec.with(execIfNotUL, onTouch) - }; + var EXT; + + this.init = function () { + contextMenu(); + dragndrop(); + unload(); + pop(); + resize(); + config(); + header(); + }; + + function header() { + var fm = DOM.getFM(); - var EXT; - - this.init = function () { - contextMenu(); - dragndrop(); - unload(); - pop(); - resize(); - config(); - header(); + var isDataset = function(el) { + return el.dataset; }; - function header() { - var fm = DOM.getFM(); - - var isDataset = function(el) { - return el.dataset; - }; - - var isPanel = function(el) { - return /^js-(left|right)$/.test(el.dataset.name); - }; - - Events.addClick(fm, function(event) { - var el = event.target; - var parent = el.parentElement; - - if (parent.dataset.name !== 'js-fm-header') - return; - - var name = (el.dataset.name || '') - .replace('js-', ''); - - if (!/^(name|size|date)$/.test(name)) - return; - - var panel = getPath(el) - .filter(isDataset) - .filter(isPanel) - .pop(); - - CloudCmd.sortPanel(name, panel); - }); - } + var isPanel = function(el) { + return /^js-(left|right)$/.test(el.dataset.name); + }; - function getPath(el, path) { - path = path || []; - - if (!el) - return path; - + Events.addClick(fm, function(event) { + var el = event.target; var parent = el.parentElement; - return getPath(parent, path.concat(el)); - } - - function config() { - DOM.Files.get('config', function(e, config) { - var type = config && config.packer; - EXT = DOM.getPackerExt(type); - }); - } - - this.initKeysPanel = function() { - var keysElement = DOM.getById('js-keyspanel'); - - if (!keysElement) + if (parent.dataset.name !== 'js-fm-header') return; - Events.addClick(keysElement, function(event) { - var element = event.target; - var id = element.id; - var operation = function(name) { - var Operation = CloudCmd.Operation; - var fn = Operation.show.bind(null, name); - - return fn; - }; - - var clickFuncs = { - 'f1' : CloudCmd.Help.show, - 'f2' : DOM.renameCurrent, - 'f3' : CloudCmd.View.show, - 'f4' : CloudCmd.EditFile.show, - 'f5' : operation('copy'), - 'f6' : operation('move'), - 'f7' : DOM.promptNewDir, - 'f8' : operation('delete'), - 'f9' : CloudCmd.Menu.show, - 'f10' : CloudCmd.Config.show, - '~' : CloudCmd.Konsole.show, - 'contact' : CloudCmd.Contact.show, - }; - - var func = clickFuncs[id]; - - if (func) - func(); - }); - }; - - this.setOnPanel = function(side) { - var panel, - filesElement, - pathElement; + var name = (el.dataset.name || '') + .replace('js-', ''); - if (typeof side === 'string') - panel = DOM.getByDataName('js-' + side); - else - panel = side; + if (!/^(name|size|date)$/.test(name)) + return; - filesElement = DOM.getByDataName('js-files', panel); - pathElement = DOM.getByDataName('js-path', panel); + var panel = getPath(el) + .filter(isDataset) + .filter(isPanel) + .pop(); - /* ставим загрузку гифа на клик*/ - Events.addClick(pathElement, getPathListener(panel)); - Events.add(filesElement, EventsFiles); - }; - - function getPathListener(panel) { - var fn = onPathElementClick.bind(null, panel); - - return fn; - } - - function isNoCurrent(panel) { - var noCurrent, - infoPanel = Info.panel, - namePanel = panel.getAttribute('data-name'), - nameInfoPanel = infoPanel.getAttribute('data-name'); - - if (namePanel !== nameInfoPanel) - noCurrent = true; - - return noCurrent; - } - - function onPathElementClick(panel, event) { - var link, href, url, - noCurrent, - fs = CloudFunc.FS, - prefix = CloudCmd.PREFIX, - element = event.target, - attr = element.getAttribute('data-name'); - - switch (attr) { - case 'js-clear-storage': - Storage.clear(); - break; - - case 'js-refresh': - noCurrent = isNoCurrent(panel); - - CloudCmd.refresh(panel, { - noCurrent: noCurrent - }); - - event.preventDefault(); - break; - - case 'js-path-link': - url = CloudCmd.HOST; - href = element.href; - link = href.replace(url, ''); - /** - * browser doesn't replace % -> %25% - * do it for him - */ - link = link.replace('%%', '%25%'); - link = decodeURI(link); - link = link.replace(RegExp('^' + prefix + fs), '') || '/'; - - noCurrent = isNoCurrent(panel); - - CloudCmd.loadDir({ - path : link, - isRefresh : false, - panel : noCurrent ? panel : Info.panel - }); - - event.preventDefault(); - } - } - - function execIfNotUL(callback, event) { - var element = event.target, - tag = element.tagName; - - if (tag !== 'UL') - callback(event); - } - - function onClick(event) { - var ctrl = event.ctrlKey; - - if (!ctrl) - event.preventDefault(); - - changePanel(event.target); - } - - function toggleSelect(key, files) { - var isMac = /Mac/.test(window.navigator.platform); - - if (!key) - throw Error('key should not be undefined!'); - - if (isMac && key.meta || key.ctrl) - DOM.toggleSelectedFile(files[0]); - else if (key.shift) - files.forEach(function(current) { - if (!DOM.isSelected(current)) - DOM.toggleSelectedFile(current); - }); - else - DOM.unselectFiles(); - } - - function changePanel(element) { - var panel = Info.panel, - files = DOM.getByDataName('js-files', panel), - ul = getULElement(element); - - if (ul !== files) - DOM.changePanel(); - } - - function onDblClick(event) { - var current = getLIElement(event.target), - isDir = DOM.isCurrentIsDir(current), - path = DOM.getCurrentPath(current); - - if (isDir) { - CloudCmd.loadDir({ - path: path === '/' ? '/' : path + '/' - }); - - event.preventDefault(); - } - } - - function onTouch(event) { - var isCurrent, - current = getLIElement(event.target), - isDir = DOM.isCurrentIsDir(current); - - if (isDir) { - isCurrent = DOM.isCurrentFile(current); - - if (isCurrent) { - CloudCmd.loadDir({ - path: DOM.getCurrentPath(current) - }); - - event.preventDefault(); - } - } - } - - /* - * download file from browser to desktop - * in Chrome (HTML5) - */ - function onDragStart(event) { - var apiURL = CloudFunc.apiURL, - element = getLIElement(event.target), - isDir = Info.isDir, - link = DOM.getCurrentLink(element), - name = DOM.getCurrentName(element); - - /* if it's directory - adding json extension */ - if (isDir) { - name += EXT; - link = document.createElement('a'); - link.textContent = name; - link.href = apiURL + '/pack' + Info.path + EXT; - } - - event.dataTransfer.setData('DownloadURL', - 'application/octet-stream' + ':' + - name + ':' + - link); - } - - function getLIElement(element) { - if (!element) - return element; - - while (element.tagName !== 'LI') - element = element.parentElement; - - return element; - } - - function getULElement(element) { - while (element.tagName !== 'UL') - element = element.parentElement; - - return element; - } - - function setCurrentFileByEvent(event) { - var fromName, - toName, - BUTTON_LEFT = 0, - files = [], - key = { - ctrl: event.ctrlKey, - meta: event.metaKey, - shift: event.shiftKey - }, - - element = getLIElement(event.target); - - fromName = Info.name; - DOM.setCurrentFile(element); - toName = Info.name; - - if (key.shift) - files = getFilesRange(fromName, toName); - else - files.push(Info.element); - - if (event.button === BUTTON_LEFT) - toggleSelect(key, files); - } - - function getFilesRange(from, to) { - var i = 0, - delta = 0, - result = [], - files = DOM.getFiles(), - names = DOM.getFilenames(files), - indexFrom, - indexTo; - - if (names[0] === '..') { - names.shift(); - delta = 1; - } - - indexFrom = names.indexOf(from); - indexTo = names.indexOf(to); - - if (indexFrom < indexTo) - for (i = indexFrom; i <= indexTo; i++) - result.push(files[i + delta]); - else if (indexFrom > indexTo) - for (i = indexFrom; i >= indexTo; i--) - result.push(files[i + delta]); - else - result.push(to); - - return result; - } - - function contextMenu() { - var fm = DOM.getFM(); - - Events.addOnce('contextmenu', fm, function(event) { - CloudCmd.Menu.show({ - x: event.clientX, - y: event.clientY - }); - }); - - Events.addContextMenu(fm, function(event) { - CloudCmd.Menu.ENABLED || event.preventDefault(); - }); - } - - function dragndrop() { - var panels = DOM.getByClassAll('panel'), - forEach = Array.prototype.forEach, - - select = function() { - forEach.call(panels, function(panel) { - panel.classList.add('selected-panel'); - }); - }, - - unselect = function() { - forEach.call(panels, function(panel) { - panel.classList.remove('selected-panel'); - }); - }, - onDrop = function(event) { - var files = event.dataTransfer.files, - items = event.dataTransfer.items; - - event.preventDefault(); - - if (items && items.length && items[0].webkitGetAsEntry) { - files = [].filter.call(items, function(item) { - return item.kind === 'file'; - }); - - DOM.uploadDirectory(files); - } else { - DOM.uploadFiles(files); - } - }, - /** - * In Mac OS Chrome dropEffect = 'none' - * so drop do not firing up when try - * to upload file from download bar - */ - onDragOver = function(event) { - var dataTransfer = event.dataTransfer, - effectAllowed = dataTransfer.effectAllowed; - - if (/move|linkMove/.test(effectAllowed)) - dataTransfer.dropEffect = 'move'; - else - dataTransfer.dropEffect = 'copy'; - - event.preventDefault(); - }; - - Events.add('dragenter', select); - Events.add(['dragleave', 'drop'], unselect); - - forEach.call(panels, function(panel) { - Events.add('dragover', panel, onDragOver) - .add('drop', panel, onDrop); - }); - } - - function unload() { - DOM.Events.add(['unload', 'beforeunload'], function (event) { - var ret, - Key = CloudCmd.Key, - isBind = Key && Key.isBind(); - - if (!isBind) { - event.preventDefault(); - ret = 'Please make sure that you saved all work.'; - } - - return ret; - }); - } - - function pop() { - Events.add('popstate', function(event) { - var path = event.state || ''; - - path = path.replace(CloudFunc.FS, ''); - - if (!path) - CloudCmd.route(location.hash); - else - CloudCmd.loadDir({ - path : path, - history : false - }); - }); - } - - function resize() { - Events.add('resize', function() { - var name, isLeft, - is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH, - panel = Info.panel; - - if (panel) { - name = panel.getAttribute('data-name'), - isLeft = name === 'js-left'; - } - - if (is && !isLeft) - DOM.changePanel(); - }); - } - + CloudCmd.sortPanel(name, panel); + }); } -})(Util, DOM, CloudFunc, CloudCmd); + function getPath(el, path) { + path = path || []; + + if (!el) + return path; + + var parent = el.parentElement; + + return getPath(parent, path.concat(el)); + } + + function config() { + DOM.Files.get('config', function(e, config) { + var type = config && config.packer; + EXT = DOM.getPackerExt(type); + }); + } + + this.initKeysPanel = function() { + var keysElement = DOM.getById('js-keyspanel'); + + if (!keysElement) + return; + + Events.addClick(keysElement, function(event) { + var element = event.target; + var id = element.id; + var operation = function(name) { + var Operation = CloudCmd.Operation; + var fn = Operation.show.bind(null, name); + + return fn; + }; + + var clickFuncs = { + 'f1' : CloudCmd.Help.show, + 'f2' : DOM.renameCurrent, + 'f3' : CloudCmd.View.show, + 'f4' : CloudCmd.EditFile.show, + 'f5' : operation('copy'), + 'f6' : operation('move'), + 'f7' : DOM.promptNewDir, + 'f8' : operation('delete'), + 'f9' : CloudCmd.Menu.show, + 'f10' : CloudCmd.Config.show, + '~' : CloudCmd.Konsole.show, + 'contact' : CloudCmd.Contact.show, + }; + + var func = clickFuncs[id]; + + if (func) + func(); + }); + }; + + this.setOnPanel = function(side) { + var panel, + filesElement, + pathElement; + + if (typeof side === 'string') + panel = DOM.getByDataName('js-' + side); + else + panel = side; + + filesElement = DOM.getByDataName('js-files', panel); + pathElement = DOM.getByDataName('js-path', panel); + + /* ставим загрузку гифа на клик*/ + Events.addClick(pathElement, getPathListener(panel)); + Events.add(filesElement, EventsFiles); + }; + + function getPathListener(panel) { + var fn = onPathElementClick.bind(null, panel); + + return fn; + } + + function isNoCurrent(panel) { + var noCurrent, + infoPanel = Info.panel, + namePanel = panel.getAttribute('data-name'), + nameInfoPanel = infoPanel.getAttribute('data-name'); + + if (namePanel !== nameInfoPanel) + noCurrent = true; + + return noCurrent; + } + + function onPathElementClick(panel, event) { + var link, href, url, + noCurrent, + fs = CloudFunc.FS, + prefix = CloudCmd.PREFIX, + element = event.target, + attr = element.getAttribute('data-name'); + + switch (attr) { + case 'js-clear-storage': + Storage.clear(); + break; + + case 'js-refresh': + noCurrent = isNoCurrent(panel); + + CloudCmd.refresh(panel, { + noCurrent: noCurrent + }); + + event.preventDefault(); + break; + + case 'js-path-link': + url = CloudCmd.HOST; + href = element.href; + link = href.replace(url, ''); + /** + * browser doesn't replace % -> %25% + * do it for him + */ + link = link.replace('%%', '%25%'); + link = decodeURI(link); + link = link.replace(RegExp('^' + prefix + fs), '') || '/'; + + noCurrent = isNoCurrent(panel); + + CloudCmd.loadDir({ + path : link, + isRefresh : false, + panel : noCurrent ? panel : Info.panel + }); + + event.preventDefault(); + } + } + + function execIfNotUL(callback, event) { + var element = event.target, + tag = element.tagName; + + if (tag !== 'UL') + callback(event); + } + + function onClick(event) { + var ctrl = event.ctrlKey; + + if (!ctrl) + event.preventDefault(); + + changePanel(event.target); + } + + function toggleSelect(key, files) { + var isMac = /Mac/.test(window.navigator.platform); + + if (!key) + throw Error('key should not be undefined!'); + + if (isMac && key.meta || key.ctrl) + DOM.toggleSelectedFile(files[0]); + else if (key.shift) + files.forEach(function(current) { + if (!DOM.isSelected(current)) + DOM.toggleSelectedFile(current); + }); + else + DOM.unselectFiles(); + } + + function changePanel(element) { + var panel = Info.panel, + files = DOM.getByDataName('js-files', panel), + ul = getULElement(element); + + if (ul !== files) + DOM.changePanel(); + } + + function onDblClick(event) { + var current = getLIElement(event.target), + isDir = DOM.isCurrentIsDir(current), + path = DOM.getCurrentPath(current); + + if (isDir) { + CloudCmd.loadDir({ + path: path === '/' ? '/' : path + '/' + }); + + event.preventDefault(); + } + } + + function onTouch(event) { + var isCurrent, + current = getLIElement(event.target), + isDir = DOM.isCurrentIsDir(current); + + if (isDir) { + isCurrent = DOM.isCurrentFile(current); + + if (isCurrent) { + CloudCmd.loadDir({ + path: DOM.getCurrentPath(current) + }); + + event.preventDefault(); + } + } + } + + /* + * download file from browser to desktop + * in Chrome (HTML5) + */ + function onDragStart(event) { + var apiURL = CloudFunc.apiURL, + element = getLIElement(event.target), + isDir = Info.isDir, + link = DOM.getCurrentLink(element), + name = DOM.getCurrentName(element); + + /* if it's directory - adding json extension */ + if (isDir) { + name += EXT; + link = document.createElement('a'); + link.textContent = name; + link.href = apiURL + '/pack' + Info.path + EXT; + } + + event.dataTransfer.setData('DownloadURL', + 'application/octet-stream' + ':' + + name + ':' + + link); + } + + function getLIElement(element) { + if (!element) + return element; + + while (element.tagName !== 'LI') + element = element.parentElement; + + return element; + } + + function getULElement(element) { + while (element.tagName !== 'UL') + element = element.parentElement; + + return element; + } + + function setCurrentFileByEvent(event) { + var fromName, + toName, + BUTTON_LEFT = 0, + files = [], + key = { + ctrl: event.ctrlKey, + meta: event.metaKey, + shift: event.shiftKey + }, + + element = getLIElement(event.target); + + fromName = Info.name; + DOM.setCurrentFile(element); + toName = Info.name; + + if (key.shift) + files = getFilesRange(fromName, toName); + else + files.push(Info.element); + + if (event.button === BUTTON_LEFT) + toggleSelect(key, files); + } + + function getFilesRange(from, to) { + var i = 0, + delta = 0, + result = [], + files = DOM.getFiles(), + names = DOM.getFilenames(files), + indexFrom, + indexTo; + + if (names[0] === '..') { + names.shift(); + delta = 1; + } + + indexFrom = names.indexOf(from); + indexTo = names.indexOf(to); + + if (indexFrom < indexTo) + for (i = indexFrom; i <= indexTo; i++) + result.push(files[i + delta]); + else if (indexFrom > indexTo) + for (i = indexFrom; i >= indexTo; i--) + result.push(files[i + delta]); + else + result.push(to); + + return result; + } + + function contextMenu() { + var fm = DOM.getFM(); + + Events.addOnce('contextmenu', fm, function(event) { + CloudCmd.Menu.show({ + x: event.clientX, + y: event.clientY + }); + }); + + Events.addContextMenu(fm, function(event) { + CloudCmd.Menu.ENABLED || event.preventDefault(); + }); + } + + function dragndrop() { + var panels = DOM.getByClassAll('panel'), + forEach = Array.prototype.forEach, + + select = function() { + forEach.call(panels, function(panel) { + panel.classList.add('selected-panel'); + }); + }, + + unselect = function() { + forEach.call(panels, function(panel) { + panel.classList.remove('selected-panel'); + }); + }, + onDrop = function(event) { + var files = event.dataTransfer.files, + items = event.dataTransfer.items; + + event.preventDefault(); + + if (items && items.length && items[0].webkitGetAsEntry) { + files = [].filter.call(items, function(item) { + return item.kind === 'file'; + }); + + DOM.uploadDirectory(files); + } else { + DOM.uploadFiles(files); + } + }, + /** + * In Mac OS Chrome dropEffect = 'none' + * so drop do not firing up when try + * to upload file from download bar + */ + onDragOver = function(event) { + var dataTransfer = event.dataTransfer, + effectAllowed = dataTransfer.effectAllowed; + + if (/move|linkMove/.test(effectAllowed)) + dataTransfer.dropEffect = 'move'; + else + dataTransfer.dropEffect = 'copy'; + + event.preventDefault(); + }; + + Events.add('dragenter', select); + Events.add(['dragleave', 'drop'], unselect); + + forEach.call(panels, function(panel) { + Events.add('dragover', panel, onDragOver) + .add('drop', panel, onDrop); + }); + } + + function unload() { + DOM.Events.add(['unload', 'beforeunload'], function (event) { + var ret, + Key = CloudCmd.Key, + isBind = Key && Key.isBind(); + + if (!isBind) { + event.preventDefault(); + ret = 'Please make sure that you saved all work.'; + } + + return ret; + }); + } + + function pop() { + Events.add('popstate', function(event) { + var path = event.state || ''; + + path = path.replace(CloudFunc.FS, ''); + + if (!path) + CloudCmd.route(location.hash); + else + CloudCmd.loadDir({ + path : path, + history : false + }); + }); + } + + function resize() { + Events.add('resize', function() { + var name, isLeft, + is = window.innerWidth < CloudCmd.MIN_ONE_PANEL_WIDTH, + panel = Info.panel; + + if (panel) { + name = panel.getAttribute('data-name'), + isLeft = name === 'js-left'; + } + + if (is && !isLeft) + DOM.changePanel(); + }); + } + +} + diff --git a/client/load.js b/client/load.js index b680f0a7..88c85a59 100644 --- a/client/load.js +++ b/client/load.js @@ -1,371 +1,381 @@ +'use strict'; + /* global Util */ /* global DOM */ -/* global Emitify */ -/* global itype */ -(function (Util, DOM) { - 'use strict'; - - /* global rendy */ - - var DOMProto = Object.getPrototypeOf(DOM); - - DOMProto.load = new LoaderProto(Util, DOM.Images, DOM.Events); - - function LoaderProto(Util, Images, Events) { - /** - * Функция создаёт элемент и загружает файл с src. - * - * @param pParams_o = { - * name, - название тэга - * src', - путь к файлу - * func, - обьект, содержаий одну из функций - * или сразу две onload и onerror - * {onload: function() {}, onerror: function();} - * style, - * id, - * element, - * async, - true by default - * inner: 'id{color:red, }, - * class, - * notAppend - false by default - * - */ - function load(params) { - var element, type, - p = params, - func = p.func, - name = p.name, - parent = p.parent || document.body, - - /* - * if passed arguments function - * then it's onload by default - * - * if object - then onload and onerror - */ - funcLoad = function() { - var callback = func && func.onload || func; - - Events.remove('error', element, funcError); - - Util.exec(callback); - }, - - funcError = function() { - var callback, - template = 'file {{ src }} could not be loaded', - msg = rendy(template, { - src: p.src - }), - - error = new Error(msg); - - if (func) - callback = func.onerror || func.onload || func; - - parent.removeChild(element); - - Images.show.error(msg); - - Util.exec(callback, error); - }; +const DOMProto = Object.getPrototypeOf(DOM); +const rendy = require('rendy'); +const itype = require('itype/legacy'); +const Emitify = require('emitify'); + +DOMProto.load = new LoaderProto(Util, DOM.Images, DOM.Events); + +function LoaderProto(Util, Images, Events) { + /** + * Функция создаёт элемент и загружает файл с src. + * + * @param pParams_o = { + * name, - название тэга + * src', - путь к файлу + * func, - обьект, содержаий одну из функций + * или сразу две onload и onerror + * {onload: function() {}, onerror: function();} + * style, + * id, + * element, + * async, - true by default + * inner: 'id{color:red, }, + * class, + * notAppend - false by default + * + */ + function load(params) { + var element, type, + p = params, + func = p.func, + name = p.name, + parent = p.parent || document.body, - /* убираем путь к файлу, оставляя только название файла */ - if (!p.id && p.src) - p.id = load.getIdBySrc(p.src); - - element = document.getElementById(p.id); + /* + * if passed arguments function + * then it's onload by default + * + * if object - then onload and onerror + */ + funcLoad = function() { + var callback = func && func.onload || func; + + Events.remove('error', element, funcError); + + Util.exec(callback); + }, - if (element) { - Util.exec(func); - } else { - element = document.createElement(name); - - if (name === 'script' || name === 'link') - Events.addOnce('load', element, funcLoad) - .addError(element, funcError); - - if (p.id) - element.id = p.id; - - if (p.className) - element.className = p.className; - - if (p.src) { - /* if work with css use href */ - if (name === 'link') { - element.href = p.src; - element.rel = 'stylesheet'; - } else - element.src = p.src; - } - - if (p.attribute) { - type = itype(p.attribute); + funcError = function() { + var callback, + template = 'file {{ src }} could not be loaded', + msg = rendy(template, { + src: p.src + }), - switch(type) { - case 'string': - element.setAttribute(p.attribute, ''); - break; - - case 'object': - Object.keys(p.attribute).forEach(function(name) { - element.setAttribute(name, p.attribute[name]); - }); - break; - } - } + error = new Error(msg); - if (p.style) - element.style.cssText = p.style; + if (func) + callback = func.onerror || func.onload || func; - if (p.async && name === 'script' || p.async === undefined) - element.async = true; + parent.removeChild(element); - if (!p.notAppend) - parent.appendChild(element); + Images.show.error(msg); - if (p.inner) - element.innerHTML = p.inner; + Util.exec(callback, error); + }; + + /* убираем путь к файлу, оставляя только название файла */ + if (!p.id && p.src) + p.id = load.getIdBySrc(p.src); + + element = document.getElementById(p.id); + + if (element) { + Util.exec(func); + } else { + element = document.createElement(name); + + if (name === 'script' || name === 'link') + Events.addOnce('load', element, funcLoad) + .addError(element, funcError); + + if (p.id) + element.id = p.id; + + if (p.className) + element.className = p.className; + + if (p.src) { + /* if work with css use href */ + if (name === 'link') { + element.href = p.src; + element.rel = 'stylesheet'; + } else + element.src = p.src; } - return element; + if (p.attribute) { + type = itype(p.attribute); + + switch(type) { + case 'string': + element.setAttribute(p.attribute, ''); + break; + + case 'object': + Object.keys(p.attribute).forEach(function(name) { + element.setAttribute(name, p.attribute[name]); + }); + break; + } + } + + if (p.style) + element.style.cssText = p.style; + + if (p.async && name === 'script' || p.async === undefined) + element.async = true; + + if (!p.notAppend) + parent.appendChild(element); + + if (p.inner) + element.innerHTML = p.inner; } - /** - * Function gets id by src - * @param pSrc - * - * Example: http://domain.com/1.js -> 1_js - */ - load.getIdBySrc = function(src) { - var num, sub, id, - isStr = itype.string(src); - - if (isStr) { - if (~src.indexOf(':')) - src += '-join'; - - num = src.lastIndexOf('/') + 1, - sub = src.substr(src, num), - id = src.replace(sub, ''); - - /* убираем точки */ - id = id.replace(/\./g, '-'); - } - - return id; - }; + return element; + } + + /** + * Function gets id by src + * @param pSrc + * + * Example: http://domain.com/1.js -> 1_js + */ + load.getIdBySrc = function(src) { + var num, sub, id, + isStr = itype.string(src); - /** - * load file countent via ajax - * - * @param pParams - */ - load.ajax = function(params) { - var data, - p = params, - isObject = itype.object(p.data), - isArray = itype.array(p.data), - isArrayBuf = itype(p.data) === 'arraybuffer', - type = p.type || p.method || 'GET', - headers = p.headers || {}, - xhr = new XMLHttpRequest(); + if (isStr) { + if (~src.indexOf(':')) + src += '-join'; - xhr.open(type, p.url, true); + num = src.lastIndexOf('/') + 1, + sub = src.substr(src, num), + id = src.replace(sub, ''); - Object.keys(headers).forEach(function(name) { - var value = headers[name]; - xhr.setRequestHeader(name, value); - }); + /* убираем точки */ + id = id.replace(/\./g, '-'); + } + + return id; + }; + + /** + * load file countent via ajax + * + * @param pParams + */ + load.ajax = function(params) { + var data, + p = params, + isObject = itype.object(p.data), + isArray = itype.array(p.data), + isArrayBuf = itype(p.data) === 'arraybuffer', + type = p.type || p.method || 'GET', + headers = p.headers || {}, + xhr = new XMLHttpRequest(); + + xhr.open(type, p.url, true); + + Object.keys(headers).forEach(function(name) { + var value = headers[name]; + xhr.setRequestHeader(name, value); + }); + + if (p.responseType) + xhr.responseType = p.responseType; + + if (!isArrayBuf && isObject || isArray) + data = Util.json.stringify(p.data); + else + data = p.data; + + xhr.onreadystatechange = function(event) { + var TYPE_JSON, type, data, isContain, notText, + xhr = event.target, + OK = 200; - if (p.responseType) - xhr.responseType = p.responseType; - - if (!isArrayBuf && isObject || isArray) - data = Util.json.stringify(p.data); - else - data = p.data; - - xhr.onreadystatechange = function(event) { - var TYPE_JSON, type, data, isContain, notText, - xhr = event.target, - OK = 200; + if (xhr.readyState === xhr.DONE) { + Images.clearProgress(); + TYPE_JSON = 'application/json'; + type = xhr.getResponseHeader('content-type'); - if (xhr.readyState === xhr.DONE) { - Images.clearProgress(); - TYPE_JSON = 'application/json'; - type = xhr.getResponseHeader('content-type'); + if (xhr.status !== OK) { + Util.exec(p.error, xhr); + } else { + data = xhr.response; + notText = p.dataType !== 'text', + isContain = ~type.indexOf(TYPE_JSON); - if (xhr.status !== OK) { - Util.exec(p.error, xhr); - } else { - data = xhr.response; - notText = p.dataType !== 'text', - isContain = ~type.indexOf(TYPE_JSON); + if (type && isContain && notText) + data = Util.json.parse(xhr.response) || xhr.response; - if (type && isContain && notText) - data = Util.json.parse(xhr.response) || xhr.response; - - Util.exec(p.success, data, xhr.statusText, xhr); - } + Util.exec(p.success, data, xhr.statusText, xhr); } - }; - - xhr.send(data); + } }; - load.put = function(url, body) { - var emitter = Emitify(), - xhr = new XMLHttpRequest(); + xhr.send(data); + }; + + load.put = function(url, body) { + var emitter = Emitify(), + xhr = new XMLHttpRequest(); + + url = encodeURI(url); + url = url.replace('#', '%23'); + + xhr.open('put', url, true); + + xhr.upload.onprogress = function(event) { + var percent, count; - url = encodeURI(url); - url = url.replace('#', '%23'); - - xhr.open('put', url, true); - - xhr.upload.onprogress = function(event) { - var percent, count; + if (event.lengthComputable) { + percent = (event.loaded / event.total) * 100; + count = Math.round(percent); - if (event.lengthComputable) { - percent = (event.loaded / event.total) * 100; - count = Math.round(percent); - - emitter.emit('progress', count); + emitter.emit('progress', count); + } + + }; + + xhr.onreadystatechange = function() { + var error, + over = xhr.readyState === xhr.DONE, + OK = 200; + + if (over) + if (xhr.status === OK) { + emitter.emit('end'); + } else { + error = Error(xhr.responseText); + emitter.emit('error', error); } - - }; - - xhr.onreadystatechange = function() { - var error, - over = xhr.readyState === xhr.DONE, - OK = 200; - - if (over) - if (xhr.status === OK) { - emitter.emit('end'); - } else { - error = Error(xhr.responseText); - emitter.emit('error', error); - } - }; - - xhr.send(body); - - return emitter; }; - load.ext = function(src, func) { - var element, - ext = Util.getExt(src); - - switch (ext) { - case '.js': - element = load.js(src, func); - break; - - case '.css': - element = load.css(src, func); - break; - - default: - element = load({ - src : src, - func : func - }); - } - - return element; - }; + xhr.send(body); - /** - * create elements and load them to DOM-tree - * one-by-one - * - * @param params - * @param callback - */ - load.series = function(params, callback) { - var funcs = []; - - if (params) { - funcs = params.map(function(url) { - return load.ext.bind(null, url); - }) - .concat(callback); - - Util.exec.series(funcs); - } - - return load; - }; + return emitter; + }; + + load.ext = function(src, func) { + var element, + ext = Util.getExt(src); - /** - * improve callback of funcs so - * we pop number of function and - * if it's last we call pCallBack - * - * @param params - * @param callback - onload function - */ - load.parallel = function(params, callback) { - var funcs = []; - - if (params) { - funcs = params.map(function(url) { - return load.ext.bind(null, url); - }); - - Util.exec.parallel(funcs, callback); - } - - return load; - }; + switch (ext) { + case '.js': + element = load.js(src, func); + break; - /** - * Функция загружает js-файл - * - * @param pSrc - * @param pFunc - */ - load.js = function(src, func) { - var element = load({ - name : 'script', - src : src, - func : func - }); - - return element; - }, + case '.css': + element = load.css(src, func); + break; - load.css = function(src, callback) { - var element = load({ - name : 'link', + default: + element = load({ src : src, - parent : document.head, - func : callback + func : func }); - - return element; - }; + } - /** - * Функция создаёт елемент style и записывает туда стили - * @param pParams_o - структура параметров, заполняеться таким - * образом: {src: ' ',func: '', id: '', element: '', inner: ''} - * все параметры опциональны - */ - load.style = function(params) { - if (!params.name) - params.name = 'style'; + return element; + }; + + /** + * create elements and load them to DOM-tree + * one-by-one + * + * @param params + * @param callback + */ + load.series = function(params, callback) { + var funcs = []; + + if (params) { + funcs = params.map(function(url) { + return load.ext.bind(null, url); + }) + .concat(callback); - if (!params.parent) - params.parent = document.head; - - return load(params); - }; + Util.exec.series(funcs); + } return load; - } -})(Util, DOM); + }; + + /** + * improve callback of funcs so + * we pop number of function and + * if it's last we call pCallBack + * + * @param params + * @param callback - onload function + */ + load.parallel = function(params, callback) { + var funcs = []; + + if (params) { + funcs = params.map(function(url) { + return load.ext.bind(null, url); + }); + + Util.exec.parallel(funcs, callback); + } + + return load; + }; + + /** + * Функция загружает js-файл + * + * @param src + * @param func + */ + load.js = (src, func) => { + const name = 'script'; + + return load({ + name, + src, + func, + }); + }, + + load.css = (src, func) => { + const name = 'link'; + const {head:parent} = document; + + return load({ + name, + src, + parent, + func + }); + }; + + /** + * Функция создаёт елемент style и записывает туда стили + * @param params - структура параметров, заполняеться таким + * образом: {src: ' ',func: '', id: '', element: '', inner: ''} + * все параметры опциональны + */ + load.style = (params) => { + const { + id, + src, + name = 'style', + func, + inner, + parent = document.head, + element, + } = params; + + return load({ + id, + src, + func, + name, + inner, + parent, + element, + }); + }; + + return load; +} diff --git a/client/markdown.js b/client/markdown.js index ce44582a..5d8fbd7c 100644 --- a/client/markdown.js +++ b/client/markdown.js @@ -1,58 +1,56 @@ -var CloudCmd, Util, DOM; +'use strict'; -(function(CloudCmd, Util, DOM) { - 'use strict'; - - CloudCmd.Markdown = MarkdownProto; +/*global CloudCmd, Util, DOM */ + +window.CloudCmd.Markdown = MarkdownProto; + +function MarkdownProto(nameParam, optionsParam) { + var Images = DOM.Images, + RESTful = DOM.RESTful, + Markdown = RESTful.Markdown, + MD = this; - function MarkdownProto(nameParam, optionsParam) { - var Images = DOM.Images, - RESTful = DOM.RESTful, - Markdown = RESTful.Markdown, - MD = this; - - function init() { - Images.show.load('top'); - - Util.exec.series([ - CloudCmd.View, - Util.exec.with(MD.show, null, null), - ]); - } + function init() { + Images.show.load('top'); - this.show = function(name, options) { - var o = options || optionsParam || {}, - relativeQuery = '?relative'; - - if (!name) - name = nameParam; - - Images.show.load(o.positionLoad); - - if (o.relative) - name += relativeQuery; - - Markdown.read(name, function(error, result) { - var div = DOM.load({ - name : 'div', - className : 'help', - inner : result - }); - - Images.hide(); - - CloudCmd.View.show(div); - - nameParam = - optionsParam = null; - }); - }; - - this.hide = function() { - CloudCmd.View.hide(); - }; - - init(); + Util.exec.series([ + CloudCmd.View, + Util.exec.with(MD.show, null, null), + ]); } -})(CloudCmd, Util, DOM); + this.show = function(name, options) { + var o = options || optionsParam || {}, + relativeQuery = '?relative'; + + if (!name) + name = nameParam; + + Images.show.load(o.positionLoad); + + if (o.relative) + name += relativeQuery; + + Markdown.read(name, function(error, result) { + var div = DOM.load({ + name : 'div', + className : 'help', + inner : result + }); + + Images.hide(); + + CloudCmd.View.show(div); + + nameParam = + optionsParam = null; + }); + }; + + this.hide = function() { + CloudCmd.View.hide(); + }; + + init(); +} + diff --git a/client/menu.js b/client/menu.js index b7768045..28dd7ad0 100644 --- a/client/menu.js +++ b/client/menu.js @@ -1,357 +1,351 @@ -var CloudCmd, Util, DOM, CloudFunc, MenuIO; +/* global CloudCmd, Util, DOM, CloudFunc */ -(function(CloudCmd, Util, DOM, CloudFunc) { - 'use strict'; +'use strict'; + +CloudCmd.Menu = MenuProto; + +function MenuProto(position) { + const config = CloudCmd.config; + const Buffer = DOM.Buffer; + const Info = DOM.CurrentInfo; - CloudCmd.Menu = MenuProto; + let Loading = true, + Key = CloudCmd.Key, + Events = DOM.Events, + Dialog = DOM.Dialog, + Images = DOM.Images, + Menu = this, + TITLE = 'Menu', - function MenuProto(position) { - var config = CloudCmd.config; - var Buffer = DOM.Buffer, - Info = DOM.CurrentInfo, - Loading = true, - Key = CloudCmd.Key, - Events = DOM.Events, - Dialog = DOM.Dialog, - Images = DOM.Images, - Menu = this, - TITLE = 'Menu', - - MenuShowedName, - MenuContext, - MenuContextFile; + MenuShowedName, + MenuContext, + MenuContextFile; + + this.ENABLED = false; + + function init() { + Loading = true; + Menu.show(); - this.ENABLED = false; - - function init() { - Loading = true; - Menu.show(); - - Events.addKey(listener); - } - - this.hide = function() { - MenuContext.hide(); - MenuContextFile.hide(); - }; - - this.show = function(position) { - var x, y, - showFunc; - - if (position) { - x = position.x; - y = position.y; - } - - showFunc = function() { - show(x, y); - Images.hide(); - }; - - Util.exec.if(MenuIO, showFunc, function() { - DOM.loadMenu(function(error) { - if (error) - Dialog.alert(TITLE, error); - else - showFunc(); - }); - }); - }; - - function show(x, y) { - var pos; - - if (!x || !y) { - if (position) { - x = position.x; - y = position.y; - } else { - pos = getCurrentPosition(); - - x = pos.x; - y = pos.y; - } - } - - if (!Loading) { - MenuContext.show(x, y); - MenuContextFile.show(x, y); - } else { - loadFileMenuData(function(isAuth, menuDataFile) { - var is, menu, - NOT_FILE = true, - fm = DOM.getFM(), - menuData = getMenuData(isAuth), - options = getOptions(NOT_FILE), - optionsFile = getOptions(); - - MenuContext = new MenuIO(fm, options, menuData); - MenuContextFile = new MenuIO(fm, optionsFile, menuDataFile); - is = DOM.getCurrentByPosition({ - x: x, - y: y - }); - - if (is) - menu = MenuContextFile; - else - menu = MenuContext; - - menu.show(x, y); - - Loading = false; - position = null; - }); - } - } - - function getOptions(notFile) { - var name, func, options; - - if (notFile) { - name = 'context'; - func = Key.unsetBind; - } else { - name = 'contextFile'; - } - - options = { - icon : true, - beforeClose : Key.setBind, - beforeShow : Util.exec.with(beforeShow, func), - beforeClick : beforeClick, - name : name, - }; - - return options; - } - - function getMenuData(isAuth) { - var menu = { - 'Paste' : Buffer.paste, - 'New' : { - 'File' : DOM.promptNewFile, - 'Directory' : DOM.promptNewDir - }, - 'Upload' : function() { - CloudCmd.Upload.show(); - }, - 'Upload From Cloud': uploadFromCloud, - '(Un)Select All': DOM.toggleAllSelectedFiles - }; - - if (isAuth) - menu['Log Out'] = CloudCmd.logOut; - - return menu; - } - - function curry(fn) { - var args = [].slice.call(arguments, 1); - - return function() { - fn.apply(null, args.concat(arguments)); - }; - } - - function loadFileMenuData(callback) { - var is = CloudCmd.config('auth'); - var show = function(name) { - CloudCmd[name].show(); - }, - Dialog = DOM.Dialog, - menuData = getMenuData(is), - menu = { - 'View' : curry(show, 'View'), - 'Edit' : curry(show, 'Edit'), - 'Rename' : function() { - setTimeout(DOM.renameCurrent, 100); - }, - 'Delete' : function() { - CloudCmd.Operation.show('delete'); - }, - 'Pack' : function() { - CloudCmd.Operation.show('pack'); - }, - 'Extract' : function() { - CloudCmd.Operation.show('extract'); - }, - 'Download' : preDownload, - 'Upload To Cloud': curry(uploadTo, 'Cloud'), - 'Cut' : function() { - isCurrent(Buffer.cut, function() { - Dialog.alert.noFiles(TITLE); - }); - }, - 'Copy' : function() { - isCurrent(Buffer.copy, function() { - Dialog.alert.noFiles(TITLE); - }); - }, - }; - - Util.copyObj(menu, menuData); - - callback(is, menu); - } - - function isCurrent(yesFn, noFn) { - if (Info.name !== '..') - yesFn(); - else - noFn(); - } - - function isPath(x, y) { - var el, elements, is, - panel = Info.panel; - - if (panel) { - el = document.elementFromPoint(x, y), - elements = panel.querySelectorAll('[data-name="js-path"] *'), - is = ~[].indexOf.call(elements, el); - } - - return is; - } - - function beforeShow(callback, params) { - var name = params.name, - notShow = DOM.getCurrentByPosition({ - x: params.x, - y: params.y - }); - - if (params.name === 'contextFile') { - notShow = !notShow; - } - - if (!notShow) - MenuShowedName = name; - - Util.exec(callback); - - if (!notShow) - notShow = isPath(params.x, params.y); - - return notShow; - } - - function beforeClick(name) { - var notCall; - - if (MenuShowedName !== name) - notCall = true; - - return notCall; - } - - function uploadTo(nameModule) { - Info.getData(function(error, data) { - var name = Info.name, - execFrom = CloudCmd.execFromModule; - - execFrom(nameModule, 'uploadFile', name, data); - }); - - CloudCmd.log('Uploading to ' + name + '...'); - } - - function uploadFromCloud() { - Images.show.load('top'); - - CloudCmd.execFromModule('Cloud', 'saveFile', function(name, data) { - var path = DOM.getCurrentDirPath() + name; - - DOM.RESTful.write(path, data, function(error) { - !error && CloudCmd.refresh(); - }); - }); - } - - function preDownload() { - download(config('packer')); - } - - function download(type) { - var TIME = 30 * 1000, - prefixUr = CloudCmd.PREFIX_URL, - FS = CloudFunc.FS, - PACK = '/pack', - date = Date.now(), - files = DOM.getActiveFiles(); - - if (!files.length) - DOM.Dialog.alert.noFiles(TITLE); - else - files.forEach(function(file) { - var element, - selected = DOM.isSelected(file), - path = DOM.getCurrentPath(file), - id = DOM.load.getIdBySrc(path), - isDir = DOM.isCurrentIsDir(file); - - CloudCmd.log('downloading file ' + path + '...'); - - /* - * if we send ajax request - - * no need in hash so we escape # - * and all other characters, like "%" - */ - path = path.replace(/#/g, '%23'); - path = encodeURI(path); - - if (isDir) - path = prefixUr + PACK + path + DOM.getPackerExt(type); - else - path = prefixUr + FS + path + '?download'; - - element = DOM.load({ - id : id + '-' + date, - name : 'iframe', - async : false, - className : 'hidden', - src : path - }); - - setTimeout(function() { - document.body.removeChild(element); - }, TIME); - - if (selected) - DOM.toggleSelectedFile(file); - }); - } - - function getCurrentPosition() { - var current = Info.element, - rect = current.getBoundingClientRect(); - position = { - x: rect.left + rect.width / 3, - y: rect.top - }; - - return position; - } - - function listener(event) { - var position, - F9 = Key.F9, - ESC = Key.ESC, - key = event.keyCode, - isBind = Key.isBind(); - - if (isBind && key === F9) { - position = getCurrentPosition(); - MenuContext.show(position.x, position.y); - - event.preventDefault(); - } else if (key === ESC) { - Menu.hide(); - } - } - - init(); + Events.addKey(listener); } -})(CloudCmd, Util, DOM, CloudFunc); + + this.hide = function() { + MenuContext.hide(); + MenuContextFile.hide(); + }; + + this.show = function(position) { + var x, y, + showFunc; + + if (position) { + x = position.x; + y = position.y; + } + + showFunc = function() { + show(x, y); + Images.hide(); + }; + + Util.exec.if(window.MenuIO, showFunc, () => { + DOM.loadMenu((error) => { + if (error) + return Dialog.alert(TITLE, error); + + showFunc(); + }); + }); + }; + + function show(x, y) { + var pos; + + if (!x || !y) { + if (position) { + x = position.x; + y = position.y; + } else { + pos = getCurrentPosition(); + + x = pos.x; + y = pos.y; + } + } + + if (!Loading) { + MenuContext.show(x, y); + MenuContextFile.show(x, y); + return; + } + + loadFileMenuData((isAuth, menuDataFile) => { + const NOT_FILE = true; + const fm = DOM.getFM(); + const menuData = getMenuData(isAuth); + const options = getOptions(NOT_FILE); + const optionsFile = getOptions(); + const MenuIO = window.MenuIO; + + MenuContext = new MenuIO(fm, options, menuData); + MenuContextFile = new MenuIO(fm, optionsFile, menuDataFile); + + const is = DOM.getCurrentByPosition({x, y}); + const menu = is ? MenuContextFile : MenuContext; + + menu.show(x, y); + + Loading = false; + position = null; + }); + } + + function getOptions(notFile) { + var name, func, options; + + if (notFile) { + name = 'context'; + func = Key.unsetBind; + } else { + name = 'contextFile'; + } + + options = { + icon : true, + beforeClose : Key.setBind, + beforeShow : Util.exec.with(beforeShow, func), + beforeClick : beforeClick, + name : name, + }; + + return options; + } + + function getMenuData(isAuth) { + var menu = { + 'Paste' : Buffer.paste, + 'New' : { + 'File' : DOM.promptNewFile, + 'Directory' : DOM.promptNewDir + }, + 'Upload' : function() { + CloudCmd.Upload.show(); + }, + 'Upload From Cloud': uploadFromCloud, + '(Un)Select All': DOM.toggleAllSelectedFiles + }; + + if (isAuth) + menu['Log Out'] = CloudCmd.logOut; + + return menu; + } + + function curry(fn) { + var args = [].slice.call(arguments, 1); + + return function() { + fn.apply(null, args.concat(arguments)); + }; + } + + function loadFileMenuData(callback) { + var is = CloudCmd.config('auth'); + var show = function(name) { + CloudCmd[name].show(); + }, + Dialog = DOM.Dialog, + menuData = getMenuData(is), + menu = { + 'View' : curry(show, 'View'), + 'Edit' : curry(show, 'Edit'), + 'Rename' : function() { + setTimeout(DOM.renameCurrent, 100); + }, + 'Delete' : function() { + CloudCmd.Operation.show('delete'); + }, + 'Pack' : function() { + CloudCmd.Operation.show('pack'); + }, + 'Extract' : function() { + CloudCmd.Operation.show('extract'); + }, + 'Download' : preDownload, + 'Upload To Cloud': curry(uploadTo, 'Cloud'), + 'Cut' : function() { + isCurrent(Buffer.cut, function() { + Dialog.alert.noFiles(TITLE); + }); + }, + 'Copy' : function() { + isCurrent(Buffer.copy, function() { + Dialog.alert.noFiles(TITLE); + }); + }, + }; + + Util.copyObj(menu, menuData); + + callback(is, menu); + } + + function isCurrent(yesFn, noFn) { + if (Info.name !== '..') + yesFn(); + else + noFn(); + } + + function isPath(x, y) { + var el, elements, is, + panel = Info.panel; + + if (panel) { + el = document.elementFromPoint(x, y), + elements = panel.querySelectorAll('[data-name="js-path"] *'), + is = ~[].indexOf.call(elements, el); + } + + return is; + } + + function beforeShow(callback, params) { + var name = params.name, + notShow = DOM.getCurrentByPosition({ + x: params.x, + y: params.y + }); + + if (params.name === 'contextFile') { + notShow = !notShow; + } + + if (!notShow) + MenuShowedName = name; + + Util.exec(callback); + + if (!notShow) + notShow = isPath(params.x, params.y); + + return notShow; + } + + function beforeClick(name) { + var notCall; + + if (MenuShowedName !== name) + notCall = true; + + return notCall; + } + + function uploadTo(nameModule) { + Info.getData(function(error, data) { + var name = Info.name, + execFrom = CloudCmd.execFromModule; + + execFrom(nameModule, 'uploadFile', name, data); + }); + + CloudCmd.log('Uploading to ' + name + '...'); + } + + function uploadFromCloud() { + Images.show.load('top'); + + CloudCmd.execFromModule('Cloud', 'saveFile', function(name, data) { + var path = DOM.getCurrentDirPath() + name; + + DOM.RESTful.write(path, data, function(error) { + !error && CloudCmd.refresh(); + }); + }); + } + + function preDownload() { + download(config('packer')); + } + + function download(type) { + var TIME = 30 * 1000, + prefixUr = CloudCmd.PREFIX_URL, + FS = CloudFunc.FS, + PACK = '/pack', + date = Date.now(), + files = DOM.getActiveFiles(); + + if (!files.length) + DOM.Dialog.alert.noFiles(TITLE); + else + files.forEach(function(file) { + var element, + selected = DOM.isSelected(file), + path = DOM.getCurrentPath(file), + id = DOM.load.getIdBySrc(path), + isDir = DOM.isCurrentIsDir(file); + + CloudCmd.log('downloading file ' + path + '...'); + + /* + * if we send ajax request - + * no need in hash so we escape # + * and all other characters, like "%" + */ + path = path.replace(/#/g, '%23'); + path = encodeURI(path); + + if (isDir) + path = prefixUr + PACK + path + DOM.getPackerExt(type); + else + path = prefixUr + FS + path + '?download'; + + element = DOM.load({ + id : id + '-' + date, + name : 'iframe', + async : false, + className : 'hidden', + src : path + }); + + setTimeout(function() { + document.body.removeChild(element); + }, TIME); + + if (selected) + DOM.toggleSelectedFile(file); + }); + } + + function getCurrentPosition() { + var current = Info.element, + rect = current.getBoundingClientRect(); + position = { + x: rect.left + rect.width / 3, + y: rect.top + }; + + return position; + } + + function listener(event) { + var position, + F9 = Key.F9, + ESC = Key.ESC, + key = event.keyCode, + isBind = Key.isBind(); + + if (isBind && key === F9) { + position = getCurrentPosition(); + MenuContext.show(position.x, position.y); + + event.preventDefault(); + } else if (key === ESC) { + Menu.hide(); + } + } + + init(); +} diff --git a/client/notify.js b/client/notify.js index 48d8ebe8..0cc4f634 100644 --- a/client/notify.js +++ b/client/notify.js @@ -1,63 +1,56 @@ +/* global Util */ +/* global DOM */ /* global CloudCmd */ -var Util, DOM; -(function(Util, DOM) { - 'use strict'; +'use strict'; + +const Notify = Util.extendProto(NotifyProto); +const DOMProto = Object.getPrototypeOf(DOM); + +Util.extend(DOMProto, { + Notify +}); + +function NotifyProto() { + var Events = DOM.Events, + Show, + Notify = this, + Notification = window.Notification; - var config = CloudCmd.config; - var Notify = Util.extendProto(NotifyProto); - var DOMProto = Object.getPrototypeOf(DOM); - - Util.extend(DOMProto, { - Notify: Notify + Events.add({ + 'blur': () => { + Show = true; + }, + 'focus': () => { + Show = false; + } }); - function NotifyProto() { - var Events = DOM.Events, - Show, - Notify = this, - Notification = window.Notification; + this.send = (msg) => { + const notifications = CloudCmd.config('notifications'); + const focus = window.focus.bind(window); + const granted = Notify.check(); - Events.add({ - 'blur': function() { - Show = true; - }, - 'focus': function() { - Show = false; - } - }); + if (notifications && granted && Show) { + const notify = new Notification(msg, { + icon: '/img/favicon/favicon-notify.png' + }); + + Events.addClick(notify, focus); + } + }; + + this.check = () => { + const Not = Notification; + const perm = Not && Not.permission; - this.send = function(msg) { - var notify, - notifications = config('notifications'), - focus = window.focus.bind(window), - granted = Notify.check(); - - if (notifications && granted && Show) { - notify = new Notification(msg, { - icon: '/img/favicon/favicon-notify.png' - }); - - Events.addClick(notify, focus); - } - }; - - this.check = function () { - var ret, - Not = Notification, - perm = Not && Not.permission; - - if (perm === 'granted') - ret = true; - - return ret; - }; - - this.request = function () { - var Not = Notification; - - if (Not) - Not.requestPermission(); - }; - } -})(Util, DOM); + if (perm === 'granted') + return true; + }; + + this.request = () => { + if (Notification) + Notification.requestPermission(); + }; +} + diff --git a/client/operation.js b/client/operation.js index c9c16e27..c8d4d203 100644 --- a/client/operation.js +++ b/client/operation.js @@ -1,579 +1,571 @@ /* global CloudCmd */ /* global Util */ /* global DOM */ -/* global rendy */ -/* global currify */ /* global spero */ /* global remedy */ /* global ishtar */ /* global salam */ /* global omnes */ -(function(CloudCmd, Util, DOM, rendy) { - 'use strict'; +'use strict'; + +CloudCmd.Operation = OperationProto; + +const currify = require('currify/legacy'); + +function OperationProto(operation, data) { + let Name = 'Operation', + TITLE = CloudCmd.TITLE, + config = CloudCmd.config, + Loaded, + RESTful = DOM.RESTful, + + exec = Util.exec, + + copyFn = RESTful.cp, + moveFn = RESTful.mv, + deleteFn = RESTful.delete, + packFn = RESTful.pack, + extractFn = RESTful.extract, + + Images = DOM.Images, + Dialog = DOM.Dialog; - CloudCmd.Operation = OperationProto; + const Info = DOM.CurrentInfo; + const showLoad = Images.show.load.bind(null, 'top'); + const Operation = this; + + function init() { + showLoad(); - function OperationProto(operation, data) { - var Name = 'Operation', - TITLE = CloudCmd.TITLE, - config = CloudCmd.config, - Loaded, - RESTful = DOM.RESTful, - - exec = Util.exec, - - copyFn = RESTful.cp, - moveFn = RESTful.mv, - deleteFn = RESTful.delete, - packFn = RESTful.pack, - extractFn = RESTful.extract, - - Images = DOM.Images, - Dialog = DOM.Dialog, - - showLoad = Images.show.load.bind(null, 'top'), - - Operation = this; - - function init() { - showLoad(); - - Util.exec.series([ - DOM.loadSocket, - function(callback) { - if (config('progress')) - load(function(callback) { - create(CloudCmd.PREFIX, callback); - }); - - callback(); - }, - function() { - Loaded = true; - Images.hide(); - Operation.show(operation, data); - } - ]); - } - - function authCheck(spawn, ok) { - if (!config('auth')) - return ok(); - - spawn.on('accept', ok); - spawn.on('reject', function() { - Dialog.alert(TITLE, 'Wrong credentials!'); - }); - - spawn.emit('auth', config('username'), config('password')); - } - - function _initSpero(prefix, fn) { - spero(prefix + '/spero', prefix, function(copier) { - fn(); - - copier.on('connect', function() { - authCheck(copier, function() { - copyFn = function(data, callback) { - setListeners(copier, callback); - copier.copy(data.from, data.to, data.names); - }; + Util.exec.series([ + DOM.loadSocket, + function(callback) { + if (config('progress')) + load(function(callback) { + create(CloudCmd.PREFIX, callback); }); - }); - copier.on('disconnect', function() { - copyFn = DOM.RESTful.cp; - }); - }); - } - - function _initRemedy(prefix, fn) { - remedy(prefix + '/remedy', prefix, function(remover) { - fn(); - remover.on('connect', function() { - authCheck(remover, function() { - deleteFn = function(from, files, callback) { - setListeners(remover, callback); - from = from.replace(/\?.*/, ''); - remover.remove(from, files); - }; - }); - }); - - remover.on('disconnect', function() { - deleteFn = DOM.RESTful.remove; - }); - }); - } - - function _setPacker(prefix, name, pack, fn) { - pack(prefix + '/' + name, prefix, function(packer) { - fn(); - packer.on('connect', function() { - authCheck(packer, function() { - packFn = function(data, callback) { - setListeners(packer, {noContinue: true}, callback); - packer.pack(data.from, data.to, data.names); - }; - }); - }); - - packer.on('disconnect', function() { - packFn = RESTful.pack; - }); - }); - } - - function _initPacker(prefix, fn) { - if (config('packer') === 'zip') - return _setPacker(prefix, 'salam', salam, fn); - - _setPacker(prefix, 'ishtar', ishtar, fn); - } - - function _initExtractor(prefix, fn) { - omnes(prefix + '/omnes', prefix, function(packer) { - fn(); - packer.on('connect', function() { - authCheck(packer, function() { - extractFn = function(data, callback) { - setListeners(packer, {noContinue: true}, callback); - packer.extract(data.from, data.to); - }; - }); - }); - - packer.on('disconnect', function() { - extractFn = RESTful.extract; - }); - }); - } - - function create(prefix) { - var initSpero = currify(_initSpero); - var initRemedy = currify(_initRemedy); - var initPacker = currify(_initPacker); - var initExtractor = currify(_initExtractor); - - exec.parallel([ - initSpero(prefix), - initRemedy(prefix), - initPacker(prefix), - initExtractor(prefix) - ], exec.ret); - } - - function setListeners(emitter, options, callback) { - if (!callback) { - callback = options; - options = {}; + callback(); + }, + function() { + Loaded = true; + Images.hide(); + Operation.show(operation, data); } - - var done; - var lastError; - - var listeners = { - progress: function(value) { - done = value === 100; - Images.setProgress(value); - }, - - end: function() { - Images - .hide() - .clearProgress(); - - events.forEach(function(name) { - emitter.removeListener(name, listeners[name]); - }); - - if (lastError || done) - callback(lastError); - }, - - error: function(error) { - lastError = error; - - if (options.noContinue) { - listeners.end(error); - Dialog.alert(TITLE, error); - } else { - Dialog.confirm(TITLE, error + '\n Continue?') - .then(function() { - emitter.continue(); - }, function() { - emitter.abort(); - }); - } - } - }; - - var events = Object.keys(listeners); - - events.forEach(function(name) { - emitter.on(name, listeners[name]); - }); - } - - this.hide = function() { - CloudCmd.View.hide(); - }; - - this.show = function(operation, data) { - if (Loaded) - switch(operation) { - case 'copy': - Operation.copy(data); - break; - - case 'move': - Operation.move(data); - break; - - case 'delete': - Operation.delete(); - break; - - case 'delete:silent': - Operation.deleteSilent(); - break; - - case 'pack': - Operation.pack(); - break; - - case 'extract': - Operation.extract(); - break; - } - }; - - this.copy = function(data) { - processFiles(data, copyFn, message('Copy')); - }; - - this.move = function(data) { - processFiles(data, moveFn, message('Rename/Move')); - }; - - this.delete = function() { - promptDelete(); - }; - - this.deleteSilent = function() { - deleteSilent(); - }; - - this.pack = function() { - var isZip = config('packer') === 'zip'; - twopack('pack', isZip ? 'zip' : 'tar'); - }; - - this.extract = function() { - var isZip = config('packer') === 'zip'; - twopack('extract', isZip ? 'zip' : 'tar'); - }; - - /** - * prompt and delete current file or selected files - * - * @currentFile - */ - function promptDelete() { - var type, isDir, msg, - name = '', - msgAsk = 'Do you really want to delete the ', - msgSel = 'selected ', - files = DOM.getSelectedFiles(), - names = DOM.getFilenames(files), - i, - n = names.length, - current = DOM.getCurrentFile(); - - if (n) { - for (i = 0; i < 5 && i < n; i++) - name += '\n' + names[i]; - - if (n >= 5) - name += '\n...'; - - msg = msgAsk + msgSel + n + ' files/directories?\n' + name ; - } else { - isDir = DOM.isCurrentIsDir(current); - - if (isDir) - type = 'directory'; - else - type = 'file'; - - type += ' '; - - name = DOM.getCurrentName(current); - msg = msgAsk + msgSel + type + name + '?'; - } - - if (name === '..') - return Dialog.alert.noFiles(TITLE); - - Dialog.confirm(TITLE, msg, {cancel: false}).then(function() { - deleteSilent(files); - }); - } - - /** - * delete current or selected files - * - * @files - */ - function deleteSilent(files) { - var n, names, - query = '?files', - Info = DOM.CurrentInfo, - path = Info.dirPath, - name = Info.name; - - if (name === '..') - return Dialog.alert.noFiles(TITLE); - - showLoad(); - - if (!files) - files = DOM.getSelectedFiles(); - - names = DOM.getFilenames(files), - n = names.length; - - if (!n) - names = [Info.name]; - - deleteFn(path + query, names, function(error) { - var Storage = DOM.Storage, - dirPath = Info.dirPath, - delCurrent = DOM.deleteCurrent, - delSelected = DOM.deleteSelected, - getByName = DOM.getCurrentByName; - - if (!error) { - if (n > 1) - delSelected(files); - else - delCurrent(getByName(name)); - - Storage.removeMatch(dirPath); - } - }); - } - - /* - * process files (copy or move) - * @param data - * @param operation - */ - function processFiles(data, operation, message) { - var name, selFiles, files, - Info = DOM.CurrentInfo, - panel, - shouldAsk, - sameName, - ok, - tmpl = '"{{ name }}" already exist. Overwrite?', - - from = '', - to = '', - - names = []; - - if (data) { - from = data.from; - to = data.to; - names = data.names; - panel = Info.panel; - } else { - from = Info.dirPath; - to = DOM.getNotCurrentDirPath(); - selFiles = DOM.getSelectedFiles(); - names = DOM.getFilenames(selFiles); - data = {}; - shouldAsk = true; - panel = Info.panelPassive; - } - - if (!names.length) - names.push(DOM.getCurrentName()); - - name = names[0]; - - sameName = !!DOM.getCurrentByName(name, panel); - - if (name === '..') { - Dialog.alert.noFiles(TITLE); - } else { - if (shouldAsk) - message(to, names).then(ask); - else - ask(to); - } - - function ask(to) { - ok = from !== to && to; - - if (ok) - if (shouldAsk && sameName) - Dialog.confirm(TITLE, rendy(tmpl, { - name: name - }), {cancel: false}).then(function() { - go(); - }); - else - go(); - - function go() { - showLoad(); - - files = { - from : from, - to : to, - names : names - }; - - operation(files, function(error) { - !error && DOM.Storage.remove(from, function() { - var panel = Info.panel, - panelPassive = Info.panelPassive, - setCurrent = function() { - if (!name) - name = data.names[0]; - - DOM.setCurrentByName(name); - }; - - if (!Info.isOnePanel) - CloudCmd.refresh(panelPassive, { - noCurrent: true - }); - - CloudCmd.refresh(panel, setCurrent); - }); - }); - } - } - } - - function getTypeReg(type) { - if (type === 'zip') - return /\.zip$/; - - return /\.tar\.gz$/; - } - - function checkEmpty(name, operation) { - if (!operation) - throw Error(name + ' could not be empty!'); - } - - function twopack(operation, type) { - var op, - fileFrom, - Images = DOM.Images, - Info = DOM.CurrentInfo, - name = Info.name, - path = Info.path, - dirPath = Info.dirPath, - activeFiles = DOM.getActiveFiles(), - names = DOM.getFilenames(activeFiles); - - checkEmpty('operation', operation); - - if (!names.length) { - Dialog.alert.noFiles(TITLE); - } else { - switch(operation) { - case 'extract': - op = extractFn; - - fileFrom = { - from : path, - to : dirPath - }; - - name = name.replace(getTypeReg(type), ''); - - break; - - case 'pack': - op = packFn; - - if (names.length > 1) - name = Info.dir; - - name += DOM.getPackerExt(type); - - fileFrom = { - from : dirPath, - to : dirPath + name, - names : names - }; - break; - } - - Images.show.load('top'); - - op(fileFrom, function(error) { - !error && CloudCmd.refresh(null, function() { - DOM.setCurrentByName(name); - }); - }); - } - } - - function message(msg) { - return function(to, names) { - var promise, - n = names.length, - name = names[0]; - - msg += ' '; - - if (names.length > 1) - msg += n + ' file(s)'; - else - msg += '"' + name + '"'; - - msg += ' to'; - - promise = Dialog.prompt(TITLE, msg, to, {cancel: false}); - - return promise; - }; - } - - function load(callback) { - var prefix = CloudCmd.PREFIX, - files = [ - '/spero/spero.js', - '/remedy/remedy.js', - '/ishtar/ishtar.js', - '/salam/salam.js', - '/omnes/omnes.js' - ].map(function(name) { - return prefix + name; - }); - - DOM.load.parallel(files, function(error) { - if (error) { - Dialog.alert(TITLE, error.message); - } else { - Loaded = true; - Util.timeEnd(Name + ' load'); - Util.exec(callback); - } - }); - - Util.time(Name + ' load'); - } - - init(); + ]); } -})(CloudCmd, Util, DOM, rendy); + function authCheck(spawn, ok) { + if (!config('auth')) + return ok(); + + spawn.on('accept', ok); + spawn.on('reject', function() { + Dialog.alert(TITLE, 'Wrong credentials!'); + }); + + spawn.emit('auth', config('username'), config('password')); + } + + function _initSpero(prefix, fn) { + spero(prefix + '/spero', prefix, function(copier) { + fn(); + + copier.on('connect', function() { + authCheck(copier, function() { + copyFn = function(data, callback) { + setListeners(copier, callback); + copier.copy(data.from, data.to, data.names); + }; + }); + }); + + copier.on('disconnect', function() { + copyFn = DOM.RESTful.cp; + }); + }); + } + + function _initRemedy(prefix, fn) { + remedy(prefix + '/remedy', prefix, function(remover) { + fn(); + remover.on('connect', function() { + authCheck(remover, function() { + deleteFn = function(from, files, callback) { + setListeners(remover, callback); + from = from.replace(/\?.*/, ''); + remover.remove(from, files); + }; + }); + }); + + remover.on('disconnect', function() { + deleteFn = DOM.RESTful.remove; + }); + }); + } + + function _setPacker(prefix, name, pack, fn) { + pack(prefix + '/' + name, prefix, function(packer) { + fn(); + packer.on('connect', function() { + authCheck(packer, function() { + packFn = function(data, callback) { + setListeners(packer, {noContinue: true}, callback); + packer.pack(data.from, data.to, data.names); + }; + }); + }); + + packer.on('disconnect', function() { + packFn = RESTful.pack; + }); + }); + } + + function _initPacker(prefix, fn) { + if (config('packer') === 'zip') + return _setPacker(prefix, 'salam', salam, fn); + + _setPacker(prefix, 'ishtar', ishtar, fn); + } + + function _initExtractor(prefix, fn) { + omnes(prefix + '/omnes', prefix, function(packer) { + fn(); + packer.on('connect', function() { + authCheck(packer, function() { + extractFn = function(data, callback) { + setListeners(packer, {noContinue: true}, callback); + packer.extract(data.from, data.to); + }; + }); + }); + + packer.on('disconnect', function() { + extractFn = RESTful.extract; + }); + }); + } + + function create(prefix) { + var initSpero = currify(_initSpero); + var initRemedy = currify(_initRemedy); + var initPacker = currify(_initPacker); + var initExtractor = currify(_initExtractor); + + exec.parallel([ + initSpero(prefix), + initRemedy(prefix), + initPacker(prefix), + initExtractor(prefix) + ], exec.ret); + } + + function setListeners(emitter, options, callback) { + if (!callback) { + callback = options; + options = {}; + } + + var done; + var lastError; + + var listeners = { + progress: function(value) { + done = value === 100; + Images.setProgress(value); + }, + + end: function() { + Images + .hide() + .clearProgress(); + + events.forEach(function(name) { + emitter.removeListener(name, listeners[name]); + }); + + if (lastError || done) + callback(lastError); + }, + + error: function(error) { + lastError = error; + + if (options.noContinue) { + listeners.end(error); + Dialog.alert(TITLE, error); + } else { + Dialog.confirm(TITLE, error + '\n Continue?') + .then(function() { + emitter.continue(); + }, function() { + emitter.abort(); + }); + } + } + }; + + var events = Object.keys(listeners); + + events.forEach(function(name) { + emitter.on(name, listeners[name]); + }); + } + + this.hide = function() { + CloudCmd.View.hide(); + }; + + this.show = function(operation, data) { + if (Loaded) + switch(operation) { + case 'copy': + Operation.copy(data); + break; + + case 'move': + Operation.move(data); + break; + + case 'delete': + Operation.delete(); + break; + + case 'delete:silent': + Operation.deleteSilent(); + break; + + case 'pack': + Operation.pack(); + break; + + case 'extract': + Operation.extract(); + break; + } + }; + + this.copy = function(data) { + processFiles(data, copyFn, message('Copy')); + }; + + this.move = function(data) { + processFiles(data, moveFn, message('Rename/Move')); + }; + + this.delete = function() { + promptDelete(); + }; + + this.deleteSilent = function() { + deleteSilent(); + }; + + this.pack = function() { + var isZip = config('packer') === 'zip'; + twopack('pack', isZip ? 'zip' : 'tar'); + }; + + this.extract = function() { + var isZip = config('packer') === 'zip'; + twopack('extract', isZip ? 'zip' : 'tar'); + }; + + /** + * prompt and delete current file or selected files + * + * @currentFile + */ + function promptDelete() { + var type, isDir, msg, + name = '', + msgAsk = 'Do you really want to delete the ', + msgSel = 'selected ', + files = DOM.getSelectedFiles(), + names = DOM.getFilenames(files), + i, + n = names.length, + current = DOM.getCurrentFile(); + + if (n) { + for (i = 0; i < 5 && i < n; i++) + name += '\n' + names[i]; + + if (n >= 5) + name += '\n...'; + + msg = msgAsk + msgSel + n + ' files/directories?\n' + name ; + } else { + isDir = DOM.isCurrentIsDir(current); + + if (isDir) + type = 'directory'; + else + type = 'file'; + + type += ' '; + + name = DOM.getCurrentName(current); + msg = msgAsk + msgSel + type + name + '?'; + } + + if (name === '..') + return Dialog.alert.noFiles(TITLE); + + Dialog.confirm(TITLE, msg, {cancel: false}).then(function() { + deleteSilent(files); + }); + } + + /** + * delete current or selected files + * + * @files + */ + function deleteSilent(files) { + var n, names, + query = '?files', + path = Info.dirPath, + name = Info.name; + + if (name === '..') + return Dialog.alert.noFiles(TITLE); + + showLoad(); + + if (!files) + files = DOM.getSelectedFiles(); + + names = DOM.getFilenames(files), + n = names.length; + + if (!n) + names = [Info.name]; + + deleteFn(path + query, names, function(error) { + var Storage = DOM.Storage, + dirPath = Info.dirPath, + delCurrent = DOM.deleteCurrent, + delSelected = DOM.deleteSelected, + getByName = DOM.getCurrentByName; + + if (!error) { + if (n > 1) + delSelected(files); + else + delCurrent(getByName(name)); + + Storage.removeMatch(dirPath); + } + }); + } + + /* + * process files (copy or move) + * @param data + * @param operation + */ + function processFiles(data, operation, message) { + var name, selFiles, files, + panel, + shouldAsk, + sameName, + ok, + + from = '', + to = '', + + names = []; + + if (data) { + from = data.from; + to = data.to; + names = data.names; + panel = Info.panel; + } else { + from = Info.dirPath; + to = DOM.getNotCurrentDirPath(); + selFiles = DOM.getSelectedFiles(); + names = DOM.getFilenames(selFiles); + data = {}; + shouldAsk = true; + panel = Info.panelPassive; + } + + if (!names.length) + names.push(DOM.getCurrentName()); + + name = names[0]; + + sameName = !!DOM.getCurrentByName(name, panel); + + if (name === '..') + return Dialog.alert.noFiles(TITLE); + + if (shouldAsk) + return message(to, names).then(ask); + + ask(to); + + function ask(to) { + ok = from !== to && to; + + if (ok) + if (!shouldAsk || !sameName) + return go; + + const str = `"${ name }" already exist. Overwrite?`; + const cancel = false; + + Dialog.confirm(TITLE, str, {cancel}).then(go); + + function go() { + showLoad(); + + files = { + from : from, + to : to, + names : names + }; + + operation(files, function(error) { + !error && DOM.Storage.remove(from, function() { + var panel = Info.panel, + panelPassive = Info.panelPassive, + setCurrent = function() { + if (!name) + name = data.names[0]; + + DOM.setCurrentByName(name); + }; + + if (!Info.isOnePanel) + CloudCmd.refresh(panelPassive, { + noCurrent: true + }); + + CloudCmd.refresh(panel, setCurrent); + }); + }); + } + } + } + + function getTypeReg(type) { + if (type === 'zip') + return /\.zip$/; + + return /\.tar\.gz$/; + } + + function checkEmpty(name, operation) { + if (!operation) + throw Error(name + ' could not be empty!'); + } + + function twopack(operation, type) { + var op, + fileFrom, + Images = DOM.Images, + name = Info.name, + path = Info.path, + dirPath = Info.dirPath, + activeFiles = DOM.getActiveFiles(), + names = DOM.getFilenames(activeFiles); + + checkEmpty('operation', operation); + + if (!names.length) { + Dialog.alert.noFiles(TITLE); + } else { + switch(operation) { + case 'extract': + op = extractFn; + + fileFrom = { + from : path, + to : dirPath + }; + + name = name.replace(getTypeReg(type), ''); + + break; + + case 'pack': + op = packFn; + + if (names.length > 1) + name = Info.dir; + + name += DOM.getPackerExt(type); + + fileFrom = { + from : dirPath, + to : dirPath + name, + names : names + }; + break; + } + + Images.show.load('top'); + + op(fileFrom, function(error) { + !error && CloudCmd.refresh(null, function() { + DOM.setCurrentByName(name); + }); + }); + } + } + + function message(msg) { + return function(to, names) { + var promise, + n = names.length, + name = names[0]; + + msg += ' '; + + if (names.length > 1) + msg += n + ' file(s)'; + else + msg += '"' + name + '"'; + + msg += ' to'; + + promise = Dialog.prompt(TITLE, msg, to, {cancel: false}); + + return promise; + }; + } + + function load(callback) { + var prefix = CloudCmd.PREFIX, + files = [ + '/spero/spero.js', + '/remedy/remedy.js', + '/ishtar/ishtar.js', + '/salam/salam.js', + '/omnes/omnes.js' + ].map(function(name) { + return prefix + name; + }); + + DOM.load.parallel(files, function(error) { + if (error) { + Dialog.alert(TITLE, error.message); + } else { + Loaded = true; + Util.timeEnd(Name + ' load'); + Util.exec(callback); + } + }); + + Util.time(Name + ' load'); + } + + init(); +} + diff --git a/client/polyfill.js b/client/polyfill.js index 750cc350..a82e98bf 100644 --- a/client/polyfill.js +++ b/client/polyfill.js @@ -1,201 +1,197 @@ -/* global itype */ +'use strict'; -var Util, DOM, jQuery; +/* global Util, DOM, $ */ -(function(window, document, Util, DOM, $) { - 'use strict'; - - var type = itype; - - if (!window.XMLHttpRequest || !document.head) - DOM.load.ajax = $.ajax; +const type = require('itype/legacy'); + +if (!window.XMLHttpRequest || !document.head) + DOM.load.ajax = $.ajax; + +/* setting head ie6 - ie8 */ +if (!document.head) + document.head = $('head')[0]; + +if (!Function.bind) + Function.prototype.bind = function (context) { + var aArgs = [].slice.call(arguments, 1), + fToBind = this, + NOP = function () {}, + fBound = function () { + var arr = [].slice.call(arguments), + args = aArgs.concat(arr); + + return fToBind.apply(context, args); + }; - /* setting head ie6 - ie8 */ - if (!document.head) - document.head = $('head')[0]; - - if (!Function.bind) - Function.prototype.bind = function (context) { - var aArgs = [].slice.call(arguments, 1), - fToBind = this, - NOP = function () {}, - fBound = function () { - var arr = [].slice.call(arguments), - args = aArgs.concat(arr); - - return fToBind.apply(context, args); - }; - - NOP.prototype = this.prototype; - fBound.prototype = new NOP(); - - return fBound; - }; - - if (!Array.isArray) - Array.isArray = function(arr) { - return type(arr) === 'array'; - }; - - if (!document.addEventListener) - /** - * safe add event listener on ie - * @param pType - * @param pListener - */ - DOM.Events.add = function(pType, pElement, pListener) { - var lRet; - - if (!pElement) - pElement = window; - - lRet = $(pElement).bind(pType, null, pListener); - - return lRet; - }; - - if (!document.removeEventListener) { - DOM.Events.remove = function(pType, pElement, pListener) { - if (!pElement) - pElement = window; - - $(pElement).unbind(pType, pListener); - }; - } - - if (!document.getElementsByClassName) { - DOM.getByClassAll = function(pClass, pElement) { - var lClass = '.' + pClass, - lResult; - - if (pElement) - lResult = $(pElement).find(lClass); - else - lResult = $.find(lClass); - - return lResult; - }; - } - - /* function polyfill webkit standart function - * https://gist.github.com/2581101 - */ - DOM.scrollIntoViewIfNeeded = function(element, centerIfNeeded) { - var parent, - topWidth, - leftWidth, - parentComputedStyle, - parentBorderTopWidth, - parentBorderLeftWidth, - overTop, - overBottom, - overLeft, - overRight, - alignWithTop; + NOP.prototype = this.prototype; + fBound.prototype = new NOP(); - if (window.getComputedStyle) { - if (arguments.length === 1) - centerIfNeeded = false; - - parent = element.parentNode; - parentComputedStyle = window.getComputedStyle(parent, null); - - topWidth = parentComputedStyle.getPropertyValue('border-top-width'); - leftWidth = parentComputedStyle.getPropertyValue('border-left-width'); - - parentBorderTopWidth = parseInt(topWidth, 10); - parentBorderLeftWidth = parseInt(leftWidth, 10); - - overTop = element.offsetTop - parent.offsetTop < parent.scrollTop, - overBottom = - (element.offsetTop - - parent.offsetTop + - element.clientHeight - - parentBorderTopWidth) > - (parent.scrollTop + parent.clientHeight), - - overLeft = element.offsetLeft - - parent.offsetLeft < parent.scrollLeft, - - overRight = - (element.offsetLeft - - parent.offsetLeft + - element.clientWidth - - parentBorderLeftWidth) > - (parent.scrollLeft + parent.clientWidth), - - alignWithTop = overTop && !overBottom; - - if ((overTop || overBottom) && centerIfNeeded) - parent.scrollTop = - element.offsetTop - - parent.offsetTop - - parent.clientHeight / 2 - - parentBorderTopWidth + - element.clientHeight / 2; - - if ((overLeft || overRight) && centerIfNeeded) - parent.scrollLeft = - element.offsetLeft - - parent.offsetLeft - - parent.clientWidth / 2 - - parentBorderLeftWidth + - element.clientWidth / 2; - - if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) - element.scrollIntoView(alignWithTop); - } + return fBound; }; - - if (!window.JSON) { - Util.json.parse = $.parseJSON; + +if (!Array.isArray) + Array.isArray = function(arr) { + return type(arr) === 'array'; + }; + +if (!document.addEventListener) + /** + * safe add event listener on ie + * @param pType + * @param pListener + */ + DOM.Events.add = function(pType, pElement, pListener) { + var lRet; - /* https://gist.github.com/754454 */ - Util.json.stringify = function(obj) { - var n, v, has, - ret = '', - value = '', - json = [], - isStr = type.string(obj), - isObj = type.object(obj), - isArray = type.array(obj); + if (!pElement) + pElement = window; + + lRet = $(pElement).bind(pType, null, pListener); + + return lRet; + }; + +if (!document.removeEventListener) { + DOM.Events.remove = function(pType, pElement, pListener) { + if (!pElement) + pElement = window; + + $(pElement).unbind(pType, pListener); + }; +} + +if (!document.getElementsByClassName) { + DOM.getByClassAll = function(pClass, pElement) { + var lClass = '.' + pClass, + lResult; + + if (pElement) + lResult = $(pElement).find(lClass); + else + lResult = $.find(lClass); + + return lResult; + }; +} + +/* function polyfill webkit standart function + * https://gist.github.com/2581101 + */ +DOM.scrollIntoViewIfNeeded = function(element, centerIfNeeded) { + var parent, + topWidth, + leftWidth, + parentComputedStyle, + parentBorderTopWidth, + parentBorderLeftWidth, + overTop, + overBottom, + overLeft, + overRight, + alignWithTop; + + if (window.getComputedStyle) { + if (arguments.length === 1) + centerIfNeeded = false; + + parent = element.parentNode; + parentComputedStyle = window.getComputedStyle(parent, null); + + topWidth = parentComputedStyle.getPropertyValue('border-top-width'); + leftWidth = parentComputedStyle.getPropertyValue('border-left-width'); + + parentBorderTopWidth = parseInt(topWidth, 10); + parentBorderLeftWidth = parseInt(leftWidth, 10); - if (!isObj || obj === null) { - // simple data type - if (isStr) - obj = '"' + obj + '"'; + overTop = element.offsetTop - parent.offsetTop < parent.scrollTop, + overBottom = + (element.offsetTop - + parent.offsetTop + + element.clientHeight - + parentBorderTopWidth) > + (parent.scrollTop + parent.clientHeight), + + overLeft = element.offsetLeft - + parent.offsetLeft < parent.scrollLeft, + + overRight = + (element.offsetLeft - + parent.offsetLeft + + element.clientWidth - + parentBorderLeftWidth) > + (parent.scrollLeft + parent.clientWidth), + + alignWithTop = overTop && !overBottom; + + if ((overTop || overBottom) && centerIfNeeded) + parent.scrollTop = + element.offsetTop - + parent.offsetTop - + parent.clientHeight / 2 - + parentBorderTopWidth + + element.clientHeight / 2; + + if ((overLeft || overRight) && centerIfNeeded) + parent.scrollLeft = + element.offsetLeft - + parent.offsetLeft - + parent.clientWidth / 2 - + parentBorderLeftWidth + + element.clientWidth / 2; + + if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) + element.scrollIntoView(alignWithTop); + } +}; + +if (!window.JSON) { + Util.json.parse = $.parseJSON; + + /* https://gist.github.com/754454 */ + Util.json.stringify = function(obj) { + var n, v, has, + ret = '', + value = '', + json = [], + isStr = type.string(obj), + isObj = type.object(obj), + isArray = type.array(obj); + + if (!isObj || obj === null) { + // simple data type + if (isStr) + obj = '"' + obj + '"'; + + ret += obj; + } else { + // recurse array or object + for (n in obj) { + v = obj[n]; + has = obj.hasOwnProperty(n); - ret += obj; - } else { - // recurse array or object - for (n in obj) { - v = obj[n]; - has = obj.hasOwnProperty(n); + if (has) { + isStr = type.string(v); + isObj = type.object(v); - if (has) { - isStr = type.string(v); - isObj = type.object(v); - - if (isStr) - v = '"' + v + '"'; - else if (v && isObj) - v = Util.json.stringify(v); - - if (!isArray) - value = '"' + n + '":'; - - json.push(value + v); - } + if (isStr) + v = '"' + v + '"'; + else if (v && isObj) + v = Util.json.stringify(v); + + if (!isArray) + value = '"' + n + '":'; + + json.push(value + v); } - - if (isArray) - ret = '[' + json + ']'; - else - ret = '{' + json + '}'; } - return ret; - }; - } - -})(window, document, Util, DOM, jQuery); + if (isArray) + ret = '[' + json + ']'; + else + ret = '{' + json + '}'; + } + + return ret; + }; +} + diff --git a/client/rest.js b/client/rest.js index af397d0f..da30a931 100644 --- a/client/rest.js +++ b/client/rest.js @@ -1,215 +1,213 @@ -/* global itype */ +'use strict'; -var Util, DOM, CloudFunc, CloudCmd; +const itype = require('itype/legacy'); -(function(Util, DOM, CloudFunc) { - 'use strict'; +/* global Util, DOM, CloudFunc, CloudCmd */ + +const RESTful= Util.extendProto(RESTfulProto); +const DOMProto = Object.getPrototypeOf(DOM); + +Util.extend(DOMProto, { + RESTful +}); + +function RESTfulProto() { + const Images = DOM.Images; - var RESTful = Util.extendProto(RESTfulProto), - DOMProto = Object.getPrototypeOf(DOM); - - Util.extend(DOMProto, { - RESTful: RESTful - }); - - function RESTfulProto() { - var Images = DOM.Images; + this.delete = (url, data, callback) => { + var isFunc = itype.function(data); - this.delete = function(url, data, callback) { - var isFunc = itype.function(data); - - if (!callback && isFunc) { - callback = data; - data = null; - } - + if (!callback && isFunc) { + callback = data; + data = null; + } + + sendRequest({ + method : 'DELETE', + url : CloudFunc.FS + url, + data, + callback, + imgPosition : { top: !!data } + }); + }; + + this.patch = function(url, data, callback) { + var isFunc = itype.function(data); + + if (!callback && isFunc) { + callback = data; + data = null; + } + + sendRequest({ + method : 'PATCH', + url : CloudFunc.FS + url, + data : data, + callback : callback, + imgPosition : { top: true } + }); + }; + + this.write = function(url, data, callback) { + var isFunc = itype.function(data); + + if (!callback && isFunc) { + callback = data; + data = null; + } + + sendRequest({ + method : 'PUT', + url : CloudFunc.FS + url, + data : data, + callback : callback, + imgPosition : { top: true } + }); + }; + + this.read = function(url, dataType, callback) { + var isQuery = /\?/.test(url); + var isBeautify = /\?beautify$/.test(url); + var isMinify = /\?minify$/.test(url); + var notLog = !isQuery || isBeautify || isMinify; + var isFunc = itype.function(dataType); + + if (!callback && isFunc) { + callback = dataType; + dataType = 'text'; + } + + sendRequest({ + method: 'GET', + url: CloudFunc.FS + url, + callback: callback, + notLog: notLog, + dataType: dataType + }); + }; + + this.cp = function(data, callback) { + sendRequest({ + method : 'PUT', + url : '/cp', + data : data, + callback : callback, + imgPosition : { top: true } + }); + }; + + this.pack = function(data, callback) { + sendRequest({ + method : 'PUT', + url : '/pack', + data : data, + callback : callback + }); + }; + + this.extract = function(data, callback) { + sendRequest({ + method : 'PUT', + url : '/extract', + data : data, + callback : callback + }); + }; + + this.mv = function(data, callback) { + sendRequest({ + method : 'PUT', + url : '/mv', + data : data, + callback : callback, + imgPosition : { top: true } + }); + }; + + this.Config = { + read: function(callback) { sendRequest({ - method : 'DELETE', - url : CloudFunc.FS + url, - data : data, + method : 'GET', + url : '/config', callback : callback, - imgPosition : { top: !!data } + imgPosition : { top: true }, + notLog : true }); - }; + }, - this.patch = function(url, data, callback) { - var isFunc = itype.function(data); - - if (!callback && isFunc) { - callback = data; - data = null; - } - + write: function(data, callback) { sendRequest({ method : 'PATCH', - url : CloudFunc.FS + url, + url : '/config', data : data, callback : callback, imgPosition : { top: true } }); - }; - - this.write = function(url, data, callback) { - var isFunc = itype.function(data); - - if (!callback && isFunc) { - callback = data; - data = null; - } - - sendRequest({ - method : 'PUT', - url : CloudFunc.FS + url, - data : data, - callback : callback, - imgPosition : { top: true } - }); - }; - - this.read = function(url, dataType, callback) { - var isQuery = /\?/.test(url); - var isBeautify = /\?beautify$/.test(url); - var isMinify = /\?minify$/.test(url); - var notLog = !isQuery || isBeautify || isMinify; - var isFunc = itype.function(dataType); - - if (!callback && isFunc) { - callback = dataType; - dataType = 'text'; - } - - sendRequest({ - method: 'GET', - url: CloudFunc.FS + url, - callback: callback, - notLog: notLog, - dataType: dataType - }); - }; - - this.cp = function(data, callback) { - sendRequest({ - method : 'PUT', - url : '/cp', - data : data, - callback : callback, - imgPosition : { top: true } - }); - }; - - this.pack = function(data, callback) { - sendRequest({ - method : 'PUT', - url : '/pack', - data : data, - callback : callback - }); - }; - - this.extract = function(data, callback) { - sendRequest({ - method : 'PUT', - url : '/extract', - data : data, - callback : callback - }); - }; - - this.mv = function(data, callback) { - sendRequest({ - method : 'PUT', - url : '/mv', - data : data, - callback : callback, - imgPosition : { top: true } - }); - }; - - this.Config = { - read: function(callback) { - sendRequest({ - method : 'GET', - url : '/config', - callback : callback, - imgPosition : { top: true }, - notLog : true - }); - }, - - write: function(data, callback) { - sendRequest({ - method : 'PATCH', - url : '/config', - data : data, - callback : callback, - imgPosition : { top: true } - }); - } - }; - - this.Markdown = { - read : function(url, callback) { - sendRequest({ - method : 'GET', - url : '/markdown' + url, - callback : callback, - imgPosition : { top: true }, - notLog : true - }); - }, - - render : function(data, callback) { - sendRequest({ - method : 'PUT', - url : '/markdown', - data : data, - callback : callback, - imgPosition : { top: true }, - notLog : true - }); - } - }; - - function sendRequest(params) { - var p = params, - prefixUrl = CloudCmd.PREFIX_URL; - - p.url = prefixUrl + p.url; - p.url = encodeURI(p.url); - - /* - * if we send ajax request - - * no need in hash so we escape # - */ - p.url = p.url.replace('#', '%23'); - - DOM.load.ajax({ - method : p.method, - url : p.url, - data : p.data, - dataType : p.dataType, - error : function(jqXHR) { - var response = jqXHR.responseText, - statusText = jqXHR.statusText, - status = jqXHR.status, - text = status === 404 ? response : statusText; - - Images.show.error(text); - setTimeout(function() { - DOM.Dialog.alert(CloudCmd.TITLE, text); - }, 100); - - p.callback(Error(text)); - }, - success : function(data) { - Images.hide(); - - if (!p.notLog) - CloudCmd.log(data); - - p.callback(null, data); - } - }); } + }; + + this.Markdown = { + read : function(url, callback) { + sendRequest({ + method : 'GET', + url : '/markdown' + url, + callback : callback, + imgPosition : { top: true }, + notLog : true + }); + }, + + render : function(data, callback) { + sendRequest({ + method : 'PUT', + url : '/markdown', + data : data, + callback : callback, + imgPosition : { top: true }, + notLog : true + }); + } + }; + + function sendRequest(params) { + var p = params, + prefixUrl = CloudCmd.PREFIX_URL; + + p.url = prefixUrl + p.url; + p.url = encodeURI(p.url); + + /* + * if we send ajax request - + * no need in hash so we escape # + */ + p.url = p.url.replace('#', '%23'); + + DOM.load.ajax({ + method : p.method, + url : p.url, + data : p.data, + dataType : p.dataType, + error : function(jqXHR) { + var response = jqXHR.responseText, + statusText = jqXHR.statusText, + status = jqXHR.status, + text = status === 404 ? response : statusText; + + Images.show.error(text); + setTimeout(function() { + DOM.Dialog.alert(CloudCmd.TITLE, text); + }, 100); + + p.callback(Error(text)); + }, + success : function(data) { + Images.hide(); + + if (!p.notLog) + CloudCmd.log(data); + + p.callback(null, data); + } + }); } -})(Util, DOM, CloudFunc); +} diff --git a/client/sort.js b/client/sort.js index b0014cc9..a69faba6 100644 --- a/client/sort.js +++ b/client/sort.js @@ -1,38 +1,35 @@ +'use strict'; + /* global CloudCmd */ -/* global DOM */ +const DOM = require('./dom'); -(function() { - 'use strict'; +var Info = DOM.CurrentInfo; +var sort = CloudCmd.sort; +var order = CloudCmd.order; +var position = DOM.getPanelPosition(); +var sortPrevious = sort[position]; + +CloudCmd.sortPanel = function(name, panel) { + panel = panel || DOM.getPanel(); - var Info = DOM.CurrentInfo; - var sort = CloudCmd.sort; - var order = CloudCmd.order; - var position = DOM.getPanelPosition(); - var sortPrevious = sort[position]; + var position = panel + .dataset + .name + .replace('js-', ''); - CloudCmd.sortPanel = function(name, panel) { - panel = panel || DOM.getPanel(); - - var position = panel - .dataset - .name - .replace('js-', ''); - - if (name !== sortPrevious) { + if (name !== sortPrevious) { + order[position] = 'asc'; + } else { + if (order[position] === 'asc') + order[position] = 'desc'; + else order[position] = 'asc'; - } else { - if (order[position] === 'asc') - order[position] = 'desc'; - else - order[position] = 'asc'; - } - - sortPrevious = - sort[position] = name; - - CloudCmd.refresh(panel, { - noCurrent: position !== Info.panelPosition - }); - }; -})(); - + } + + sortPrevious = + sort[position] = name; + + CloudCmd.refresh(panel, { + noCurrent: position !== Info.panelPosition + }); +}; diff --git a/client/storage.js b/client/storage.js index 564d7cba..697f6bce 100644 --- a/client/storage.js +++ b/client/storage.js @@ -1,103 +1,103 @@ -/* global Util */ -/* global DOM */ -/* global itype */ +'use strict'; -(function(Util, DOM, localStorage, exec, json, itype) { - 'use strict'; +const itype = require('itype/legacy'); +const Util = require('../common/util'); +const DOM = require('./dom'); +const jonny = require('jonny'); +const exec = require('execon'); + +const Storage = Util.extendProto(StorageProto); +const DOMProto = Object.getPrototypeOf(DOM); + +Util.extend(DOMProto, { + Storage +}); + +function StorageProto() { + /* приватный переключатель возможности работы с кэшем */ + var Allowed; - var Storage = Util.extendProto(StorageProto), - DOMProto = Object.getPrototypeOf(DOM); + /* функция проверяет возможно ли работать с кэшем каким-либо образом */ + this.isAllowed = () => { + return Allowed && !!localStorage; + }; - Util.extend(DOMProto, { - Storage: Storage - }); - - function StorageProto() { - /* приватный переключатель возможности работы с кэшем */ - var Allowed; + /** + * allow Storage usage + */ + this.setAllowed = (isAllowed) => { + Allowed = isAllowed; + }; + + /** remove element */ + this.remove = (item, callback) => { + var ret = Allowed; - /* функция проверяет возможно ли работать с кэшем каким-либо образом */ - this.isAllowed = function() { - var ret = Allowed && !!localStorage; - return ret; - }; + if (ret) + localStorage.removeItem(item); - /** - * allow Storage usage - */ - this.setAllowed = function(isAllowed) { - Allowed = isAllowed; - }; + exec(callback, null, ret); - /** remove element */ - this.remove = function(item, callback) { - var ret = Allowed; + return this; + }; + + this.removeMatch = (string, callback) => { + var reg = RegExp('^' + string + '.*$'); + + Object.keys(localStorage).forEach(function(name) { + var is = reg.test(name); - if (ret) - localStorage.removeItem(item); - - exec(callback, null, ret); - - return this; - }; + if (is) + localStorage.removeItem(name); + }); - this.removeMatch = function(string, callback) { - var reg = RegExp('^' + string + '.*$'); - - Object.keys(localStorage).forEach(function(name) { - var is = reg.test(name); - - if (is) - localStorage.removeItem(name); + exec(callback); + + return this; + }; + + /** если доступен localStorage и + * в нём есть нужная нам директория - + * записываем данные в него + */ + this.set = (name, data, callback) => { + var str, error; + + if (itype.object(data)) + str = jonny.stringify(data); + + if (Allowed && name) + error = exec.try(() => { + localStorage.setItem(name, str || data); }); - - exec(callback); - - return this; - }; - /** если доступен localStorage и - * в нём есть нужная нам директория - - * записываем данные в него - */ - this.set = function(name, data, callback) { - var str, error; - - if (itype.object(data)) - str = json.stringify(data); - - if (Allowed && name) - error = exec.try(function() { - localStorage.setItem(name, str || data); - }); - - exec(callback, error); - - return this; - }, + exec(callback, error); - /** Если доступен Storage принимаем из него данные*/ - this.get = function(name, callback) { - var ret; - - if (Allowed) - ret = localStorage.getItem(name); - - exec(callback, null, ret); - - return this; - }, + return this; + }, + + /** Если доступен Storage принимаем из него данные*/ + this.get = function(name, callback) { + var ret; - /** функция чистит весь кэш для всех каталогов*/ - this.clear = function(callback) { - var ret = Allowed; + if (Allowed) + ret = localStorage.getItem(name); + + exec(callback, null, ret); - if (ret) - localStorage.clear(); - - exec(callback, null, ret); - - return this; - }; - } -})(Util, DOM, localStorage, Util.exec, Util.json, itype); + return this; + }, + + /** функция чистит весь кэш для всех каталогов*/ + this.clear = function(callback) { + var ret = Allowed; + + if (ret) + localStorage.clear(); + + exec(callback, null, ret); + + return this; + }; +} + diff --git a/client/upload.js b/client/upload.js index f9f44718..2a32e411 100644 --- a/client/upload.js +++ b/client/upload.js @@ -1,66 +1,63 @@ -var CloudCmd, Util, DOM; +/* global CloudCmd, Util, DOM */ -(function(CloudCmd, Util, DOM) { - 'use strict'; +'use strict'; + +CloudCmd.Upload = UploadProto; + +function UploadProto() { + var Images = DOM.Images, + Files = DOM.Files, + + Upload = this; - CloudCmd.Upload = UploadProto; - - function UploadProto() { - var Images = DOM.Images, - Files = DOM.Files, - - Upload = this; + function init() { + Images.show.load('top'); - function init() { - Images.show.load('top'); - - Util.exec.series([ - CloudCmd.View, - Upload.show - ]); - } - - this.show = function() { - Images.show.load('top'); - - Files.get('upload', function(error, data) { - CloudCmd.View.show(data, { - autoSize : true, - afterShow : afterShow - }); - }); - - DOM.load.style({ - id : 'upload-css', - inner : '[data-name=js-upload-file-button] {' + - 'font-family: "Droid Sans Mono", "Ubuntu Mono", "Consolas", monospace;' + - 'font-size: 20px;' + - 'width: 97%' + - '}' - }); - - }; - - this.hide = function() { - CloudCmd.View.hide(); - }; - - function afterShow() { - var button = DOM.getByDataName('js-upload-file-button'); - - Images.hide(); - - DOM.Events.add('change', button, function(event) { - var files = event.target.files; - - Upload.hide(); - - DOM.uploadFiles(files); - }); - } - - init(); + Util.exec.series([ + CloudCmd.View, + Upload.show + ]); } -})(CloudCmd, Util, DOM); + this.show = function() { + Images.show.load('top'); + + Files.get('upload', function(error, data) { + CloudCmd.View.show(data, { + autoSize : true, + afterShow : afterShow + }); + }); + + DOM.load.style({ + id : 'upload-css', + inner : '[data-name=js-upload-file-button] {' + + 'font-family: "Droid Sans Mono", "Ubuntu Mono", "Consolas", monospace;' + + 'font-size: 20px;' + + 'width: 97%' + + '}' + }); + + }; + + this.hide = function() { + CloudCmd.View.hide(); + }; + + function afterShow() { + var button = DOM.getByDataName('js-upload-file-button'); + + Images.hide(); + + DOM.Events.add('change', button, (event) => { + const files = event.target.files; + + Upload.hide(); + + DOM.uploadFiles(files); + }); + } + + init(); +} diff --git a/client/view.js b/client/view.js index 0e5bb2db..2c6b2bd1 100644 --- a/client/view.js +++ b/client/view.js @@ -1,408 +1,407 @@ -/* global itype */ +'use strict'; -var CloudCmd, Util, DOM, CloudFunc, $, exec; +/* global CloudCmd, Util, DOM, CloudFunc, $ */ -(function(CloudCmd, Util, DOM, CloudFunc) { - 'use strict'; +const itype = require('itype/legacy'); +const rendy = require('rendy'); +const exec = require('execon'); + +CloudCmd.View = ViewProto; + +function ViewProto(CallBack) { + var Name = 'View', + Loading = false, + Events = DOM.Events, + Info = DOM.CurrentInfo, + Key = CloudCmd.Key, + Images = DOM.Images, + View = exec.bind(Util), + Element, TemplateAudio, Overlay; - /* global rendy */ + const Config = { + beforeShow: (callback) => { + Images.hide(); + Key.unsetBind(); + showOverlay(); + exec(callback); + }, + beforeClose: (callback) => { + Key.setBind(); + exec(callback); + hideOverlay(); + }, + afterShow: (callback) => { + Element.focus(); + exec(callback); + }, + afterClose: (callback) => { + exec(callback); + }, + fitToView : true, + loop : false, + openEffect : 'none', + closeEffect : 'none', + autoSize : false, + height : '100%', + width : '100%', + minWidth : 0, + minHeight : 0, + padding : 0, + preload : 0, + keys : null, + mouseWheel : false, + arrows : false, + helpers : { + overlay : null, + title : null + } + }; - CloudCmd.View = ViewProto; + View.show = show; + View.hide = hide; - function ViewProto(CallBack) { - var Name = 'View', - Loading = false, - Events = DOM.Events, - Info = DOM.CurrentInfo, - Key = CloudCmd.Key, - Images = DOM.Images, - View = exec.bind(Util), - Element, TemplateAudio, Overlay, - Config = { - beforeShow : function(callback) { - Images.hide(); - Key.unsetBind(); - showOverlay(); - exec(callback); - }, - beforeClose : function(callback) { - Key.setBind(); - exec(callback); - hideOverlay(); - }, - afterShow : function(callback) { - Element.focus(); - exec(callback); - }, - afterClose : function(callback) { - exec(callback); - }, - fitToView : true, - loop : false, - openEffect : 'none', - closeEffect : 'none', - autoSize : false, - height : '100%', - width : '100%', - minWidth : 0, - minHeight : 0, - padding : 0, - preload : 0, - keys : null, - mouseWheel : false, - arrows : false, - helpers : { - overlay : null, - title : null - } - }; + function init() { + var func = CallBack || exec.with(show, null); - View.show = show; - View.hide = hide; + Loading = true; - function init() { - var func = CallBack || exec.with(show, null); - - Loading = true; - - exec.series([ - DOM.loadJquery, - load, - function(callback) { - Loading = false; - exec(callback); - } - ], func); - - Config.parent = Overlay = DOM.load({ - id : 'js-view', - name : 'div', - className : 'fancybox-overlay fancybox-overlay-fixed' - }); - - ['click', 'contextmenu'].forEach(function(name) { - Events.add(name, Overlay, onOverLayClick); - }); - - Events.addKey(listener); - } - - /** - * function shows FancyBox - */ - function show(data, options) { - var path, element, type; - var prefixUrl = CloudCmd.PREFIX_URL + CloudFunc.FS; - - if (Loading) - return; - - Element = $('
'); - - if (data) { - element = $(Element).append(data); - - var config = initConfig(Config, options); - - $.fancybox(element, config); - } else { - Images.show.load(); - path = prefixUrl + Info.path; - type = getType(path); - - switch(type) { - default: - Info.getData(function(error, data) { - if (error) - return Images.hide(); - - var element = document.createTextNode(data); - /* add margin only for view text documents */ - Element.css('margin', '2%'); - - $.fancybox(Element.append(element), Config); - }); - break; - - case 'image': - showImage(path, prefixUrl); - break; - - case 'media': - getMediaElement(path, function(element) { - var media = DOM.getByDataName('js-media', element); - var onKey = exec.with(onMediaKey, media); - - $.fancybox.open(element, { - parent : Overlay, - beforeShow : function() { - Config.beforeShow(); - Events.addKey(onKey); - }, - beforeClose : function() { - Config.beforeClose(); - Events.rmKey(onKey); - }, - afterShow: function() { - element - .querySelector('audio, video') - .focus(); - }, - helpers: { - overlay : null, - title : null - } - }); - }); - break; - } + exec.series([ + DOM.loadJquery, + load, + function(callback) { + Loading = false; + exec(callback); } - } + ], func); - function initConfig(Config, options) { - var config = {}; - - Util.copyObj(config, Config); - - if (!options) - return config; - - Object.keys(options).forEach(function(name) { - var isConfig = !!config[name]; - var item = options[name]; - var isFunc = itype.function(item); - - if (!isFunc || !isConfig) { - config[name] = options[name]; - } else { - var func = config[name]; - config[name] = function() { - exec.series([func, item]); - }; - } - }); - - return config; - } + Config.parent = Overlay = DOM.load({ + id : 'js-view', + name : 'div', + className : 'fancybox-overlay fancybox-overlay-fixed' + }); - function hide() { - $.fancybox.close(); - } + ['click', 'contextmenu'].forEach(function(name) { + Events.add(name, Overlay, onOverLayClick); + }); - function showImage(path, prefixUrl) { - var config, - current = Info.name, - files = [].slice.call(Info.files), - names = files - .filter(function(file) { - var name = DOM.getCurrentName(file); - return isImage(name); - }) - .filter(function(file) { - var name = DOM.getCurrentName(file); - return name !== current; - }).map(function(file) { - var path = DOM.getCurrentPath(file), - name = DOM.getCurrentName(file); - - return { - href: prefixUrl + path, - title: name - }; - }); - - names.unshift({ - href: path, - title: current - }); - - config = Util.copyObj({ - }, Config); - - config = Util.copyObj(config, { - autoSize : true, - type : 'image', - prevEffect : 'none', - nextEffect : 'none', - arrows : true, - keys : true, - helpers : { - overlay : null, - title : {} - } - }); - - $.fancybox.open(names, config); - } - - function isImage(name) { - var isMatch; - - isMatch = [ - 'jp(e|g|eg)', - 'gif', - 'png', - 'bmp', - 'webp', - 'svg', - 'ico' - ].some(function(ext) { - var reg = RegExp('\\.' + ext + '$', 'i'); - return reg.test(name); - }); - - return isMatch; - } - - function isMedia(name) { - var isMatch; - - isMatch = isAudio(name) || isVideo(name); - - return isMatch; - } - - function isAudio(name) { - return /\.(mp3|ogg|m4a)$/i.test(name); - } - - function isVideo(name) { - return /\.(mp4|avi)$/i.test(name); - } - - function getType(name) { - var type; - - if (isImage(name)) - type = 'image'; - else if (isMedia(name)) - type = 'media'; - - return type; - } - - function getMediaElement(src, callback) { - check(src, callback); - - DOM.Files.get('view/media-tmpl', function(error, template) { - var rendered, element, type, is, - name = Info.name; - - if (error) { - alert(error); - } else { - if (!TemplateAudio) - TemplateAudio = template; - - is = isAudio(name); - type = is ? 'audio' : 'video'; - - rendered = rendy(TemplateAudio, { - src : src, - type: type, - name: Info.name - }); - - element = $(rendered)[0]; - callback(element); - } - }); - } - - function check(src, callback) { - if (typeof src !== 'string') - throw Error('src should be a string!'); - - if (typeof callback !== 'function') - throw Error('callback should be a function'); - } - - function onMediaKey(media, event) { - var key = event.keyCode; - - if (key === Key.SPACE) { - if (media.paused) - media.play(); - else - media.pause(); - } - } - - /** - * function loads css and js of FancyBox - * @callback - executes, when everything loaded - */ - function load(callback) { - Util.time(Name + ' load'); - - DOM.loadRemote('fancybox', function() { - var prefix = CloudCmd.PREFIX; - - DOM.load.css(prefix + '/css/view.css', callback); - - DOM.load.style({ - id : 'view-inlince-css', - inner : [ - '.fancybox-title-float-wrap .child {', - '-webkit-border-radius: 0;', - '-moz-border-radius: 0;', - 'border-radius: 0;', - '}' - ].join('') - }); - }); - } - - function onOverLayClick(event) { - var isCurrent, isFiles, isFilesPassive, - files = Info.files, - filesPassive = Info.filesPassive, - element = event.target, - isOverlay = element === Overlay, - position = { - x: event.clientX, - y: event.clientY - }; - - if (isOverlay) { - hideOverlay(); - element = DOM.getCurrentByPosition(position); - - if (element) { - isFiles = ~files.indexOf(element); - isFilesPassive = ~filesPassive.indexOf(element); - - if (isFiles || isFilesPassive) { - isCurrent = DOM.isCurrentFile(element); - - if (!isCurrent) - DOM.setCurrentFile(element); - } - } - - View.hide(); - } - } - - function hideOverlay() { - Overlay.classList.remove('view-overlay'); - } - - function showOverlay() { - Overlay.classList.add('view-overlay'); - } - - function listener(event) { - var keyCode = event.keyCode, - ESC = Key.ESC; - - if (keyCode === ESC) - hide(); - } - - init(); - - return View; + Events.addKey(listener); } + + /** + * function shows FancyBox + */ + function show(data, options) { + var path, element, type; + var prefixUrl = CloudCmd.PREFIX_URL + CloudFunc.FS; + + if (Loading) + return; + + Element = $('
'); + + if (data) { + element = $(Element).append(data); + + var config = initConfig(Config, options); + + $.fancybox(element, config); + } else { + Images.show.load(); + path = prefixUrl + Info.path; + type = getType(path); + + switch(type) { + default: + Info.getData(function(error, data) { + if (error) + return Images.hide(); + + var element = document.createTextNode(data); + /* add margin only for view text documents */ + Element.css('margin', '2%'); + + $.fancybox(Element.append(element), Config); + }); + break; + + case 'image': + showImage(path, prefixUrl); + break; + + case 'media': + getMediaElement(path, function(element) { + var media = DOM.getByDataName('js-media', element); + var onKey = exec.with(onMediaKey, media); + + $.fancybox.open(element, { + parent : Overlay, + beforeShow : function() { + Config.beforeShow(); + Events.addKey(onKey); + }, + beforeClose : function() { + Config.beforeClose(); + Events.rmKey(onKey); + }, + afterShow: function() { + element + .querySelector('audio, video') + .focus(); + }, + helpers: { + overlay : null, + title : null + } + }); + }); + break; + } + } + } + + function initConfig(Config, options) { + var config = {}; + + Util.copyObj(config, Config); + + if (!options) + return config; + + Object.keys(options).forEach(function(name) { + var isConfig = !!config[name]; + var item = options[name]; + var isFunc = itype.function(item); + + if (!isFunc || !isConfig) { + config[name] = options[name]; + } else { + var func = config[name]; + config[name] = function() { + exec.series([func, item]); + }; + } + }); + + return config; + } + + function hide() { + $.fancybox.close(); + } + + function showImage(path, prefixUrl) { + var config, + current = Info.name, + files = [].slice.call(Info.files), + names = files + .filter(function(file) { + var name = DOM.getCurrentName(file); + return isImage(name); + }) + .filter(function(file) { + var name = DOM.getCurrentName(file); + return name !== current; + }).map(function(file) { + var path = DOM.getCurrentPath(file), + name = DOM.getCurrentName(file); + + return { + href: prefixUrl + path, + title: name + }; + }); + + names.unshift({ + href: path, + title: current + }); + + config = Util.copyObj({ + }, Config); + + config = Util.copyObj(config, { + autoSize : true, + type : 'image', + prevEffect : 'none', + nextEffect : 'none', + arrows : true, + keys : true, + helpers : { + overlay : null, + title : {} + } + }); + + $.fancybox.open(names, config); + } + + function isImage(name) { + var isMatch; + + isMatch = [ + 'jp(e|g|eg)', + 'gif', + 'png', + 'bmp', + 'webp', + 'svg', + 'ico' + ].some(function(ext) { + var reg = RegExp('\\.' + ext + '$', 'i'); + return reg.test(name); + }); + + return isMatch; + } + + function isMedia(name) { + var isMatch; + + isMatch = isAudio(name) || isVideo(name); + + return isMatch; + } + + function isAudio(name) { + return /\.(mp3|ogg|m4a)$/i.test(name); + } + + function isVideo(name) { + return /\.(mp4|avi)$/i.test(name); + } + + function getType(name) { + var type; + + if (isImage(name)) + type = 'image'; + else if (isMedia(name)) + type = 'media'; + + return type; + } + + function getMediaElement(src, callback) { + check(src, callback); + + DOM.Files.get('view/media-tmpl', function(error, template) { + var rendered, element, type, is, + name = Info.name; + + if (error) { + alert(error); + } else { + if (!TemplateAudio) + TemplateAudio = template; + + is = isAudio(name); + type = is ? 'audio' : 'video'; + + rendered = rendy(TemplateAudio, { + src : src, + type: type, + name: Info.name + }); + + element = $(rendered)[0]; + callback(element); + } + }); + } + + function check(src, callback) { + if (typeof src !== 'string') + throw Error('src should be a string!'); + + if (typeof callback !== 'function') + throw Error('callback should be a function'); + } + + function onMediaKey(media, event) { + var key = event.keyCode; + + if (key === Key.SPACE) { + if (media.paused) + media.play(); + else + media.pause(); + } + } + + /** + * function loads css and js of FancyBox + * @callback - executes, when everything loaded + */ + function load(callback) { + Util.time(Name + ' load'); + + DOM.loadRemote('fancybox', function() { + var prefix = CloudCmd.PREFIX; + + DOM.load.css(prefix + '/css/view.css', callback); + + DOM.load.style({ + id : 'view-inlince-css', + inner : [ + '.fancybox-title-float-wrap .child {', + '-webkit-border-radius: 0;', + '-moz-border-radius: 0;', + 'border-radius: 0;', + '}' + ].join('') + }); + }); + } + + function onOverLayClick(event) { + var isCurrent, isFiles, isFilesPassive, + files = Info.files, + filesPassive = Info.filesPassive, + element = event.target, + isOverlay = element === Overlay, + position = { + x: event.clientX, + y: event.clientY + }; + + if (isOverlay) { + hideOverlay(); + element = DOM.getCurrentByPosition(position); + + if (element) { + isFiles = ~files.indexOf(element); + isFilesPassive = ~filesPassive.indexOf(element); + + if (isFiles || isFilesPassive) { + isCurrent = DOM.isCurrentFile(element); + + if (!isCurrent) + DOM.setCurrentFile(element); + } + } + + View.hide(); + } + } + + function hideOverlay() { + Overlay.classList.remove('view-overlay'); + } + + function showOverlay() { + Overlay.classList.add('view-overlay'); + } + + function listener(event) { + var keyCode = event.keyCode, + ESC = Key.ESC; + + if (keyCode === ESC) + hide(); + } + + init(); + + return View; +} -})(CloudCmd, Util, DOM, CloudFunc); diff --git a/common/util.js b/common/util.js index 93f6e2e9..ae8360c9 100644 --- a/common/util.js +++ b/common/util.js @@ -1,252 +1,239 @@ -(function(scope) { - 'use strict'; +'use strict'; + +const exec = require('execon'); +const rendy = require('rendy'); +const jonny = require('jonny'); + +module.exports = new UtilProto(exec); + +function UtilProto(exec) { + const Util = this; + const Scope = global || window; - var exec; - var rendy; - var jonny; - var Scope = scope.window ? window : global; + this.getStrBigFirst = getStrBigFirst; + this.kebabToCamelCase = kebabToCamelCase; - if (typeof module === 'object' && module.exports) { - exec = require('execon'); - rendy = require('rendy'); - jonny = require('jonny'); - module.exports = new UtilProto(exec); - } else if (!Scope.Util) { - exec = window.exec; - rendy = window.rendy; - jonny = window.jonny; - Scope.Util = new UtilProto(exec); - } - - function UtilProto(exec) { - var Util = this; - - this.getStrBigFirst = getStrBigFirst; - this.kebabToCamelCase = kebabToCamelCase; - - /** - * Copy properties from from to to - * - * @param from - * @param to - */ - this.copyObj = function(to, from) { - if (!from) { - from = to; - to = {}; - } - - if (to) - Object.keys(from).forEach(function(name) { - to[name] = from[name]; - }); - - return to; - }; - - /** - * copy objFrom properties to target - * - * @target - * @objFrom - */ - this.extend = function(target, objFrom) { - var obj; - var keys; - var proto; - var isFunc = typeof objFrom === 'function'; - var isArray = Array.isArray(objFrom); - var isObj = typeof target === 'object'; - var ret = isObj ? target : {}; - - if (isArray) - objFrom.forEach(function(item) { - ret = Util.extend(target, item); - }); - - else if (objFrom) { - obj = isFunc ? new objFrom() : objFrom; - keys = Object.keys(obj); - - if (!keys.length) { - proto = Object.getPrototypeOf(objFrom); - keys = Object.keys(proto); - } - - keys.forEach(function(name) { - ret[name] = obj[name]; - }); - } - - return ret; - }; - - /** - * extend proto - * - * @obj - */ - this.extendProto = function(obj) { - var ret, F = function() {}; - F.prototype = Util.extend({}, obj); - ret = new F(); - - return ret; - }; - - this.json = jonny; - - this.escapeRegExp = function(str) { - var isStr = typeof str === 'string'; - - if (isStr) - str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); - - return str; - }; - - /** - * get regexp from wild card - */ - this.getRegExp = function(wildcard) { - var regExp; - - if (!wildcard) - wildcard = '*'; - - wildcard = '^' + wildcard /* search from start of line */ - .replace('.', '\\.') - .replace('*', '.*') - .replace('?', '.?'); - - wildcard += '$'; /* search to end of line */ - - regExp = new RegExp(wildcard); - - return regExp; - }; - - this.exec = exec; - - /** - * function gets file extension - * - * @param pFileName - * @return Ext - */ - this.getExt = function(name) { - var ret = ''; - var dot; - var isStr = typeof name === 'string' - - if (isStr) { - dot = name.lastIndexOf('.'); - - if (~dot) - ret = name.substr(dot); - } - - return ret; - }; - - /** - * get values from Object Array name properties - * or - * @pObj - */ - this.getNamesFromObjArray = function(arr) { - var ret = []; - - if (!Array.isArray(arr)) - throw Error('arr should be array!'); - - ret = arr.map(function(item) { - return item.name; - }); - - return ret; - }; - - /** - * find object by name in arrray - * - * @param array - * @param name - */ - this.findObjByNameInArr = function(array, name) { - var ret; - - if (!Array.isArray(array)) - throw Error('array should be array!'); - - if (typeof name !== 'string') - throw Error('name should be string!'); - - array.some(function(item) { - var is = item.name === name, - isArray = Array.isArray(item); - - if (is) - ret = item; - else if (isArray) - item.some(function(item) { - is = item.name === name; - - if (is) - ret = item.data; - - return is; - }); - - return is; - }); - - return ret; - }; - - /** - * start timer - * @param name - */ - this.time = function(name) { - var console = Scope.console; - - Util.exec.ifExist(console, 'time', [name]); - - return this; - }; - - /** - * stop timer - * @param name - */ - this.timeEnd = function(name) { - var console = Scope.console; - - Util.exec.ifExist(console, 'timeEnd', [name]); - - return this; - }; - - function getStrBigFirst(str) { - if (!str) - throw Error('str could not be empty!'); - - var first = str[0].toUpperCase(); - return first + str.slice(1); + /** + * Copy properties from from to to + * + * @param from + * @param to + */ + this.copyObj = function(to, from) { + if (!from) { + from = to; + to = {}; } - function kebabToCamelCase(str) { - if (!str) - throw Error('str could not be empty!'); + if (to) + Object.keys(from).forEach(function(name) { + to[name] = from[name]; + }); + + return to; + }; + + /** + * copy objFrom properties to target + * + * @target + * @objFrom + */ + this.extend = function(target, objFrom) { + var obj; + var keys; + var proto; + var isFunc = typeof objFrom === 'function'; + var isArray = Array.isArray(objFrom); + var isObj = typeof target === 'object'; + var ret = isObj ? target : {}; + + if (isArray) + objFrom.forEach(function(item) { + ret = Util.extend(target, item); + }); + + else if (objFrom) { + obj = isFunc ? new objFrom() : objFrom; + keys = Object.keys(obj); - return str - .split('-') - .map(getStrBigFirst) - .join('') - .replace(/.js$/, ''); + if (!keys.length) { + proto = Object.getPrototypeOf(objFrom); + keys = Object.keys(proto); + } + + keys.forEach(function(name) { + ret[name] = obj[name]; + }); } + return ret; + }; + + /** + * extend proto + * + * @obj + */ + this.extendProto = function(obj) { + var ret, F = function() {}; + F.prototype = Util.extend({}, obj); + ret = new F(); + + return ret; + }; + + this.json = jonny; + + this.escapeRegExp = function(str) { + var isStr = typeof str === 'string'; + + if (isStr) + str = str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); + + return str; + }; + + /** + * get regexp from wild card + */ + this.getRegExp = function(wildcard) { + var regExp; + + if (!wildcard) + wildcard = '*'; + + wildcard = '^' + wildcard /* search from start of line */ + .replace('.', '\\.') + .replace('*', '.*') + .replace('?', '.?'); + + wildcard += '$'; /* search to end of line */ + + regExp = new RegExp(wildcard); + + return regExp; + }; + + this.exec = exec; + + /** + * function gets file extension + * + * @param pFileName + * @return Ext + */ + this.getExt = function(name) { + var ret = ''; + var dot; + var isStr = typeof name === 'string' + + if (isStr) { + dot = name.lastIndexOf('.'); + + if (~dot) + ret = name.substr(dot); + } + + return ret; + }; + + /** + * get values from Object Array name properties + * or + * @pObj + */ + this.getNamesFromObjArray = function(arr) { + var ret = []; + + if (!Array.isArray(arr)) + throw Error('arr should be array!'); + + ret = arr.map(function(item) { + return item.name; + }); + + return ret; + }; + + /** + * find object by name in arrray + * + * @param array + * @param name + */ + this.findObjByNameInArr = function(array, name) { + var ret; + + if (!Array.isArray(array)) + throw Error('array should be array!'); + + if (typeof name !== 'string') + throw Error('name should be string!'); + + array.some(function(item) { + var is = item.name === name, + isArray = Array.isArray(item); + + if (is) + ret = item; + else if (isArray) + item.some(function(item) { + is = item.name === name; + + if (is) + ret = item.data; + + return is; + }); + + return is; + }); + + return ret; + }; + + /** + * start timer + * @param name + */ + this.time = function(name) { + const console = Scope.console; + + Util.exec.ifExist(console, 'time', [name]); + + return this; + }; + + /** + * stop timer + * @param name + */ + this.timeEnd = function(name) { + var console = Scope.console; + + Util.exec.ifExist(console, 'timeEnd', [name]); + + return this; + }; + + function getStrBigFirst(str) { + if (!str) + throw Error('str could not be empty!'); + + var first = str[0].toUpperCase(); + return first + str.slice(1); } -})(this); + function kebabToCamelCase(str) { + if (!str) + throw Error('str could not be empty!'); + + return str + .split('-') + .map(getStrBigFirst) + .join('') + .replace(/.js$/, ''); + } +} + diff --git a/modules/currify/.bower.json b/modules/currify/.bower.json deleted file mode 100644 index fc019608..00000000 --- a/modules/currify/.bower.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "currify", - "description": "translate the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single or more arguments", - "homepage": "https://github.com/coderaiser/currify", - "authors": [ - "coderaiser " - ], - "main": "lib/currify.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "curry", - "functional" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "test" - ], - "version": "2.0.3", - "_release": "2.0.3", - "_resolution": { - "type": "version", - "tag": "v2.0.3", - "commit": "be9ab0b0f7b8e685da89321df384ac902fa3c587" - }, - "_source": "https://github.com/coderaiser/currify.git", - "_target": "2.0.3", - "_originalSource": "currify" -} \ No newline at end of file diff --git a/modules/currify/ChangeLog b/modules/currify/ChangeLog deleted file mode 100644 index 043b37be..00000000 --- a/modules/currify/ChangeLog +++ /dev/null @@ -1,34 +0,0 @@ -2016.12.05, v2.0.3 - -fix: -- (currify) bundle: empty currify in dist - - -2016.11.23, v2.0.2 - -fix: -- (currify) when to much function.length use default - - -2016.11.23, v2.0.1 - -fix: -- (currify) add support of 4 and 5 arguments - - -2016.11.23, v2.0.0 - -feature: -- (travis) node_js: v6, v7 -- (currify) fn.length in curried functions -- (package) scripts: coverage -- (gitignore) *.swp -- (currify) es2015-ify -- (package) redrun v5.0.0 -- (package) redrun v4.0.0 -- (package) npm-run-all -> redrun -- (package) jscs v3.0.3 -- (license) add -- (gitignore) npm-debug.log -> npm-debug.log* -- (package) browserify v13.0.0 - diff --git a/modules/currify/LICENSE b/modules/currify/LICENSE deleted file mode 100644 index eaec9a10..00000000 --- a/modules/currify/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/modules/currify/README.md b/modules/currify/README.md deleted file mode 100644 index ed93ad7a..00000000 --- a/modules/currify/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# Currify [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] - -Translate the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single or more arguments. - -## Install - -``` -npm i currify --save -``` - -## How to use? - -```js -const currify = require('currify'); - -const mean = (a, b, c) => (a + b) / c; -const mean1 = currify(mean, 1); -const mean2 = mean1(2); - -mean2(2); -// returns -1.5 -``` - -## Environments - -In old `node.js` environments that not fully supports `es2015`, `currify` could be used with: - -```js -var currify = require('currify/legacy'); -``` - -## Related - -- [zames](https://github.com/coderaiser/zames "zames") - converts callback-based functions to Promises and apply currying to arguments - -## License - -MIT - -[NPMIMGURL]: https://img.shields.io/npm/v/currify.svg?style=flat -[BuildStatusIMGURL]: https://img.shields.io/travis/coderaiser/currify/master.svg?style=flat -[DependencyStatusIMGURL]: https://img.shields.io/gemnasium/coderaiser/currify.svg?style=flat -[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat -[NPMURL]: https://npmjs.org/package/currify "npm" -[BuildStatusURL]: https://travis-ci.org/coderaiser/currify "Build Status" -[DependencyStatusURL]: https://gemnasium.com/coderaiser/currify "Dependency Status" -[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License" diff --git a/modules/currify/bower.json b/modules/currify/bower.json deleted file mode 100644 index ce227de5..00000000 --- a/modules/currify/bower.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "currify", - "description": "translate the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single or more arguments", - "homepage": "https://github.com/coderaiser/currify", - "authors": [ - "coderaiser " - ], - "main": "lib/currify.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "curry", - "functional" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "test" - ] -} diff --git a/modules/currify/dist/currify.min.js b/modules/currify/dist/currify.min.js deleted file mode 100644 index 69e423eb..00000000 --- a/modules/currify/dist/currify.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(r){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=r();else if("function"==typeof define&&define.amd)define([],r);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.currify=r()}}(function(){return function r(n,e,t){function o(f,u){if(!e[f]){if(!n[f]){var c="function"==typeof require&&require;if(!u&&c)return c(f,!0);if(i)return i(f,!0);var l=new Error("Cannot find module '"+f+"'");throw l.code="MODULE_NOT_FOUND",l}var p=e[f]={exports:{}};n[f][0].call(p.exports,function(r){var e=n[f][1][r];return o(e?e:r)},p,p.exports,r,n,e,t)}return e[f].exports}for(var i="function"==typeof require&&require,f=0;f=n.length)return n.apply(void 0,t(e));var u=function(){return r.apply(void 0,[n].concat(t(e),Array.prototype.slice.call(arguments)))},c=n.length-arguments.length,l=f(u)[c];return l||u}},{}]},{},["currify"])("currify")}); diff --git a/modules/currify/lib/currify.js b/modules/currify/lib/currify.js deleted file mode 100644 index 9c13b48d..00000000 --- a/modules/currify/lib/currify.js +++ /dev/null @@ -1,44 +0,0 @@ -'use strict'; - -const tail = list => [].slice.call(list, 1); -const f = (fn) => [ - function(a) { - return fn(...arguments); - }, - function(a, b) { - return fn(...arguments); - }, - function(a, b, c) { - return fn(...arguments); - }, - function(a, b, c, d) { - return fn(...arguments); - }, - function(a, b, c, d, e) { - return fn(...arguments); - } -]; - -module.exports = function currify(fn) { - check(fn); - - const args = tail(arguments); - - if (args.length >= fn.length) - return fn(...args); - - const again = function() { - return currify(...[fn, ...args, ...arguments]); - }; - - const count = fn.length - arguments.length; - const func = f(again)[count]; - - return func || again; -} - -function check(fn) { - if (typeof fn !== 'function') - throw Error('fn should be function!'); -} - diff --git a/modules/currify/package.json b/modules/currify/package.json deleted file mode 100644 index 3d9851a2..00000000 --- a/modules/currify/package.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "name": "currify", - "version": "2.0.3", - "description": "translate the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single or more arguments", - "main": "lib/currify.js", - "scripts": { - "test": "tape test/*.js", - "coverage": "nyc npm test", - "lint": "eslint lib test", - "build": "redrun clean 6to5 legacy:* bundle bundle minify", - "minify": "minify dist/currify.js > dist/currify.min.js", - "6to5": "babel -d legacy/lib lib", - "wisdom": "npm run build", - "clean": "rimraf dist/* legacy/*", - "bundle:base": "browserify -s currify --ng false", - "bundle": "npm run bundle:base -- -r ./legacy/lib/currify.js:currify ./legacy/lib/currify.js -o dist/currify.js", - "watcher": "nodemon -w test -w lib --exec", - "watch:test": "npm run watcher -- npm test", - "watch:lint": "npm run watcher -- 'npm run lint'", - "watch:tape": "nodemon -w test -w lib --exec tape", - "watch:coverage:base": "npm run watcher -- nyc npm test", - "watch:coverage:tape": "npm run watcher -- nyc tape", - "watch:coverage": "bin/redrun.js watch:coverage:base", - "legacy:index": "echo \"module.exports = require('./lib/currify');\" > legacy/index.js" - }, - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/currify.git" - }, - "keywords": [ - "currify", - "partial", - "functional" - ], - "author": "coderaiser (http://coderaiser.github.io/)", - "license": "MIT", - "bugs": { - "url": "https://github.com/coderaiser/currify/issues" - }, - "homepage": "https://github.com/coderaiser/currify", - "devDependencies": { - "babel-cli": "^6.1.1", - "babel-preset-es2015": "^6.0.15", - "browserify": "^13.0.0", - "eslint": "^3.10.2", - "minify": "^2.0.13", - "nodemon": "^1.11.0", - "nyc": "^10.0.0", - "redrun": "^5.0.1", - "rimraf": "^2.4.3", - "tape": "^4.2.0" - } -} diff --git a/modules/execon/.bower.json b/modules/execon/.bower.json deleted file mode 100644 index 982fa49b..00000000 --- a/modules/execon/.bower.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "execon", - "version": "1.2.9", - "homepage": "https://github.com/coderaiser/execon", - "authors": [ - "coderaiser " - ], - "description": "Patterns of function calls", - "main": "lib/exec.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "exec" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "_release": "1.2.9", - "_resolution": { - "type": "version", - "tag": "v1.2.9", - "commit": "b71d2c60651f957486301e10462aab80a0f62ee1" - }, - "_source": "git://github.com/coderaiser/execon.git", - "_target": "~1.2.8", - "_originalSource": "execon" -} \ No newline at end of file diff --git a/modules/execon/ChangeLog b/modules/execon/ChangeLog deleted file mode 100644 index e0f07343..00000000 --- a/modules/execon/ChangeLog +++ /dev/null @@ -1,86 +0,0 @@ -2015.10.23, v1.2.9 - -fix: -- (exec) parallel throw: add " " - - -2015.10.21, v1.2.8 - -fix: -- (exec) with do not return value - -feature: -- (travis) add -- (gitignore) add - - -2015.10.01, v1.2.7 - -fix: -- (exec) with: concat arguments - - -2015.10.01, v1.2.6 - -feature: -- (exec) with: bind.apply -> function apply - - -2015.07.21, v1.2.5 - -fix: -- (exec) eachSeries - - -2015.07.21, v1.2.4 - -fix: -- (exec) each, eachSeries - - -2015.07.21, v1.2.3 - -fix: -- (exec) each, eachSeries: call callback when !listeners.length - - -2015.06.05, v1.2.2 - -feature: -- (exec) with: callback.bind -> bind.apply - - -2015.06.05, v1.2.1 - -feature: -- (exec) exec.with: arguments[0] -> slice.call(arguments) - - -2015.06.03, v1.2.0 - -feature: -- (exec) add each, eachSeries -- (exec) series: rm getType call - - -2015.01.28, v1.1.1 - -feature: -- (exec) scope -> global -- (bower) add -- (package) node-execon -> execon -- (package) v1.1.0 -- (execon) series: add callback - - -2015.01.15, v1.1.0 - -feature: -- (execon) series: add callback - - -2014.11.24, v1.0.1 - -fix: -- (package) check -> exec - diff --git a/modules/execon/LICENSE b/modules/execon/LICENSE deleted file mode 100644 index 7511174b..00000000 --- a/modules/execon/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2015 coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/modules/execon/README.md b/modules/execon/README.md deleted file mode 100644 index 661484b4..00000000 --- a/modules/execon/README.md +++ /dev/null @@ -1,154 +0,0 @@ -# Execon [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![BuildStatusIMGURL]][BuildStatusURL] - -Patterns of function calls. - -## Install -![NPM_INFO][NPM_INFO_IMG] -``` -npm i execon --save -# or -bower i execon --save -``` - -## Api - -```js -var exec = require('execon'); -``` - -### exec -Check is parameter is function, if it's - executes it with given parameters - -Was: - -```js -function(callback, p1, p2, pN) { - if (typeof callback === 'function') - callback(p1, p2, pN); -} -``` - -Now - -```js -function(callback, p1, p2, pN) { - exec(callback, p1, p2, pN); -} -``` - -or just - -```js -exec.ret(callback, p1, p2, pN); -``` - -### exec.if -Conditional execution one of two functions - -Preconditions: - -```js -function one() { - console.log(1); -} - -function two(callback) { - setTimeout(callback, 1000); -} -``` - - -Before: - -```js -if (2 > 3) - one(); -else - two(one); - -``` - -After: - -```js -exec.if(2 > 3, one, two); -``` - -### exec.parallel -if a you need a couple async operation do same work, and then call callback, this function for you. - -**Node.js example**. - -```js -var fs = require('fs'), - Util = require('execon'); - -exec.parallel([ - function(callback) { - fs.readFile('file1', callback); - }, - function(callback) { - fs.readFile('file2', callback); - } -], function(error, data1, data2) { - if (error) - console.log(error) - else - console.log(data1, data2); -}); -``` -**Vanilla js example.** - -```js -var ONE_SECOND = 1000, - TWO_SECONDS = 2000, - func = function(time, str, callback) { - setTimeout(function() { - console.log(str); - callback(null, str); - }, time); - }, - - func1 = func.bind(null, TWO_SECONDS, 'first'), - func2 = func.bind(null, ONE_SECOND, 'second'); - -exec.parallel([func1, func2], function(error, str1, str2) { - console.log(str1, str2); -}); -``` - -### exec.series -executes functions one-by-one - -```js -function one(callback){ - setTimeout(function() { - console.log(1) - callback(); - }, 1000); -} - -function two(callback) { - console.log(2); - callback(); -} - -exec.series([one, two], function(error) { - console.log(error || 'done'); -}); -``` - -## License - -MIT - -[NPM_INFO_IMG]: https://nodei.co/npm/execon.png?downloads=true&&stars&&downloadRank "npm install rendy" -[NPMIMGURL]: https://img.shields.io/npm/v/execon.svg?style=flat -[DependencyStatusIMGURL]: https://img.shields.io/gemnasium/coderaiser/execon.svg?style=flat -[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat -[NPMURL]: https://npmjs.org/package/execon "npm" -[BuildStatusURL]: https://travis-ci.org/coderaiser/execon "Build Status" -[DependencyStatusURL]: https://gemnasium.com/coderaiser/execon "Dependency Status" -[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License" -[BuildStatusIMGURL]: https://img.shields.io/travis/coderaiser/execon/master.svg?style=flat -[BuildStatusURL]: https://travis-ci.org/coderaiser/execon "Build Status" diff --git a/modules/execon/bower.json b/modules/execon/bower.json deleted file mode 100644 index d181b66d..00000000 --- a/modules/execon/bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "execon", - "version": "1.2.9", - "homepage": "https://github.com/coderaiser/execon", - "authors": [ - "coderaiser " - ], - "description": "Patterns of function calls", - "main": "lib/exec.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "exec" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/modules/execon/lib/exec.js b/modules/execon/lib/exec.js deleted file mode 100644 index 1b9b85b2..00000000 --- a/modules/execon/lib/exec.js +++ /dev/null @@ -1,244 +0,0 @@ -(function(global) { - 'use strict'; - - if (typeof module === 'object' && module.exports) - module.exports = new ExecProto(); - else - global.exec = new ExecProto(); - - function ExecProto() { - var slice = Array.prototype.slice, - /** - * function do save exec of function - * @param callback - * @param arg1 - * ... - * @param argN - */ - exec = function(callback) { - var ret, - isFunc = typeof callback === 'function', - args = slice.call(arguments, 1); - - if (isFunc) - ret = callback.apply(null, args); - - return ret; - }; - - /* - * return function that calls callback with arguments - */ - exec.with = function(callback) { - var slice = Array.prototype.slice, - args = slice.call(arguments, 1); - - return function() { - var array = slice.call(arguments), - all = args.concat(array); - - return callback.apply(null, all); - }; - }; - - /** - * return save exec function - * @param callback - */ - exec.ret = function() { - var result, - args = slice.call(arguments); - - args.unshift(exec); - result = exec.with.apply(null, args); - - return result; - }; - - /** - * function do conditional save exec of function - * @param condition - * @param callback - * @param func - */ - exec.if = function(condition, callback, func) { - var ret; - - if (condition) - exec(callback); - else - exec(func, callback); - - return ret; - }; - - /** - * exec function if it exist in object - * - * @param obj - * @param name - * @param arg - */ - exec.ifExist = function(obj, name, arg) { - var ret, - func = obj && obj[name]; - - if (func) - func = func.apply(obj, arg); - - return ret; - }; - - exec.parallel = function(funcs, callback) { - var ERROR = 'could not be empty!', - keys = [], - callbackWas = false, - arr = [], - obj = {}, - count = 0, - countFuncs = 0, - type = getType(funcs); - - if (!funcs) - throw Error('funcs ' + ERROR); - - if (!callback) - throw Error('callback ' + ERROR); - - switch(type) { - case 'array': - countFuncs = funcs.length; - - funcs.forEach(function(func, num) { - exec(func, function() { - checkFunc(num, arguments); - }); - }); - break; - - case 'object': - keys = Object.keys(funcs); - countFuncs = keys.length; - - keys.forEach(function(name) { - var func = funcs[name]; - - exec(func, function() { - checkFunc(name, arguments, obj); - }); - }); - break; - } - - function checkFunc(num, data) { - var args = slice.call(data, 1), - isLast = false, - error = data[0], - length = args.length; - - ++count; - - isLast = count === countFuncs; - - if (!error) - if (length >= 2) - arr[num] = args; - else - arr[num] = args[0]; - - if (!callbackWas && (error || isLast)) { - callbackWas = true; - - if (type === 'array') - callback.apply(null, [error].concat(arr)); - else - callback(error, arr); - } - } - }; - - /** - * load functions thrue callbacks one-by-one - * @param funcs {Array} - array of functions - */ - exec.series = function(funcs, callback) { - var fn, - i = funcs.length, - check = function(error) { - var done; - - --i; - - if (!i || error) { - done = true; - exec(callback, error); - } - - return done; - }; - - if (!Array.isArray(funcs)) - throw Error('funcs should be array!'); - - fn = funcs.shift(); - - exec(fn, function(error) { - if (!check(error)) - exec.series(funcs, callback); - }); - }; - - exec.each = function(array, iterator, callback) { - var listeners = array.map(function(item) { - return iterator.bind(null, item); - }); - - if (!listeners.length) - callback(); - else - exec.parallel(listeners, callback); - }; - - exec.eachSeries = function(array, iterator, callback) { - var listeners = array.map(function(item) { - return iterator.bind(null, item); - }); - - if (typeof callback !== 'function') - throw Error('callback should be function'); - - if (!listeners.length) - callback(); - else - exec.series(listeners, callback); - }; - - /** - * function execute param function in - * try...catch block - * - * @param callback - */ - exec.try = function(callback) { - var ret; - try { - ret = callback(); - } catch(error) { - ret = error; - } - - return ret; - }; - - function getType(variable) { - var regExp = new RegExp('\\s([a-zA-Z]+)'), - str = {}.toString.call(variable), - typeBig = str.match(regExp)[1], - result = typeBig.toLowerCase(); - - return result; - } - - return exec; - } -})(this); diff --git a/modules/execon/package.json b/modules/execon/package.json deleted file mode 100644 index 3455d224..00000000 --- a/modules/execon/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "execon", - "version": "1.2.9", - "author": "coderaiser (https://github.com/coderaiser)", - "description": "Patterns of function calls", - "homepage": "http://github.com/coderaiser/execon", - "scripts": { - "test": "tape test/*.js" - }, - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/execon.git" - }, - "dependencies": {}, - "license": "MIT", - "engines": { - "node": ">=0.8" - }, - "main": "lib/exec.js", - "devDependencies": { - "tape": "~4.2.1" - } -} diff --git a/modules/format-io/.bower.json b/modules/format-io/.bower.json deleted file mode 100644 index a0fd0c6a..00000000 --- a/modules/format-io/.bower.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "format-io", - "version": "0.9.6", - "homepage": "https://github.com/coderaiser/format-io", - "authors": [ - "coderaiser " - ], - "description": "Format size, permissions, etc", - "main": "lib/format.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "format", - "size", - "permissions" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "_release": "0.9.6", - "_resolution": { - "type": "version", - "tag": "v0.9.6", - "commit": "3381e500de22cc60a25a4049589c377198f8cc57" - }, - "_source": "git://github.com/coderaiser/format-io.git", - "_target": "~0.9.6", - "_originalSource": "format-io" -} \ No newline at end of file diff --git a/modules/format-io/ChangeLog b/modules/format-io/ChangeLog deleted file mode 100644 index 00c56124..00000000 --- a/modules/format-io/ChangeLog +++ /dev/null @@ -1,6 +0,0 @@ -2015.02.18, v0.9.6 - -feature: -- (bower) add -- (format) scope -> global - diff --git a/modules/format-io/LICENSE b/modules/format-io/LICENSE deleted file mode 100644 index 2c5ecaa0..00000000 --- a/modules/format-io/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/modules/format-io/README.md b/modules/format-io/README.md deleted file mode 100644 index 40972930..00000000 --- a/modules/format-io/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# Format - -Library for format size, permissions, etc. - -# How to use? - -Format could be used in browser or node. - -In browser: - -```js - -``` - -In node: - -```js -var Format = require('format-io'); -``` - -# API - -## size - -```js - var size = 1024 * 1024 * 5, - sizeStr = Format.size(size); - //'5.00mb' -``` - -## permissions.symbolic - -```js - var perm = '00777', - permStr = Format.permissions.symbolic(perm); - //'rwx rwx rwx -``` - -## permissions.numeric - -```js - var perm = 'rwx rwx rwx', - permNum = Format.permissions.numeric(perm); - //'00777' -``` - -# License - -MIT diff --git a/modules/format-io/bower.json b/modules/format-io/bower.json deleted file mode 100644 index 967aa75a..00000000 --- a/modules/format-io/bower.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "format-io", - "version": "0.9.6", - "homepage": "https://github.com/coderaiser/format-io", - "authors": [ - "coderaiser " - ], - "description": "Format size, permissions, etc", - "main": "lib/format.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "format", - "size", - "permissions" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ] -} diff --git a/modules/format-io/lib/format.js b/modules/format-io/lib/format.js deleted file mode 100644 index d13ba705..00000000 --- a/modules/format-io/lib/format.js +++ /dev/null @@ -1,163 +0,0 @@ -(function(global) { - 'use strict'; - - if (typeof module === 'object' && module.exports) - module.exports = new FormatProto(); - else - global.Format = new FormatProto(); - - function FormatProto() { - this.addSlashToEnd = function(path) { - var length, isSlash; - - if (path) { - length = path.length - 1; - isSlash = path[length] === '/'; - - if (!isSlash) - path += '/'; - } - - return path; - }; - - /** Функция получает короткие размеры - * конвертируя байт в килобайты, мегабойты, - * гигайбайты и терабайты - * @pSize - размер в байтах - */ - this.size = function(size) { - var isNumber = typeof size === 'number', - l1KB = 1024, - l1MB = l1KB * l1KB, - l1GB = l1MB * l1KB, - l1TB = l1GB * l1KB, - l1PB = l1TB * l1KB; - - if (isNumber) { - if (size < l1KB) size = size + 'b'; - else if (size < l1MB) size = (size / l1KB).toFixed(2) + 'kb'; - else if (size < l1GB) size = (size / l1MB).toFixed(2) + 'mb'; - else if (size < l1TB) size = (size / l1GB).toFixed(2) + 'gb'; - else if (size < l1PB) size = (size / l1TB).toFixed(2) + 'tb'; - else size = (size / l1PB).toFixed(2) + 'pb'; - } - - return size; - }; - - /** - * Функция переводит права из цыфрового вида в символьный - * @param perms - строка с правами доступа - * к файлу в 8-миричной системе - */ - this.permissions = { - symbolic: function(perms) { - var type, owner, group, all, - is = typeof perms !== undefined, - permsStr = '', - permissions = ''; - /* - S_IRUSR 0000400 protection: readable by owner - S_IWUSR 0000200 writable by owner - S_IXUSR 0000100 executable by owner - S_IRGRP 0000040 readable by group - S_IWGRP 0000020 writable by group - S_IXGRP 0000010 executable by group - S_IROTH 0000004 readable by all - S_IWOTH 0000002 writable by all - S_IXOTH 0000001 executable by all - */ - - if (is) { - permsStr = perms.toString(); - /* тип файла */ - type = permsStr.charAt(0); - - switch (type - 0) { - case 1: /* обычный файл */ - type = '-'; - break; - case 2: /* байт-ориентированное (символьное) устройство*/ - type = 'c'; - break; - case 4: /* каталог */ - type = 'd'; - break; - default: - type = '-'; - } - - /* оставляем последние 3 символа*/ - if (permsStr.length > 5) - permsStr = permsStr.substr(3); - else - permsStr = permsStr.substr(2); - - /* Рекомендации гугла советуют вместо string[3] - * использовать string.charAt(3) - */ - /* - http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Standards_features#Standards_features - - Always preferred over non-standards featuresFor - maximum portability and compatibility, always - prefer standards features over non-standards - features (e.g., string.charAt(3) over string[3] - and element access with DOM functions instead - of using an application-specific shorthand). - */ - /* Переводим в двоичную систему */ - owner = (permsStr[0] - 0).toString(2), - group = (permsStr[1] - 0).toString(2), - all = (permsStr[2] - 0).toString(2), - - /* переводим в символьную систему*/ - permissions = - (owner[0] - 0 > 0 ? 'r' : '-') + - (owner[1] - 0 > 0 ? 'w' : '-') + - (owner[2] - 0 > 0 ? 'x' : '-') + - ' ' + - (group[0] - 0 > 0 ? 'r' : '-') + - (group[1] - 0 > 0 ? 'w' : '-') + - (group[2] - 0 > 0 ? 'x' : '-') + - ' ' + - (all[0] - 0 > 0 ? 'r' : '-') + - (all[1] - 0 > 0 ? 'w' : '-') + - (all[2] - 0 > 0 ? 'x' : '-'); - } - - return permissions; - }, - - /** - * Функция конвертирует права доступа к файлам из символьного вида - * в цыфровой - */ - numeric: function(perms) { - var owner, group, all, - length = perms && perms.length === 11; - - if (length) { - owner = (perms[0] === 'r' ? 4 : 0) + - (perms[1] === 'w' ? 2 : 0) + - (perms[2] === 'x' ? 1 : 0), - - group = (perms[4] === 'r' ? 4 : 0) + - (perms[5] === 'w' ? 2 : 0) + - (perms[6] === 'x' ? 1 : 0), - - all = (perms[8] === 'r' ? 4 : 0) + - (perms[9] === 'w' ? 2 : 0) + - (perms[10] === 'x' ? 1 : 0); - - /* добавляем 2 цифры до 5 */ - perms = '00' + owner + group + all; - } - - return perms; - } - }; - } - -})(this); diff --git a/modules/format-io/package.json b/modules/format-io/package.json deleted file mode 100644 index eba72224..00000000 --- a/modules/format-io/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "format-io", - "version": "0.9.6", - "author": "coderaiser (https://github.com/coderaiser)", - "description": "Format size, permissions, etc", - "homepage": "http://github.com/coderaiser/format-io", - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/format-io.git" - }, - "keywords": [ - "format", - "size", - "permissions" - ], - "dependencies": {}, - "license": "MIT", - "engines": { - "node": ">=0.4.x" - }, - "main": "lib/format.js" -} diff --git a/modules/itype/.bower.json b/modules/itype/.bower.json deleted file mode 100644 index 9bc44c1f..00000000 --- a/modules/itype/.bower.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "itype", - "description": "Improved type check", - "main": "dist/itype.js", - "authors": [ - "coderaiser (https://github.com/coderaiser)" - ], - "license": "MIT", - "keywords": [ - "type", - "string", - "array", - "object", - "boolean", - "null", - "undefined", - "check" - ], - "homepage": "https://github.com/coderaiser/itype", - "ignore": [ - ".*", - "test", - "lib" - ], - "version": "2.0.3", - "_release": "2.0.3", - "_resolution": { - "type": "version", - "tag": "v2.0.3", - "commit": "ec7f35bfdc6f9078d4e4792dd347bf98dd2f8ccc" - }, - "_source": "https://github.com/coderaiser/itype.git", - "_target": "2.0.3", - "_originalSource": "itype" -} \ No newline at end of file diff --git a/modules/itype/ChangeLog b/modules/itype/ChangeLog deleted file mode 100644 index 688cb754..00000000 --- a/modules/itype/ChangeLog +++ /dev/null @@ -1,35 +0,0 @@ -2016.12.28, v2.0.3 - -fix: -- (bower) main - - -2016.12.28, v2.0.2 - -feature: -- (bower) ignore: add ".*" - - -2016.12.28, v2.0.1 - -feature: -- (bower) add - - -2016.12.28, v2.0.0 - -feature: -- (itype) add browser support - - -2015.01.30, v1.0.2 - -feature: -- (type) change format of regexp - - -2014.12.22, v1.0.1 - -feature: -- (itype) add null - diff --git a/modules/itype/LICENSE b/modules/itype/LICENSE deleted file mode 100644 index 2c5ecaa0..00000000 --- a/modules/itype/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/modules/itype/README.md b/modules/itype/README.md deleted file mode 100644 index a4d02c6e..00000000 --- a/modules/itype/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# iType [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] [![Coverage Status][CoverageIMGURL]][CoverageURL] - -Improved type check. - -## Install - -``` -npm i itype --save -``` - -## How to use? - -```js -var itype = require('itype'); - -console.og(itype.string('hello')) -// returns -true - -console.log(itype('world')); -// returns -'string' - -console.log(itype.array([1, 2])); -// returns -true -``` - -## Environments - -In old `node.js` environments that not fully supports `es2015`, `itype` could be used with: - -```js -var itype = require('itype/legacy'); -``` - -## License - -MIT - -[NPMIMGURL]: https://img.shields.io/npm/v/itype.svg?style=flat -[BuildStatusIMGURL]: https://img.shields.io/travis/coderaiser/itype/master.svg?style=flat -[DependencyStatusIMGURL]: https://img.shields.io/gemnasium/coderaiser/itype.svg?style=flat -[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat -[NPMURL]: https://npmjs.org/package/itype "npm" -[BuildStatusURL]: https://travis-ci.org/coderaiser/itype "Build Status" -[DependencyStatusURL]: https://gemnasium.com/coderaiser/itype "Dependency Status" -[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License" - -[CoverageURL]: https://coveralls.io/github/coderaiser/itype?branch=master -[CoverageIMGURL]: https://coveralls.io/repos/coderaiser/itype/badge.svg?branch=master&service=github - diff --git a/modules/itype/bower.json b/modules/itype/bower.json deleted file mode 100644 index b301800d..00000000 --- a/modules/itype/bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "itype", - "description": "Improved type check", - "main": "dist/itype.js", - "authors": [ - "coderaiser (https://github.com/coderaiser)" - ], - "license": "MIT", - "keywords": [ - "type", - "string", - "array", - "object", - "boolean", - "null", - "undefined", - "check" - ], - "homepage": "https://github.com/coderaiser/itype", - "ignore": [ - ".*", - "test", - "lib" - ] -} diff --git a/modules/itype/dist/itype.js b/modules/itype/dist/itype.js deleted file mode 100644 index d81277f8..00000000 --- a/modules/itype/dist/itype.js +++ /dev/null @@ -1,49 +0,0 @@ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.itype = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o (https://github.com/coderaiser)", - "description": "Improved type check", - "main": "lib/itype.js", - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/itype.git" - }, - "keywords": [ - "type", - "string", - "array", - "object", - "boolean", - "null", - "undefined", - "check" - ], - "scripts": { - "test": "tape test/*.js", - "watcher": "nodemon -w test -w lib --exec", - "watch:test": "npm run watcher -- npm test", - "watch:coverage": "npm run watcher -- npm run coverage", - "lint": "eslint lib test", - "build": "redrun clean init 6to5 legacy:* bundle minify", - "init": "mkdirp dist legacy", - "minify": "minify dist/itype.js > dist/itype.min.js", - "wisdom": "npm run build", - "clean": "rimraf legacy dist", - "bundle:base": "browserify -s itype --ng false", - "bundle": "npm run bundle:base -- -r ./legacy/lib/itype.js:itype ./legacy/lib/itype.js -o dist/itype.js", - "coverage": "nyc npm test", - "report": "nyc report --reporter=text-lcov | coveralls", - "6to5": "buble lib -o legacy/lib", - "legacy:index": "echo \"module.exports = require('./lib/itype');\" > legacy/index.js" - }, - "dependencies": {}, - "license": "MIT", - "devDependencies": { - "browserify": "^13.0.0", - "buble": "^0.15.1", - "coveralls": "^2.11.9", - "eslint": "^3.10.2", - "minify": "^2.0.5", - "mkdirp": "^0.5.1", - "nodemon": "^1.11.0", - "nyc": "^10.0.0", - "redrun": "^5.0.1", - "tape": "^4.5.1" - } -} diff --git a/modules/jonny/.bower.json b/modules/jonny/.bower.json deleted file mode 100644 index 37a9f087..00000000 --- a/modules/jonny/.bower.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "jonny", - "version": "1.0.1", - "homepage": "https://github.com/coderaiser/jonny", - "authors": [ - "coderaiser " - ], - "description": "work with json without exaptions", - "main": "lib/jonny.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "json", - "try" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "modules" - ], - "dependencies": {}, - "_release": "1.0.1", - "_resolution": { - "type": "version", - "tag": "v1.0.1", - "commit": "b8909d33db868af9797c95881891c5d432209f1a" - }, - "_source": "https://github.com/coderaiser/jonny.git", - "_target": "1.0.1", - "_originalSource": "jonny" -} \ No newline at end of file diff --git a/modules/jonny/LICENSE b/modules/jonny/LICENSE deleted file mode 100644 index a103b669..00000000 --- a/modules/jonny/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/modules/jonny/README.md b/modules/jonny/README.md deleted file mode 100644 index a6eb21e5..00000000 --- a/modules/jonny/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# Jonny - -Work with json without exeptions. - -## Install - -``` -npm i jonny --save -``` - -## How to use? - -```js -var jonny = require('jonny'), - obj = jonny.parse('{ "hello": "world" }'); - - console.log(jonny.stringify(obj, 0, 4)); - // results - // "{ - // "hello": "world" - // }" -``` - -## License - -MIT diff --git a/modules/jonny/bower.json b/modules/jonny/bower.json deleted file mode 100644 index de3db23a..00000000 --- a/modules/jonny/bower.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "name": "jonny", - "version": "1.0.0", - "homepage": "https://github.com/coderaiser/jonny", - "authors": [ - "coderaiser " - ], - "description": "work with json without exaptions", - "main": "lib/jonny.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "json", - "try" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "modules" - ], - "dependencies": { - } -} diff --git a/modules/jonny/lib/jonny.js b/modules/jonny/lib/jonny.js deleted file mode 100644 index 74d9e3db..00000000 --- a/modules/jonny/lib/jonny.js +++ /dev/null @@ -1,45 +0,0 @@ -(function(global) { - 'use strict'; - - if (typeof module !== 'undefined' && module.exports) - module.exports = new Jonny(); - else - global.jonny = new Jonny(); - - function Jonny() { - this.parse = function() { - var ret, - args = arguments; - - tryCatch(function() { - ret = JSON.parse.apply(JSON, args); - }); - - return ret; - }; - - this.stringify = function() { - var ret, - args = arguments; - - tryCatch(function() { - ret = JSON.stringify.apply(JSON, args); - }); - - return ret; - }; - - function tryCatch(fn) { - var error; - - try { - fn(); - } catch(e) { - error = e; - } - - return error; - } - } - -})(this); diff --git a/modules/jonny/package.json b/modules/jonny/package.json deleted file mode 100644 index 7b9af053..00000000 --- a/modules/jonny/package.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "name": "jonny", - "version": "1.0.0", - "description": "work with json without exaptions", - "main": "lib/jonny.js", - "dependencies": { - "diff-match-patch": "~1.0.0" - }, - "devDependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/jonny.git" - }, - "keywords": [ - "json", - "try" - ], - "author": "coderaiser (http://coderaiser.github.io/)", - "license": "MIT", - "bugs": { - "url": "https://github.com/coderaiser/jonny/issues" - }, - "homepage": "https://github.com/coderaiser/jonny" -} diff --git a/modules/rendy/.bower.json b/modules/rendy/.bower.json deleted file mode 100644 index bad121e9..00000000 --- a/modules/rendy/.bower.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "rendy", - "version": "1.1.0", - "homepage": "https://github.com/coderaiser/rendy", - "authors": [ - "coderaiser " - ], - "description": "simple template engine", - "main": "lib/rendy.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "template", - "engine", - "rendy" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "test" - ], - "_release": "1.1.0", - "_resolution": { - "type": "version", - "tag": "v1.1.0", - "commit": "4ad810d131db34863df83977afea92b6fb2f1127" - }, - "_source": "git://github.com/coderaiser/rendy.git", - "_target": "~1.1.0", - "_originalSource": "rendy", - "_direct": true -} \ No newline at end of file diff --git a/modules/rendy/ChangeLog b/modules/rendy/ChangeLog deleted file mode 100644 index 7fe73aaa..00000000 --- a/modules/rendy/ChangeLog +++ /dev/null @@ -1,59 +0,0 @@ -2015.05.21, v1.1.0 - -feature: -- (rendy) 5 times spead up -- (package) should v6.0.1 -- (travis) add iojs, rm global gulp -- (package) scripts: test -- (test) greedy -- (package) should v5.2 -- (package) scripts: gulp - - -2015.03.13, v1.0.6 - -fix: -- (rendy) clean up regexp: lazy -> greedy - - -2015.03.13, v1.0.5 - -feature: -- (rendy) put vars in forEach -- (package) should v5.0.0 -- (bower) add - - -2015.01.26, v1.0.4 - -feature: -- (rendy) improve speed - - -2015.01.26, v1.0.3 - -feature: -- (rendy) speed up in 10 times: rm greedy quantifier -- (package) should v4.6 -- (package) should v4.4.1 - - -2014.12.12, v1.0.2 - -fix: -- (util) render: do not remove empty blocks "{{", "}}" -- (rendy) indexOf -> ~indexOf - -feature: -- (package) v1.0.1 -- (rendy) add expr - - -2014.12.12, v1.0.1 - -fix: -- (rendy) indexOf -> ~indexOf - -feature: -- (rendy) add expr - diff --git a/modules/rendy/LICENSE b/modules/rendy/LICENSE deleted file mode 100644 index 78aa4e7f..00000000 --- a/modules/rendy/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2015 coderaiser - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/modules/rendy/README.md b/modules/rendy/README.md deleted file mode 100644 index 33addac5..00000000 --- a/modules/rendy/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# Rendy [![License][LicenseIMGURL]][LicenseURL] [![NPM version][NPMIMGURL]][NPMURL] [![Dependency Status][DependencyStatusIMGURL]][DependencyStatusURL] [![Build Status][BuildStatusIMGURL]][BuildStatusURL] -Simple template engine compatible with [handlebars](http://handlebarsjs.com "Handlebars") and [mustache](https://mustache.github.io "Mustache"). - -## Install -![NPM_INFO][NPM_INFO_IMG] - -`npm i rendy --save` - -## How to use? -Rendy could be used in browser or node. - -Browser version: - -```html - - -``` - -Node version: - -```js -var rendy = require('rendy'), - Tmpl = 'hello {{ who }}'; - result = rendy(Tmpl, { - who: 'world' - }); - // returns - 'hello world' - -``` - -## License - -MIT - -[NPM_INFO_IMG]: https://nodei.co/npm/rendy.png?downloads&&stars&&downloadRank "npm install rendy" -[NPMIMGURL]: https://img.shields.io/npm/v/rendy.svg?style=flat -[BuildStatusIMGURL]: https://img.shields.io/travis/coderaiser/rendy/master.svg?style=flat -[DependencyStatusIMGURL]: https://img.shields.io/gemnasium/coderaiser/rendy.svg?style=flat -[LicenseIMGURL]: https://img.shields.io/badge/license-MIT-317BF9.svg?style=flat -[NPMURL]: https://npmjs.org/package/rendy "npm" -[BuildStatusURL]: https://travis-ci.org/coderaiser/rendy "Build Status" -[DependencyStatusURL]: https://gemnasium.com/coderaiser/rendy "Dependency Status" -[LicenseURL]: https://tldrlegal.com/license/mit-license "MIT License" - diff --git a/modules/rendy/bower.json b/modules/rendy/bower.json deleted file mode 100644 index f192df47..00000000 --- a/modules/rendy/bower.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "rendy", - "version": "1.1.0", - "homepage": "https://github.com/coderaiser/rendy", - "authors": [ - "coderaiser " - ], - "description": "simple template engine", - "main": "lib/rendy.js", - "moduleType": [ - "globals", - "node" - ], - "keywords": [ - "template", - "engine", - "rendy" - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "test" - ] -} diff --git a/modules/rendy/gulpfile.js b/modules/rendy/gulpfile.js deleted file mode 100644 index 35b48186..00000000 --- a/modules/rendy/gulpfile.js +++ /dev/null @@ -1,18 +0,0 @@ -(function() { - 'use strict'; - - var gulp = require('gulp'), - mocha = require('gulp-mocha'); - - gulp.task('test', function() { - gulp.src('test/test.js') - .pipe(mocha({reporter: 'min'})) - .on('error', onError); - }); - - gulp.task('default', ['test']); - - function onError(error) { - console.log(error.message); - } -})(); diff --git a/modules/rendy/lib/rendy.js b/modules/rendy/lib/rendy.js deleted file mode 100644 index 526527c0..00000000 --- a/modules/rendy/lib/rendy.js +++ /dev/null @@ -1,43 +0,0 @@ -(function(global) { - 'use strict'; - - if (typeof module === 'object' && module.exports) - module.exports = rendy; - else - global.rendy = rendy; - - /** - * render template with data - * - * @param templ - * @param data - */ - function rendy(templ, data) { - var result = templ; - - check(templ, data); - - Object - .keys(data) - .forEach(function(param) { - var name = '{{ ' + param + ' }}', - str = data[param]; - - while(~result.indexOf(name)) - result = result.replace(name, str); - }); - - if (~result.indexOf('{{')) - result = result.replace(/{{.*?}}/g, ''); - - return result; - } - - function check(templ, data) { - if (typeof templ !== 'string') - throw(Error('template should be string!')); - - if (typeof data !== 'object') - throw(Error('data should be object!')); - } -})(this); diff --git a/modules/rendy/package.json b/modules/rendy/package.json deleted file mode 100644 index fb95af5c..00000000 --- a/modules/rendy/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "rendy", - "version": "1.1.0", - "description": "simplest template engine", - "main": "lib/rendy.js", - "scripts": { - "test": "gulp test" - }, - "repository": { - "type": "git", - "url": "git://github.com/coderaiser/rendy.git" - }, - "keywords": [ - "template", - "engine" - ], - "author": "coderaiser (http://coderaiser.github.io/)", - "license": "MIT", - "bugs": { - "url": "https://github.com/coderaiser/rendy/issues" - }, - "homepage": "https://github.com/coderaiser/rendy", - "devDependencies": { - "gulp": "~3.8.10", - "gulp-mocha": "~2.0.0", - "should": "~6.0.1" - } -} diff --git a/package.json b/package.json index fc4f775b..e3a45b7b 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ }, "scripts": { "start": "node bin/cloudcmd.js", + "start:debug": "NODE_ENV=debug node bin/cloudcmd.js", "start:dev": "nodemon bin/cloudcmd.js", "security": "nsp check", "codestyle": "redrun lint spell", @@ -54,11 +55,11 @@ "lint:js:es5": "redrun es5:*", "eslint:bin": "eslint --rule 'no-console:0' bin test server", "fix:eslint:bin": "redrun eslint:bin -- --fix", - "jshint": "jshint bin/release.js", + "jshint": "jshint bin client server", "jscs": "jscs --esnext $npm_package_config_dirs", - "es5:jshint": "jshint --config .es5/.jshintrc $npm_package_config_dirs_dirs_legacy --exclude bin/release.js", - "es5:eslint": "eslint -c .es5/.eslintrc --rule 'no-console:0' $npm_package_config_dirs_legacy --ignore-path bin/release.js", - "fix:es5:eslint": "redrun es5:eslint -- --fix", + "jshint:client": "jshint --config .es5/.jshintrc $npm_package_config_dirs_dirs_legacy --exclude bin/release.js", + "eslint:client": "eslint --rule 'no-console:0' --env browser client", + "fix:eslint": "redrun eslint:client -- --fix", "test": "tape 'test/**/*.js'", "watch:test": "nodemon -w server -w test -w common -x \"npm run test\"", "spell": "yaspeller .", @@ -83,6 +84,9 @@ "report": "nyc report --reporter=text-lcov | coveralls", "6to5:bin": "babel bin -d legacy/bin", "6to5:server": "babel server -d server_", + "6to5:client": "webpack", + "6to5:client:debug": "NODE_ENV=debug webpack", + "watch:client": "NODE_ENV=debug webpack --watch", "build": "redrun rm:* 6to5:* mkdir:* legacy:*", "legacy:package": "echo \"module.exports = require('../package');\" > legacy/package.js", "mkdir:server": "mkdirp legacy/server", @@ -144,8 +148,10 @@ }, "devDependencies": { "babel-cli": "^6.18.0", + "babel-loader": "^6.2.10", "babel-preset-es2015": "^6.18.0", "coveralls": "^2.11.6", + "emitify": "^2.1.1", "es6-promisify": "^5.0.0", "eslint": "^3.1.1", "gunzip-maybe": "^1.3.1", @@ -170,6 +176,7 @@ "tape": "^4.4.0", "tar-stream": "^1.5.2", "version-io": "^1.2.5", + "webpack": "^2.2.1", "yaspeller": "^3.0.0" }, "engines": { diff --git a/server/cloudcmd.js b/server/cloudcmd.js index 034b36cf..fad93203 100644 --- a/server/cloudcmd.js +++ b/server/cloudcmd.js @@ -35,6 +35,8 @@ const root = () => config('root'); const emptyFunc = (req, res, next) => next(); emptyFunc.middle = () => emptyFunc; +const isDebug = process.env.NODE_ENV === 'debug'; + function getPrefix(prefix) { if (typeof prefix === 'function') return prefix() || ''; @@ -297,8 +299,11 @@ function setUrl(pref) { req.url = req.url.replace(prefix, '') || '/'; - if (req.url === '/cloudcmd.js') - req.url = '/client/cloudcmd.js'; + if (/^\/cloudcmd\.js(\.map)?$/.test(req.url)) + req.url = `/dist${req.url}`; + + if (isDebug) + req.url = req.url.replace(/^\/dist\//, '/dist-debug/'); next(); }; diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..6a418b36 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,55 @@ +const path = require('path'); +const webpack = require('webpack'); +const {optimize} = webpack +const {UglifyJsPlugin} = optimize; + +const dir = './client'; + +const {env} = process; +const isDebug = env.NODE_ENV === 'debug'; + +const dist = path.resolve(__dirname, 'dist'); +const distDebug = path.resolve(__dirname, 'dist-debug'); +const devtool = isDebug ? 'eval' : 'source-map'; + +module.exports = { + devtool, + entry: { + cloudcmd: `${dir}/cloudcmd.js`, + edit: `${dir}/edit.js`, + 'edit-file': `${dir}/edit-file.js`, + 'edit-names': `${dir}/edit-names.js`, + menu: `${dir}/menu.js`, + view: `${dir}/view.js`, + help: `${dir}/help.js`, + markdown: `${dir}/markdown.js`, + config: `${dir}/config.js`, + contact: `${dir}/contact.js`, + upload: `${dir}/upload.js`, + operation: `${dir}/operation.js`, + konsole: `${dir}/konsole.js`, + cloud: `${dir}/cloud.js` + }, + output: { + filename: '[name].js', + path: isDebug ? distDebug : dist, + libraryTarget: 'umd' + }, + plugins: [ + new UglifyJsPlugin({ + sourceMap: true + }), + ], + module: { + loaders: [{ + test: /\.js$/, + exclude: /(node_)?modules/, + loader: 'babel-loader', + query: { + presets: ['es2015'] + } + } + ] + } +}; +