diff --git a/assets/UserActionManager/UserActionManager.js b/assets/UserActionManager/UserActionManager.js new file mode 100644 index 0000000..b76d39d --- /dev/null +++ b/assets/UserActionManager/UserActionManager.js @@ -0,0 +1,39 @@ +/** @module UserActionManager */ +/** + * в разработке + */ +kit.PluginManager.register('UserActionManager',function(module, exports, require, global) { + + var actionList = ['click', 'hover']; + + var UserAction = function () { + + }; + var proto = UserAction.prototype; + proto.setAction = function (action) { + if(actionList.indexOf(action) === -1) { + action = 'click'; + } + this.action = action; + return this; + }; + proto.setNode = function (node) { + this.node = node; + return this; + }; + proto.setTakeNode = function (takeNode) { + this.takeNode = takeNode; + return this; + }; + + + /** + * @memberof kitCore + * @instance + */ + var UserActionManager = function () { + + }; + + return module.exports = UserActionManager; +}); diff --git a/assets/collection/collection.js b/assets/collection/collection.js index 75ab199..705723f 100644 --- a/assets/collection/collection.js +++ b/assets/collection/collection.js @@ -1,9 +1,9 @@ /** @module collection */ kit.PluginManager.register('collection',function(module, exports, require, global) { - function valueEx(value) { + function valueEx(value, item, key) { if(typeof value === 'function') { - return value(); + return value(item, key); } return value; } @@ -18,7 +18,8 @@ kit.PluginManager.register('collection',function(module, exports, require, globa idStr += (Math.floor((Math.random() * 35))).toString(36); } while (idStr.length < length); return (idStr); - }; + } + var ArrayCollection = function (data){ this.data = data; @@ -28,7 +29,9 @@ kit.PluginManager.register('collection',function(module, exports, require, globa }; ArrayCollection.prototype.put = function (key, value) { this.data[key] = value; + return this; }; + ArrayCollection.prototype.set = ArrayCollection.prototype.put; ArrayCollection.prototype.push = function (value) { this.data.push(value); }; @@ -36,11 +39,36 @@ kit.PluginManager.register('collection',function(module, exports, require, globa if(this.data.hasOwnProperty(key)) { return this.data[key]; } - return valueEx(defValue); + return valueEx(defValue, this.data[key], key); }; ArrayCollection.prototype.has = function (key) { return this.data.hasOwnProperty(key); }; + ArrayCollection.prototype.count = function () { + return Object.keys(this.data).length; + }; + ArrayCollection.prototype.isEmpty = function () { + return this.count() === 0; + }; + ArrayCollection.prototype.map = function (callback) { + for (var key of Object.keys(this.data)) { + this.data[key] = callback(this.data[key], key, this.data); + } + return this; + }; + ArrayCollection.prototype.each = function (callback) { + var BreakException = {}; + try { + for (var key of Object.keys(this.data)) { + if(callback(this.data[key], key, this.data) === false) { + throw BreakException; + } + } + } catch (e) { + if (e !== BreakException) throw e; + } + return this; + }; var ObjectCollection = function (data){ @@ -48,26 +76,94 @@ kit.PluginManager.register('collection',function(module, exports, require, globa }; ObjectCollection.prototype.all = ArrayCollection.prototype.all; ObjectCollection.prototype.put = ArrayCollection.prototype.put; + ObjectCollection.prototype.set = ArrayCollection.prototype.put; ObjectCollection.prototype.push = function (value) { this.data[uniqueId(8)] = value; + return this; }; ObjectCollection.prototype.get = ArrayCollection.prototype.get; ObjectCollection.prototype.has = ArrayCollection.prototype.has; + ObjectCollection.prototype.count = ArrayCollection.prototype.count; + ObjectCollection.prototype.isEmpty = ArrayCollection.prototype.isEmpty; + ObjectCollection.prototype.map = ArrayCollection.prototype.map; + ObjectCollection.prototype.each = ArrayCollection.prototype.each; + + var NodeCollection = function (data){ + this.data = data; + }; + NodeCollection.prototype.all = ArrayCollection.prototype.all; + NodeCollection.prototype.put = ArrayCollection.prototype.put; + NodeCollection.prototype.set = ArrayCollection.prototype.put; + NodeCollection.prototype.push = ArrayCollection.prototype.push; + NodeCollection.prototype.get = ArrayCollection.prototype.get; + NodeCollection.prototype.has = ArrayCollection.prototype.has; + NodeCollection.prototype.count = ArrayCollection.prototype.count; + NodeCollection.prototype.isEmpty = ArrayCollection.prototype.isEmpty; + NodeCollection.prototype.map = ArrayCollection.prototype.map; + NodeCollection.prototype.each = ArrayCollection.prototype.each; + + function collectionCall(method, args) { + if(this.__driver.__proto__.hasOwnProperty(method)) { + var r = this.__driver[method].apply(this.__driver, args); + return r === this.__driver ? this : r; + } + return this; + } /** + * @extends ArrayCollection * @memberof kitCore * @instance */ var Collection = function (data) { - if(typeof data === 'object') { - return new ObjectCollection(data); + if(data instanceof NodeList) { + this.__driver = new NodeCollection(data); } - if(Array.isArray(data)) { - return new ArrayCollection(data); + else if(Array.isArray(data)) { + this.__driver = new ArrayCollection(data); } - return new ArrayCollection([data]); - } + else if(typeof data === 'object') { + this.__driver = new ObjectCollection(data); + } + else { + console.warn('collection: not support data', data); + } + }; + Collection.prototype.all = function () { + return collectionCall.call(this, 'all', arguments); + }; + Collection.prototype.put = function (key, value) { + return collectionCall.call(this, 'put', arguments); + }; + Collection.prototype.set = function (key, value) { + return collectionCall.call(this, 'set', arguments); + }; + Collection.prototype.push = function (value) { + return collectionCall.call(this, 'push', arguments); + }; + Collection.prototype.get = function (key, defValue = undefined) { + return collectionCall.call(this, 'get', arguments); + }; + Collection.prototype.has = function (key) { + return collectionCall.call(this, 'has', arguments); + }; + Collection.prototype.count = function () { + return collectionCall.call(this, 'count', arguments); + }; + Collection.prototype.isEmpty = function () { + return collectionCall.call(this, 'isEmpty', arguments); + }; + Collection.prototype.map = function (callback) { + return collectionCall.call(this, 'map', arguments); + }; + Collection.prototype.each = function (callback) { + return collectionCall.call(this, 'each', arguments); + }; + + return module.exports = Collection; }); + + diff --git a/assets/core/core.js b/assets/core/core.js index 88b06aa..a239cdb 100644 --- a/assets/core/core.js +++ b/assets/core/core.js @@ -436,12 +436,13 @@ window.kit = window.kit || {}; * @return {boolean} */ __proto.require = function (pluginId, callback) { - //console.warn('PluginManager.require: plugin ' + pluginId + ' ('+(this.plugins[pluginId]?this.plugins[pluginId].state:'0')+')'); var plugin = this.__getPlugin(pluginId); - if(plugin) { - pluginId = plugin.id; + if(!plugin) { + console.warn('PluginManager.require: plugin ' + pluginId + ' not found ('+(this.plugins[pluginId]?this.plugins[pluginId].state:'0')+')'); + return undefined; } + pluginId = plugin.id; var module = plugin.module; if(!this.__checkState(pluginId, stateList.registered)) { @@ -578,15 +579,25 @@ window.kit = window.kit || {}; if(this.plugins.hasOwnProperty(pluginId)) { return this.plugins[pluginId]; } - var _pluginId; + var _pluginId, alias; for (_pluginId in this.plugins) { if(this.plugins.hasOwnProperty(_pluginId) && this.plugins[_pluginId].config.alias.indexOf(pluginId) !== -1) { return this.plugins[_pluginId]; } } - _pluginId = pluginId[0].toUpperCase() + pluginId.slice(1); - if(_pluginId !== pluginId) { - return this.__getPlugin(_pluginId); + var pluginIdLowerCase = pluginId.toLowerCase(); + for (_pluginId in this.plugins) { + if(!this.plugins.hasOwnProperty(_pluginId)) { + continue; + } + if(pluginIdLowerCase === _pluginId.toLowerCase()) { + return this.plugins[_pluginId]; + } + for(alias of this.plugins[_pluginId].config.alias) { + if(pluginIdLowerCase === alias.toLowerCase()) { + return this.plugins[_pluginId]; + } + } } return undefined; }; diff --git a/assets/core/core.register.js b/assets/core/core.register.js index f2616be..824c16d 100644 --- a/assets/core/core.register.js +++ b/assets/core/core.register.js @@ -6,7 +6,7 @@ __PluginManager__.registerPlugins({ '/menu.css' ], type: 'loader', - deps: ['lib', 'align', 'utils', 'animations'] + deps: ['lib', 'align', 'dataStructures', 'animations'] }, lib: { path: __pmConfig__.assetsPath + '/lib', @@ -18,9 +18,9 @@ __PluginManager__.registerPlugins({ module: '/align.js', type: 'loader', }, - utils: { - path: __pmConfig__.assetsPath + '/utils', - module: '/utils.js', + support: { + path: __pmConfig__.assetsPath + '/support', + module: '/support.js', type: 'loader', }, jquery: { @@ -147,6 +147,21 @@ __PluginManager__.registerPlugins({ module: '/animations.js', type: 'loader', }, + Collection: { + path: __pmConfig__.assetsPath + '/collection', + module: '/collection.js', + type: 'loader', + }, + dataStructures: { + path: __pmConfig__.assetsPath + '/dataStructures', + module: '/dataStructures.js', + type: 'loader', + }, + UserActionManager: { + path: __pmConfig__.assetsPath + '/UserActionManager', + module: '/UserActionManager.js', + type: 'loader', + }, }); diff --git a/assets/dataStructures/dataStructures.js b/assets/dataStructures/dataStructures.js new file mode 100644 index 0000000..cfe5fe8 --- /dev/null +++ b/assets/dataStructures/dataStructures.js @@ -0,0 +1,55 @@ +/** @module dataStructures */ +__PluginManager__.register('dataStructures', function(module, exports, require, global){ + /** + * @memberof kitCore + * @instance + */ + var dataStructures = { + StackExecutionLimiter: (function () { + var stack = function (context, callback, timeout = 1000) { + this.counter = 0; + this.timerId = 0; + this.timeout = 0; + this.arguments = null; + this.context = null; + this.setContext(context); + this.setCallback(callback); + this.setTimeout(timeout); + }; + stack.prototype.setCallback = function(callback){ + this.callback = callback; + }; + stack.prototype.setContext = function(context){ + this.context = context || window; + }; + stack.prototype.setTimeout = function(timeout){ + this.timeout = timeout; + }; + stack.prototype.exec = function() { + this.arguments = arguments; + this.counter++; + + if(this.timerId === 0) { + this.__exec(this.counter); + } + }; + stack.prototype.__exec = function (counter) { + this.timerId = setTimeout((function(){ + if(this.counter > counter) { + this.__exec(this.counter); + return null; + } + this.timerId = 0; + }).bind(this), this.timeout); + this.callback.apply(this.context, this.arguments); + }; + stack.prototype.reset = function () { + clearTimeout(this.timerId); + this.timerId = 0; + }; + return stack; + })() + }; + + return module.exports = dataStructures; +}); diff --git a/assets/menu/menu.js b/assets/menu/menu.js index 237dc48..bbf9c02 100644 --- a/assets/menu/menu.js +++ b/assets/menu/menu.js @@ -1,11 +1,11 @@ /** @module menu */ -//todo: instance, options, auto-options-by-node, fast reCalc, fast reInit, userEventManager, collection +//todo: instance, options, auto-options-by-node, userEventManager __PluginManager__.register('menu',function(module, exports, require) { var align = require('align'); var libModule = require('lib'); - var utils = require('utils'); + var dataStructures = require('dataStructures'); /** * @class kitMenuClassDefaultOptions @@ -120,19 +120,20 @@ __PluginManager__.register('menu',function(module, exports, require) { } this.addAnimation(); }; + + Menu.prototype.hide = function () { + getChainActiveMenuDataList(this.id).reverse().forEach(function (data) { + data.menu.hideNodeNow(); + }); + return this; + }; Menu.prototype.hideNode = function () { - // console.log('Menu: hideNode'); - this.hideNodeDeferred(); + this.hideNodeNow(); }; Menu.prototype.hideNodeDeferred = function () { this.deferredHideCancel(); this.deferredHideID = setTimeout(this.hideNodeNow.bind(this), this.options.hideDelay); - // console.log('hideNodeDeferred ' + this.deferredHideID); }; - - /** - * @returns {Menu} - */ Menu.prototype.deferredHideCancel = function () { if(this.deferredHideID) { clearTimeout(this.deferredHideID); @@ -140,10 +141,6 @@ __PluginManager__.register('menu',function(module, exports, require) { } return this; }; - - /** - * @returns {Menu} - */ Menu.prototype.hideNodeNow = function () { // console.log('Menu: hideNodeNow'); this.deferredHideCancel(); @@ -167,18 +164,7 @@ __PluginManager__.register('menu',function(module, exports, require) { } }; - /** - * @returns {Menu} - */ - Menu.prototype.hide = function () { - this.hideNodeNow(); - var tmp = this; - while(tmp instanceof MenuClass) { - tmp = tmp.hideNodeNow().getParentMenu(); - } - return this; - }; - Menu.prototype.calcStyle = function (recursive = false) { + Menu.prototype.calcStyle = function () { // console.log('calcStyle ' + this.id); if(!(this.options.parent instanceof Element)) { console.warn('Menu.options.parent NOT instanceof Element'); @@ -208,33 +194,12 @@ __PluginManager__.register('menu',function(module, exports, require) { .setHorizontal(hDirection, hAlign) .setVertical('bottom', 'top'); - - if(recursive) { - this.calcStyleChildMenu(true, MenuList); - } }; - Menu.prototype.calcStyleChildMenu = function(recursive = false, MenuList = null){ - var i, MenuListActive = []; - for(i in MenuList){ - if(!MenuList.hasOwnProperty(i) || !(MenuList[i] instanceof Menu)) { - continue; - } - - if(MenuList[i].bActive && this !== MenuList[i]) { - MenuListActive.push(MenuList[i]); - } - } - - for(i in MenuListActive){ - if(MenuListActive[i].getParentMenu() === this) { - MenuListActive[i].calcStyle(); - - if(recursive) { - MenuListActive[i].calcStyleChildMenu(true, MenuListActive); - } - } - } + Menu.prototype.calcStyleChain = function(){ + getChainActiveMenuDataList(this.id).forEach(function (data) { + data.menu.calcStyle(); + }) }; /** @@ -389,10 +354,6 @@ __PluginManager__.register('menu',function(module, exports, require) { this.node.removeEventListener('mouseenter', this.nodeActionHandler, false); this.node.removeEventListener('mouseleave', this.nodeActionHandler, false); }; - Menu.prototype.toggleParent = function() { - this.node.classList.toggle('active'); - return this.node.classList.contains('active'); - }; Menu.prototype.insertToNode = function (parent) { if(!(parent instanceof Element)) { console.warn('Menu.insertToNode - node NOT instanceof Element'); @@ -435,14 +396,19 @@ __PluginManager__.register('menu',function(module, exports, require) { //this.removeAnimation(); if(this.node.parentElement !== this.options.parent) { + this.removeAnimation(); this.node.remove(); - this.options.parent.prepend(this.getNode()); + this.options.parent.prepend(this.node); } this.render(); if(this.bActive) { - this.calcStyle(recursiveCalcStyle); + if(recursiveCalcStyle) { + this.calcStyleChain(); + } else { + this.calcStyle(); + } this.showNode(); } else { this.hideNode(); @@ -455,10 +421,10 @@ __PluginManager__.register('menu',function(module, exports, require) { Menu.prototype.toggle = function() { - if(this.toggleParent()) { + if(this.node.classList.toggle('active')) { this.showNode(); } else { - this.hideNode(); + this.hide(); } }; Menu.prototype.parentAction = function (event) { @@ -467,7 +433,7 @@ __PluginManager__.register('menu',function(module, exports, require) { switch (event.type) { case 'mouseout': if (this.needHideByParent(event.relatedTarget)) { - this.hideNode(); + this.hideNodeDeferred(); } break; case 'mouseover': @@ -488,7 +454,7 @@ __PluginManager__.register('menu',function(module, exports, require) { break; case 'mouseleave': if(this.options.eventType === 'hover') { - this.hideNode(); + this.hideNodeDeferred(); } break; case 'mouseenter': @@ -842,32 +808,109 @@ __PluginManager__.register('menu',function(module, exports, require) { } return new MenuClass(options, items); }; - var getActiveMenuIdList = function(){ + var getActiveMenuDataList = function(){ + function valueEx(value) { + if(typeof value === 'function') { + return value(); + } + return value; + } var idList = []; - MenuList.forEach(function(element, index, array){ + var dataList = []; + var refList = []; + function getParentId(id, element) { + if(!element) { + element = MenuList[id]; + } + var parentId = false, parentMenu; + if(!(refList.hasOwnProperty(id) && refList[id].parentMenu)) { + if(element) { + refList[id] = refList[id] || {}; + parentMenu = refList[id].parentMenu = element.getParentMenu(); + } + parentMenu && (parentId = parentMenu.id); + return parentId; + } + return refList[id].parentMenu.id; + } + + MenuList.forEach(function(element){ var pos, posId, id, parentId; - if((element instanceof MenuClass) && element.bInit && element.bActive) { - id = element.id; - parentId = false; - element.getParentMenu() && (parentId = element.getParentMenu().id); - !(parentId!==false&&(((pos=idList.indexOf(parentId))!==-1)?((idList.indexOf(id)===-1)&&idList.splice(pos - +1,0,id)):(((posId=idList.indexOf(id))!==-1)?idList.splice(posId,0,parentId):(idList.push(parentId), - idList.push(id))),0))&&(idList.indexOf(id)===-1)&&(idList.push(id)); + if(!((element instanceof MenuClass) && element.bInit && element.bActive)) { + return; + } + id = element.id; + refList[id] = refList[id] || {}; + refList[id].menu = element; + parentId = getParentId(id, element); + var depth = function (id){ + return function() { + return 1 + valueEx(refList[refList[id].data.parentId].data.depth) + }; + }; + !( + parentId!==false + && + ( + ((pos=idList.indexOf(parentId))!==-1) + ? + ( + (idList.indexOf(id)===-1)&&(idList.splice(pos+1,0,id), dataList.splice(pos+1,0, refList[id].data = {id:id, depth: depth(id), parentId: parentId, type: 1})) + ) + : + ( + ( + refList[parentId] = refList[parentId] || {}, + (posId=idList.indexOf(id))!==-1 + )? + ( + idList.splice(posId,0,parentId), + dataList.splice(posId,0,refList[parentId].data = {id:parentId, depth: depth(parentId), parentId: getParentId(parentId), type: 5}) + ): + ( + idList.push(parentId), + dataList.push(refList[parentId].data = {id:parentId, depth: depth(parentId), parentId: getParentId(parentId), type: 2}), + idList.push(id), + dataList.push(refList[id].data = {id:id, depth: depth(id), parentId: parentId, type: 3}) + ) + ), + 0 + ) + ) + &&(idList.indexOf(id)===-1)&&(idList.push(id), dataList.push(refList[id].data = {id:id, depth: 1, parentId: 0, type: 4})); + }); + dataList.forEach(function (data) { + data.depth = valueEx(data.depth); + data.menu = refList[data.id].menu; + }); + return dataList; + }; + var getChainActiveMenuDataList = function (id) { + var dataList = getActiveMenuDataList(), result = [], depth = 0; + dataList.forEach(function(data) { + if(data.id === id) { + depth = data.depth; + } + if(depth === data.depth && data.id !== id) { + depth = 0; + } + if(depth) { + result.push(data); } }); - return idList + return result; }; var reInitAllMenu = function(){ - var idList = getActiveMenuIdList(); - idList.forEach(function(id, i, arr) { - MenuList[id].reInit(); + var dataList = getActiveMenuDataList(); + dataList.forEach(function(data) { + data.menu.reInit(); }); }; var reCalcAllMenu = function(){ console.log('reCalcAllMenu'); - var idList = getActiveMenuIdList(); - idList.forEach(function(id, i, arr) { - MenuList[id].calcStyle(); + var dataList = getActiveMenuDataList(); + dataList.forEach(function(data) { + data.menu.calcStyle(); }); }; var autoload = function(doc = document, selector = '.kit-menu'){ @@ -884,7 +927,7 @@ __PluginManager__.register('menu',function(module, exports, require) { ); }; - var reCalcAllMenuLimiter = new utils.StackExecutionLimiter(this, reCalcAllMenu, 200); + var reCalcAllMenuLimiter = new dataStructures.StackExecutionLimiter(this, reCalcAllMenu, 250); var globalHandlers = { resize: function(){ reCalcAllMenuLimiter.exec(); @@ -903,6 +946,8 @@ __PluginManager__.register('menu',function(module, exports, require) { reInitAllMenu: reInitAllMenu, reCalcAllMenu: reCalcAllMenu, autoload: autoload, + getActiveMenuDataList: getActiveMenuDataList, + getChainActiveMenuDataList: getChainActiveMenuDataList, MenuList: MenuList, }; diff --git a/assets/support/support.js b/assets/support/support.js new file mode 100644 index 0000000..6fd70cc --- /dev/null +++ b/assets/support/support.js @@ -0,0 +1,20 @@ +/** @module support */ +__PluginManager__.register('support', function(module, exports, require, global){ + + var str = { + ucFirst: function (str) { + if (!str) return str; + return str[0].toUpperCase() + str.slice(1); + } + }; + + /** + * @memberof kitCore + * @instance + */ + var support = { + str: str, + }; + + return module.exports = support; +}); diff --git a/assets/utils/utils.js b/assets/utils/utils.js deleted file mode 100644 index 85582c2..0000000 --- a/assets/utils/utils.js +++ /dev/null @@ -1,65 +0,0 @@ -/** @module utils */ -__PluginManager__.register('utils', function(module, exports, require){ - var StackExecutionLimiter = (function () { - var stack = function (context, callback, timeout = 1000) { - this.counter = 0; - this.timerId = 0; - this.timeout = 0; - this.arguments = null; - this.context = null; - this.setContext(context); - this.setCallback(callback); - this.setTimeout(timeout); - }; - stack.prototype.setCallback = function(callback){ - this.callback = callback; - }; - stack.prototype.setContext = function(context){ - this.context = context || window; - }; - stack.prototype.setTimeout = function(timeout){ - this.timeout = timeout; - }; - stack.prototype.exec = function() { - this.arguments = arguments; - this.counter++; - - if(this.timerId === 0) { - this.__exec(this.counter); - } - }; - stack.prototype.__exec = function (counter) { - this.timerId = setTimeout((function(){ - if(this.counter > counter) { - this.__exec(this.counter); - return null; - } - this.timerId = 0; - }).bind(this), this.timeout); - this.callback.apply(this.context, this.arguments); - }; - stack.prototype.reset = function () { - clearTimeout(this.timerId); - this.timerId = 0; - }; - return stack; - })(); - var str = { - ucFirst: function (str) { - if (!str) return str; - return str[0].toUpperCase() + str.slice(1); - } - }; - - - /** - * @memberof kitCore - * @instance - */ - var utils = { - StackExecutionLimiter: StackExecutionLimiter, - str: str, - }; - - return module.exports = utils; -}); diff --git a/tests/index.php b/tests/index.php index 968223a..d3149ee 100644 --- a/tests/index.php +++ b/tests/index.php @@ -5,5 +5,6 @@ flex-kit cheatsheet card/block + kit.Collection \ No newline at end of file diff --git a/tests/kit.Collection.php b/tests/kit.Collection.php new file mode 100644 index 0000000..47ec277 --- /dev/null +++ b/tests/kit.Collection.php @@ -0,0 +1,77 @@ + + + + + + + + + +