![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/magento2-base/lib/web/knockoutjs/ |
/*! Knockout Fast Foreach v0.4.1 (2015-07-17T14:06:15.974Z) By: Brian M Hunt (C) 2015 License: MIT Adds `fastForEach` to `ko.bindingHandlers`. */ (function (root, factory) { if (typeof define === 'function' && define.amd) { define(['knockout'], factory); } else if (typeof exports === 'object') { module.exports = factory(require('knockout')); } else { root.KnockoutFastForeach = factory(root.ko); } }(this, function (ko) { "use strict"; // index.js // -------- // Fast For Each // // Employing sound techniques to make a faster Knockout foreach binding. // -------- // Utilities // from https://github.com/jonschlinkert/is-plain-object function isPlainObject(o) { return !!o && typeof o === 'object' && o.constructor === Object; } // From knockout/src/virtualElements.js var commentNodesHaveTextProperty = document && document.createComment("test").text === "<!--test-->"; var startCommentRegex = commentNodesHaveTextProperty ? /^<!--\s*ko(?:\s+([\s\S]+))?\s*-->$/ : /^\s*ko(?:\s+([\s\S]+))?\s*$/; var supportsDocumentFragment = document && typeof document.createDocumentFragment === "function"; function isVirtualNode(node) { return (node.nodeType === 8) && startCommentRegex.test(commentNodesHaveTextProperty ? node.text : node.nodeValue); } // Get a copy of the (possibly virtual) child nodes of the given element, // put them into a container, then empty the given node. function makeTemplateNode(sourceNode) { var container = document.createElement("div"); var parentNode; if (sourceNode.content) { // For e.g. <template> tags parentNode = sourceNode.content; } else if (sourceNode.tagName === 'SCRIPT') { parentNode = document.createElement("div"); parentNode.innerHTML = sourceNode.text; } else { // Anything else e.g. <div> parentNode = sourceNode; } ko.utils.arrayForEach(ko.virtualElements.childNodes(parentNode), function (child) { // FIXME - This cloneNode could be expensive; we may prefer to iterate over the // parentNode children in reverse (so as not to foul the indexes as childNodes are // removed from parentNode when inserted into the container) if (child) { container.insertBefore(child.cloneNode(true), null); } }); return container; } function insertAllAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode) { var frag, len, i; // poor man's node and array check, should be enough for this if (typeof nodeOrNodeArrayToInsert.nodeType !== "undefined" && typeof nodeOrNodeArrayToInsert.length === "undefined") { throw new Error("Expected a single node or a node array"); } if (typeof nodeOrNodeArrayToInsert.nodeType !== "undefined") { ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert, insertAfterNode); return; } if (nodeOrNodeArrayToInsert.length === 1) { ko.virtualElements.insertAfter(containerNode, nodeOrNodeArrayToInsert[0], insertAfterNode); return; } if (supportsDocumentFragment) { frag = document.createDocumentFragment(); for (i = 0, len = nodeOrNodeArrayToInsert.length; i !== len; ++i) { frag.appendChild(nodeOrNodeArrayToInsert[i]); } ko.virtualElements.insertAfter(containerNode, frag, insertAfterNode); } else { // Nodes are inserted in reverse order - pushed down immediately after // the last node for the previous item or as the first node of element. for (i = nodeOrNodeArrayToInsert.length - 1; i >= 0; --i) { var child = nodeOrNodeArrayToInsert[i]; if (!child) { return; } ko.virtualElements.insertAfter(containerNode, child, insertAfterNode); } } } // Mimic a KO change item 'add' function valueToChangeAddItem(value, index) { return { status: 'added', value: value, index: index }; } function isAdditionAdjacentToLast(changeIndex, arrayChanges) { return changeIndex > 0 && changeIndex < arrayChanges.length && arrayChanges[changeIndex].status === "added" && arrayChanges[changeIndex - 1].status === "added" && arrayChanges[changeIndex - 1].index === arrayChanges[changeIndex].index - 1; } function FastForEach(spec) { this.element = spec.element; this.container = isVirtualNode(this.element) ? this.element.parentNode : this.element; this.$context = spec.$context; this.data = spec.data; this.as = spec.as; this.noContext = spec.noContext; this.templateNode = makeTemplateNode( spec.name ? document.getElementById(spec.name).cloneNode(true) : spec.element ); this.afterQueueFlush = spec.afterQueueFlush; this.beforeQueueFlush = spec.beforeQueueFlush; this.changeQueue = []; this.lastNodesList = []; this.indexesToDelete = []; this.rendering_queued = false; // Remove existing content. ko.virtualElements.emptyNode(this.element); // Prime content var primeData = ko.unwrap(this.data); if (primeData.map) { this.onArrayChange(primeData.map(valueToChangeAddItem)); } // Watch for changes if (ko.isObservable(this.data)) { if (!this.data.indexOf) { // Make sure the observable is trackable. this.data = this.data.extend({trackArrayChanges: true}); } this.changeSubs = this.data.subscribe(this.onArrayChange, this, 'arrayChange'); } } FastForEach.animateFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame || function(cb) { return window.setTimeout(cb, 1000 / 60); }; FastForEach.prototype.dispose = function () { if (this.changeSubs) { this.changeSubs.dispose(); } }; // If the array changes we register the change. FastForEach.prototype.onArrayChange = function (changeSet) { var self = this; var changeMap = { added: [], deleted: [] }; for (var i = 0, len = changeSet.length; i < len; i++) { // the change is appended to a last change info object when both are 'added' and have indexes next to each other // here I presume that ko is sending changes in monotonic order (in index variable) which happens to be true, tested with push and splice with multiple pushed values if (isAdditionAdjacentToLast(i, changeSet)) { var batchValues = changeMap.added[changeMap.added.length - 1].values; if (!batchValues) { // transform the last addition into a batch addition object var lastAddition = changeMap.added.pop(); var batchAddition = { isBatch: true, status: 'added', index: lastAddition.index, values: [lastAddition.value] }; batchValues = batchAddition.values; changeMap.added.push(batchAddition); } batchValues.push(changeSet[i].value); } else { changeMap[changeSet[i].status].push(changeSet[i]); } } if (changeMap.deleted.length > 0) { this.changeQueue.push.apply(this.changeQueue, changeMap.deleted); this.changeQueue.push({status: 'clearDeletedIndexes'}); } this.changeQueue.push.apply(this.changeQueue, changeMap.added); // Once a change is registered, the ticking count-down starts for the processQueue. if (this.changeQueue.length > 0 && !this.rendering_queued) { this.rendering_queued = true; FastForEach.animateFrame.call(window, function () { self.processQueue(); }); } }; // Reflect all the changes in the queue in the DOM, then wipe the queue. FastForEach.prototype.processQueue = function () { var self = this; // Callback so folks can do things before the queue flush. if (typeof this.beforeQueueFlush === 'function') { this.beforeQueueFlush(this.changeQueue); } ko.utils.arrayForEach(this.changeQueue, function (changeItem) { // console.log(self.data(), "CI", JSON.stringify(changeItem, null, 2), JSON.stringify($(self.element).text())) self[changeItem.status](changeItem); // console.log(" ==> ", JSON.stringify($(self.element).text())) }); this.rendering_queued = false; // Callback so folks can do things. if (typeof this.afterQueueFlush === 'function') { this.afterQueueFlush(this.changeQueue); } this.changeQueue = []; }; // Process a changeItem with {status: 'added', ...} FastForEach.prototype.added = function (changeItem) { var index = changeItem.index; var valuesToAdd = changeItem.isBatch ? changeItem.values : [changeItem.value]; var referenceElement = this.lastNodesList[index - 1] || null; // gather all childnodes for a possible batch insertion var allChildNodes = []; for (var i = 0, len = valuesToAdd.length; i < len; ++i) { var templateClone = this.templateNode.cloneNode(true); var childContext; if (this.noContext) { childContext = this.$context.extend({ '$item': valuesToAdd[i] }); } else { childContext = this.$context.createChildContext(valuesToAdd[i], this.as || null); } // apply bindings first, and then process child nodes, because bindings can add childnodes ko.applyBindingsToDescendants(childContext, templateClone); var childNodes = ko.virtualElements.childNodes(templateClone); // Note discussion at https://github.com/angular/angular.js/issues/7851 allChildNodes.push.apply(allChildNodes, Array.prototype.slice.call(childNodes)); this.lastNodesList.splice(index + i, 0, childNodes[childNodes.length - 1]); } insertAllAfter(this.element, allChildNodes, referenceElement); }; // Process a changeItem with {status: 'deleted', ...} FastForEach.prototype.deleted = function (changeItem) { var index = changeItem.index; var ptr = this.lastNodesList[index], // We use this.element because that will be the last previous node // for virtual element lists. lastNode = this.lastNodesList[index - 1] || this.element; do { ptr = ptr.previousSibling; ko.removeNode((ptr && ptr.nextSibling) || ko.virtualElements.firstChild(this.element)); } while (ptr && ptr !== lastNode); // The "last node" in the DOM from which we begin our delets of the next adjacent node is // now the sibling that preceded the first node of this item. this.lastNodesList[index] = this.lastNodesList[index - 1]; this.indexesToDelete.push(index); }; // We batch our deletion of item indexes in our parallel array. // See brianmhunt/knockout-fast-foreach#6/#8 FastForEach.prototype.clearDeletedIndexes = function () { // We iterate in reverse on the presumption (following the unit tests) that KO's diff engine // processes diffs (esp. deletes) monotonically ascending i.e. from index 0 -> N. for (var i = this.indexesToDelete.length - 1; i >= 0; --i) { this.lastNodesList.splice(this.indexesToDelete[i], 1); } this.indexesToDelete = []; }; ko.bindingHandlers.fastForEach = { // Valid valueAccessors: // [] // ko.observable([]) // ko.observableArray([]) // ko.computed // {data: array, name: string, as: string} init: function init(element, valueAccessor, bindings, vm, context) { var value = valueAccessor(), ffe; if (isPlainObject(value)) { value.element = value.element || element; value.$context = context; ffe = new FastForEach(value); } else { ffe = new FastForEach({ element: element, data: ko.unwrap(context.$rawData) === value ? context.$rawData : value, $context: context }); } ko.utils.domNodeDisposal.addDisposeCallback(element, function () { ffe.dispose(); }); return {controlsDescendantBindings: true}; }, // Export for testing, debugging, and overloading. FastForEach: FastForEach }; ko.virtualElements.allowedBindings.fastForEach = true; }));