Socket
Socket
Sign inDemoInstall

nested-sort

Package Overview
Dependencies
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nested-sort - npm Package Compare versions

Comparing version 2.0.2 to 2.1.0

215

dist/nested-sort.cjs.js
'use strict';
/**
* @typedef {object} dataEngineDataItem
* @property {number|string} id
* @property {string} text
* @property {number|string} [parent]
*/
class DataEngine {
/**
* @constructor
* @param {array.<dataEngineDataItem>} data
*/
constructor({ data }) {
this.data = data;
this.sortedData = [];
this.sortedDataDomArray = [];
}
/**
* @returns {array.<dataEngineDataItem>}
*/
sortListItems() {
this.sortedData = [...this.data].sort((item1, item2) => {
if (!item1.parent && item2.parent) return -1
return (!item2.parent && item1.parent) ? 1 : 0;
});
return this.sortedData
}
/**
* @param {dataEngineDataItem} item
* @param {string} nodeName
* @returns {HTMLElement}
*/
createItemElement(item, nodeName = 'li') {
const { id, text } = item;
const el = document.createElement(nodeName);
el.dataset.id = id;
if (nodeName === 'li') el.innerHTML = text;
return el
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
elementIsParentOfItem(node, item) {
return node.dataset.id === `${item.parent}`
}
/**
* @param {HTMLElement} node
* @param {object} item
* @param {string} nodeName
* @returns {HTMLElement|null}
*/
getParentNodeOfItem(node, item, nodeName) {
return node.querySelector(`${nodeName}[data-id="${item.parent}"]`)
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
elementIsAncestorOfItem(node, item) {
return !!this.getParentNodeOfItem(node, item, 'li')
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {HTMLElement}
*/
getDirectListParentOfItem(node, item) {
return this.getParentNodeOfItem(node, item, 'ul')
}
/**
* @param {object} item
* @returns {boolean}
*/
maybeAppendItemToParentDom(item) {
const { parent } = item;
const topParent = this.sortedDataDomArray.find(topLevelListItem => {
return this.elementIsParentOfItem(topLevelListItem, item) || this.elementIsAncestorOfItem(topLevelListItem, item)
});
if (!topParent) return false;
const listItem = this.createItemElement(item);
let directParentList = this.getDirectListParentOfItem(topParent, item);
if (!directParentList) {
// so we need to create the direct parent UL and append it to the direct parent LI
directParentList = this.createItemElement({ id: parent }, 'ul');
const directParentListItem = this.getParentNodeOfItem(topParent, item, 'li') || topParent;
directParentListItem.appendChild(directParentList);
}
directParentList.appendChild(listItem);
return true
}
/**
* @returns {array}
*/
getListItemsDom() {
this.sortedDataDomArray = [];
let processedItems = [];
while (processedItems.length !== this.sortListItems().length) {
processedItems = this.sortedData.reduce((processedItems, item) => {
const { id } = item;
if (processedItems.includes(id)) return processedItems
let itemAdded;
if (!item.parent) {
const listItem = this.createItemElement(item);
this.sortedDataDomArray.push(listItem);
itemAdded = true;
} else {
itemAdded = this.maybeAppendItemToParentDom(item);
}
if (itemAdded) processedItems.push(id);
return processedItems
}, processedItems);
}
return this.sortedDataDomArray
}
/**
* @param {HTMLUListElement} ul
* @returns {{parent, id: string}[]}
*/
convertDomToData(ul) {
return Array.from(ul.querySelectorAll('li')).map(li => {
const parentListItem = li.parentNode;
const parent = parentListItem.dataset.id;
return {
id: li.dataset.id,
parent
}
})
}
/**
* @returns {HTMLUListElement}
*/
render() {
const list = document.createElement('ul');
this.getListItemsDom().forEach(listItem => list.appendChild(listItem));
return list
}
}
class nestedSort {
/**
* @constructor
* @param {{onDrop: function}} actions
* @param {array} data
* @param {number} droppingEdge
* @param {string} el
* @param {array|string} listClassNames
*/
constructor({
actions: { onDrop } = {},
data,
droppingEdge = 15,
el
el,
listClassNames
} = {}) {
this.data = data;
this.selector = el;

@@ -15,2 +191,6 @@ this.sortableList = null;

this.targetedNode = null;
this.listClassNames = this.createListClassNamesArray(listClassNames);
this.actions = {
onDrop
};

@@ -47,5 +227,27 @@ this.targetNode = {

this.maybeInitDataDom();
this.initDragAndDrop();
}
getDataEngine() {
if (this.dataEngine instanceof DataEngine) {
return this.dataEngine
}
this.dataEngine = new DataEngine({data: this.data});
return this.dataEngine
}
createListClassNamesArray(listClassNames) {
if (!listClassNames) return []
return Array.isArray(listClassNames) ? listClassNames : listClassNames.split(' ')
}
maybeInitDataDom() {
if (!(Array.isArray(this.data) && this.data.length)) return;
const list = this.getDataEngine().render();
list.classList.add(...this.listClassNames);
document.getElementById(this.selector).appendChild(list);
}
initDragAndDrop() {

@@ -57,3 +259,4 @@

this.sortableList = document.getElementById(this.selector);
const list = document.getElementById(this.selector);
this.sortableList = list.nodeName === 'UL' ? list : list.querySelector('ul');

@@ -66,2 +269,3 @@ this.sortableList.querySelectorAll('li').forEach(el => {

el.addEventListener('dragend', this.onDragEnd.bind(this), false);
el.addEventListener('drop', this.onDrop.bind(this), false);

@@ -103,3 +307,2 @@ this.addListItemStyles(el);

e.target.addEventListener('dragover', this.onDragOver.bind(this), false);
e.target.addEventListener('drop', this.onDrop.bind(this), false);
e.target.addEventListener('dragleave', this.onDragLeave.bind(this), false);

@@ -125,4 +328,9 @@ }

e.preventDefault();
e.stopPropagation();
this.maybeDrop();
this.cleanupPlaceholderLists();
if (typeof this.actions.onDrop === 'function') {
this.actions.onDrop(this.getDataEngine().convertDomToData(this.sortableList));
}
}

@@ -282,2 +490,3 @@

ul.classList.remove(this.classNames.placeholder);
ul.dataset.id = ul.parentNode.dataset.id;
}

@@ -284,0 +493,0 @@ });

@@ -0,7 +1,183 @@

/**
* @typedef {object} dataEngineDataItem
* @property {number|string} id
* @property {string} text
* @property {number|string} [parent]
*/
class DataEngine {
/**
* @constructor
* @param {array.<dataEngineDataItem>} data
*/
constructor({ data }) {
this.data = data;
this.sortedData = [];
this.sortedDataDomArray = [];
}
/**
* @returns {array.<dataEngineDataItem>}
*/
sortListItems() {
this.sortedData = [...this.data].sort((item1, item2) => {
if (!item1.parent && item2.parent) return -1
return (!item2.parent && item1.parent) ? 1 : 0;
});
return this.sortedData
}
/**
* @param {dataEngineDataItem} item
* @param {string} nodeName
* @returns {HTMLElement}
*/
createItemElement(item, nodeName = 'li') {
const { id, text } = item;
const el = document.createElement(nodeName);
el.dataset.id = id;
if (nodeName === 'li') el.innerHTML = text;
return el
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
elementIsParentOfItem(node, item) {
return node.dataset.id === `${item.parent}`
}
/**
* @param {HTMLElement} node
* @param {object} item
* @param {string} nodeName
* @returns {HTMLElement|null}
*/
getParentNodeOfItem(node, item, nodeName) {
return node.querySelector(`${nodeName}[data-id="${item.parent}"]`)
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
elementIsAncestorOfItem(node, item) {
return !!this.getParentNodeOfItem(node, item, 'li')
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {HTMLElement}
*/
getDirectListParentOfItem(node, item) {
return this.getParentNodeOfItem(node, item, 'ul')
}
/**
* @param {object} item
* @returns {boolean}
*/
maybeAppendItemToParentDom(item) {
const { parent } = item;
const topParent = this.sortedDataDomArray.find(topLevelListItem => {
return this.elementIsParentOfItem(topLevelListItem, item) || this.elementIsAncestorOfItem(topLevelListItem, item)
});
if (!topParent) return false;
const listItem = this.createItemElement(item);
let directParentList = this.getDirectListParentOfItem(topParent, item);
if (!directParentList) {
// so we need to create the direct parent UL and append it to the direct parent LI
directParentList = this.createItemElement({ id: parent }, 'ul');
const directParentListItem = this.getParentNodeOfItem(topParent, item, 'li') || topParent;
directParentListItem.appendChild(directParentList);
}
directParentList.appendChild(listItem);
return true
}
/**
* @returns {array}
*/
getListItemsDom() {
this.sortedDataDomArray = [];
let processedItems = [];
while (processedItems.length !== this.sortListItems().length) {
processedItems = this.sortedData.reduce((processedItems, item) => {
const { id } = item;
if (processedItems.includes(id)) return processedItems
let itemAdded;
if (!item.parent) {
const listItem = this.createItemElement(item);
this.sortedDataDomArray.push(listItem);
itemAdded = true;
} else {
itemAdded = this.maybeAppendItemToParentDom(item);
}
if (itemAdded) processedItems.push(id);
return processedItems
}, processedItems);
}
return this.sortedDataDomArray
}
/**
* @param {HTMLUListElement} ul
* @returns {{parent, id: string}[]}
*/
convertDomToData(ul) {
return Array.from(ul.querySelectorAll('li')).map(li => {
const parentListItem = li.parentNode;
const parent = parentListItem.dataset.id;
return {
id: li.dataset.id,
parent
}
})
}
/**
* @returns {HTMLUListElement}
*/
render() {
const list = document.createElement('ul');
this.getListItemsDom().forEach(listItem => list.appendChild(listItem));
return list
}
}
class nestedSort {
/**
* @constructor
* @param {{onDrop: function}} actions
* @param {array} data
* @param {number} droppingEdge
* @param {string} el
* @param {array|string} listClassNames
*/
constructor({
actions: { onDrop } = {},
data,
droppingEdge = 15,
el
el,
listClassNames
} = {}) {
this.data = data;
this.selector = el;

@@ -13,2 +189,6 @@ this.sortableList = null;

this.targetedNode = null;
this.listClassNames = this.createListClassNamesArray(listClassNames);
this.actions = {
onDrop
};

@@ -45,5 +225,27 @@ this.targetNode = {

this.maybeInitDataDom();
this.initDragAndDrop();
}
getDataEngine() {
if (this.dataEngine instanceof DataEngine) {
return this.dataEngine
}
this.dataEngine = new DataEngine({data: this.data});
return this.dataEngine
}
createListClassNamesArray(listClassNames) {
if (!listClassNames) return []
return Array.isArray(listClassNames) ? listClassNames : listClassNames.split(' ')
}
maybeInitDataDom() {
if (!(Array.isArray(this.data) && this.data.length)) return;
const list = this.getDataEngine().render();
list.classList.add(...this.listClassNames);
document.getElementById(this.selector).appendChild(list);
}
initDragAndDrop() {

@@ -55,3 +257,4 @@

this.sortableList = document.getElementById(this.selector);
const list = document.getElementById(this.selector);
this.sortableList = list.nodeName === 'UL' ? list : list.querySelector('ul');

@@ -64,2 +267,3 @@ this.sortableList.querySelectorAll('li').forEach(el => {

el.addEventListener('dragend', this.onDragEnd.bind(this), false);
el.addEventListener('drop', this.onDrop.bind(this), false);

@@ -101,3 +305,2 @@ this.addListItemStyles(el);

e.target.addEventListener('dragover', this.onDragOver.bind(this), false);
e.target.addEventListener('drop', this.onDrop.bind(this), false);
e.target.addEventListener('dragleave', this.onDragLeave.bind(this), false);

@@ -123,4 +326,9 @@ }

e.preventDefault();
e.stopPropagation();
this.maybeDrop();
this.cleanupPlaceholderLists();
if (typeof this.actions.onDrop === 'function') {
this.actions.onDrop(this.getDataEngine().convertDomToData(this.sortableList));
}
}

@@ -280,2 +488,3 @@

ul.classList.remove(this.classNames.placeholder);
ul.dataset.id = ul.parentNode.dataset.id;
}

@@ -282,0 +491,0 @@ });

@@ -29,11 +29,255 @@ (function (global, factory) {

function _toConsumableArray(arr) {
return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread();
}
function _arrayWithoutHoles(arr) {
if (Array.isArray(arr)) return _arrayLikeToArray(arr);
}
function _iterableToArray(iter) {
if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter);
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(n);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _nonIterableSpread() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* @typedef {object} dataEngineDataItem
* @property {number|string} id
* @property {string} text
* @property {number|string} [parent]
*/
var DataEngine = /*#__PURE__*/function () {
/**
* @constructor
* @param {array.<dataEngineDataItem>} data
*/
function DataEngine(_ref) {
var data = _ref.data;
_classCallCheck(this, DataEngine);
this.data = data;
this.sortedData = [];
this.sortedDataDomArray = [];
}
/**
* @returns {array.<dataEngineDataItem>}
*/
_createClass(DataEngine, [{
key: "sortListItems",
value: function sortListItems() {
this.sortedData = _toConsumableArray(this.data).sort(function (item1, item2) {
if (!item1.parent && item2.parent) return -1;
return !item2.parent && item1.parent ? 1 : 0;
});
return this.sortedData;
}
/**
* @param {dataEngineDataItem} item
* @param {string} nodeName
* @returns {HTMLElement}
*/
}, {
key: "createItemElement",
value: function createItemElement(item) {
var nodeName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'li';
var id = item.id,
text = item.text;
var el = document.createElement(nodeName);
el.dataset.id = id;
if (nodeName === 'li') el.innerHTML = text;
return el;
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
}, {
key: "elementIsParentOfItem",
value: function elementIsParentOfItem(node, item) {
return node.dataset.id === "".concat(item.parent);
}
/**
* @param {HTMLElement} node
* @param {object} item
* @param {string} nodeName
* @returns {HTMLElement|null}
*/
}, {
key: "getParentNodeOfItem",
value: function getParentNodeOfItem(node, item, nodeName) {
return node.querySelector("".concat(nodeName, "[data-id=\"").concat(item.parent, "\"]"));
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {boolean}
*/
}, {
key: "elementIsAncestorOfItem",
value: function elementIsAncestorOfItem(node, item) {
return !!this.getParentNodeOfItem(node, item, 'li');
}
/**
* @param {HTMLElement} node
* @param {object} item
* @returns {HTMLElement}
*/
}, {
key: "getDirectListParentOfItem",
value: function getDirectListParentOfItem(node, item) {
return this.getParentNodeOfItem(node, item, 'ul');
}
/**
* @param {object} item
* @returns {boolean}
*/
}, {
key: "maybeAppendItemToParentDom",
value: function maybeAppendItemToParentDom(item) {
var _this = this;
var parent = item.parent;
var topParent = this.sortedDataDomArray.find(function (topLevelListItem) {
return _this.elementIsParentOfItem(topLevelListItem, item) || _this.elementIsAncestorOfItem(topLevelListItem, item);
});
if (!topParent) return false;
var listItem = this.createItemElement(item);
var directParentList = this.getDirectListParentOfItem(topParent, item);
if (!directParentList) {
// so we need to create the direct parent UL and append it to the direct parent LI
directParentList = this.createItemElement({
id: parent
}, 'ul');
var directParentListItem = this.getParentNodeOfItem(topParent, item, 'li') || topParent;
directParentListItem.appendChild(directParentList);
}
directParentList.appendChild(listItem);
return true;
}
/**
* @returns {array}
*/
}, {
key: "getListItemsDom",
value: function getListItemsDom() {
var _this2 = this;
this.sortedDataDomArray = [];
var processedItems = [];
while (processedItems.length !== this.sortListItems().length) {
processedItems = this.sortedData.reduce(function (processedItems, item) {
var id = item.id;
if (processedItems.includes(id)) return processedItems;
var itemAdded;
if (!item.parent) {
var listItem = _this2.createItemElement(item);
_this2.sortedDataDomArray.push(listItem);
itemAdded = true;
} else {
itemAdded = _this2.maybeAppendItemToParentDom(item);
}
if (itemAdded) processedItems.push(id);
return processedItems;
}, processedItems);
}
return this.sortedDataDomArray;
}
/**
* @param {HTMLUListElement} ul
* @returns {{parent, id: string}[]}
*/
}, {
key: "convertDomToData",
value: function convertDomToData(ul) {
return Array.from(ul.querySelectorAll('li')).map(function (li) {
var parentListItem = li.parentNode;
var parent = parentListItem.dataset.id;
return {
id: li.dataset.id,
parent: parent
};
});
}
/**
* @returns {HTMLUListElement}
*/
}, {
key: "render",
value: function render() {
var list = document.createElement('ul');
this.getListItemsDom().forEach(function (listItem) {
return list.appendChild(listItem);
});
return list;
}
}]);
return DataEngine;
}();
var nestedSort = /*#__PURE__*/function () {
/**
* @constructor
* @param {{onDrop: function}} actions
* @param {array} data
* @param {number} droppingEdge
* @param {string} el
* @param {array|string} listClassNames
*/
function nestedSort() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$actions = _ref.actions;
_ref$actions = _ref$actions === void 0 ? {} : _ref$actions;
var onDrop = _ref$actions.onDrop,
data = _ref.data,
_ref$droppingEdge = _ref.droppingEdge,
droppingEdge = _ref$droppingEdge === void 0 ? 15 : _ref$droppingEdge,
el = _ref.el;
el = _ref.el,
listClassNames = _ref.listClassNames;
_classCallCheck(this, nestedSort);
this.data = data;
this.selector = el;

@@ -45,2 +289,6 @@ this.sortableList = null;

this.targetedNode = null;
this.listClassNames = this.createListClassNamesArray(listClassNames);
this.actions = {
onDrop: onDrop
};
this.targetNode = {

@@ -71,2 +319,3 @@ X: null,

};
this.maybeInitDataDom();
this.initDragAndDrop();

@@ -76,2 +325,32 @@ }

_createClass(nestedSort, [{
key: "getDataEngine",
value: function getDataEngine() {
if (this.dataEngine instanceof DataEngine) {
return this.dataEngine;
}
this.dataEngine = new DataEngine({
data: this.data
});
return this.dataEngine;
}
}, {
key: "createListClassNamesArray",
value: function createListClassNamesArray(listClassNames) {
if (!listClassNames) return [];
return Array.isArray(listClassNames) ? listClassNames : listClassNames.split(' ');
}
}, {
key: "maybeInitDataDom",
value: function maybeInitDataDom() {
var _list$classList;
if (!(Array.isArray(this.data) && this.data.length)) return;
var list = this.getDataEngine().render();
(_list$classList = list.classList).add.apply(_list$classList, _toConsumableArray(this.listClassNames));
document.getElementById(this.selector).appendChild(list);
}
}, {
key: "initDragAndDrop",

@@ -83,3 +362,4 @@ value: function initDragAndDrop() {

this.initPlaceholderList();
this.sortableList = document.getElementById(this.selector);
var list = document.getElementById(this.selector);
this.sortableList = list.nodeName === 'UL' ? list : list.querySelector('ul');
this.sortableList.querySelectorAll('li').forEach(function (el) {

@@ -90,2 +370,3 @@ el.setAttribute('draggable', 'true');

el.addEventListener('dragend', _this.onDragEnd.bind(_this), false);
el.addEventListener('drop', _this.onDrop.bind(_this), false);

@@ -132,3 +413,2 @@ _this.addListItemStyles(el);

e.target.addEventListener('dragover', this.onDragOver.bind(this), false);
e.target.addEventListener('drop', this.onDrop.bind(this), false);
e.target.addEventListener('dragleave', this.onDragLeave.bind(this), false);

@@ -157,4 +437,9 @@ }

e.preventDefault();
e.stopPropagation();
this.maybeDrop();
this.cleanupPlaceholderLists();
if (typeof this.actions.onDrop === 'function') {
this.actions.onDrop(this.getDataEngine().convertDomToData(this.sortableList));
}
}

@@ -335,2 +620,3 @@ }, {

ul.classList.remove(_this3.classNames.placeholder);
ul.dataset.id = ul.parentNode.dataset.id;
}

@@ -337,0 +623,0 @@ });

3

package.json
{
"name": "nested-sort",
"version": "2.0.2",
"version": "2.1.0",
"author": "Hesam Bahrami (Genzo)",

@@ -32,2 +32,3 @@ "description": "A JavaScript library to create a nested list of elements",

"watch": "concurrently 'yarn build:watch' 'yarn serve -l tcp://127.0.0.1'",
"test:coverage": "jest --coverage",
"test": "jest && yarn build"

@@ -34,0 +35,0 @@ },

@@ -5,2 +5,18 @@ # Nested Sort

## Download
* [CDN copies](https://www.jsdelivr.com/package/npm/nested-sort) [![](https://data.jsdelivr.com/v1/package/npm/nested-sort/badge)](https://www.jsdelivr.com/package/npm/nested-sort)
## Installation
Using npm:
```shell
$ npm i nested-sort
```
## Demo
There are some samples in the `dev` folder.
## Developer environment requirements

@@ -19,2 +35,3 @@

yarn test --watch
yarn test:coverage
```

@@ -21,0 +38,0 @@

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc