|
|
/******/ (() => { // webpackBootstrap
|
|
|
/******/ "use strict";
|
|
|
/******/ var __webpack_modules__ = ({
|
|
|
|
|
|
/***/ 6689:
|
|
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
|
|
|
|
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
|
/* harmony export */ createUndoManager: () => (/* binding */ createUndoManager)
|
|
|
/* harmony export */ });
|
|
|
/* harmony import */ var _wordpress_is_shallow_equal__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(923);
|
|
|
/* harmony import */ var _wordpress_is_shallow_equal__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_wordpress_is_shallow_equal__WEBPACK_IMPORTED_MODULE_0__);
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/** @typedef {import('./types').HistoryRecord} HistoryRecord */
|
|
|
/** @typedef {import('./types').HistoryChange} HistoryChange */
|
|
|
/** @typedef {import('./types').HistoryChanges} HistoryChanges */
|
|
|
/** @typedef {import('./types').UndoManager} UndoManager */
|
|
|
|
|
|
/**
|
|
|
* Merge changes for a single item into a record of changes.
|
|
|
*
|
|
|
* @param {Record< string, HistoryChange >} changes1 Previous changes
|
|
|
* @param {Record< string, HistoryChange >} changes2 NextChanges
|
|
|
*
|
|
|
* @return {Record< string, HistoryChange >} Merged changes
|
|
|
*/
|
|
|
function mergeHistoryChanges(changes1, changes2) {
|
|
|
/**
|
|
|
* @type {Record< string, HistoryChange >}
|
|
|
*/
|
|
|
const newChanges = {
|
|
|
...changes1
|
|
|
};
|
|
|
Object.entries(changes2).forEach(([key, value]) => {
|
|
|
if (newChanges[key]) {
|
|
|
newChanges[key] = {
|
|
|
...newChanges[key],
|
|
|
to: value.to
|
|
|
};
|
|
|
} else {
|
|
|
newChanges[key] = value;
|
|
|
}
|
|
|
});
|
|
|
return newChanges;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Adds history changes for a single item into a record of changes.
|
|
|
*
|
|
|
* @param {HistoryRecord} record The record to merge into.
|
|
|
* @param {HistoryChanges} changes The changes to merge.
|
|
|
*/
|
|
|
const addHistoryChangesIntoRecord = (record, changes) => {
|
|
|
const existingChangesIndex = record?.findIndex(({
|
|
|
id: recordIdentifier
|
|
|
}) => {
|
|
|
return typeof recordIdentifier === 'string' ? recordIdentifier === changes.id : _wordpress_is_shallow_equal__WEBPACK_IMPORTED_MODULE_0___default()(recordIdentifier, changes.id);
|
|
|
});
|
|
|
const nextRecord = [...record];
|
|
|
if (existingChangesIndex !== -1) {
|
|
|
// If the edit is already in the stack leave the initial "from" value.
|
|
|
nextRecord[existingChangesIndex] = {
|
|
|
id: changes.id,
|
|
|
changes: mergeHistoryChanges(nextRecord[existingChangesIndex].changes, changes.changes)
|
|
|
};
|
|
|
} else {
|
|
|
nextRecord.push(changes);
|
|
|
}
|
|
|
return nextRecord;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Creates an undo manager.
|
|
|
*
|
|
|
* @return {UndoManager} Undo manager.
|
|
|
*/
|
|
|
function createUndoManager() {
|
|
|
/**
|
|
|
* @type {HistoryRecord[]}
|
|
|
*/
|
|
|
let history = [];
|
|
|
/**
|
|
|
* @type {HistoryRecord}
|
|
|
*/
|
|
|
let stagedRecord = [];
|
|
|
/**
|
|
|
* @type {number}
|
|
|
*/
|
|
|
let offset = 0;
|
|
|
const dropPendingRedos = () => {
|
|
|
history = history.slice(0, offset || undefined);
|
|
|
offset = 0;
|
|
|
};
|
|
|
const appendStagedRecordToLatestHistoryRecord = () => {
|
|
|
var _history$index;
|
|
|
const index = history.length === 0 ? 0 : history.length - 1;
|
|
|
let latestRecord = (_history$index = history[index]) !== null && _history$index !== void 0 ? _history$index : [];
|
|
|
stagedRecord.forEach(changes => {
|
|
|
latestRecord = addHistoryChangesIntoRecord(latestRecord, changes);
|
|
|
});
|
|
|
stagedRecord = [];
|
|
|
history[index] = latestRecord;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Checks whether a record is empty.
|
|
|
* A record is considered empty if it the changes keep the same values.
|
|
|
* Also updates to function values are ignored.
|
|
|
*
|
|
|
* @param {HistoryRecord} record
|
|
|
* @return {boolean} Whether the record is empty.
|
|
|
*/
|
|
|
const isRecordEmpty = record => {
|
|
|
const filteredRecord = record.filter(({
|
|
|
changes
|
|
|
}) => {
|
|
|
return Object.values(changes).some(({
|
|
|
from,
|
|
|
to
|
|
|
}) => typeof from !== 'function' && typeof to !== 'function' && !_wordpress_is_shallow_equal__WEBPACK_IMPORTED_MODULE_0___default()(from, to));
|
|
|
});
|
|
|
return !filteredRecord.length;
|
|
|
};
|
|
|
return {
|
|
|
/**
|
|
|
* Record changes into the history.
|
|
|
*
|
|
|
* @param {HistoryRecord=} record A record of changes to record.
|
|
|
* @param {boolean} isStaged Whether to immediately create an undo point or not.
|
|
|
*/
|
|
|
addRecord(record, isStaged = false) {
|
|
|
const isEmpty = !record || isRecordEmpty(record);
|
|
|
if (isStaged) {
|
|
|
if (isEmpty) {
|
|
|
return;
|
|
|
}
|
|
|
record.forEach(changes => {
|
|
|
stagedRecord = addHistoryChangesIntoRecord(stagedRecord, changes);
|
|
|
});
|
|
|
} else {
|
|
|
dropPendingRedos();
|
|
|
if (stagedRecord.length) {
|
|
|
appendStagedRecordToLatestHistoryRecord();
|
|
|
}
|
|
|
if (isEmpty) {
|
|
|
return;
|
|
|
}
|
|
|
history.push(record);
|
|
|
}
|
|
|
},
|
|
|
undo() {
|
|
|
if (stagedRecord.length) {
|
|
|
dropPendingRedos();
|
|
|
appendStagedRecordToLatestHistoryRecord();
|
|
|
}
|
|
|
const undoRecord = history[history.length - 1 + offset];
|
|
|
if (!undoRecord) {
|
|
|
return;
|
|
|
}
|
|
|
offset -= 1;
|
|
|
return undoRecord;
|
|
|
},
|
|
|
redo() {
|
|
|
const redoRecord = history[history.length + offset];
|
|
|
if (!redoRecord) {
|
|
|
return;
|
|
|
}
|
|
|
offset += 1;
|
|
|
return redoRecord;
|
|
|
},
|
|
|
hasUndo() {
|
|
|
return !!history[history.length - 1 + offset];
|
|
|
},
|
|
|
hasRedo() {
|
|
|
return !!history[history.length + offset];
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
/***/ }),
|
|
|
|
|
|
/***/ 3249:
|
|
|
/***/ ((module) => {
|
|
|
|
|
|
|
|
|
|
|
|
function _typeof(obj) {
|
|
|
if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
|
|
|
_typeof = function (obj) {
|
|
|
return typeof obj;
|
|
|
};
|
|
|
} else {
|
|
|
_typeof = function (obj) {
|
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
|
};
|
|
|
}
|
|
|
|
|
|
return _typeof(obj);
|
|
|
}
|
|
|
|
|
|
function _classCallCheck(instance, Constructor) {
|
|
|
if (!(instance instanceof Constructor)) {
|
|
|
throw new TypeError("Cannot call a class as a function");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function _defineProperties(target, props) {
|
|
|
for (var i = 0; i < props.length; i++) {
|
|
|
var descriptor = props[i];
|
|
|
descriptor.enumerable = descriptor.enumerable || false;
|
|
|
descriptor.configurable = true;
|
|
|
if ("value" in descriptor) descriptor.writable = true;
|
|
|
Object.defineProperty(target, descriptor.key, descriptor);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
function _createClass(Constructor, protoProps, staticProps) {
|
|
|
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
|
|
if (staticProps) _defineProperties(Constructor, staticProps);
|
|
|
return Constructor;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Given an instance of EquivalentKeyMap, returns its internal value pair tuple
|
|
|
* for a key, if one exists. The tuple members consist of the last reference
|
|
|
* value for the key (used in efficient subsequent lookups) and the value
|
|
|
* assigned for the key at the leaf node.
|
|
|
*
|
|
|
* @param {EquivalentKeyMap} instance EquivalentKeyMap instance.
|
|
|
* @param {*} key The key for which to return value pair.
|
|
|
*
|
|
|
* @return {?Array} Value pair, if exists.
|
|
|
*/
|
|
|
function getValuePair(instance, key) {
|
|
|
var _map = instance._map,
|
|
|
_arrayTreeMap = instance._arrayTreeMap,
|
|
|
_objectTreeMap = instance._objectTreeMap; // Map keeps a reference to the last object-like key used to set the
|
|
|
// value, which can be used to shortcut immediately to the value.
|
|
|
|
|
|
if (_map.has(key)) {
|
|
|
return _map.get(key);
|
|
|
} // Sort keys to ensure stable retrieval from tree.
|
|
|
|
|
|
|
|
|
var properties = Object.keys(key).sort(); // Tree by type to avoid conflicts on numeric object keys, empty value.
|
|
|
|
|
|
var map = Array.isArray(key) ? _arrayTreeMap : _objectTreeMap;
|
|
|
|
|
|
for (var i = 0; i < properties.length; i++) {
|
|
|
var property = properties[i];
|
|
|
map = map.get(property);
|
|
|
|
|
|
if (map === undefined) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
var propertyValue = key[property];
|
|
|
map = map.get(propertyValue);
|
|
|
|
|
|
if (map === undefined) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var valuePair = map.get('_ekm_value');
|
|
|
|
|
|
if (!valuePair) {
|
|
|
return;
|
|
|
} // If reached, it implies that an object-like key was set with another
|
|
|
// reference, so delete the reference and replace with the current.
|
|
|
|
|
|
|
|
|
_map.delete(valuePair[0]);
|
|
|
|
|
|
valuePair[0] = key;
|
|
|
map.set('_ekm_value', valuePair);
|
|
|
|
|
|
_map.set(key, valuePair);
|
|
|
|
|
|
return valuePair;
|
|
|
}
|
|
|
/**
|
|
|
* Variant of a Map object which enables lookup by equivalent (deeply equal)
|
|
|
* object and array keys.
|
|
|
*/
|
|
|
|
|
|
|
|
|
var EquivalentKeyMap =
|
|
|
/*#__PURE__*/
|
|
|
function () {
|
|
|
/**
|
|
|
* Constructs a new instance of EquivalentKeyMap.
|
|
|
*
|
|
|
* @param {Iterable.<*>} iterable Initial pair of key, value for map.
|
|
|
*/
|
|
|
function EquivalentKeyMap(iterable) {
|
|
|
_classCallCheck(this, EquivalentKeyMap);
|
|
|
|
|
|
this.clear();
|
|
|
|
|
|
if (iterable instanceof EquivalentKeyMap) {
|
|
|
// Map#forEach is only means of iterating with support for IE11.
|
|
|
var iterablePairs = [];
|
|
|
iterable.forEach(function (value, key) {
|
|
|
iterablePairs.push([key, value]);
|
|
|
});
|
|
|
iterable = iterablePairs;
|
|
|
}
|
|
|
|
|
|
if (iterable != null) {
|
|
|
for (var i = 0; i < iterable.length; i++) {
|
|
|
this.set(iterable[i][0], iterable[i][1]);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
* Accessor property returning the number of elements.
|
|
|
*
|
|
|
* @return {number} Number of elements.
|
|
|
*/
|
|
|
|
|
|
|
|
|
_createClass(EquivalentKeyMap, [{
|
|
|
key: "set",
|
|
|
|
|
|
/**
|
|
|
* Add or update an element with a specified key and value.
|
|
|
*
|
|
|
* @param {*} key The key of the element to add.
|
|
|
* @param {*} value The value of the element to add.
|
|
|
*
|
|
|
* @return {EquivalentKeyMap} Map instance.
|
|
|
*/
|
|
|
value: function set(key, value) {
|
|
|
// Shortcut non-object-like to set on internal Map.
|
|
|
if (key === null || _typeof(key) !== 'object') {
|
|
|
this._map.set(key, value);
|
|
|
|
|
|
return this;
|
|
|
} // Sort keys to ensure stable assignment into tree.
|
|
|
|
|
|
|
|
|
var properties = Object.keys(key).sort();
|
|
|
var valuePair = [key, value]; // Tree by type to avoid conflicts on numeric object keys, empty value.
|
|
|
|
|
|
var map = Array.isArray(key) ? this._arrayTreeMap : this._objectTreeMap;
|
|
|
|
|
|
for (var i = 0; i < properties.length; i++) {
|
|
|
var property = properties[i];
|
|
|
|
|
|
if (!map.has(property)) {
|
|
|
map.set(property, new EquivalentKeyMap());
|
|
|
}
|
|
|
|
|
|
map = map.get(property);
|
|
|
var propertyValue = key[property];
|
|
|
|
|
|
if (!map.has(propertyValue)) {
|
|
|
map.set(propertyValue, new EquivalentKeyMap());
|
|
|
}
|
|
|
|
|
|
map = map.get(propertyValue);
|
|
|
} // If an _ekm_value exists, there was already an equivalent key. Before
|
|
|
// overriding, ensure that the old key reference is removed from map to
|
|
|
// avoid memory leak of accumulating equivalent keys. This is, in a
|
|
|
// sense, a poor man's WeakMap, while still enabling iterability.
|
|
|
|
|
|
|
|
|
var previousValuePair = map.get('_ekm_value');
|
|
|
|
|
|
if (previousValuePair) {
|
|
|
this._map.delete(previousValuePair[0]);
|
|
|
}
|
|
|
|
|
|
map.set('_ekm_value', valuePair);
|
|
|
|
|
|
this._map.set(key, valuePair);
|
|
|
|
|
|
return this;
|
|
|
}
|
|
|
/**
|
|
|
* Returns a specified element.
|
|
|
*
|
|
|
* @param {*} key The key of the element to return.
|
|
|
*
|
|
|
* @return {?*} The element associated with the specified key or undefined
|
|
|
* if the key can't be found.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "get",
|
|
|
value: function get(key) {
|
|
|
// Shortcut non-object-like to get from internal Map.
|
|
|
if (key === null || _typeof(key) !== 'object') {
|
|
|
return this._map.get(key);
|
|
|
}
|
|
|
|
|
|
var valuePair = getValuePair(this, key);
|
|
|
|
|
|
if (valuePair) {
|
|
|
return valuePair[1];
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
|
* Returns a boolean indicating whether an element with the specified key
|
|
|
* exists or not.
|
|
|
*
|
|
|
* @param {*} key The key of the element to test for presence.
|
|
|
*
|
|
|
* @return {boolean} Whether an element with the specified key exists.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "has",
|
|
|
value: function has(key) {
|
|
|
if (key === null || _typeof(key) !== 'object') {
|
|
|
return this._map.has(key);
|
|
|
} // Test on the _presence_ of the pair, not its value, as even undefined
|
|
|
// can be a valid member value for a key.
|
|
|
|
|
|
|
|
|
return getValuePair(this, key) !== undefined;
|
|
|
}
|
|
|
/**
|
|
|
* Removes the specified element.
|
|
|
*
|
|
|
* @param {*} key The key of the element to remove.
|
|
|
*
|
|
|
* @return {boolean} Returns true if an element existed and has been
|
|
|
* removed, or false if the element does not exist.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "delete",
|
|
|
value: function _delete(key) {
|
|
|
if (!this.has(key)) {
|
|
|
return false;
|
|
|
} // This naive implementation will leave orphaned child trees. A better
|
|
|
// implementation should traverse and remove orphans.
|
|
|
|
|
|
|
|
|
this.set(key, undefined);
|
|
|
return true;
|
|
|
}
|
|
|
/**
|
|
|
* Executes a provided function once per each key/value pair, in insertion
|
|
|
* order.
|
|
|
*
|
|
|
* @param {Function} callback Function to execute for each element.
|
|
|
* @param {*} thisArg Value to use as `this` when executing
|
|
|
* `callback`.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "forEach",
|
|
|
value: function forEach(callback) {
|
|
|
var _this = this;
|
|
|
|
|
|
var thisArg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this;
|
|
|
|
|
|
this._map.forEach(function (value, key) {
|
|
|
// Unwrap value from object-like value pair.
|
|
|
if (key !== null && _typeof(key) === 'object') {
|
|
|
value = value[1];
|
|
|
}
|
|
|
|
|
|
callback.call(thisArg, value, key, _this);
|
|
|
});
|
|
|
}
|
|
|
/**
|
|
|
* Removes all elements.
|
|
|
*/
|
|
|
|
|
|
}, {
|
|
|
key: "clear",
|
|
|
value: function clear() {
|
|
|
this._map = new Map();
|
|
|
this._arrayTreeMap = new Map();
|
|
|
this._objectTreeMap = new Map();
|
|
|
}
|
|
|
}, {
|
|
|
key: "size",
|
|
|
get: function get() {
|
|
|
return this._map.size;
|
|
|
}
|
|
|
}]);
|
|
|
|
|
|
return EquivalentKeyMap;
|
|
|
}();
|
|
|
|
|
|
module.exports = EquivalentKeyMap;
|
|
|
|
|
|
|
|
|
/***/ }),
|
|
|
|
|
|
/***/ 7734:
|
|
|
/***/ ((module) => {
|
|
|
|
|
|
|
|
|
|
|
|
// do not edit .js files directly - edit src/index.jst
|
|
|
|
|
|
|
|
|
var envHasBigInt64Array = typeof BigInt64Array !== 'undefined';
|
|
|
|
|
|
|
|
|
module.exports = function equal(a, b) {
|
|
|
if (a === b) return true;
|
|
|
|
|
|
if (a && b && typeof a == 'object' && typeof b == 'object') {
|
|
|
if (a.constructor !== b.constructor) return false;
|
|
|
|
|
|
var length, i, keys;
|
|
|
if (Array.isArray(a)) {
|
|
|
length = a.length;
|
|
|
if (length != b.length) return false;
|
|
|
for (i = length; i-- !== 0;)
|
|
|
if (!equal(a[i], b[i])) return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
if ((a instanceof Map) && (b instanceof Map)) {
|
|
|
if (a.size !== b.size) return false;
|
|
|
for (i of a.entries())
|
|
|
if (!b.has(i[0])) return false;
|
|
|
for (i of a.entries())
|
|
|
if (!equal(i[1], b.get(i[0]))) return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if ((a instanceof Set) && (b instanceof Set)) {
|
|
|
if (a.size !== b.size) return false;
|
|
|
for (i of a.entries())
|
|
|
if (!b.has(i[0])) return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
|
length = a.length;
|
|
|
if (length != b.length) return false;
|
|
|
for (i = length; i-- !== 0;)
|
|
|
if (a[i] !== b[i]) return false;
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
|
|
|
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
|
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
|
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
|
|
|
|
keys = Object.keys(a);
|
|
|
length = keys.length;
|
|
|
if (length !== Object.keys(b).length) return false;
|
|
|
|
|
|
for (i = length; i-- !== 0;)
|
|
|
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
|
|
|
|
for (i = length; i-- !== 0;) {
|
|
|
var key = keys[i];
|
|
|
|
|
|
if (!equal(a[key], b[key])) return false;
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// true if both NaN, false otherwise
|
|
|
return a!==a && b!==b;
|
|
|
};
|
|
|
|
|
|
|
|
|
/***/ }),
|
|
|
|
|
|
/***/ 923:
|
|
|
/***/ ((module) => {
|
|
|
|
|
|
module.exports = window["wp"]["isShallowEqual"];
|
|
|
|
|
|
/***/ })
|
|
|
|
|
|
/******/ });
|
|
|
/************************************************************************/
|
|
|
/******/ // The module cache
|
|
|
/******/ var __webpack_module_cache__ = {};
|
|
|
/******/
|
|
|
/******/ // The require function
|
|
|
/******/ function __webpack_require__(moduleId) {
|
|
|
/******/ // Check if module is in cache
|
|
|
/******/ var cachedModule = __webpack_module_cache__[moduleId];
|
|
|
/******/ if (cachedModule !== undefined) {
|
|
|
/******/ return cachedModule.exports;
|
|
|
/******/ }
|
|
|
/******/ // Create a new module (and put it into the cache)
|
|
|
/******/ var module = __webpack_module_cache__[moduleId] = {
|
|
|
/******/ // no module.id needed
|
|
|
/******/ // no module.loaded needed
|
|
|
/******/ exports: {}
|
|
|
/******/ };
|
|
|
/******/
|
|
|
/******/ // Execute the module function
|
|
|
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
|
|
|
/******/
|
|
|
/******/ // Return the exports of the module
|
|
|
/******/ return module.exports;
|
|
|
/******/ }
|
|
|
/******/
|
|
|
/************************************************************************/
|
|
|
/******/ /* webpack/runtime/compat get default export */
|
|
|
/******/ (() => {
|
|
|
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
|
|
/******/ __webpack_require__.n = (module) => {
|
|
|
/******/ var getter = module && module.__esModule ?
|
|
|
/******/ () => (module['default']) :
|
|
|
/******/ () => (module);
|
|
|
/******/ __webpack_require__.d(getter, { a: getter });
|
|
|
/******/ return getter;
|
|
|
/******/ };
|
|
|
/******/ })();
|
|
|
/******/
|
|
|
/******/ /* webpack/runtime/define property getters */
|
|
|
/******/ (() => {
|
|
|
/******/ // define getter functions for harmony exports
|
|
|
/******/ __webpack_require__.d = (exports, definition) => {
|
|
|
/******/ for(var key in definition) {
|
|
|
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
|
|
|
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
|
|
|
/******/ }
|
|
|
/******/ }
|
|
|
/******/ };
|
|
|
/******/ })();
|
|
|
/******/
|
|
|
/******/ /* webpack/runtime/hasOwnProperty shorthand */
|
|
|
/******/ (() => {
|
|
|
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
|
|
|
/******/ })();
|
|
|
/******/
|
|
|
/******/ /* webpack/runtime/make namespace object */
|
|
|
/******/ (() => {
|
|
|
/******/ // define __esModule on exports
|
|
|
/******/ __webpack_require__.r = (exports) => {
|
|
|
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
|
|
|
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
|
/******/ }
|
|
|
/******/ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
/******/ };
|
|
|
/******/ })();
|
|
|
/******/
|
|
|
/************************************************************************/
|
|
|
var __webpack_exports__ = {};
|
|
|
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
|
|
|
(() => {
|
|
|
// ESM COMPAT FLAG
|
|
|
__webpack_require__.r(__webpack_exports__);
|
|
|
|
|
|
// EXPORTS
|
|
|
__webpack_require__.d(__webpack_exports__, {
|
|
|
EntityProvider: () => (/* reexport */ EntityProvider),
|
|
|
__experimentalFetchLinkSuggestions: () => (/* reexport */ _experimental_fetch_link_suggestions),
|
|
|
__experimentalFetchUrlData: () => (/* reexport */ _experimental_fetch_url_data),
|
|
|
__experimentalUseEntityRecord: () => (/* reexport */ __experimentalUseEntityRecord),
|
|
|
__experimentalUseEntityRecords: () => (/* reexport */ __experimentalUseEntityRecords),
|
|
|
__experimentalUseResourcePermissions: () => (/* reexport */ __experimentalUseResourcePermissions),
|
|
|
fetchBlockPatterns: () => (/* reexport */ fetchBlockPatterns),
|
|
|
store: () => (/* binding */ store),
|
|
|
useEntityBlockEditor: () => (/* reexport */ useEntityBlockEditor),
|
|
|
useEntityId: () => (/* reexport */ useEntityId),
|
|
|
useEntityProp: () => (/* reexport */ useEntityProp),
|
|
|
useEntityRecord: () => (/* reexport */ useEntityRecord),
|
|
|
useEntityRecords: () => (/* reexport */ useEntityRecords),
|
|
|
useResourcePermissions: () => (/* reexport */ useResourcePermissions)
|
|
|
});
|
|
|
|
|
|
// NAMESPACE OBJECT: ./node_modules/@wordpress/core-data/build-module/actions.js
|
|
|
var build_module_actions_namespaceObject = {};
|
|
|
__webpack_require__.r(build_module_actions_namespaceObject);
|
|
|
__webpack_require__.d(build_module_actions_namespaceObject, {
|
|
|
__experimentalBatch: () => (__experimentalBatch),
|
|
|
__experimentalReceiveCurrentGlobalStylesId: () => (__experimentalReceiveCurrentGlobalStylesId),
|
|
|
__experimentalReceiveThemeBaseGlobalStyles: () => (__experimentalReceiveThemeBaseGlobalStyles),
|
|
|
__experimentalReceiveThemeGlobalStyleVariations: () => (__experimentalReceiveThemeGlobalStyleVariations),
|
|
|
__experimentalSaveSpecifiedEntityEdits: () => (__experimentalSaveSpecifiedEntityEdits),
|
|
|
__unstableCreateUndoLevel: () => (__unstableCreateUndoLevel),
|
|
|
addEntities: () => (addEntities),
|
|
|
deleteEntityRecord: () => (deleteEntityRecord),
|
|
|
editEntityRecord: () => (editEntityRecord),
|
|
|
receiveAutosaves: () => (receiveAutosaves),
|
|
|
receiveCurrentTheme: () => (receiveCurrentTheme),
|
|
|
receiveCurrentUser: () => (receiveCurrentUser),
|
|
|
receiveDefaultTemplateId: () => (receiveDefaultTemplateId),
|
|
|
receiveEmbedPreview: () => (receiveEmbedPreview),
|
|
|
receiveEntityRecords: () => (receiveEntityRecords),
|
|
|
receiveNavigationFallbackId: () => (receiveNavigationFallbackId),
|
|
|
receiveRevisions: () => (receiveRevisions),
|
|
|
receiveThemeGlobalStyleRevisions: () => (receiveThemeGlobalStyleRevisions),
|
|
|
receiveThemeSupports: () => (receiveThemeSupports),
|
|
|
receiveUploadPermissions: () => (receiveUploadPermissions),
|
|
|
receiveUserPermission: () => (receiveUserPermission),
|
|
|
receiveUserQuery: () => (receiveUserQuery),
|
|
|
redo: () => (redo),
|
|
|
saveEditedEntityRecord: () => (saveEditedEntityRecord),
|
|
|
saveEntityRecord: () => (saveEntityRecord),
|
|
|
undo: () => (undo)
|
|
|
});
|
|
|
|
|
|
// NAMESPACE OBJECT: ./node_modules/@wordpress/core-data/build-module/selectors.js
|
|
|
var build_module_selectors_namespaceObject = {};
|
|
|
__webpack_require__.r(build_module_selectors_namespaceObject);
|
|
|
__webpack_require__.d(build_module_selectors_namespaceObject, {
|
|
|
__experimentalGetCurrentGlobalStylesId: () => (__experimentalGetCurrentGlobalStylesId),
|
|
|
__experimentalGetCurrentThemeBaseGlobalStyles: () => (__experimentalGetCurrentThemeBaseGlobalStyles),
|
|
|
__experimentalGetCurrentThemeGlobalStylesVariations: () => (__experimentalGetCurrentThemeGlobalStylesVariations),
|
|
|
__experimentalGetDirtyEntityRecords: () => (__experimentalGetDirtyEntityRecords),
|
|
|
__experimentalGetEntitiesBeingSaved: () => (__experimentalGetEntitiesBeingSaved),
|
|
|
__experimentalGetEntityRecordNoResolver: () => (__experimentalGetEntityRecordNoResolver),
|
|
|
__experimentalGetTemplateForLink: () => (__experimentalGetTemplateForLink),
|
|
|
canUser: () => (canUser),
|
|
|
canUserEditEntityRecord: () => (canUserEditEntityRecord),
|
|
|
getAuthors: () => (getAuthors),
|
|
|
getAutosave: () => (getAutosave),
|
|
|
getAutosaves: () => (getAutosaves),
|
|
|
getBlockPatternCategories: () => (getBlockPatternCategories),
|
|
|
getBlockPatterns: () => (getBlockPatterns),
|
|
|
getCurrentTheme: () => (getCurrentTheme),
|
|
|
getCurrentThemeGlobalStylesRevisions: () => (getCurrentThemeGlobalStylesRevisions),
|
|
|
getCurrentUser: () => (getCurrentUser),
|
|
|
getDefaultTemplateId: () => (getDefaultTemplateId),
|
|
|
getEditedEntityRecord: () => (getEditedEntityRecord),
|
|
|
getEmbedPreview: () => (getEmbedPreview),
|
|
|
getEntitiesByKind: () => (getEntitiesByKind),
|
|
|
getEntitiesConfig: () => (getEntitiesConfig),
|
|
|
getEntity: () => (getEntity),
|
|
|
getEntityConfig: () => (getEntityConfig),
|
|
|
getEntityRecord: () => (getEntityRecord),
|
|
|
getEntityRecordEdits: () => (getEntityRecordEdits),
|
|
|
getEntityRecordNonTransientEdits: () => (getEntityRecordNonTransientEdits),
|
|
|
getEntityRecords: () => (getEntityRecords),
|
|
|
getEntityRecordsTotalItems: () => (getEntityRecordsTotalItems),
|
|
|
getEntityRecordsTotalPages: () => (getEntityRecordsTotalPages),
|
|
|
getLastEntityDeleteError: () => (getLastEntityDeleteError),
|
|
|
getLastEntitySaveError: () => (getLastEntitySaveError),
|
|
|
getRawEntityRecord: () => (getRawEntityRecord),
|
|
|
getRedoEdit: () => (getRedoEdit),
|
|
|
getReferenceByDistinctEdits: () => (getReferenceByDistinctEdits),
|
|
|
getRevision: () => (getRevision),
|
|
|
getRevisions: () => (getRevisions),
|
|
|
getThemeSupports: () => (getThemeSupports),
|
|
|
getUndoEdit: () => (getUndoEdit),
|
|
|
getUserPatternCategories: () => (getUserPatternCategories),
|
|
|
getUserQueryResults: () => (getUserQueryResults),
|
|
|
hasEditsForEntityRecord: () => (hasEditsForEntityRecord),
|
|
|
hasEntityRecords: () => (hasEntityRecords),
|
|
|
hasFetchedAutosaves: () => (hasFetchedAutosaves),
|
|
|
hasRedo: () => (hasRedo),
|
|
|
hasUndo: () => (hasUndo),
|
|
|
isAutosavingEntityRecord: () => (isAutosavingEntityRecord),
|
|
|
isDeletingEntityRecord: () => (isDeletingEntityRecord),
|
|
|
isPreviewEmbedFallback: () => (isPreviewEmbedFallback),
|
|
|
isRequestingEmbedPreview: () => (isRequestingEmbedPreview),
|
|
|
isSavingEntityRecord: () => (isSavingEntityRecord)
|
|
|
});
|
|
|
|
|
|
// NAMESPACE OBJECT: ./node_modules/@wordpress/core-data/build-module/private-selectors.js
|
|
|
var private_selectors_namespaceObject = {};
|
|
|
__webpack_require__.r(private_selectors_namespaceObject);
|
|
|
__webpack_require__.d(private_selectors_namespaceObject, {
|
|
|
getBlockPatternsForPostType: () => (getBlockPatternsForPostType),
|
|
|
getNavigationFallbackId: () => (getNavigationFallbackId),
|
|
|
getUndoManager: () => (getUndoManager)
|
|
|
});
|
|
|
|
|
|
// NAMESPACE OBJECT: ./node_modules/@wordpress/core-data/build-module/resolvers.js
|
|
|
var resolvers_namespaceObject = {};
|
|
|
__webpack_require__.r(resolvers_namespaceObject);
|
|
|
__webpack_require__.d(resolvers_namespaceObject, {
|
|
|
__experimentalGetCurrentGlobalStylesId: () => (resolvers_experimentalGetCurrentGlobalStylesId),
|
|
|
__experimentalGetCurrentThemeBaseGlobalStyles: () => (resolvers_experimentalGetCurrentThemeBaseGlobalStyles),
|
|
|
__experimentalGetCurrentThemeGlobalStylesVariations: () => (resolvers_experimentalGetCurrentThemeGlobalStylesVariations),
|
|
|
__experimentalGetTemplateForLink: () => (resolvers_experimentalGetTemplateForLink),
|
|
|
canUser: () => (resolvers_canUser),
|
|
|
canUserEditEntityRecord: () => (resolvers_canUserEditEntityRecord),
|
|
|
getAuthors: () => (resolvers_getAuthors),
|
|
|
getAutosave: () => (resolvers_getAutosave),
|
|
|
getAutosaves: () => (resolvers_getAutosaves),
|
|
|
getBlockPatternCategories: () => (resolvers_getBlockPatternCategories),
|
|
|
getBlockPatterns: () => (resolvers_getBlockPatterns),
|
|
|
getCurrentTheme: () => (resolvers_getCurrentTheme),
|
|
|
getCurrentThemeGlobalStylesRevisions: () => (resolvers_getCurrentThemeGlobalStylesRevisions),
|
|
|
getCurrentUser: () => (resolvers_getCurrentUser),
|
|
|
getDefaultTemplateId: () => (resolvers_getDefaultTemplateId),
|
|
|
getEditedEntityRecord: () => (resolvers_getEditedEntityRecord),
|
|
|
getEmbedPreview: () => (resolvers_getEmbedPreview),
|
|
|
getEntityRecord: () => (resolvers_getEntityRecord),
|
|
|
getEntityRecords: () => (resolvers_getEntityRecords),
|
|
|
getNavigationFallbackId: () => (resolvers_getNavigationFallbackId),
|
|
|
getRawEntityRecord: () => (resolvers_getRawEntityRecord),
|
|
|
getRevision: () => (resolvers_getRevision),
|
|
|
getRevisions: () => (resolvers_getRevisions),
|
|
|
getThemeSupports: () => (resolvers_getThemeSupports),
|
|
|
getUserPatternCategories: () => (resolvers_getUserPatternCategories)
|
|
|
});
|
|
|
|
|
|
;// CONCATENATED MODULE: external ["wp","data"]
|
|
|
const external_wp_data_namespaceObject = window["wp"]["data"];
|
|
|
// EXTERNAL MODULE: ./node_modules/fast-deep-equal/es6/index.js
|
|
|
var es6 = __webpack_require__(7734);
|
|
|
var es6_default = /*#__PURE__*/__webpack_require__.n(es6);
|
|
|
;// CONCATENATED MODULE: external ["wp","compose"]
|
|
|
const external_wp_compose_namespaceObject = window["wp"]["compose"];
|
|
|
// EXTERNAL MODULE: ./node_modules/@wordpress/undo-manager/build-module/index.js
|
|
|
var build_module = __webpack_require__(6689);
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/if-matching-action.js
|
|
|
/** @typedef {import('../types').AnyFunction} AnyFunction */
|
|
|
|
|
|
/**
|
|
|
* A higher-order reducer creator which invokes the original reducer only if
|
|
|
* the dispatching action matches the given predicate, **OR** if state is
|
|
|
* initializing (undefined).
|
|
|
*
|
|
|
* @param {AnyFunction} isMatch Function predicate for allowing reducer call.
|
|
|
*
|
|
|
* @return {AnyFunction} Higher-order reducer.
|
|
|
*/
|
|
|
const ifMatchingAction = isMatch => reducer => (state, action) => {
|
|
|
if (state === undefined || isMatch(action)) {
|
|
|
return reducer(state, action);
|
|
|
}
|
|
|
return state;
|
|
|
};
|
|
|
/* harmony default export */ const if_matching_action = (ifMatchingAction);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/replace-action.js
|
|
|
/** @typedef {import('../types').AnyFunction} AnyFunction */
|
|
|
|
|
|
/**
|
|
|
* Higher-order reducer creator which substitutes the action object before
|
|
|
* passing to the original reducer.
|
|
|
*
|
|
|
* @param {AnyFunction} replacer Function mapping original action to replacement.
|
|
|
*
|
|
|
* @return {AnyFunction} Higher-order reducer.
|
|
|
*/
|
|
|
const replaceAction = replacer => reducer => (state, action) => {
|
|
|
return reducer(state, replacer(action));
|
|
|
};
|
|
|
/* harmony default export */ const replace_action = (replaceAction);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/conservative-map-item.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Given the current and next item entity record, returns the minimally "modified"
|
|
|
* result of the next item, preferring value references from the original item
|
|
|
* if equal. If all values match, the original item is returned.
|
|
|
*
|
|
|
* @param {Object} item Original item.
|
|
|
* @param {Object} nextItem Next item.
|
|
|
*
|
|
|
* @return {Object} Minimally modified merged item.
|
|
|
*/
|
|
|
function conservativeMapItem(item, nextItem) {
|
|
|
// Return next item in its entirety if there is no original item.
|
|
|
if (!item) {
|
|
|
return nextItem;
|
|
|
}
|
|
|
let hasChanges = false;
|
|
|
const result = {};
|
|
|
for (const key in nextItem) {
|
|
|
if (es6_default()(item[key], nextItem[key])) {
|
|
|
result[key] = item[key];
|
|
|
} else {
|
|
|
hasChanges = true;
|
|
|
result[key] = nextItem[key];
|
|
|
}
|
|
|
}
|
|
|
if (!hasChanges) {
|
|
|
return item;
|
|
|
}
|
|
|
|
|
|
// Only at this point, backfill properties from the original item which
|
|
|
// weren't explicitly set into the result above. This is an optimization
|
|
|
// to allow `hasChanges` to return early.
|
|
|
for (const key in item) {
|
|
|
if (!result.hasOwnProperty(key)) {
|
|
|
result[key] = item[key];
|
|
|
}
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/on-sub-key.js
|
|
|
/** @typedef {import('../types').AnyFunction} AnyFunction */
|
|
|
|
|
|
/**
|
|
|
* Higher-order reducer creator which creates a combined reducer object, keyed
|
|
|
* by a property on the action object.
|
|
|
*
|
|
|
* @param {string} actionProperty Action property by which to key object.
|
|
|
*
|
|
|
* @return {AnyFunction} Higher-order reducer.
|
|
|
*/
|
|
|
const onSubKey = actionProperty => reducer => (state = {}, action) => {
|
|
|
// Retrieve subkey from action. Do not track if undefined; useful for cases
|
|
|
// where reducer is scoped by action shape.
|
|
|
const key = action[actionProperty];
|
|
|
if (key === undefined) {
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
// Avoid updating state if unchanged. Note that this also accounts for a
|
|
|
// reducer which returns undefined on a key which is not yet tracked.
|
|
|
const nextKeyState = reducer(state[key], action);
|
|
|
if (nextKeyState === state[key]) {
|
|
|
return state;
|
|
|
}
|
|
|
return {
|
|
|
...state,
|
|
|
[key]: nextKeyState
|
|
|
};
|
|
|
};
|
|
|
/* harmony default export */ const on_sub_key = (onSubKey);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/tslib/tslib.es6.mjs
|
|
|
/******************************************************************************
|
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
|
purpose with or without fee is hereby granted.
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
|
***************************************************************************** */
|
|
|
/* global Reflect, Promise, SuppressedError, Symbol */
|
|
|
|
|
|
var extendStatics = function(d, b) {
|
|
|
extendStatics = Object.setPrototypeOf ||
|
|
|
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
|
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
|
return extendStatics(d, b);
|
|
|
};
|
|
|
|
|
|
function __extends(d, b) {
|
|
|
if (typeof b !== "function" && b !== null)
|
|
|
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
|
extendStatics(d, b);
|
|
|
function __() { this.constructor = d; }
|
|
|
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
|
}
|
|
|
|
|
|
var __assign = function() {
|
|
|
__assign = Object.assign || function __assign(t) {
|
|
|
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
|
s = arguments[i];
|
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
|
|
|
}
|
|
|
return t;
|
|
|
}
|
|
|
return __assign.apply(this, arguments);
|
|
|
}
|
|
|
|
|
|
function __rest(s, e) {
|
|
|
var t = {};
|
|
|
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
|
t[p] = s[p];
|
|
|
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
|
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
|
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
|
t[p[i]] = s[p[i]];
|
|
|
}
|
|
|
return t;
|
|
|
}
|
|
|
|
|
|
function __decorate(decorators, target, key, desc) {
|
|
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
|
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
|
}
|
|
|
|
|
|
function __param(paramIndex, decorator) {
|
|
|
return function (target, key) { decorator(target, key, paramIndex); }
|
|
|
}
|
|
|
|
|
|
function __esDecorate(ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
|
|
|
function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
|
|
|
var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
|
|
|
var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
|
|
|
var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
|
|
|
var _, done = false;
|
|
|
for (var i = decorators.length - 1; i >= 0; i--) {
|
|
|
var context = {};
|
|
|
for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
|
|
|
for (var p in contextIn.access) context.access[p] = contextIn.access[p];
|
|
|
context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
|
|
|
var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
|
|
|
if (kind === "accessor") {
|
|
|
if (result === void 0) continue;
|
|
|
if (result === null || typeof result !== "object") throw new TypeError("Object expected");
|
|
|
if (_ = accept(result.get)) descriptor.get = _;
|
|
|
if (_ = accept(result.set)) descriptor.set = _;
|
|
|
if (_ = accept(result.init)) initializers.unshift(_);
|
|
|
}
|
|
|
else if (_ = accept(result)) {
|
|
|
if (kind === "field") initializers.unshift(_);
|
|
|
else descriptor[key] = _;
|
|
|
}
|
|
|
}
|
|
|
if (target) Object.defineProperty(target, contextIn.name, descriptor);
|
|
|
done = true;
|
|
|
};
|
|
|
|
|
|
function __runInitializers(thisArg, initializers, value) {
|
|
|
var useValue = arguments.length > 2;
|
|
|
for (var i = 0; i < initializers.length; i++) {
|
|
|
value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
|
|
|
}
|
|
|
return useValue ? value : void 0;
|
|
|
};
|
|
|
|
|
|
function __propKey(x) {
|
|
|
return typeof x === "symbol" ? x : "".concat(x);
|
|
|
};
|
|
|
|
|
|
function __setFunctionName(f, name, prefix) {
|
|
|
if (typeof name === "symbol") name = name.description ? "[".concat(name.description, "]") : "";
|
|
|
return Object.defineProperty(f, "name", { configurable: true, value: prefix ? "".concat(prefix, " ", name) : name });
|
|
|
};
|
|
|
|
|
|
function __metadata(metadataKey, metadataValue) {
|
|
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(metadataKey, metadataValue);
|
|
|
}
|
|
|
|
|
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
|
});
|
|
|
}
|
|
|
|
|
|
function __generator(thisArg, body) {
|
|
|
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
|
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
|
function step(op) {
|
|
|
if (f) throw new TypeError("Generator is already executing.");
|
|
|
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
|
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
|
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
|
switch (op[0]) {
|
|
|
case 0: case 1: t = op; break;
|
|
|
case 4: _.label++; return { value: op[1], done: false };
|
|
|
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
|
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
|
default:
|
|
|
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
|
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
|
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
|
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
|
if (t[2]) _.ops.pop();
|
|
|
_.trys.pop(); continue;
|
|
|
}
|
|
|
op = body.call(thisArg, _);
|
|
|
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
|
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
|
}
|
|
|
}
|
|
|
|
|
|
var __createBinding = Object.create ? (function(o, m, k, k2) {
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
|
}
|
|
|
Object.defineProperty(o, k2, desc);
|
|
|
}) : (function(o, m, k, k2) {
|
|
|
if (k2 === undefined) k2 = k;
|
|
|
o[k2] = m[k];
|
|
|
});
|
|
|
|
|
|
function __exportStar(m, o) {
|
|
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);
|
|
|
}
|
|
|
|
|
|
function __values(o) {
|
|
|
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
|
if (m) return m.call(o);
|
|
|
if (o && typeof o.length === "number") return {
|
|
|
next: function () {
|
|
|
if (o && i >= o.length) o = void 0;
|
|
|
return { value: o && o[i++], done: !o };
|
|
|
}
|
|
|
};
|
|
|
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
|
}
|
|
|
|
|
|
function __read(o, n) {
|
|
|
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
|
|
if (!m) return o;
|
|
|
var i = m.call(o), r, ar = [], e;
|
|
|
try {
|
|
|
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
|
|
}
|
|
|
catch (error) { e = { error: error }; }
|
|
|
finally {
|
|
|
try {
|
|
|
if (r && !r.done && (m = i["return"])) m.call(i);
|
|
|
}
|
|
|
finally { if (e) throw e.error; }
|
|
|
}
|
|
|
return ar;
|
|
|
}
|
|
|
|
|
|
/** @deprecated */
|
|
|
function __spread() {
|
|
|
for (var ar = [], i = 0; i < arguments.length; i++)
|
|
|
ar = ar.concat(__read(arguments[i]));
|
|
|
return ar;
|
|
|
}
|
|
|
|
|
|
/** @deprecated */
|
|
|
function __spreadArrays() {
|
|
|
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
|
|
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
|
|
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
|
|
r[k] = a[j];
|
|
|
return r;
|
|
|
}
|
|
|
|
|
|
function __spreadArray(to, from, pack) {
|
|
|
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
|
if (ar || !(i in from)) {
|
|
|
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
|
ar[i] = from[i];
|
|
|
}
|
|
|
}
|
|
|
return to.concat(ar || Array.prototype.slice.call(from));
|
|
|
}
|
|
|
|
|
|
function __await(v) {
|
|
|
return this instanceof __await ? (this.v = v, this) : new __await(v);
|
|
|
}
|
|
|
|
|
|
function __asyncGenerator(thisArg, _arguments, generator) {
|
|
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
|
var g = generator.apply(thisArg, _arguments || []), i, q = [];
|
|
|
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
|
|
|
function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
|
|
|
function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
|
|
|
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
|
|
|
function fulfill(value) { resume("next", value); }
|
|
|
function reject(value) { resume("throw", value); }
|
|
|
function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
|
|
|
}
|
|
|
|
|
|
function __asyncDelegator(o) {
|
|
|
var i, p;
|
|
|
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
|
|
|
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: false } : f ? f(v) : v; } : f; }
|
|
|
}
|
|
|
|
|
|
function __asyncValues(o) {
|
|
|
if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
|
|
|
var m = o[Symbol.asyncIterator], i;
|
|
|
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
|
|
|
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
|
|
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
|
}
|
|
|
|
|
|
function __makeTemplateObject(cooked, raw) {
|
|
|
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
|
|
return cooked;
|
|
|
};
|
|
|
|
|
|
var __setModuleDefault = Object.create ? (function(o, v) {
|
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
|
}) : function(o, v) {
|
|
|
o["default"] = v;
|
|
|
};
|
|
|
|
|
|
function __importStar(mod) {
|
|
|
if (mod && mod.__esModule) return mod;
|
|
|
var result = {};
|
|
|
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
|
__setModuleDefault(result, mod);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
function __importDefault(mod) {
|
|
|
return (mod && mod.__esModule) ? mod : { default: mod };
|
|
|
}
|
|
|
|
|
|
function __classPrivateFieldGet(receiver, state, kind, f) {
|
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
|
}
|
|
|
|
|
|
function __classPrivateFieldSet(receiver, state, value, kind, f) {
|
|
|
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
|
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
|
}
|
|
|
|
|
|
function __classPrivateFieldIn(state, receiver) {
|
|
|
if (receiver === null || (typeof receiver !== "object" && typeof receiver !== "function")) throw new TypeError("Cannot use 'in' operator on non-object");
|
|
|
return typeof state === "function" ? receiver === state : state.has(receiver);
|
|
|
}
|
|
|
|
|
|
function __addDisposableResource(env, value, async) {
|
|
|
if (value !== null && value !== void 0) {
|
|
|
if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
|
|
|
var dispose;
|
|
|
if (async) {
|
|
|
if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
|
|
|
dispose = value[Symbol.asyncDispose];
|
|
|
}
|
|
|
if (dispose === void 0) {
|
|
|
if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
|
|
|
dispose = value[Symbol.dispose];
|
|
|
}
|
|
|
if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
|
|
|
env.stack.push({ value: value, dispose: dispose, async: async });
|
|
|
}
|
|
|
else if (async) {
|
|
|
env.stack.push({ async: true });
|
|
|
}
|
|
|
return value;
|
|
|
}
|
|
|
|
|
|
var _SuppressedError = typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
|
var e = new Error(message);
|
|
|
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
|
};
|
|
|
|
|
|
function __disposeResources(env) {
|
|
|
function fail(e) {
|
|
|
env.error = env.hasError ? new _SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
|
|
|
env.hasError = true;
|
|
|
}
|
|
|
function next() {
|
|
|
while (env.stack.length) {
|
|
|
var rec = env.stack.pop();
|
|
|
try {
|
|
|
var result = rec.dispose && rec.dispose.call(rec.value);
|
|
|
if (rec.async) return Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
|
|
|
}
|
|
|
catch (e) {
|
|
|
fail(e);
|
|
|
}
|
|
|
}
|
|
|
if (env.hasError) throw env.error;
|
|
|
}
|
|
|
return next();
|
|
|
}
|
|
|
|
|
|
/* harmony default export */ const tslib_es6 = ({
|
|
|
__extends,
|
|
|
__assign,
|
|
|
__rest,
|
|
|
__decorate,
|
|
|
__param,
|
|
|
__metadata,
|
|
|
__awaiter,
|
|
|
__generator,
|
|
|
__createBinding,
|
|
|
__exportStar,
|
|
|
__values,
|
|
|
__read,
|
|
|
__spread,
|
|
|
__spreadArrays,
|
|
|
__spreadArray,
|
|
|
__await,
|
|
|
__asyncGenerator,
|
|
|
__asyncDelegator,
|
|
|
__asyncValues,
|
|
|
__makeTemplateObject,
|
|
|
__importStar,
|
|
|
__importDefault,
|
|
|
__classPrivateFieldGet,
|
|
|
__classPrivateFieldSet,
|
|
|
__classPrivateFieldIn,
|
|
|
__addDisposableResource,
|
|
|
__disposeResources,
|
|
|
});
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/lower-case/dist.es2015/index.js
|
|
|
/**
|
|
|
* Source: ftp://ftp.unicode.org/Public/UCD/latest/ucd/SpecialCasing.txt
|
|
|
*/
|
|
|
var SUPPORTED_LOCALE = {
|
|
|
tr: {
|
|
|
regexp: /\u0130|\u0049|\u0049\u0307/g,
|
|
|
map: {
|
|
|
İ: "\u0069",
|
|
|
I: "\u0131",
|
|
|
İ: "\u0069",
|
|
|
},
|
|
|
},
|
|
|
az: {
|
|
|
regexp: /\u0130/g,
|
|
|
map: {
|
|
|
İ: "\u0069",
|
|
|
I: "\u0131",
|
|
|
İ: "\u0069",
|
|
|
},
|
|
|
},
|
|
|
lt: {
|
|
|
regexp: /\u0049|\u004A|\u012E|\u00CC|\u00CD|\u0128/g,
|
|
|
map: {
|
|
|
I: "\u0069\u0307",
|
|
|
J: "\u006A\u0307",
|
|
|
Į: "\u012F\u0307",
|
|
|
Ì: "\u0069\u0307\u0300",
|
|
|
Í: "\u0069\u0307\u0301",
|
|
|
Ĩ: "\u0069\u0307\u0303",
|
|
|
},
|
|
|
},
|
|
|
};
|
|
|
/**
|
|
|
* Localized lower case.
|
|
|
*/
|
|
|
function localeLowerCase(str, locale) {
|
|
|
var lang = SUPPORTED_LOCALE[locale.toLowerCase()];
|
|
|
if (lang)
|
|
|
return lowerCase(str.replace(lang.regexp, function (m) { return lang.map[m]; }));
|
|
|
return lowerCase(str);
|
|
|
}
|
|
|
/**
|
|
|
* Lower case as a function.
|
|
|
*/
|
|
|
function lowerCase(str) {
|
|
|
return str.toLowerCase();
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/no-case/dist.es2015/index.js
|
|
|
|
|
|
// Support camel case ("camelCase" -> "camel Case" and "CAMELCase" -> "CAMEL Case").
|
|
|
var DEFAULT_SPLIT_REGEXP = [/([a-z0-9])([A-Z])/g, /([A-Z])([A-Z][a-z])/g];
|
|
|
// Remove all non-word characters.
|
|
|
var DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;
|
|
|
/**
|
|
|
* Normalize the string into something other libraries can manipulate easier.
|
|
|
*/
|
|
|
function noCase(input, options) {
|
|
|
if (options === void 0) { options = {}; }
|
|
|
var _a = options.splitRegexp, splitRegexp = _a === void 0 ? DEFAULT_SPLIT_REGEXP : _a, _b = options.stripRegexp, stripRegexp = _b === void 0 ? DEFAULT_STRIP_REGEXP : _b, _c = options.transform, transform = _c === void 0 ? lowerCase : _c, _d = options.delimiter, delimiter = _d === void 0 ? " " : _d;
|
|
|
var result = replace(replace(input, splitRegexp, "$1\0$2"), stripRegexp, "\0");
|
|
|
var start = 0;
|
|
|
var end = result.length;
|
|
|
// Trim the delimiter from around the output string.
|
|
|
while (result.charAt(start) === "\0")
|
|
|
start++;
|
|
|
while (result.charAt(end - 1) === "\0")
|
|
|
end--;
|
|
|
// Transform each token independently.
|
|
|
return result.slice(start, end).split("\0").map(transform).join(delimiter);
|
|
|
}
|
|
|
/**
|
|
|
* Replace `re` in the input string with the replacement value.
|
|
|
*/
|
|
|
function replace(input, re, value) {
|
|
|
if (re instanceof RegExp)
|
|
|
return input.replace(re, value);
|
|
|
return re.reduce(function (input, re) { return input.replace(re, value); }, input);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/upper-case-first/dist.es2015/index.js
|
|
|
/**
|
|
|
* Upper case the first character of an input string.
|
|
|
*/
|
|
|
function upperCaseFirst(input) {
|
|
|
return input.charAt(0).toUpperCase() + input.substr(1);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/capital-case/dist.es2015/index.js
|
|
|
|
|
|
|
|
|
|
|
|
function capitalCaseTransform(input) {
|
|
|
return upperCaseFirst(input.toLowerCase());
|
|
|
}
|
|
|
function capitalCase(input, options) {
|
|
|
if (options === void 0) { options = {}; }
|
|
|
return noCase(input, __assign({ delimiter: " ", transform: capitalCaseTransform }, options));
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/pascal-case/dist.es2015/index.js
|
|
|
|
|
|
|
|
|
function pascalCaseTransform(input, index) {
|
|
|
var firstChar = input.charAt(0);
|
|
|
var lowerChars = input.substr(1).toLowerCase();
|
|
|
if (index > 0 && firstChar >= "0" && firstChar <= "9") {
|
|
|
return "_" + firstChar + lowerChars;
|
|
|
}
|
|
|
return "" + firstChar.toUpperCase() + lowerChars;
|
|
|
}
|
|
|
function dist_es2015_pascalCaseTransformMerge(input) {
|
|
|
return input.charAt(0).toUpperCase() + input.slice(1).toLowerCase();
|
|
|
}
|
|
|
function pascalCase(input, options) {
|
|
|
if (options === void 0) { options = {}; }
|
|
|
return noCase(input, __assign({ delimiter: "", transform: pascalCaseTransform }, options));
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: external ["wp","apiFetch"]
|
|
|
const external_wp_apiFetch_namespaceObject = window["wp"]["apiFetch"];
|
|
|
var external_wp_apiFetch_default = /*#__PURE__*/__webpack_require__.n(external_wp_apiFetch_namespaceObject);
|
|
|
;// CONCATENATED MODULE: external ["wp","i18n"]
|
|
|
const external_wp_i18n_namespaceObject = window["wp"]["i18n"];
|
|
|
;// CONCATENATED MODULE: external ["wp","richText"]
|
|
|
const external_wp_richText_namespaceObject = window["wp"]["richText"];
|
|
|
;// CONCATENATED MODULE: ./node_modules/uuid/dist/esm-browser/native.js
|
|
|
const randomUUID = typeof crypto !== 'undefined' && crypto.randomUUID && crypto.randomUUID.bind(crypto);
|
|
|
/* harmony default export */ const esm_browser_native = ({
|
|
|
randomUUID
|
|
|
});
|
|
|
;// CONCATENATED MODULE: ./node_modules/uuid/dist/esm-browser/rng.js
|
|
|
// Unique ID creation requires a high quality random # generator. In the browser we therefore
|
|
|
// require the crypto API and do not support built-in fallback to lower quality random number
|
|
|
// generators (like Math.random()).
|
|
|
let getRandomValues;
|
|
|
const rnds8 = new Uint8Array(16);
|
|
|
function rng() {
|
|
|
// lazy load so that environments that need to polyfill have a chance to do so
|
|
|
if (!getRandomValues) {
|
|
|
// getRandomValues needs to be invoked in a context where "this" is a Crypto implementation.
|
|
|
getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto);
|
|
|
|
|
|
if (!getRandomValues) {
|
|
|
throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return getRandomValues(rnds8);
|
|
|
}
|
|
|
;// CONCATENATED MODULE: ./node_modules/uuid/dist/esm-browser/stringify.js
|
|
|
|
|
|
/**
|
|
|
* Convert array of 16 byte values to UUID string format of the form:
|
|
|
* XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
|
|
|
*/
|
|
|
|
|
|
const byteToHex = [];
|
|
|
|
|
|
for (let i = 0; i < 256; ++i) {
|
|
|
byteToHex.push((i + 0x100).toString(16).slice(1));
|
|
|
}
|
|
|
|
|
|
function unsafeStringify(arr, offset = 0) {
|
|
|
// Note: Be careful editing this code! It's been tuned for performance
|
|
|
// and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434
|
|
|
return byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]];
|
|
|
}
|
|
|
|
|
|
function stringify(arr, offset = 0) {
|
|
|
const uuid = unsafeStringify(arr, offset); // Consistency check for valid UUID. If this throws, it's likely due to one
|
|
|
// of the following:
|
|
|
// - One or more input array values don't map to a hex octet (leading to
|
|
|
// "undefined" in the uuid)
|
|
|
// - Invalid input values for the RFC `version` or `variant` fields
|
|
|
|
|
|
if (!validate(uuid)) {
|
|
|
throw TypeError('Stringified UUID is invalid');
|
|
|
}
|
|
|
|
|
|
return uuid;
|
|
|
}
|
|
|
|
|
|
/* harmony default export */ const esm_browser_stringify = ((/* unused pure expression or super */ null && (stringify)));
|
|
|
;// CONCATENATED MODULE: ./node_modules/uuid/dist/esm-browser/v4.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function v4(options, buf, offset) {
|
|
|
if (esm_browser_native.randomUUID && !buf && !options) {
|
|
|
return esm_browser_native.randomUUID();
|
|
|
}
|
|
|
|
|
|
options = options || {};
|
|
|
const rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved`
|
|
|
|
|
|
rnds[6] = rnds[6] & 0x0f | 0x40;
|
|
|
rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided
|
|
|
|
|
|
if (buf) {
|
|
|
offset = offset || 0;
|
|
|
|
|
|
for (let i = 0; i < 16; ++i) {
|
|
|
buf[offset + i] = rnds[i];
|
|
|
}
|
|
|
|
|
|
return buf;
|
|
|
}
|
|
|
|
|
|
return unsafeStringify(rnds);
|
|
|
}
|
|
|
|
|
|
/* harmony default export */ const esm_browser_v4 = (v4);
|
|
|
;// CONCATENATED MODULE: external ["wp","url"]
|
|
|
const external_wp_url_namespaceObject = window["wp"]["url"];
|
|
|
;// CONCATENATED MODULE: external ["wp","deprecated"]
|
|
|
const external_wp_deprecated_namespaceObject = window["wp"]["deprecated"];
|
|
|
var external_wp_deprecated_default = /*#__PURE__*/__webpack_require__.n(external_wp_deprecated_namespaceObject);
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/set-nested-value.js
|
|
|
/**
|
|
|
* Sets the value at path of object.
|
|
|
* If a portion of path doesn’t exist, it’s created.
|
|
|
* Arrays are created for missing index properties while objects are created
|
|
|
* for all other missing properties.
|
|
|
*
|
|
|
* Path is specified as either:
|
|
|
* - a string of properties, separated by dots, for example: "x.y".
|
|
|
* - an array of properties, for example `[ 'x', 'y' ]`.
|
|
|
*
|
|
|
* This function intentionally mutates the input object.
|
|
|
*
|
|
|
* Inspired by _.set().
|
|
|
*
|
|
|
* @see https://lodash.com/docs/4.17.15#set
|
|
|
*
|
|
|
* @todo Needs to be deduplicated with its copy in `@wordpress/edit-site`.
|
|
|
*
|
|
|
* @param {Object} object Object to modify
|
|
|
* @param {Array|string} path Path of the property to set.
|
|
|
* @param {*} value Value to set.
|
|
|
*/
|
|
|
function setNestedValue(object, path, value) {
|
|
|
if (!object || typeof object !== 'object') {
|
|
|
return object;
|
|
|
}
|
|
|
const normalizedPath = Array.isArray(path) ? path : path.split('.');
|
|
|
normalizedPath.reduce((acc, key, idx) => {
|
|
|
if (acc[key] === undefined) {
|
|
|
if (Number.isInteger(normalizedPath[idx + 1])) {
|
|
|
acc[key] = [];
|
|
|
} else {
|
|
|
acc[key] = {};
|
|
|
}
|
|
|
}
|
|
|
if (idx === normalizedPath.length - 1) {
|
|
|
acc[key] = value;
|
|
|
}
|
|
|
return acc[key];
|
|
|
}, object);
|
|
|
return object;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/get-nested-value.js
|
|
|
/**
|
|
|
* Helper util to return a value from a certain path of the object.
|
|
|
* Path is specified as either:
|
|
|
* - a string of properties, separated by dots, for example: "x.y".
|
|
|
* - an array of properties, for example `[ 'x', 'y' ]`.
|
|
|
* You can also specify a default value in case the result is nullish.
|
|
|
*
|
|
|
* @param {Object} object Input object.
|
|
|
* @param {string|Array} path Path to the object property.
|
|
|
* @param {*} defaultValue Default value if the value at the specified path is undefined.
|
|
|
* @return {*} Value of the object property at the specified path.
|
|
|
*/
|
|
|
function getNestedValue(object, path, defaultValue) {
|
|
|
if (!object || typeof object !== 'object' || typeof path !== 'string' && !Array.isArray(path)) {
|
|
|
return object;
|
|
|
}
|
|
|
const normalizedPath = Array.isArray(path) ? path : path.split('.');
|
|
|
let value = object;
|
|
|
normalizedPath.forEach(fieldName => {
|
|
|
value = value?.[fieldName];
|
|
|
});
|
|
|
return value !== undefined ? value : defaultValue;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/queried-data/actions.js
|
|
|
/**
|
|
|
* Returns an action object used in signalling that items have been received.
|
|
|
*
|
|
|
* @param {Array} items Items received.
|
|
|
* @param {?Object} edits Optional edits to reset.
|
|
|
* @param {?Object} meta Meta information about pagination.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveItems(items, edits, meta) {
|
|
|
return {
|
|
|
type: 'RECEIVE_ITEMS',
|
|
|
items: Array.isArray(items) ? items : [items],
|
|
|
persistedEdits: edits,
|
|
|
meta
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that entity records have been
|
|
|
* deleted and they need to be removed from entities state.
|
|
|
*
|
|
|
* @param {string} kind Kind of the removed entities.
|
|
|
* @param {string} name Name of the removed entities.
|
|
|
* @param {Array|number|string} records Record IDs of the removed entities.
|
|
|
* @param {boolean} invalidateCache Controls whether we want to invalidate the cache.
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function removeItems(kind, name, records, invalidateCache = false) {
|
|
|
return {
|
|
|
type: 'REMOVE_ITEMS',
|
|
|
itemIds: Array.isArray(records) ? records : [records],
|
|
|
kind,
|
|
|
name,
|
|
|
invalidateCache
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that queried data has been
|
|
|
* received.
|
|
|
*
|
|
|
* @param {Array} items Queried items received.
|
|
|
* @param {?Object} query Optional query object.
|
|
|
* @param {?Object} edits Optional edits to reset.
|
|
|
* @param {?Object} meta Meta information about pagination.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveQueriedItems(items, query = {}, edits, meta) {
|
|
|
return {
|
|
|
...receiveItems(items, edits, meta),
|
|
|
query
|
|
|
};
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/batch/default-processor.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Maximum number of requests to place in a single batch request. Obtained by
|
|
|
* sending a preflight OPTIONS request to /batch/v1/.
|
|
|
*
|
|
|
* @type {number?}
|
|
|
*/
|
|
|
let maxItems = null;
|
|
|
function chunk(arr, chunkSize) {
|
|
|
const tmp = [...arr];
|
|
|
const cache = [];
|
|
|
while (tmp.length) {
|
|
|
cache.push(tmp.splice(0, chunkSize));
|
|
|
}
|
|
|
return cache;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Default batch processor. Sends its input requests to /batch/v1.
|
|
|
*
|
|
|
* @param {Array} requests List of API requests to perform at once.
|
|
|
*
|
|
|
* @return {Promise} Promise that resolves to a list of objects containing
|
|
|
* either `output` (if that request was successful) or `error`
|
|
|
* (if not ).
|
|
|
*/
|
|
|
async function defaultProcessor(requests) {
|
|
|
if (maxItems === null) {
|
|
|
const preflightResponse = await external_wp_apiFetch_default()({
|
|
|
path: '/batch/v1',
|
|
|
method: 'OPTIONS'
|
|
|
});
|
|
|
maxItems = preflightResponse.endpoints[0].args.requests.maxItems;
|
|
|
}
|
|
|
const results = [];
|
|
|
|
|
|
// @ts-ignore We would have crashed or never gotten to this point if we hadn't received the maxItems count.
|
|
|
for (const batchRequests of chunk(requests, maxItems)) {
|
|
|
const batchResponse = await external_wp_apiFetch_default()({
|
|
|
path: '/batch/v1',
|
|
|
method: 'POST',
|
|
|
data: {
|
|
|
validation: 'require-all-validate',
|
|
|
requests: batchRequests.map(request => ({
|
|
|
path: request.path,
|
|
|
body: request.data,
|
|
|
// Rename 'data' to 'body'.
|
|
|
method: request.method,
|
|
|
headers: request.headers
|
|
|
}))
|
|
|
}
|
|
|
});
|
|
|
let batchResults;
|
|
|
if (batchResponse.failed) {
|
|
|
batchResults = batchResponse.responses.map(response => ({
|
|
|
error: response?.body
|
|
|
}));
|
|
|
} else {
|
|
|
batchResults = batchResponse.responses.map(response => {
|
|
|
const result = {};
|
|
|
if (response.status >= 200 && response.status < 300) {
|
|
|
result.output = response.body;
|
|
|
} else {
|
|
|
result.error = response.body;
|
|
|
}
|
|
|
return result;
|
|
|
});
|
|
|
}
|
|
|
results.push(...batchResults);
|
|
|
}
|
|
|
return results;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/batch/create-batch.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Creates a batch, which can be used to combine multiple API requests into one
|
|
|
* API request using the WordPress batch processing API (/v1/batch).
|
|
|
*
|
|
|
* ```
|
|
|
* const batch = createBatch();
|
|
|
* const dunePromise = batch.add( {
|
|
|
* path: '/v1/books',
|
|
|
* method: 'POST',
|
|
|
* data: { title: 'Dune' }
|
|
|
* } );
|
|
|
* const lotrPromise = batch.add( {
|
|
|
* path: '/v1/books',
|
|
|
* method: 'POST',
|
|
|
* data: { title: 'Lord of the Rings' }
|
|
|
* } );
|
|
|
* const isSuccess = await batch.run(); // Sends one POST to /v1/batch.
|
|
|
* if ( isSuccess ) {
|
|
|
* console.log(
|
|
|
* 'Saved two books:',
|
|
|
* await dunePromise,
|
|
|
* await lotrPromise
|
|
|
* );
|
|
|
* }
|
|
|
* ```
|
|
|
*
|
|
|
* @param {Function} [processor] Processor function. Can be used to replace the
|
|
|
* default functionality which is to send an API
|
|
|
* request to /v1/batch. Is given an array of
|
|
|
* inputs and must return a promise that
|
|
|
* resolves to an array of objects containing
|
|
|
* either `output` or `error`.
|
|
|
*/
|
|
|
function createBatch(processor = defaultProcessor) {
|
|
|
let lastId = 0;
|
|
|
/** @type {Array<{ input: any; resolve: ( value: any ) => void; reject: ( error: any ) => void }>} */
|
|
|
let queue = [];
|
|
|
const pending = new ObservableSet();
|
|
|
return {
|
|
|
/**
|
|
|
* Adds an input to the batch and returns a promise that is resolved or
|
|
|
* rejected when the input is processed by `batch.run()`.
|
|
|
*
|
|
|
* You may also pass a thunk which allows inputs to be added
|
|
|
* asychronously.
|
|
|
*
|
|
|
* ```
|
|
|
* // Both are allowed:
|
|
|
* batch.add( { path: '/v1/books', ... } );
|
|
|
* batch.add( ( add ) => add( { path: '/v1/books', ... } ) );
|
|
|
* ```
|
|
|
*
|
|
|
* If a thunk is passed, `batch.run()` will pause until either:
|
|
|
*
|
|
|
* - The thunk calls its `add` argument, or;
|
|
|
* - The thunk returns a promise and that promise resolves, or;
|
|
|
* - The thunk returns a non-promise.
|
|
|
*
|
|
|
* @param {any|Function} inputOrThunk Input to add or thunk to execute.
|
|
|
*
|
|
|
* @return {Promise|any} If given an input, returns a promise that
|
|
|
* is resolved or rejected when the batch is
|
|
|
* processed. If given a thunk, returns the return
|
|
|
* value of that thunk.
|
|
|
*/
|
|
|
add(inputOrThunk) {
|
|
|
const id = ++lastId;
|
|
|
pending.add(id);
|
|
|
const add = input => new Promise((resolve, reject) => {
|
|
|
queue.push({
|
|
|
input,
|
|
|
resolve,
|
|
|
reject
|
|
|
});
|
|
|
pending.delete(id);
|
|
|
});
|
|
|
if (typeof inputOrThunk === 'function') {
|
|
|
return Promise.resolve(inputOrThunk(add)).finally(() => {
|
|
|
pending.delete(id);
|
|
|
});
|
|
|
}
|
|
|
return add(inputOrThunk);
|
|
|
},
|
|
|
/**
|
|
|
* Runs the batch. This calls `batchProcessor` and resolves or rejects
|
|
|
* all promises returned by `add()`.
|
|
|
*
|
|
|
* @return {Promise<boolean>} A promise that resolves to a boolean that is true
|
|
|
* if the processor returned no errors.
|
|
|
*/
|
|
|
async run() {
|
|
|
if (pending.size) {
|
|
|
await new Promise(resolve => {
|
|
|
const unsubscribe = pending.subscribe(() => {
|
|
|
if (!pending.size) {
|
|
|
unsubscribe();
|
|
|
resolve(undefined);
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
let results;
|
|
|
try {
|
|
|
results = await processor(queue.map(({
|
|
|
input
|
|
|
}) => input));
|
|
|
if (results.length !== queue.length) {
|
|
|
throw new Error('run: Array returned by processor must be same size as input array.');
|
|
|
}
|
|
|
} catch (error) {
|
|
|
for (const {
|
|
|
reject
|
|
|
} of queue) {
|
|
|
reject(error);
|
|
|
}
|
|
|
throw error;
|
|
|
}
|
|
|
let isSuccess = true;
|
|
|
results.forEach((result, key) => {
|
|
|
const queueItem = queue[key];
|
|
|
if (result?.error) {
|
|
|
queueItem?.reject(result.error);
|
|
|
isSuccess = false;
|
|
|
} else {
|
|
|
var _result$output;
|
|
|
queueItem?.resolve((_result$output = result?.output) !== null && _result$output !== void 0 ? _result$output : result);
|
|
|
}
|
|
|
});
|
|
|
queue = [];
|
|
|
return isSuccess;
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
class ObservableSet {
|
|
|
constructor(...args) {
|
|
|
this.set = new Set(...args);
|
|
|
this.subscribers = new Set();
|
|
|
}
|
|
|
get size() {
|
|
|
return this.set.size;
|
|
|
}
|
|
|
add(value) {
|
|
|
this.set.add(value);
|
|
|
this.subscribers.forEach(subscriber => subscriber());
|
|
|
return this;
|
|
|
}
|
|
|
delete(value) {
|
|
|
const isSuccess = this.set.delete(value);
|
|
|
this.subscribers.forEach(subscriber => subscriber());
|
|
|
return isSuccess;
|
|
|
}
|
|
|
subscribe(subscriber) {
|
|
|
this.subscribers.add(subscriber);
|
|
|
return () => {
|
|
|
this.subscribers.delete(subscriber);
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/name.js
|
|
|
/**
|
|
|
* The reducer key used by core data in store registration.
|
|
|
* This is defined in a separate file to avoid cycle-dependency
|
|
|
*
|
|
|
* @type {string}
|
|
|
*/
|
|
|
const STORE_NAME = 'core';
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/actions.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that authors have been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} queryID Query ID.
|
|
|
* @param {Array|Object} users Users received.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveUserQuery(queryID, users) {
|
|
|
return {
|
|
|
type: 'RECEIVE_USER_QUERY',
|
|
|
users: Array.isArray(users) ? users : [users],
|
|
|
queryID
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action used in signalling that the current user has been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {Object} currentUser Current user object.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveCurrentUser(currentUser) {
|
|
|
return {
|
|
|
type: 'RECEIVE_CURRENT_USER',
|
|
|
currentUser
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in adding new entities.
|
|
|
*
|
|
|
* @param {Array} entities Entities received.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function addEntities(entities) {
|
|
|
return {
|
|
|
type: 'ADD_ENTITIES',
|
|
|
entities
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that entity records have been received.
|
|
|
*
|
|
|
* @param {string} kind Kind of the received entity record.
|
|
|
* @param {string} name Name of the received entity record.
|
|
|
* @param {Array|Object} records Records received.
|
|
|
* @param {?Object} query Query Object.
|
|
|
* @param {?boolean} invalidateCache Should invalidate query caches.
|
|
|
* @param {?Object} edits Edits to reset.
|
|
|
* @param {?Object} meta Meta information about pagination.
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveEntityRecords(kind, name, records, query, invalidateCache = false, edits, meta) {
|
|
|
// Auto drafts should not have titles, but some plugins rely on them so we can't filter this
|
|
|
// on the server.
|
|
|
if (kind === 'postType') {
|
|
|
records = (Array.isArray(records) ? records : [records]).map(record => record.status === 'auto-draft' ? {
|
|
|
...record,
|
|
|
title: ''
|
|
|
} : record);
|
|
|
}
|
|
|
let action;
|
|
|
if (query) {
|
|
|
action = receiveQueriedItems(records, query, edits, meta);
|
|
|
} else {
|
|
|
action = receiveItems(records, edits, meta);
|
|
|
}
|
|
|
return {
|
|
|
...action,
|
|
|
kind,
|
|
|
name,
|
|
|
invalidateCache
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the current theme has been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {Object} currentTheme The current theme.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveCurrentTheme(currentTheme) {
|
|
|
return {
|
|
|
type: 'RECEIVE_CURRENT_THEME',
|
|
|
currentTheme
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the current global styles id has been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} currentGlobalStylesId The current global styles id.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function __experimentalReceiveCurrentGlobalStylesId(currentGlobalStylesId) {
|
|
|
return {
|
|
|
type: 'RECEIVE_CURRENT_GLOBAL_STYLES_ID',
|
|
|
id: currentGlobalStylesId
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the theme base global styles have been received
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} stylesheet The theme's identifier
|
|
|
* @param {Object} globalStyles The global styles object.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function __experimentalReceiveThemeBaseGlobalStyles(stylesheet, globalStyles) {
|
|
|
return {
|
|
|
type: 'RECEIVE_THEME_GLOBAL_STYLES',
|
|
|
stylesheet,
|
|
|
globalStyles
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the theme global styles variations have been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} stylesheet The theme's identifier
|
|
|
* @param {Array} variations The global styles variations.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function __experimentalReceiveThemeGlobalStyleVariations(stylesheet, variations) {
|
|
|
return {
|
|
|
type: 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS',
|
|
|
stylesheet,
|
|
|
variations
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the index has been received.
|
|
|
*
|
|
|
* @deprecated since WP 5.9, this is not useful anymore, use the selector direclty.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveThemeSupports() {
|
|
|
external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeSupports", {
|
|
|
since: '5.9'
|
|
|
});
|
|
|
return {
|
|
|
type: 'DO_NOTHING'
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the theme global styles CPT post revisions have been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @deprecated since WordPress 6.5.0. Callers should use `dispatch( 'core' ).receiveRevision` instead.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {number} currentId The post id.
|
|
|
* @param {Array} revisions The global styles revisions.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveThemeGlobalStyleRevisions(currentId, revisions) {
|
|
|
external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveThemeGlobalStyleRevisions()", {
|
|
|
since: '6.5.0',
|
|
|
alternative: "wp.data.dispatch( 'core' ).receiveRevisions"
|
|
|
});
|
|
|
return {
|
|
|
type: 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS',
|
|
|
currentId,
|
|
|
revisions
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the preview data for
|
|
|
* a given URl has been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} url URL to preview the embed for.
|
|
|
* @param {*} preview Preview data.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveEmbedPreview(url, preview) {
|
|
|
return {
|
|
|
type: 'RECEIVE_EMBED_PREVIEW',
|
|
|
url,
|
|
|
preview
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Action triggered to delete an entity record.
|
|
|
*
|
|
|
* @param {string} kind Kind of the deleted entity.
|
|
|
* @param {string} name Name of the deleted entity.
|
|
|
* @param {string} recordId Record ID of the deleted entity.
|
|
|
* @param {?Object} query Special query parameters for the
|
|
|
* DELETE API call.
|
|
|
* @param {Object} [options] Delete options.
|
|
|
* @param {Function} [options.__unstableFetch] Internal use only. Function to
|
|
|
* call instead of `apiFetch()`.
|
|
|
* Must return a promise.
|
|
|
* @param {boolean} [options.throwOnError=false] If false, this action suppresses all
|
|
|
* the exceptions. Defaults to false.
|
|
|
*/
|
|
|
const deleteEntityRecord = (kind, name, recordId, query, {
|
|
|
__unstableFetch = (external_wp_apiFetch_default()),
|
|
|
throwOnError = false
|
|
|
} = {}) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.kind === kind && config.name === name);
|
|
|
let error;
|
|
|
let deletedRecord = false;
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId], {
|
|
|
exclusive: true
|
|
|
});
|
|
|
try {
|
|
|
dispatch({
|
|
|
type: 'DELETE_ENTITY_RECORD_START',
|
|
|
kind,
|
|
|
name,
|
|
|
recordId
|
|
|
});
|
|
|
let hasError = false;
|
|
|
try {
|
|
|
let path = `${entityConfig.baseURL}/${recordId}`;
|
|
|
if (query) {
|
|
|
path = (0,external_wp_url_namespaceObject.addQueryArgs)(path, query);
|
|
|
}
|
|
|
deletedRecord = await __unstableFetch({
|
|
|
path,
|
|
|
method: 'DELETE'
|
|
|
});
|
|
|
await dispatch(removeItems(kind, name, recordId, true));
|
|
|
} catch (_error) {
|
|
|
hasError = true;
|
|
|
error = _error;
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'DELETE_ENTITY_RECORD_FINISH',
|
|
|
kind,
|
|
|
name,
|
|
|
recordId,
|
|
|
error
|
|
|
});
|
|
|
if (hasError && throwOnError) {
|
|
|
throw error;
|
|
|
}
|
|
|
return deletedRecord;
|
|
|
} finally {
|
|
|
dispatch.__unstableReleaseStoreLock(lock);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns an action object that triggers an
|
|
|
* edit to an entity record.
|
|
|
*
|
|
|
* @param {string} kind Kind of the edited entity record.
|
|
|
* @param {string} name Name of the edited entity record.
|
|
|
* @param {number|string} recordId Record ID of the edited entity record.
|
|
|
* @param {Object} edits The edits.
|
|
|
* @param {Object} options Options for the edit.
|
|
|
* @param {boolean} [options.undoIgnore] Whether to ignore the edit in undo history or not.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
const editEntityRecord = (kind, name, recordId, edits, options = {}) => ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const entityConfig = select.getEntityConfig(kind, name);
|
|
|
if (!entityConfig) {
|
|
|
throw new Error(`The entity being edited (${kind}, ${name}) does not have a loaded config.`);
|
|
|
}
|
|
|
const {
|
|
|
mergedEdits = {}
|
|
|
} = entityConfig;
|
|
|
const record = select.getRawEntityRecord(kind, name, recordId);
|
|
|
const editedRecord = select.getEditedEntityRecord(kind, name, recordId);
|
|
|
const edit = {
|
|
|
kind,
|
|
|
name,
|
|
|
recordId,
|
|
|
// Clear edits when they are equal to their persisted counterparts
|
|
|
// so that the property is not considered dirty.
|
|
|
edits: Object.keys(edits).reduce((acc, key) => {
|
|
|
const recordValue = record[key];
|
|
|
const editedRecordValue = editedRecord[key];
|
|
|
const value = mergedEdits[key] ? {
|
|
|
...editedRecordValue,
|
|
|
...edits[key]
|
|
|
} : edits[key];
|
|
|
acc[key] = es6_default()(recordValue, value) ? undefined : value;
|
|
|
return acc;
|
|
|
}, {})
|
|
|
};
|
|
|
if (window.__experimentalEnableSync && entityConfig.syncConfig) {
|
|
|
if (false) {}
|
|
|
} else {
|
|
|
if (!options.undoIgnore) {
|
|
|
select.getUndoManager().addRecord([{
|
|
|
id: {
|
|
|
kind,
|
|
|
name,
|
|
|
recordId
|
|
|
},
|
|
|
changes: Object.keys(edits).reduce((acc, key) => {
|
|
|
acc[key] = {
|
|
|
from: editedRecord[key],
|
|
|
to: edits[key]
|
|
|
};
|
|
|
return acc;
|
|
|
}, {})
|
|
|
}], options.isCached);
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'EDIT_ENTITY_RECORD',
|
|
|
...edit
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Action triggered to undo the last edit to
|
|
|
* an entity record, if any.
|
|
|
*/
|
|
|
const undo = () => ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const undoRecord = select.getUndoManager().undo();
|
|
|
if (!undoRecord) {
|
|
|
return;
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'UNDO',
|
|
|
record: undoRecord
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Action triggered to redo the last undoed
|
|
|
* edit to an entity record, if any.
|
|
|
*/
|
|
|
const redo = () => ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const redoRecord = select.getUndoManager().redo();
|
|
|
if (!redoRecord) {
|
|
|
return;
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'REDO',
|
|
|
record: redoRecord
|
|
|
});
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Forces the creation of a new undo level.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
const __unstableCreateUndoLevel = () => ({
|
|
|
select
|
|
|
}) => {
|
|
|
select.getUndoManager().addRecord();
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Action triggered to save an entity record.
|
|
|
*
|
|
|
* @param {string} kind Kind of the received entity.
|
|
|
* @param {string} name Name of the received entity.
|
|
|
* @param {Object} record Record to be saved.
|
|
|
* @param {Object} options Saving options.
|
|
|
* @param {boolean} [options.isAutosave=false] Whether this is an autosave.
|
|
|
* @param {Function} [options.__unstableFetch] Internal use only. Function to
|
|
|
* call instead of `apiFetch()`.
|
|
|
* Must return a promise.
|
|
|
* @param {boolean} [options.throwOnError=false] If false, this action suppresses all
|
|
|
* the exceptions. Defaults to false.
|
|
|
*/
|
|
|
const saveEntityRecord = (kind, name, record, {
|
|
|
isAutosave = false,
|
|
|
__unstableFetch = (external_wp_apiFetch_default()),
|
|
|
throwOnError = false
|
|
|
} = {}) => async ({
|
|
|
select,
|
|
|
resolveSelect,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.kind === kind && config.name === name);
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
|
|
|
const recordId = record[entityIdKey];
|
|
|
const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, recordId || esm_browser_v4()], {
|
|
|
exclusive: true
|
|
|
});
|
|
|
try {
|
|
|
// Evaluate optimized edits.
|
|
|
// (Function edits that should be evaluated on save to avoid expensive computations on every edit.)
|
|
|
for (const [key, value] of Object.entries(record)) {
|
|
|
if (typeof value === 'function') {
|
|
|
const evaluatedValue = value(select.getEditedEntityRecord(kind, name, recordId));
|
|
|
dispatch.editEntityRecord(kind, name, recordId, {
|
|
|
[key]: evaluatedValue
|
|
|
}, {
|
|
|
undoIgnore: true
|
|
|
});
|
|
|
record[key] = evaluatedValue;
|
|
|
}
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'SAVE_ENTITY_RECORD_START',
|
|
|
kind,
|
|
|
name,
|
|
|
recordId,
|
|
|
isAutosave
|
|
|
});
|
|
|
let updatedRecord;
|
|
|
let error;
|
|
|
let hasError = false;
|
|
|
try {
|
|
|
const path = `${entityConfig.baseURL}${recordId ? '/' + recordId : ''}`;
|
|
|
const persistedRecord = select.getRawEntityRecord(kind, name, recordId);
|
|
|
if (isAutosave) {
|
|
|
// Most of this autosave logic is very specific to posts.
|
|
|
// This is fine for now as it is the only supported autosave,
|
|
|
// but ideally this should all be handled in the back end,
|
|
|
// so the client just sends and receives objects.
|
|
|
const currentUser = select.getCurrentUser();
|
|
|
const currentUserId = currentUser ? currentUser.id : undefined;
|
|
|
const autosavePost = await resolveSelect.getAutosave(persistedRecord.type, persistedRecord.id, currentUserId);
|
|
|
// Autosaves need all expected fields to be present.
|
|
|
// So we fallback to the previous autosave and then
|
|
|
// to the actual persisted entity if the edits don't
|
|
|
// have a value.
|
|
|
let data = {
|
|
|
...persistedRecord,
|
|
|
...autosavePost,
|
|
|
...record
|
|
|
};
|
|
|
data = Object.keys(data).reduce((acc, key) => {
|
|
|
if (['title', 'excerpt', 'content', 'meta'].includes(key)) {
|
|
|
acc[key] = data[key];
|
|
|
}
|
|
|
return acc;
|
|
|
}, {
|
|
|
status: data.status === 'auto-draft' ? 'draft' : data.status
|
|
|
});
|
|
|
updatedRecord = await __unstableFetch({
|
|
|
path: `${path}/autosaves`,
|
|
|
method: 'POST',
|
|
|
data
|
|
|
});
|
|
|
|
|
|
// An autosave may be processed by the server as a regular save
|
|
|
// when its update is requested by the author and the post had
|
|
|
// draft or auto-draft status.
|
|
|
if (persistedRecord.id === updatedRecord.id) {
|
|
|
let newRecord = {
|
|
|
...persistedRecord,
|
|
|
...data,
|
|
|
...updatedRecord
|
|
|
};
|
|
|
newRecord = Object.keys(newRecord).reduce((acc, key) => {
|
|
|
// These properties are persisted in autosaves.
|
|
|
if (['title', 'excerpt', 'content'].includes(key)) {
|
|
|
acc[key] = newRecord[key];
|
|
|
} else if (key === 'status') {
|
|
|
// Status is only persisted in autosaves when going from
|
|
|
// "auto-draft" to "draft".
|
|
|
acc[key] = persistedRecord.status === 'auto-draft' && newRecord.status === 'draft' ? newRecord.status : persistedRecord.status;
|
|
|
} else {
|
|
|
// These properties are not persisted in autosaves.
|
|
|
acc[key] = persistedRecord[key];
|
|
|
}
|
|
|
return acc;
|
|
|
}, {});
|
|
|
dispatch.receiveEntityRecords(kind, name, newRecord, undefined, true);
|
|
|
} else {
|
|
|
dispatch.receiveAutosaves(persistedRecord.id, updatedRecord);
|
|
|
}
|
|
|
} else {
|
|
|
let edits = record;
|
|
|
if (entityConfig.__unstablePrePersist) {
|
|
|
edits = {
|
|
|
...edits,
|
|
|
...entityConfig.__unstablePrePersist(persistedRecord, edits)
|
|
|
};
|
|
|
}
|
|
|
updatedRecord = await __unstableFetch({
|
|
|
path,
|
|
|
method: recordId ? 'PUT' : 'POST',
|
|
|
data: edits
|
|
|
});
|
|
|
dispatch.receiveEntityRecords(kind, name, updatedRecord, undefined, true, edits);
|
|
|
}
|
|
|
} catch (_error) {
|
|
|
hasError = true;
|
|
|
error = _error;
|
|
|
}
|
|
|
dispatch({
|
|
|
type: 'SAVE_ENTITY_RECORD_FINISH',
|
|
|
kind,
|
|
|
name,
|
|
|
recordId,
|
|
|
error,
|
|
|
isAutosave
|
|
|
});
|
|
|
if (hasError && throwOnError) {
|
|
|
throw error;
|
|
|
}
|
|
|
return updatedRecord;
|
|
|
} finally {
|
|
|
dispatch.__unstableReleaseStoreLock(lock);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Runs multiple core-data actions at the same time using one API request.
|
|
|
*
|
|
|
* Example:
|
|
|
*
|
|
|
* ```
|
|
|
* const [ savedRecord, updatedRecord, deletedRecord ] =
|
|
|
* await dispatch( 'core' ).__experimentalBatch( [
|
|
|
* ( { saveEntityRecord } ) => saveEntityRecord( 'root', 'widget', widget ),
|
|
|
* ( { saveEditedEntityRecord } ) => saveEntityRecord( 'root', 'widget', 123 ),
|
|
|
* ( { deleteEntityRecord } ) => deleteEntityRecord( 'root', 'widget', 123, null ),
|
|
|
* ] );
|
|
|
* ```
|
|
|
*
|
|
|
* @param {Array} requests Array of functions which are invoked simultaneously.
|
|
|
* Each function is passed an object containing
|
|
|
* `saveEntityRecord`, `saveEditedEntityRecord`, and
|
|
|
* `deleteEntityRecord`.
|
|
|
*
|
|
|
* @return {(thunkArgs: Object) => Promise} A promise that resolves to an array containing the return
|
|
|
* values of each function given in `requests`.
|
|
|
*/
|
|
|
const __experimentalBatch = requests => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const batch = createBatch();
|
|
|
const api = {
|
|
|
saveEntityRecord(kind, name, record, options) {
|
|
|
return batch.add(add => dispatch.saveEntityRecord(kind, name, record, {
|
|
|
...options,
|
|
|
__unstableFetch: add
|
|
|
}));
|
|
|
},
|
|
|
saveEditedEntityRecord(kind, name, recordId, options) {
|
|
|
return batch.add(add => dispatch.saveEditedEntityRecord(kind, name, recordId, {
|
|
|
...options,
|
|
|
__unstableFetch: add
|
|
|
}));
|
|
|
},
|
|
|
deleteEntityRecord(kind, name, recordId, query, options) {
|
|
|
return batch.add(add => dispatch.deleteEntityRecord(kind, name, recordId, query, {
|
|
|
...options,
|
|
|
__unstableFetch: add
|
|
|
}));
|
|
|
}
|
|
|
};
|
|
|
const resultPromises = requests.map(request => request(api));
|
|
|
const [, ...results] = await Promise.all([batch.run(), ...resultPromises]);
|
|
|
return results;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Action triggered to save an entity record's edits.
|
|
|
*
|
|
|
* @param {string} kind Kind of the entity.
|
|
|
* @param {string} name Name of the entity.
|
|
|
* @param {Object} recordId ID of the record.
|
|
|
* @param {Object} options Saving options.
|
|
|
*/
|
|
|
const saveEditedEntityRecord = (kind, name, recordId, options) => async ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
|
|
|
return;
|
|
|
}
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.kind === kind && config.name === name);
|
|
|
if (!entityConfig) {
|
|
|
return;
|
|
|
}
|
|
|
const entityIdKey = entityConfig.key || DEFAULT_ENTITY_KEY;
|
|
|
const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
|
|
|
const record = {
|
|
|
[entityIdKey]: recordId,
|
|
|
...edits
|
|
|
};
|
|
|
return await dispatch.saveEntityRecord(kind, name, record, options);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Action triggered to save only specified properties for the entity.
|
|
|
*
|
|
|
* @param {string} kind Kind of the entity.
|
|
|
* @param {string} name Name of the entity.
|
|
|
* @param {Object} recordId ID of the record.
|
|
|
* @param {Array} itemsToSave List of entity properties or property paths to save.
|
|
|
* @param {Object} options Saving options.
|
|
|
*/
|
|
|
const __experimentalSaveSpecifiedEntityEdits = (kind, name, recordId, itemsToSave, options) => async ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
if (!select.hasEditsForEntityRecord(kind, name, recordId)) {
|
|
|
return;
|
|
|
}
|
|
|
const edits = select.getEntityRecordNonTransientEdits(kind, name, recordId);
|
|
|
const editsToSave = {};
|
|
|
for (const item of itemsToSave) {
|
|
|
setNestedValue(editsToSave, item, getNestedValue(edits, item));
|
|
|
}
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.kind === kind && config.name === name);
|
|
|
const entityIdKey = entityConfig?.key || DEFAULT_ENTITY_KEY;
|
|
|
|
|
|
// If a record key is provided then update the existing record.
|
|
|
// This necessitates providing `recordKey` to saveEntityRecord as part of the
|
|
|
// `record` argument (here called `editsToSave`) to stop that action creating
|
|
|
// a new record and instead cause it to update the existing record.
|
|
|
if (recordId) {
|
|
|
editsToSave[entityIdKey] = recordId;
|
|
|
}
|
|
|
return await dispatch.saveEntityRecord(kind, name, editsToSave, options);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that Upload permissions have been received.
|
|
|
*
|
|
|
* @deprecated since WP 5.9, use receiveUserPermission instead.
|
|
|
*
|
|
|
* @param {boolean} hasUploadPermissions Does the user have permission to upload files?
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveUploadPermissions(hasUploadPermissions) {
|
|
|
external_wp_deprecated_default()("wp.data.dispatch( 'core' ).receiveUploadPermissions", {
|
|
|
since: '5.9',
|
|
|
alternative: 'receiveUserPermission'
|
|
|
});
|
|
|
return receiveUserPermission('create/media', hasUploadPermissions);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the current user has
|
|
|
* permission to perform an action on a REST resource.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {string} key A key that represents the action and REST resource.
|
|
|
* @param {boolean} isAllowed Whether or not the user can perform the action.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveUserPermission(key, isAllowed) {
|
|
|
return {
|
|
|
type: 'RECEIVE_USER_PERMISSION',
|
|
|
key,
|
|
|
isAllowed
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used in signalling that the autosaves for a
|
|
|
* post have been received.
|
|
|
* Ignored from documentation as it's internal to the data store.
|
|
|
*
|
|
|
* @ignore
|
|
|
*
|
|
|
* @param {number} postId The id of the post that is parent to the autosave.
|
|
|
* @param {Array|Object} autosaves An array of autosaves or singular autosave object.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveAutosaves(postId, autosaves) {
|
|
|
return {
|
|
|
type: 'RECEIVE_AUTOSAVES',
|
|
|
postId,
|
|
|
autosaves: Array.isArray(autosaves) ? autosaves : [autosaves]
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object signalling that the fallback Navigation
|
|
|
* Menu id has been received.
|
|
|
*
|
|
|
* @param {integer} fallbackId the id of the fallback Navigation Menu
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveNavigationFallbackId(fallbackId) {
|
|
|
return {
|
|
|
type: 'RECEIVE_NAVIGATION_FALLBACK_ID',
|
|
|
fallbackId
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an action object used to set the template for a given query.
|
|
|
*
|
|
|
* @param {Object} query The lookup query.
|
|
|
* @param {string} templateId The resolved template id.
|
|
|
*
|
|
|
* @return {Object} Action object.
|
|
|
*/
|
|
|
function receiveDefaultTemplateId(query, templateId) {
|
|
|
return {
|
|
|
type: 'RECEIVE_DEFAULT_TEMPLATE',
|
|
|
query,
|
|
|
templateId
|
|
|
};
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Action triggered to receive revision items.
|
|
|
*
|
|
|
* @param {string} kind Kind of the received entity record revisions.
|
|
|
* @param {string} name Name of the received entity record revisions.
|
|
|
* @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
|
|
|
* @param {Array|Object} records Revisions received.
|
|
|
* @param {?Object} query Query Object.
|
|
|
* @param {?boolean} invalidateCache Should invalidate query caches.
|
|
|
* @param {?Object} meta Meta information about pagination.
|
|
|
*/
|
|
|
const receiveRevisions = (kind, name, recordKey, records, query, invalidateCache = false, meta) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.kind === kind && config.name === name);
|
|
|
const key = entityConfig && entityConfig?.revisionKey ? entityConfig.revisionKey : DEFAULT_ENTITY_KEY;
|
|
|
dispatch({
|
|
|
type: 'RECEIVE_ITEM_REVISIONS',
|
|
|
key,
|
|
|
items: Array.isArray(records) ? records : [records],
|
|
|
recordKey,
|
|
|
meta,
|
|
|
query,
|
|
|
kind,
|
|
|
name,
|
|
|
invalidateCache
|
|
|
});
|
|
|
};
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/entities.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
const DEFAULT_ENTITY_KEY = 'id';
|
|
|
const POST_RAW_ATTRIBUTES = ['title', 'excerpt', 'content'];
|
|
|
const rootEntitiesConfig = [{
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Base'),
|
|
|
kind: 'root',
|
|
|
name: '__unstableBase',
|
|
|
baseURL: '/',
|
|
|
baseURLParams: {
|
|
|
_fields: ['description', 'gmt_offset', 'home', 'name', 'site_icon', 'site_icon_url', 'site_logo', 'timezone_string', 'url'].join(',')
|
|
|
},
|
|
|
syncConfig: {
|
|
|
fetch: async () => {
|
|
|
return external_wp_apiFetch_default()({
|
|
|
path: '/'
|
|
|
});
|
|
|
},
|
|
|
applyChangesToDoc: (doc, changes) => {
|
|
|
const document = doc.getMap('document');
|
|
|
Object.entries(changes).forEach(([key, value]) => {
|
|
|
if (document.get(key) !== value) {
|
|
|
document.set(key, value);
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
fromCRDTDoc: doc => {
|
|
|
return doc.getMap('document').toJSON();
|
|
|
}
|
|
|
},
|
|
|
syncObjectType: 'root/base',
|
|
|
getSyncObjectId: () => 'index'
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Site'),
|
|
|
name: 'site',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/settings',
|
|
|
getTitle: record => {
|
|
|
var _record$title;
|
|
|
return (_record$title = record?.title) !== null && _record$title !== void 0 ? _record$title : (0,external_wp_i18n_namespaceObject.__)('Site Title');
|
|
|
},
|
|
|
syncConfig: {
|
|
|
fetch: async () => {
|
|
|
return external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/settings'
|
|
|
});
|
|
|
},
|
|
|
applyChangesToDoc: (doc, changes) => {
|
|
|
const document = doc.getMap('document');
|
|
|
Object.entries(changes).forEach(([key, value]) => {
|
|
|
if (document.get(key) !== value) {
|
|
|
document.set(key, value);
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
fromCRDTDoc: doc => {
|
|
|
return doc.getMap('document').toJSON();
|
|
|
}
|
|
|
},
|
|
|
syncObjectType: 'root/site',
|
|
|
getSyncObjectId: () => 'index'
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Post Type'),
|
|
|
name: 'postType',
|
|
|
kind: 'root',
|
|
|
key: 'slug',
|
|
|
baseURL: '/wp/v2/types',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
syncConfig: {
|
|
|
fetch: async id => {
|
|
|
return external_wp_apiFetch_default()({
|
|
|
path: `/wp/v2/types/${id}?context=edit`
|
|
|
});
|
|
|
},
|
|
|
applyChangesToDoc: (doc, changes) => {
|
|
|
const document = doc.getMap('document');
|
|
|
Object.entries(changes).forEach(([key, value]) => {
|
|
|
if (document.get(key) !== value) {
|
|
|
document.set(key, value);
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
fromCRDTDoc: doc => {
|
|
|
return doc.getMap('document').toJSON();
|
|
|
}
|
|
|
},
|
|
|
syncObjectType: 'root/postType',
|
|
|
getSyncObjectId: id => id
|
|
|
}, {
|
|
|
name: 'media',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/media',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'mediaItems',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Media'),
|
|
|
rawAttributes: ['caption', 'title', 'description'],
|
|
|
supportsPagination: true
|
|
|
}, {
|
|
|
name: 'taxonomy',
|
|
|
kind: 'root',
|
|
|
key: 'slug',
|
|
|
baseURL: '/wp/v2/taxonomies',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'taxonomies',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Taxonomy')
|
|
|
}, {
|
|
|
name: 'sidebar',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/sidebars',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'sidebars',
|
|
|
transientEdits: {
|
|
|
blocks: true
|
|
|
},
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Widget areas')
|
|
|
}, {
|
|
|
name: 'widget',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/widgets',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'widgets',
|
|
|
transientEdits: {
|
|
|
blocks: true
|
|
|
},
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Widgets')
|
|
|
}, {
|
|
|
name: 'widgetType',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/widget-types',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'widgetTypes',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Widget types')
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('User'),
|
|
|
name: 'user',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/users',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'users'
|
|
|
}, {
|
|
|
name: 'comment',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/comments',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'comments',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Comment')
|
|
|
}, {
|
|
|
name: 'menu',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/menus',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'menus',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Menu')
|
|
|
}, {
|
|
|
name: 'menuItem',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/menu-items',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'menuItems',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Menu Item'),
|
|
|
rawAttributes: ['title']
|
|
|
}, {
|
|
|
name: 'menuLocation',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/menu-locations',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'menuLocations',
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Menu Location'),
|
|
|
key: 'name'
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Global Styles'),
|
|
|
name: 'globalStyles',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/global-styles',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'globalStylesVariations',
|
|
|
// Should be different from name.
|
|
|
getTitle: record => record?.title?.rendered || record?.title,
|
|
|
getRevisionsUrl: (parentId, revisionId) => `/wp/v2/global-styles/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
|
|
|
supportsPagination: true
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Themes'),
|
|
|
name: 'theme',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/themes',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
key: 'stylesheet'
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Plugins'),
|
|
|
name: 'plugin',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/plugins',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
key: 'plugin'
|
|
|
}, {
|
|
|
label: (0,external_wp_i18n_namespaceObject.__)('Status'),
|
|
|
name: 'status',
|
|
|
kind: 'root',
|
|
|
baseURL: '/wp/v2/statuses',
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
plural: 'statuses',
|
|
|
key: 'slug'
|
|
|
}];
|
|
|
const additionalEntityConfigLoaders = [{
|
|
|
kind: 'postType',
|
|
|
loadEntities: loadPostTypeEntities
|
|
|
}, {
|
|
|
kind: 'taxonomy',
|
|
|
loadEntities: loadTaxonomyEntities
|
|
|
}];
|
|
|
|
|
|
/**
|
|
|
* Returns a function to be used to retrieve extra edits to apply before persisting a post type.
|
|
|
*
|
|
|
* @param {Object} persistedRecord Already persisted Post
|
|
|
* @param {Object} edits Edits.
|
|
|
* @return {Object} Updated edits.
|
|
|
*/
|
|
|
const prePersistPostType = (persistedRecord, edits) => {
|
|
|
const newEdits = {};
|
|
|
if (persistedRecord?.status === 'auto-draft') {
|
|
|
// Saving an auto-draft should create a draft by default.
|
|
|
if (!edits.status && !newEdits.status) {
|
|
|
newEdits.status = 'draft';
|
|
|
}
|
|
|
|
|
|
// Fix the auto-draft default title.
|
|
|
if ((!edits.title || edits.title === 'Auto Draft') && !newEdits.title && (!persistedRecord?.title || persistedRecord?.title === 'Auto Draft')) {
|
|
|
newEdits.title = '';
|
|
|
}
|
|
|
}
|
|
|
return newEdits;
|
|
|
};
|
|
|
const serialisableBlocksCache = new WeakMap();
|
|
|
function makeBlockAttributesSerializable(attributes) {
|
|
|
const newAttributes = {
|
|
|
...attributes
|
|
|
};
|
|
|
for (const [key, value] of Object.entries(attributes)) {
|
|
|
if (value instanceof external_wp_richText_namespaceObject.RichTextData) {
|
|
|
newAttributes[key] = value.valueOf();
|
|
|
}
|
|
|
}
|
|
|
return newAttributes;
|
|
|
}
|
|
|
function makeBlocksSerializable(blocks) {
|
|
|
return blocks.map(block => {
|
|
|
const {
|
|
|
innerBlocks,
|
|
|
attributes,
|
|
|
...rest
|
|
|
} = block;
|
|
|
return {
|
|
|
...rest,
|
|
|
attributes: makeBlockAttributesSerializable(attributes),
|
|
|
innerBlocks: makeBlocksSerializable(innerBlocks)
|
|
|
};
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the list of post type entities.
|
|
|
*
|
|
|
* @return {Promise} Entities promise
|
|
|
*/
|
|
|
async function loadPostTypeEntities() {
|
|
|
const postTypes = await external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/types?context=view'
|
|
|
});
|
|
|
return Object.entries(postTypes !== null && postTypes !== void 0 ? postTypes : {}).map(([name, postType]) => {
|
|
|
var _postType$rest_namesp;
|
|
|
const isTemplate = ['wp_template', 'wp_template_part'].includes(name);
|
|
|
const namespace = (_postType$rest_namesp = postType?.rest_namespace) !== null && _postType$rest_namesp !== void 0 ? _postType$rest_namesp : 'wp/v2';
|
|
|
return {
|
|
|
kind: 'postType',
|
|
|
baseURL: `/${namespace}/${postType.rest_base}`,
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
name,
|
|
|
label: postType.name,
|
|
|
transientEdits: {
|
|
|
blocks: true,
|
|
|
selection: true
|
|
|
},
|
|
|
mergedEdits: {
|
|
|
meta: true
|
|
|
},
|
|
|
rawAttributes: POST_RAW_ATTRIBUTES,
|
|
|
getTitle: record => {
|
|
|
var _record$slug;
|
|
|
return record?.title?.rendered || record?.title || (isTemplate ? capitalCase((_record$slug = record.slug) !== null && _record$slug !== void 0 ? _record$slug : '') : String(record.id));
|
|
|
},
|
|
|
__unstablePrePersist: isTemplate ? undefined : prePersistPostType,
|
|
|
__unstable_rest_base: postType.rest_base,
|
|
|
syncConfig: {
|
|
|
fetch: async id => {
|
|
|
return external_wp_apiFetch_default()({
|
|
|
path: `/${namespace}/${postType.rest_base}/${id}?context=edit`
|
|
|
});
|
|
|
},
|
|
|
applyChangesToDoc: (doc, changes) => {
|
|
|
const document = doc.getMap('document');
|
|
|
Object.entries(changes).forEach(([key, value]) => {
|
|
|
if (typeof value !== 'function') {
|
|
|
if (key === 'blocks') {
|
|
|
if (!serialisableBlocksCache.has(value)) {
|
|
|
serialisableBlocksCache.set(value, makeBlocksSerializable(value));
|
|
|
}
|
|
|
value = serialisableBlocksCache.get(value);
|
|
|
}
|
|
|
if (document.get(key) !== value) {
|
|
|
document.set(key, value);
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
},
|
|
|
fromCRDTDoc: doc => {
|
|
|
return doc.getMap('document').toJSON();
|
|
|
}
|
|
|
},
|
|
|
syncObjectType: 'postType/' + postType.name,
|
|
|
getSyncObjectId: id => id,
|
|
|
supportsPagination: true,
|
|
|
getRevisionsUrl: (parentId, revisionId) => `/${namespace}/${postType.rest_base}/${parentId}/revisions${revisionId ? '/' + revisionId : ''}`,
|
|
|
revisionKey: isTemplate ? 'wp_id' : DEFAULT_ENTITY_KEY
|
|
|
};
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the list of the taxonomies entities.
|
|
|
*
|
|
|
* @return {Promise} Entities promise
|
|
|
*/
|
|
|
async function loadTaxonomyEntities() {
|
|
|
const taxonomies = await external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/taxonomies?context=view'
|
|
|
});
|
|
|
return Object.entries(taxonomies !== null && taxonomies !== void 0 ? taxonomies : {}).map(([name, taxonomy]) => {
|
|
|
var _taxonomy$rest_namesp;
|
|
|
const namespace = (_taxonomy$rest_namesp = taxonomy?.rest_namespace) !== null && _taxonomy$rest_namesp !== void 0 ? _taxonomy$rest_namesp : 'wp/v2';
|
|
|
return {
|
|
|
kind: 'taxonomy',
|
|
|
baseURL: `/${namespace}/${taxonomy.rest_base}`,
|
|
|
baseURLParams: {
|
|
|
context: 'edit'
|
|
|
},
|
|
|
name,
|
|
|
label: taxonomy.name
|
|
|
};
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the entity's getter method name given its kind and name.
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* const nameSingular = getMethodName( 'root', 'theme', 'get' );
|
|
|
* // nameSingular is getRootTheme
|
|
|
*
|
|
|
* const namePlural = getMethodName( 'root', 'theme', 'set' );
|
|
|
* // namePlural is setRootThemes
|
|
|
* ```
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {string} prefix Function prefix.
|
|
|
* @param {boolean} usePlural Whether to use the plural form or not.
|
|
|
*
|
|
|
* @return {string} Method name
|
|
|
*/
|
|
|
const getMethodName = (kind, name, prefix = 'get', usePlural = false) => {
|
|
|
const entityConfig = rootEntitiesConfig.find(config => config.kind === kind && config.name === name);
|
|
|
const kindPrefix = kind === 'root' ? '' : pascalCase(kind);
|
|
|
const nameSuffix = pascalCase(name) + (usePlural ? 's' : '');
|
|
|
const suffix = usePlural && 'plural' in entityConfig && entityConfig?.plural ? pascalCase(entityConfig.plural) : nameSuffix;
|
|
|
return `${prefix}${kindPrefix}${suffix}`;
|
|
|
};
|
|
|
function registerSyncConfigs(configs) {
|
|
|
configs.forEach(({
|
|
|
syncObjectType,
|
|
|
syncConfig
|
|
|
}) => {
|
|
|
getSyncProvider().register(syncObjectType, syncConfig);
|
|
|
const editSyncConfig = {
|
|
|
...syncConfig
|
|
|
};
|
|
|
delete editSyncConfig.fetch;
|
|
|
getSyncProvider().register(syncObjectType + '--edit', editSyncConfig);
|
|
|
});
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Loads the kind entities into the store.
|
|
|
*
|
|
|
* @param {string} kind Kind
|
|
|
*
|
|
|
* @return {(thunkArgs: object) => Promise<Array>} Entities
|
|
|
*/
|
|
|
const getOrLoadEntitiesConfig = kind => async ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
let configs = select.getEntitiesConfig(kind);
|
|
|
if (configs && configs.length !== 0) {
|
|
|
if (window.__experimentalEnableSync) {
|
|
|
if (false) {}
|
|
|
}
|
|
|
return configs;
|
|
|
}
|
|
|
const loader = additionalEntityConfigLoaders.find(l => l.kind === kind);
|
|
|
if (!loader) {
|
|
|
return [];
|
|
|
}
|
|
|
configs = await loader.loadEntities();
|
|
|
if (window.__experimentalEnableSync) {
|
|
|
if (false) {}
|
|
|
}
|
|
|
dispatch(addEntities(configs));
|
|
|
return configs;
|
|
|
};
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/get-normalized-comma-separable.js
|
|
|
/**
|
|
|
* Given a value which can be specified as one or the other of a comma-separated
|
|
|
* string or an array, returns a value normalized to an array of strings, or
|
|
|
* null if the value cannot be interpreted as either.
|
|
|
*
|
|
|
* @param {string|string[]|*} value
|
|
|
*
|
|
|
* @return {?(string[])} Normalized field value.
|
|
|
*/
|
|
|
function getNormalizedCommaSeparable(value) {
|
|
|
if (typeof value === 'string') {
|
|
|
return value.split(',');
|
|
|
} else if (Array.isArray(value)) {
|
|
|
return value;
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
/* harmony default export */ const get_normalized_comma_separable = (getNormalizedCommaSeparable);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/with-weak-map-cache.js
|
|
|
/**
|
|
|
* Given a function, returns an enhanced function which caches the result and
|
|
|
* tracks in WeakMap. The result is only cached if the original function is
|
|
|
* passed a valid object-like argument (requirement for WeakMap key).
|
|
|
*
|
|
|
* @param {Function} fn Original function.
|
|
|
*
|
|
|
* @return {Function} Enhanced caching function.
|
|
|
*/
|
|
|
function withWeakMapCache(fn) {
|
|
|
const cache = new WeakMap();
|
|
|
return key => {
|
|
|
let value;
|
|
|
if (cache.has(key)) {
|
|
|
value = cache.get(key);
|
|
|
} else {
|
|
|
value = fn(key);
|
|
|
|
|
|
// Can reach here if key is not valid for WeakMap, since `has`
|
|
|
// will return false for invalid key. Since `set` will throw,
|
|
|
// ensure that key is valid before setting into cache.
|
|
|
if (key !== null && typeof key === 'object') {
|
|
|
cache.set(key, value);
|
|
|
}
|
|
|
}
|
|
|
return value;
|
|
|
};
|
|
|
}
|
|
|
/* harmony default export */ const with_weak_map_cache = (withWeakMapCache);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/queried-data/get-query-parts.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* An object of properties describing a specific query.
|
|
|
*
|
|
|
* @typedef {Object} WPQueriedDataQueryParts
|
|
|
*
|
|
|
* @property {number} page The query page (1-based index, default 1).
|
|
|
* @property {number} perPage Items per page for query (default 10).
|
|
|
* @property {string} stableKey An encoded stable string of all non-
|
|
|
* pagination, non-fields query parameters.
|
|
|
* @property {?(string[])} fields Target subset of fields to derive from
|
|
|
* item objects.
|
|
|
* @property {?(number[])} include Specific item IDs to include.
|
|
|
* @property {string} context Scope under which the request is made;
|
|
|
* determines returned fields in response.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Given a query object, returns an object of parts, including pagination
|
|
|
* details (`page` and `perPage`, or default values). All other properties are
|
|
|
* encoded into a stable (idempotent) `stableKey` value.
|
|
|
*
|
|
|
* @param {Object} query Optional query object.
|
|
|
*
|
|
|
* @return {WPQueriedDataQueryParts} Query parts.
|
|
|
*/
|
|
|
function getQueryParts(query) {
|
|
|
/**
|
|
|
* @type {WPQueriedDataQueryParts}
|
|
|
*/
|
|
|
const parts = {
|
|
|
stableKey: '',
|
|
|
page: 1,
|
|
|
perPage: 10,
|
|
|
fields: null,
|
|
|
include: null,
|
|
|
context: 'default'
|
|
|
};
|
|
|
|
|
|
// Ensure stable key by sorting keys. Also more efficient for iterating.
|
|
|
const keys = Object.keys(query).sort();
|
|
|
for (let i = 0; i < keys.length; i++) {
|
|
|
const key = keys[i];
|
|
|
let value = query[key];
|
|
|
switch (key) {
|
|
|
case 'page':
|
|
|
parts[key] = Number(value);
|
|
|
break;
|
|
|
case 'per_page':
|
|
|
parts.perPage = Number(value);
|
|
|
break;
|
|
|
case 'context':
|
|
|
parts.context = value;
|
|
|
break;
|
|
|
default:
|
|
|
// While in theory, we could exclude "_fields" from the stableKey
|
|
|
// because two request with different fields have the same results
|
|
|
// We're not able to ensure that because the server can decide to omit
|
|
|
// fields from the response even if we explicitly asked for it.
|
|
|
// Example: Asking for titles in posts without title support.
|
|
|
if (key === '_fields') {
|
|
|
var _getNormalizedCommaSe;
|
|
|
parts.fields = (_getNormalizedCommaSe = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
|
|
|
// Make sure to normalize value for `stableKey`
|
|
|
value = parts.fields.join();
|
|
|
}
|
|
|
|
|
|
// Two requests with different include values cannot have same results.
|
|
|
if (key === 'include') {
|
|
|
var _getNormalizedCommaSe2;
|
|
|
if (typeof value === 'number') {
|
|
|
value = value.toString();
|
|
|
}
|
|
|
parts.include = ((_getNormalizedCommaSe2 = get_normalized_comma_separable(value)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : []).map(Number);
|
|
|
// Normalize value for `stableKey`.
|
|
|
value = parts.include.join();
|
|
|
}
|
|
|
|
|
|
// While it could be any deterministic string, for simplicity's
|
|
|
// sake mimic querystring encoding for stable key.
|
|
|
//
|
|
|
// TODO: For consistency with PHP implementation, addQueryArgs
|
|
|
// should accept a key value pair, which may optimize its
|
|
|
// implementation for our use here, vs. iterating an object
|
|
|
// with only a single key.
|
|
|
parts.stableKey += (parts.stableKey ? '&' : '') + (0,external_wp_url_namespaceObject.addQueryArgs)('', {
|
|
|
[key]: value
|
|
|
}).slice(1);
|
|
|
}
|
|
|
}
|
|
|
return parts;
|
|
|
}
|
|
|
/* harmony default export */ const get_query_parts = (with_weak_map_cache(getQueryParts));
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/queried-data/reducer.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
function getContextFromAction(action) {
|
|
|
const {
|
|
|
query
|
|
|
} = action;
|
|
|
if (!query) {
|
|
|
return 'default';
|
|
|
}
|
|
|
const queryParts = get_query_parts(query);
|
|
|
return queryParts.context;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns a merged array of item IDs, given details of the received paginated
|
|
|
* items. The array is sparse-like with `undefined` entries where holes exist.
|
|
|
*
|
|
|
* @param {?Array<number>} itemIds Original item IDs (default empty array).
|
|
|
* @param {number[]} nextItemIds Item IDs to merge.
|
|
|
* @param {number} page Page of items merged.
|
|
|
* @param {number} perPage Number of items per page.
|
|
|
*
|
|
|
* @return {number[]} Merged array of item IDs.
|
|
|
*/
|
|
|
function getMergedItemIds(itemIds, nextItemIds, page, perPage) {
|
|
|
var _itemIds$length;
|
|
|
const receivedAllIds = page === 1 && perPage === -1;
|
|
|
if (receivedAllIds) {
|
|
|
return nextItemIds;
|
|
|
}
|
|
|
const nextItemIdsStartIndex = (page - 1) * perPage;
|
|
|
|
|
|
// If later page has already been received, default to the larger known
|
|
|
// size of the existing array, else calculate as extending the existing.
|
|
|
const size = Math.max((_itemIds$length = itemIds?.length) !== null && _itemIds$length !== void 0 ? _itemIds$length : 0, nextItemIdsStartIndex + nextItemIds.length);
|
|
|
|
|
|
// Preallocate array since size is known.
|
|
|
const mergedItemIds = new Array(size);
|
|
|
for (let i = 0; i < size; i++) {
|
|
|
// Preserve existing item ID except for subset of range of next items.
|
|
|
// We need to check against the possible maximum upper boundary because
|
|
|
// a page could receive fewer than what was previously stored.
|
|
|
const isInNextItemsRange = i >= nextItemIdsStartIndex && i < nextItemIdsStartIndex + perPage;
|
|
|
mergedItemIds[i] = isInNextItemsRange ? nextItemIds[i - nextItemIdsStartIndex] : itemIds?.[i];
|
|
|
}
|
|
|
return mergedItemIds;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Helper function to filter out entities with certain IDs.
|
|
|
* Entities are keyed by their ID.
|
|
|
*
|
|
|
* @param {Object} entities Entity objects, keyed by entity ID.
|
|
|
* @param {Array} ids Entity IDs to filter out.
|
|
|
*
|
|
|
* @return {Object} Filtered entities.
|
|
|
*/
|
|
|
function removeEntitiesById(entities, ids) {
|
|
|
return Object.fromEntries(Object.entries(entities).filter(([id]) => !ids.some(itemId => {
|
|
|
if (Number.isInteger(itemId)) {
|
|
|
return itemId === +id;
|
|
|
}
|
|
|
return itemId === id;
|
|
|
})));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer tracking items state, keyed by ID. Items are assumed to be normal,
|
|
|
* where identifiers are common across all queries.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Next state.
|
|
|
*/
|
|
|
function items(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_ITEMS':
|
|
|
{
|
|
|
const context = getContextFromAction(action);
|
|
|
const key = action.key || DEFAULT_ENTITY_KEY;
|
|
|
return {
|
|
|
...state,
|
|
|
[context]: {
|
|
|
...state[context],
|
|
|
...action.items.reduce((accumulator, value) => {
|
|
|
const itemId = value[key];
|
|
|
accumulator[itemId] = conservativeMapItem(state?.[context]?.[itemId], value);
|
|
|
return accumulator;
|
|
|
}, {})
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
case 'REMOVE_ITEMS':
|
|
|
return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer tracking item completeness, keyed by ID. A complete item is one for
|
|
|
* which all fields are known. This is used in supporting `_fields` queries,
|
|
|
* where not all properties associated with an entity are necessarily returned.
|
|
|
* In such cases, completeness is used as an indication of whether it would be
|
|
|
* safe to use queried data for a non-`_fields`-limited request.
|
|
|
*
|
|
|
* @param {Object<string,Object<string,boolean>>} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object<string,Object<string,boolean>>} Next state.
|
|
|
*/
|
|
|
function itemIsComplete(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_ITEMS':
|
|
|
{
|
|
|
const context = getContextFromAction(action);
|
|
|
const {
|
|
|
query,
|
|
|
key = DEFAULT_ENTITY_KEY
|
|
|
} = action;
|
|
|
|
|
|
// An item is considered complete if it is received without an associated
|
|
|
// fields query. Ideally, this would be implemented in such a way where the
|
|
|
// complete aggregate of all fields would satisfy completeness. Since the
|
|
|
// fields are not consistent across all entities, this would require
|
|
|
// introspection on the REST schema for each entity to know which fields
|
|
|
// compose a complete item for that entity.
|
|
|
const queryParts = query ? get_query_parts(query) : {};
|
|
|
const isCompleteQuery = !query || !Array.isArray(queryParts.fields);
|
|
|
return {
|
|
|
...state,
|
|
|
[context]: {
|
|
|
...state[context],
|
|
|
...action.items.reduce((result, item) => {
|
|
|
const itemId = item[key];
|
|
|
|
|
|
// Defer to completeness if already assigned. Technically the
|
|
|
// data may be outdated if receiving items for a field subset.
|
|
|
result[itemId] = state?.[context]?.[itemId] || isCompleteQuery;
|
|
|
return result;
|
|
|
}, {})
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
case 'REMOVE_ITEMS':
|
|
|
return Object.fromEntries(Object.entries(state).map(([itemId, contextState]) => [itemId, removeEntitiesById(contextState, action.itemIds)]));
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer tracking queries state, keyed by stable query key. Each reducer
|
|
|
* query object includes `itemIds` and `requestingPageByPerPage`.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Next state.
|
|
|
*/
|
|
|
const receiveQueries = (0,external_wp_compose_namespaceObject.compose)([
|
|
|
// Limit to matching action type so we don't attempt to replace action on
|
|
|
// an unhandled action.
|
|
|
if_matching_action(action => 'query' in action),
|
|
|
// Inject query parts into action for use both in `onSubKey` and reducer.
|
|
|
replace_action(action => {
|
|
|
// `ifMatchingAction` still passes on initialization, where state is
|
|
|
// undefined and a query is not assigned. Avoid attempting to parse
|
|
|
// parts. `onSubKey` will omit by lack of `stableKey`.
|
|
|
if (action.query) {
|
|
|
return {
|
|
|
...action,
|
|
|
...get_query_parts(action.query)
|
|
|
};
|
|
|
}
|
|
|
return action;
|
|
|
}), on_sub_key('context'),
|
|
|
// Queries shape is shared, but keyed by query `stableKey` part. Original
|
|
|
// reducer tracks only a single query object.
|
|
|
on_sub_key('stableKey')])((state = {}, action) => {
|
|
|
const {
|
|
|
type,
|
|
|
page,
|
|
|
perPage,
|
|
|
key = DEFAULT_ENTITY_KEY
|
|
|
} = action;
|
|
|
if (type !== 'RECEIVE_ITEMS') {
|
|
|
return state;
|
|
|
}
|
|
|
return {
|
|
|
itemIds: getMergedItemIds(state?.itemIds || [], action.items.map(item => item[key]), page, perPage),
|
|
|
meta: action.meta
|
|
|
};
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Reducer tracking queries state.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Next state.
|
|
|
*/
|
|
|
const queries = (state = {}, action) => {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_ITEMS':
|
|
|
return receiveQueries(state, action);
|
|
|
case 'REMOVE_ITEMS':
|
|
|
const removedItems = action.itemIds.reduce((result, itemId) => {
|
|
|
result[itemId] = true;
|
|
|
return result;
|
|
|
}, {});
|
|
|
return Object.fromEntries(Object.entries(state).map(([queryGroup, contextQueries]) => [queryGroup, Object.fromEntries(Object.entries(contextQueries).map(([query, queryItems]) => [query, {
|
|
|
...queryItems,
|
|
|
itemIds: queryItems.itemIds.filter(queryId => !removedItems[queryId])
|
|
|
}]))]));
|
|
|
default:
|
|
|
return state;
|
|
|
}
|
|
|
};
|
|
|
/* harmony default export */ const reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
|
|
|
items,
|
|
|
itemIsComplete,
|
|
|
queries
|
|
|
}));
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/reducer.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @typedef {import('./types').AnyFunction} AnyFunction */
|
|
|
|
|
|
/**
|
|
|
* Reducer managing terms state. Keyed by taxonomy slug, the value is either
|
|
|
* undefined (if no request has been made for given taxonomy), null (if a
|
|
|
* request is in-flight for given taxonomy), or the array of terms for the
|
|
|
* taxonomy.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function terms(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_TERMS':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.taxonomy]: action.terms
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing authors state. Keyed by id.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function users(state = {
|
|
|
byId: {},
|
|
|
queries: {}
|
|
|
}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_USER_QUERY':
|
|
|
return {
|
|
|
byId: {
|
|
|
...state.byId,
|
|
|
// Key users by their ID.
|
|
|
...action.users.reduce((newUsers, user) => ({
|
|
|
...newUsers,
|
|
|
[user.id]: user
|
|
|
}), {})
|
|
|
},
|
|
|
queries: {
|
|
|
...state.queries,
|
|
|
[action.queryID]: action.users.map(user => user.id)
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing current user state.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function currentUser(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_CURRENT_USER':
|
|
|
return action.currentUser;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing taxonomies.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function taxonomies(state = [], action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_TAXONOMIES':
|
|
|
return action.taxonomies;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the current theme.
|
|
|
*
|
|
|
* @param {string|undefined} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {string|undefined} Updated state.
|
|
|
*/
|
|
|
function currentTheme(state = undefined, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_CURRENT_THEME':
|
|
|
return action.currentTheme.stylesheet;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the current global styles id.
|
|
|
*
|
|
|
* @param {string|undefined} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {string|undefined} Updated state.
|
|
|
*/
|
|
|
function currentGlobalStylesId(state = undefined, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_CURRENT_GLOBAL_STYLES_ID':
|
|
|
return action.id;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the theme base global styles.
|
|
|
*
|
|
|
* @param {Record<string, object>} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Record<string, object>} Updated state.
|
|
|
*/
|
|
|
function themeBaseGlobalStyles(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_THEME_GLOBAL_STYLES':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.stylesheet]: action.globalStyles
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the theme global styles variations.
|
|
|
*
|
|
|
* @param {Record<string, object>} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Record<string, object>} Updated state.
|
|
|
*/
|
|
|
function themeGlobalStyleVariations(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_THEME_GLOBAL_STYLE_VARIATIONS':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.stylesheet]: action.variations
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
const withMultiEntityRecordEdits = reducer => (state, action) => {
|
|
|
if (action.type === 'UNDO' || action.type === 'REDO') {
|
|
|
const {
|
|
|
record
|
|
|
} = action;
|
|
|
let newState = state;
|
|
|
record.forEach(({
|
|
|
id: {
|
|
|
kind,
|
|
|
name,
|
|
|
recordId
|
|
|
},
|
|
|
changes
|
|
|
}) => {
|
|
|
newState = reducer(newState, {
|
|
|
type: 'EDIT_ENTITY_RECORD',
|
|
|
kind,
|
|
|
name,
|
|
|
recordId,
|
|
|
edits: Object.entries(changes).reduce((acc, [key, value]) => {
|
|
|
acc[key] = action.type === 'UNDO' ? value.from : value.to;
|
|
|
return acc;
|
|
|
}, {})
|
|
|
});
|
|
|
});
|
|
|
return newState;
|
|
|
}
|
|
|
return reducer(state, action);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Higher Order Reducer for a given entity config. It supports:
|
|
|
*
|
|
|
* - Fetching
|
|
|
* - Editing
|
|
|
* - Saving
|
|
|
*
|
|
|
* @param {Object} entityConfig Entity config.
|
|
|
*
|
|
|
* @return {AnyFunction} Reducer.
|
|
|
*/
|
|
|
function entity(entityConfig) {
|
|
|
return (0,external_wp_compose_namespaceObject.compose)([withMultiEntityRecordEdits,
|
|
|
// Limit to matching action type so we don't attempt to replace action on
|
|
|
// an unhandled action.
|
|
|
if_matching_action(action => action.name && action.kind && action.name === entityConfig.name && action.kind === entityConfig.kind),
|
|
|
// Inject the entity config into the action.
|
|
|
replace_action(action => {
|
|
|
return {
|
|
|
key: entityConfig.key || DEFAULT_ENTITY_KEY,
|
|
|
...action
|
|
|
};
|
|
|
})])((0,external_wp_data_namespaceObject.combineReducers)({
|
|
|
queriedData: reducer,
|
|
|
edits: (state = {}, action) => {
|
|
|
var _action$query$context;
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_ITEMS':
|
|
|
const context = (_action$query$context = action?.query?.context) !== null && _action$query$context !== void 0 ? _action$query$context : 'default';
|
|
|
if (context !== 'default') {
|
|
|
return state;
|
|
|
}
|
|
|
const nextState = {
|
|
|
...state
|
|
|
};
|
|
|
for (const record of action.items) {
|
|
|
const recordId = record[action.key];
|
|
|
const edits = nextState[recordId];
|
|
|
if (!edits) {
|
|
|
continue;
|
|
|
}
|
|
|
const nextEdits = Object.keys(edits).reduce((acc, key) => {
|
|
|
var _record$key$raw;
|
|
|
// If the edited value is still different to the persisted value,
|
|
|
// keep the edited value in edits.
|
|
|
if (
|
|
|
// Edits are the "raw" attribute values, but records may have
|
|
|
// objects with more properties, so we use `get` here for the
|
|
|
// comparison.
|
|
|
!es6_default()(edits[key], (_record$key$raw = record[key]?.raw) !== null && _record$key$raw !== void 0 ? _record$key$raw : record[key]) && (
|
|
|
// Sometimes the server alters the sent value which means
|
|
|
// we need to also remove the edits before the api request.
|
|
|
!action.persistedEdits || !es6_default()(edits[key], action.persistedEdits[key]))) {
|
|
|
acc[key] = edits[key];
|
|
|
}
|
|
|
return acc;
|
|
|
}, {});
|
|
|
if (Object.keys(nextEdits).length) {
|
|
|
nextState[recordId] = nextEdits;
|
|
|
} else {
|
|
|
delete nextState[recordId];
|
|
|
}
|
|
|
}
|
|
|
return nextState;
|
|
|
case 'EDIT_ENTITY_RECORD':
|
|
|
const nextEdits = {
|
|
|
...state[action.recordId],
|
|
|
...action.edits
|
|
|
};
|
|
|
Object.keys(nextEdits).forEach(key => {
|
|
|
// Delete cleared edits so that the properties
|
|
|
// are not considered dirty.
|
|
|
if (nextEdits[key] === undefined) {
|
|
|
delete nextEdits[key];
|
|
|
}
|
|
|
});
|
|
|
return {
|
|
|
...state,
|
|
|
[action.recordId]: nextEdits
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
},
|
|
|
saving: (state = {}, action) => {
|
|
|
switch (action.type) {
|
|
|
case 'SAVE_ENTITY_RECORD_START':
|
|
|
case 'SAVE_ENTITY_RECORD_FINISH':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.recordId]: {
|
|
|
pending: action.type === 'SAVE_ENTITY_RECORD_START',
|
|
|
error: action.error,
|
|
|
isAutosave: action.isAutosave
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
},
|
|
|
deleting: (state = {}, action) => {
|
|
|
switch (action.type) {
|
|
|
case 'DELETE_ENTITY_RECORD_START':
|
|
|
case 'DELETE_ENTITY_RECORD_FINISH':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.recordId]: {
|
|
|
pending: action.type === 'DELETE_ENTITY_RECORD_START',
|
|
|
error: action.error
|
|
|
}
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
},
|
|
|
revisions: (state = {}, action) => {
|
|
|
// Use the same queriedDataReducer shape for revisions.
|
|
|
if (action.type === 'RECEIVE_ITEM_REVISIONS') {
|
|
|
const recordKey = action.recordKey;
|
|
|
delete action.recordKey;
|
|
|
const newState = reducer(state[recordKey], {
|
|
|
...action,
|
|
|
type: 'RECEIVE_ITEMS'
|
|
|
});
|
|
|
return {
|
|
|
...state,
|
|
|
[recordKey]: newState
|
|
|
};
|
|
|
}
|
|
|
if (action.type === 'REMOVE_ITEMS') {
|
|
|
return Object.fromEntries(Object.entries(state).filter(([id]) => !action.itemIds.some(itemId => {
|
|
|
if (Number.isInteger(itemId)) {
|
|
|
return itemId === +id;
|
|
|
}
|
|
|
return itemId === id;
|
|
|
})));
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer keeping track of the registered entities.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function entitiesConfig(state = rootEntitiesConfig, action) {
|
|
|
switch (action.type) {
|
|
|
case 'ADD_ENTITIES':
|
|
|
return [...state, ...action.entities];
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer keeping track of the registered entities config and data.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
const entities = (state = {}, action) => {
|
|
|
const newConfig = entitiesConfig(state.config, action);
|
|
|
|
|
|
// Generates a dynamic reducer for the entities.
|
|
|
let entitiesDataReducer = state.reducer;
|
|
|
if (!entitiesDataReducer || newConfig !== state.config) {
|
|
|
const entitiesByKind = newConfig.reduce((acc, record) => {
|
|
|
const {
|
|
|
kind
|
|
|
} = record;
|
|
|
if (!acc[kind]) {
|
|
|
acc[kind] = [];
|
|
|
}
|
|
|
acc[kind].push(record);
|
|
|
return acc;
|
|
|
}, {});
|
|
|
entitiesDataReducer = (0,external_wp_data_namespaceObject.combineReducers)(Object.entries(entitiesByKind).reduce((memo, [kind, subEntities]) => {
|
|
|
const kindReducer = (0,external_wp_data_namespaceObject.combineReducers)(subEntities.reduce((kindMemo, entityConfig) => ({
|
|
|
...kindMemo,
|
|
|
[entityConfig.name]: entity(entityConfig)
|
|
|
}), {}));
|
|
|
memo[kind] = kindReducer;
|
|
|
return memo;
|
|
|
}, {}));
|
|
|
}
|
|
|
const newData = entitiesDataReducer(state.records, action);
|
|
|
if (newData === state.records && newConfig === state.config && entitiesDataReducer === state.reducer) {
|
|
|
return state;
|
|
|
}
|
|
|
return {
|
|
|
reducer: entitiesDataReducer,
|
|
|
records: newData,
|
|
|
config: newConfig
|
|
|
};
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* @type {UndoManager}
|
|
|
*/
|
|
|
function undoManager(state = (0,build_module.createUndoManager)()) {
|
|
|
return state;
|
|
|
}
|
|
|
function editsReference(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'EDIT_ENTITY_RECORD':
|
|
|
case 'UNDO':
|
|
|
case 'REDO':
|
|
|
return {};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing embed preview data.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function embedPreviews(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_EMBED_PREVIEW':
|
|
|
const {
|
|
|
url,
|
|
|
preview
|
|
|
} = action;
|
|
|
return {
|
|
|
...state,
|
|
|
[url]: preview
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* State which tracks whether the user can perform an action on a REST
|
|
|
* resource.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function userPermissions(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_USER_PERMISSION':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.key]: action.isAllowed
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer returning autosaves keyed by their parent's post id.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function autosaves(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_AUTOSAVES':
|
|
|
const {
|
|
|
postId,
|
|
|
autosaves: autosavesData
|
|
|
} = action;
|
|
|
return {
|
|
|
...state,
|
|
|
[postId]: autosavesData
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
function blockPatterns(state = [], action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_BLOCK_PATTERNS':
|
|
|
return action.patterns;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
function blockPatternCategories(state = [], action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_BLOCK_PATTERN_CATEGORIES':
|
|
|
return action.categories;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
function userPatternCategories(state = [], action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_USER_PATTERN_CATEGORIES':
|
|
|
return action.patternCategories;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
function navigationFallbackId(state = null, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_NAVIGATION_FALLBACK_ID':
|
|
|
return action.fallbackId;
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the theme global styles revisions.
|
|
|
*
|
|
|
* @param {Record<string, object>} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Record<string, object>} Updated state.
|
|
|
*/
|
|
|
function themeGlobalStyleRevisions(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_THEME_GLOBAL_STYLE_REVISIONS':
|
|
|
return {
|
|
|
...state,
|
|
|
[action.currentId]: action.revisions
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Reducer managing the template lookup per query.
|
|
|
*
|
|
|
* @param {Record<string, string>} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Record<string, string>} Updated state.
|
|
|
*/
|
|
|
function defaultTemplates(state = {}, action) {
|
|
|
switch (action.type) {
|
|
|
case 'RECEIVE_DEFAULT_TEMPLATE':
|
|
|
return {
|
|
|
...state,
|
|
|
[JSON.stringify(action.query)]: action.templateId
|
|
|
};
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
/* harmony default export */ const build_module_reducer = ((0,external_wp_data_namespaceObject.combineReducers)({
|
|
|
terms,
|
|
|
users,
|
|
|
currentTheme,
|
|
|
currentGlobalStylesId,
|
|
|
currentUser,
|
|
|
themeGlobalStyleVariations,
|
|
|
themeBaseGlobalStyles,
|
|
|
themeGlobalStyleRevisions,
|
|
|
taxonomies,
|
|
|
entities,
|
|
|
editsReference,
|
|
|
undoManager,
|
|
|
embedPreviews,
|
|
|
userPermissions,
|
|
|
autosaves,
|
|
|
blockPatterns,
|
|
|
blockPatternCategories,
|
|
|
userPatternCategories,
|
|
|
navigationFallbackId,
|
|
|
defaultTemplates
|
|
|
}));
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/rememo/rememo.js
|
|
|
|
|
|
|
|
|
/** @typedef {(...args: any[]) => *[]} GetDependants */
|
|
|
|
|
|
/** @typedef {() => void} Clear */
|
|
|
|
|
|
/**
|
|
|
* @typedef {{
|
|
|
* getDependants: GetDependants,
|
|
|
* clear: Clear
|
|
|
* }} EnhancedSelector
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Internal cache entry.
|
|
|
*
|
|
|
* @typedef CacheNode
|
|
|
*
|
|
|
* @property {?CacheNode|undefined} [prev] Previous node.
|
|
|
* @property {?CacheNode|undefined} [next] Next node.
|
|
|
* @property {*[]} args Function arguments for cache entry.
|
|
|
* @property {*} val Function result.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef Cache
|
|
|
*
|
|
|
* @property {Clear} clear Function to clear cache.
|
|
|
* @property {boolean} [isUniqueByDependants] Whether dependants are valid in
|
|
|
* considering cache uniqueness. A cache is unique if dependents are all arrays
|
|
|
* or objects.
|
|
|
* @property {CacheNode?} [head] Cache head.
|
|
|
* @property {*[]} [lastDependants] Dependants from previous invocation.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Arbitrary value used as key for referencing cache object in WeakMap tree.
|
|
|
*
|
|
|
* @type {{}}
|
|
|
*/
|
|
|
var LEAF_KEY = {};
|
|
|
|
|
|
/**
|
|
|
* Returns the first argument as the sole entry in an array.
|
|
|
*
|
|
|
* @template T
|
|
|
*
|
|
|
* @param {T} value Value to return.
|
|
|
*
|
|
|
* @return {[T]} Value returned as entry in array.
|
|
|
*/
|
|
|
function arrayOf(value) {
|
|
|
return [value];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if the value passed is object-like, or false otherwise. A value
|
|
|
* is object-like if it can support property assignment, e.g. object or array.
|
|
|
*
|
|
|
* @param {*} value Value to test.
|
|
|
*
|
|
|
* @return {boolean} Whether value is object-like.
|
|
|
*/
|
|
|
function isObjectLike(value) {
|
|
|
return !!value && 'object' === typeof value;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Creates and returns a new cache object.
|
|
|
*
|
|
|
* @return {Cache} Cache object.
|
|
|
*/
|
|
|
function createCache() {
|
|
|
/** @type {Cache} */
|
|
|
var cache = {
|
|
|
clear: function () {
|
|
|
cache.head = null;
|
|
|
},
|
|
|
};
|
|
|
|
|
|
return cache;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if entries within the two arrays are strictly equal by
|
|
|
* reference from a starting index.
|
|
|
*
|
|
|
* @param {*[]} a First array.
|
|
|
* @param {*[]} b Second array.
|
|
|
* @param {number} fromIndex Index from which to start comparison.
|
|
|
*
|
|
|
* @return {boolean} Whether arrays are shallowly equal.
|
|
|
*/
|
|
|
function isShallowEqual(a, b, fromIndex) {
|
|
|
var i;
|
|
|
|
|
|
if (a.length !== b.length) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
for (i = fromIndex; i < a.length; i++) {
|
|
|
if (a[i] !== b[i]) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns a memoized selector function. The getDependants function argument is
|
|
|
* called before the memoized selector and is expected to return an immutable
|
|
|
* reference or array of references on which the selector depends for computing
|
|
|
* its own return value. The memoize cache is preserved only as long as those
|
|
|
* dependant references remain the same. If getDependants returns a different
|
|
|
* reference(s), the cache is cleared and the selector value regenerated.
|
|
|
*
|
|
|
* @template {(...args: *[]) => *} S
|
|
|
*
|
|
|
* @param {S} selector Selector function.
|
|
|
* @param {GetDependants=} getDependants Dependant getter returning an array of
|
|
|
* references used in cache bust consideration.
|
|
|
*/
|
|
|
/* harmony default export */ function rememo(selector, getDependants) {
|
|
|
/** @type {WeakMap<*,*>} */
|
|
|
var rootCache;
|
|
|
|
|
|
/** @type {GetDependants} */
|
|
|
var normalizedGetDependants = getDependants ? getDependants : arrayOf;
|
|
|
|
|
|
/**
|
|
|
* Returns the cache for a given dependants array. When possible, a WeakMap
|
|
|
* will be used to create a unique cache for each set of dependants. This
|
|
|
* is feasible due to the nature of WeakMap in allowing garbage collection
|
|
|
* to occur on entries where the key object is no longer referenced. Since
|
|
|
* WeakMap requires the key to be an object, this is only possible when the
|
|
|
* dependant is object-like. The root cache is created as a hierarchy where
|
|
|
* each top-level key is the first entry in a dependants set, the value a
|
|
|
* WeakMap where each key is the next dependant, and so on. This continues
|
|
|
* so long as the dependants are object-like. If no dependants are object-
|
|
|
* like, then the cache is shared across all invocations.
|
|
|
*
|
|
|
* @see isObjectLike
|
|
|
*
|
|
|
* @param {*[]} dependants Selector dependants.
|
|
|
*
|
|
|
* @return {Cache} Cache object.
|
|
|
*/
|
|
|
function getCache(dependants) {
|
|
|
var caches = rootCache,
|
|
|
isUniqueByDependants = true,
|
|
|
i,
|
|
|
dependant,
|
|
|
map,
|
|
|
cache;
|
|
|
|
|
|
for (i = 0; i < dependants.length; i++) {
|
|
|
dependant = dependants[i];
|
|
|
|
|
|
// Can only compose WeakMap from object-like key.
|
|
|
if (!isObjectLike(dependant)) {
|
|
|
isUniqueByDependants = false;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
// Does current segment of cache already have a WeakMap?
|
|
|
if (caches.has(dependant)) {
|
|
|
// Traverse into nested WeakMap.
|
|
|
caches = caches.get(dependant);
|
|
|
} else {
|
|
|
// Create, set, and traverse into a new one.
|
|
|
map = new WeakMap();
|
|
|
caches.set(dependant, map);
|
|
|
caches = map;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// We use an arbitrary (but consistent) object as key for the last item
|
|
|
// in the WeakMap to serve as our running cache.
|
|
|
if (!caches.has(LEAF_KEY)) {
|
|
|
cache = createCache();
|
|
|
cache.isUniqueByDependants = isUniqueByDependants;
|
|
|
caches.set(LEAF_KEY, cache);
|
|
|
}
|
|
|
|
|
|
return caches.get(LEAF_KEY);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Resets root memoization cache.
|
|
|
*/
|
|
|
function clear() {
|
|
|
rootCache = new WeakMap();
|
|
|
}
|
|
|
|
|
|
/* eslint-disable jsdoc/check-param-names */
|
|
|
/**
|
|
|
* The augmented selector call, considering first whether dependants have
|
|
|
* changed before passing it to underlying memoize function.
|
|
|
*
|
|
|
* @param {*} source Source object for derivation.
|
|
|
* @param {...*} extraArgs Additional arguments to pass to selector.
|
|
|
*
|
|
|
* @return {*} Selector result.
|
|
|
*/
|
|
|
/* eslint-enable jsdoc/check-param-names */
|
|
|
function callSelector(/* source, ...extraArgs */) {
|
|
|
var len = arguments.length,
|
|
|
cache,
|
|
|
node,
|
|
|
i,
|
|
|
args,
|
|
|
dependants;
|
|
|
|
|
|
// Create copy of arguments (avoid leaking deoptimization).
|
|
|
args = new Array(len);
|
|
|
for (i = 0; i < len; i++) {
|
|
|
args[i] = arguments[i];
|
|
|
}
|
|
|
|
|
|
dependants = normalizedGetDependants.apply(null, args);
|
|
|
cache = getCache(dependants);
|
|
|
|
|
|
// If not guaranteed uniqueness by dependants (primitive type), shallow
|
|
|
// compare against last dependants and, if references have changed,
|
|
|
// destroy cache to recalculate result.
|
|
|
if (!cache.isUniqueByDependants) {
|
|
|
if (
|
|
|
cache.lastDependants &&
|
|
|
!isShallowEqual(dependants, cache.lastDependants, 0)
|
|
|
) {
|
|
|
cache.clear();
|
|
|
}
|
|
|
|
|
|
cache.lastDependants = dependants;
|
|
|
}
|
|
|
|
|
|
node = cache.head;
|
|
|
while (node) {
|
|
|
// Check whether node arguments match arguments
|
|
|
if (!isShallowEqual(node.args, args, 1)) {
|
|
|
node = node.next;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// At this point we can assume we've found a match
|
|
|
|
|
|
// Surface matched node to head if not already
|
|
|
if (node !== cache.head) {
|
|
|
// Adjust siblings to point to each other.
|
|
|
/** @type {CacheNode} */ (node.prev).next = node.next;
|
|
|
if (node.next) {
|
|
|
node.next.prev = node.prev;
|
|
|
}
|
|
|
|
|
|
node.next = cache.head;
|
|
|
node.prev = null;
|
|
|
/** @type {CacheNode} */ (cache.head).prev = node;
|
|
|
cache.head = node;
|
|
|
}
|
|
|
|
|
|
// Return immediately
|
|
|
return node.val;
|
|
|
}
|
|
|
|
|
|
// No cached value found. Continue to insertion phase:
|
|
|
|
|
|
node = /** @type {CacheNode} */ ({
|
|
|
// Generate the result from original function
|
|
|
val: selector.apply(null, args),
|
|
|
});
|
|
|
|
|
|
// Avoid including the source object in the cache.
|
|
|
args[0] = null;
|
|
|
node.args = args;
|
|
|
|
|
|
// Don't need to check whether node is already head, since it would
|
|
|
// have been returned above already if it was
|
|
|
|
|
|
// Shift existing head down list
|
|
|
if (cache.head) {
|
|
|
cache.head.prev = node;
|
|
|
node.next = cache.head;
|
|
|
}
|
|
|
|
|
|
cache.head = node;
|
|
|
|
|
|
return node.val;
|
|
|
}
|
|
|
|
|
|
callSelector.getDependants = normalizedGetDependants;
|
|
|
callSelector.clear = clear;
|
|
|
clear();
|
|
|
|
|
|
return /** @type {S & EnhancedSelector} */ (callSelector);
|
|
|
}
|
|
|
|
|
|
// EXTERNAL MODULE: ./node_modules/equivalent-key-map/equivalent-key-map.js
|
|
|
var equivalent_key_map = __webpack_require__(3249);
|
|
|
var equivalent_key_map_default = /*#__PURE__*/__webpack_require__.n(equivalent_key_map);
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/queried-data/selectors.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Cache of state keys to EquivalentKeyMap where the inner map tracks queries
|
|
|
* to their resulting items set. WeakMap allows garbage collection on expired
|
|
|
* state references.
|
|
|
*
|
|
|
* @type {WeakMap<Object,EquivalentKeyMap>}
|
|
|
*/
|
|
|
const queriedItemsCacheByState = new WeakMap();
|
|
|
|
|
|
/**
|
|
|
* Returns items for a given query, or null if the items are not known.
|
|
|
*
|
|
|
* @param {Object} state State object.
|
|
|
* @param {?Object} query Optional query.
|
|
|
*
|
|
|
* @return {?Array} Query items.
|
|
|
*/
|
|
|
function getQueriedItemsUncached(state, query) {
|
|
|
const {
|
|
|
stableKey,
|
|
|
page,
|
|
|
perPage,
|
|
|
include,
|
|
|
fields,
|
|
|
context
|
|
|
} = get_query_parts(query);
|
|
|
let itemIds;
|
|
|
if (state.queries?.[context]?.[stableKey]) {
|
|
|
itemIds = state.queries[context][stableKey].itemIds;
|
|
|
}
|
|
|
if (!itemIds) {
|
|
|
return null;
|
|
|
}
|
|
|
const startOffset = perPage === -1 ? 0 : (page - 1) * perPage;
|
|
|
const endOffset = perPage === -1 ? itemIds.length : Math.min(startOffset + perPage, itemIds.length);
|
|
|
const items = [];
|
|
|
for (let i = startOffset; i < endOffset; i++) {
|
|
|
const itemId = itemIds[i];
|
|
|
if (Array.isArray(include) && !include.includes(itemId)) {
|
|
|
continue;
|
|
|
}
|
|
|
if (itemId === undefined) {
|
|
|
continue;
|
|
|
}
|
|
|
// Having a target item ID doesn't guarantee that this object has been queried.
|
|
|
if (!state.items[context]?.hasOwnProperty(itemId)) {
|
|
|
return null;
|
|
|
}
|
|
|
const item = state.items[context][itemId];
|
|
|
let filteredItem;
|
|
|
if (Array.isArray(fields)) {
|
|
|
filteredItem = {};
|
|
|
for (let f = 0; f < fields.length; f++) {
|
|
|
const field = fields[f].split('.');
|
|
|
let value = item;
|
|
|
field.forEach(fieldName => {
|
|
|
value = value?.[fieldName];
|
|
|
});
|
|
|
setNestedValue(filteredItem, field, value);
|
|
|
}
|
|
|
} else {
|
|
|
// If expecting a complete item, validate that completeness, or
|
|
|
// otherwise abort.
|
|
|
if (!state.itemIsComplete[context]?.[itemId]) {
|
|
|
return null;
|
|
|
}
|
|
|
filteredItem = item;
|
|
|
}
|
|
|
items.push(filteredItem);
|
|
|
}
|
|
|
return items;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns items for a given query, or null if the items are not known. Caches
|
|
|
* result both per state (by reference) and per query (by deep equality).
|
|
|
* The caching approach is intended to be durable to query objects which are
|
|
|
* deeply but not referentially equal, since otherwise:
|
|
|
*
|
|
|
* `getQueriedItems( state, {} ) !== getQueriedItems( state, {} )`
|
|
|
*
|
|
|
* @param {Object} state State object.
|
|
|
* @param {?Object} query Optional query.
|
|
|
*
|
|
|
* @return {?Array} Query items.
|
|
|
*/
|
|
|
const getQueriedItems = rememo((state, query = {}) => {
|
|
|
let queriedItemsCache = queriedItemsCacheByState.get(state);
|
|
|
if (queriedItemsCache) {
|
|
|
const queriedItems = queriedItemsCache.get(query);
|
|
|
if (queriedItems !== undefined) {
|
|
|
return queriedItems;
|
|
|
}
|
|
|
} else {
|
|
|
queriedItemsCache = new (equivalent_key_map_default())();
|
|
|
queriedItemsCacheByState.set(state, queriedItemsCache);
|
|
|
}
|
|
|
const items = getQueriedItemsUncached(state, query);
|
|
|
queriedItemsCache.set(query, items);
|
|
|
return items;
|
|
|
});
|
|
|
function getQueriedTotalItems(state, query = {}) {
|
|
|
var _state$queries$contex;
|
|
|
const {
|
|
|
stableKey,
|
|
|
context
|
|
|
} = get_query_parts(query);
|
|
|
return (_state$queries$contex = state.queries?.[context]?.[stableKey]?.meta?.totalItems) !== null && _state$queries$contex !== void 0 ? _state$queries$contex : null;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/is-numeric-id.js
|
|
|
/**
|
|
|
* Checks argument to determine if it's a numeric ID.
|
|
|
* For example, '123' is a numeric ID, but '123abc' is not.
|
|
|
*
|
|
|
* @param {any} id the argument to determine if it's a numeric ID.
|
|
|
* @return {boolean} true if the string is a numeric ID, false otherwise.
|
|
|
*/
|
|
|
function isNumericID(id) {
|
|
|
return /^\s*\d+\s*$/.test(id);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/is-raw-attribute.js
|
|
|
/**
|
|
|
* Checks whether the attribute is a "raw" attribute or not.
|
|
|
*
|
|
|
* @param {Object} entity Entity record.
|
|
|
* @param {string} attribute Attribute name.
|
|
|
*
|
|
|
* @return {boolean} Is the attribute raw
|
|
|
*/
|
|
|
function isRawAttribute(entity, attribute) {
|
|
|
return (entity.rawAttributes || []).includes(attribute);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/selectors.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Shared reference to an empty object for cases where it is important to avoid
|
|
|
* returning a new object reference on every invocation, as in a connected or
|
|
|
* other pure component which performs `shouldComponentUpdate` check on props.
|
|
|
* This should be used as a last resort, since the normalized data should be
|
|
|
* maintained by the reducer result in state.
|
|
|
*/
|
|
|
const EMPTY_OBJECT = {};
|
|
|
|
|
|
/**
|
|
|
* Returns true if a request is in progress for embed preview data, or false
|
|
|
* otherwise.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param url URL the preview would be for.
|
|
|
*
|
|
|
* @return Whether a request is in progress for an embed preview.
|
|
|
*/
|
|
|
const isRequestingEmbedPreview = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, url) => {
|
|
|
return select(STORE_NAME).isResolving('getEmbedPreview', [url]);
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Returns all available authors.
|
|
|
*
|
|
|
* @deprecated since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param query Optional object of query parameters to
|
|
|
* include with request. For valid query parameters see the [Users page](https://developer.wordpress.org/rest-api/reference/users/) in the REST API Handbook and see the arguments for [List Users](https://developer.wordpress.org/rest-api/reference/users/#list-users) and [Retrieve a User](https://developer.wordpress.org/rest-api/reference/users/#retrieve-a-user).
|
|
|
* @return Authors list.
|
|
|
*/
|
|
|
function getAuthors(state, query) {
|
|
|
external_wp_deprecated_default()("select( 'core' ).getAuthors()", {
|
|
|
since: '5.9',
|
|
|
alternative: "select( 'core' ).getUsers({ who: 'authors' })"
|
|
|
});
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
|
|
|
return getUserQueryResults(state, path);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the current user.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return Current user object.
|
|
|
*/
|
|
|
function getCurrentUser(state) {
|
|
|
return state.currentUser;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns all the users returned by a query ID.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param queryID Query ID.
|
|
|
*
|
|
|
* @return Users list.
|
|
|
*/
|
|
|
const getUserQueryResults = rememo((state, queryID) => {
|
|
|
var _state$users$queries$;
|
|
|
const queryResults = (_state$users$queries$ = state.users.queries[queryID]) !== null && _state$users$queries$ !== void 0 ? _state$users$queries$ : [];
|
|
|
return queryResults.map(id => state.users.byId[id]);
|
|
|
}, (state, queryID) => [state.users.queries[queryID], state.users.byId]);
|
|
|
|
|
|
/**
|
|
|
* Returns the loaded entities for the given kind.
|
|
|
*
|
|
|
* @deprecated since WordPress 6.0. Use getEntitiesConfig instead
|
|
|
* @param state Data state.
|
|
|
* @param kind Entity kind.
|
|
|
*
|
|
|
* @return Array of entities with config matching kind.
|
|
|
*/
|
|
|
function getEntitiesByKind(state, kind) {
|
|
|
external_wp_deprecated_default()("wp.data.select( 'core' ).getEntitiesByKind()", {
|
|
|
since: '6.0',
|
|
|
alternative: "wp.data.select( 'core' ).getEntitiesConfig()"
|
|
|
});
|
|
|
return getEntitiesConfig(state, kind);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the loaded entities for the given kind.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param kind Entity kind.
|
|
|
*
|
|
|
* @return Array of entities with config matching kind.
|
|
|
*/
|
|
|
const getEntitiesConfig = rememo((state, kind) => state.entities.config.filter(entity => entity.kind === kind), (state, kind) => state.entities.config);
|
|
|
/**
|
|
|
* Returns the entity config given its kind and name.
|
|
|
*
|
|
|
* @deprecated since WordPress 6.0. Use getEntityConfig instead
|
|
|
* @param state Data state.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
*
|
|
|
* @return Entity config
|
|
|
*/
|
|
|
function getEntity(state, kind, name) {
|
|
|
external_wp_deprecated_default()("wp.data.select( 'core' ).getEntity()", {
|
|
|
since: '6.0',
|
|
|
alternative: "wp.data.select( 'core' ).getEntityConfig()"
|
|
|
});
|
|
|
return getEntityConfig(state, kind, name);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the entity config given its kind and name.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
*
|
|
|
* @return Entity config
|
|
|
*/
|
|
|
function getEntityConfig(state, kind, name) {
|
|
|
return state.entities.config?.find(config => config.kind === kind && config.name === name);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* GetEntityRecord is declared as a *callable interface* with
|
|
|
* two signatures to work around the fact that TypeScript doesn't
|
|
|
* allow currying generic functions:
|
|
|
*
|
|
|
* ```ts
|
|
|
* type CurriedState = F extends ( state: any, ...args: infer P ) => infer R
|
|
|
* ? ( ...args: P ) => R
|
|
|
* : F;
|
|
|
* type Selector = <K extends string | number>(
|
|
|
* state: any,
|
|
|
* kind: K,
|
|
|
* key: K extends string ? 'string value' : false
|
|
|
* ) => K;
|
|
|
* type BadlyInferredSignature = CurriedState< Selector >
|
|
|
* // BadlyInferredSignature evaluates to:
|
|
|
* // (kind: string number, key: false | "string value") => string number
|
|
|
* ```
|
|
|
*
|
|
|
* The signature without the state parameter shipped as CurriedSignature
|
|
|
* is used in the return value of `select( coreStore )`.
|
|
|
*
|
|
|
* See https://github.com/WordPress/gutenberg/pull/41578 for more details.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Returns the Entity's record object by key. Returns `null` if the value is not
|
|
|
* yet received, undefined if the value entity is known to not exist, or the
|
|
|
* entity object if it exists and is received.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param key Record's key
|
|
|
* @param query Optional query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available "Retrieve a [Entity kind]".
|
|
|
*
|
|
|
* @return Record.
|
|
|
*/
|
|
|
const getEntityRecord = rememo((state, kind, name, key, query) => {
|
|
|
var _query$context;
|
|
|
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
|
|
|
if (!queriedState) {
|
|
|
return undefined;
|
|
|
}
|
|
|
const context = (_query$context = query?.context) !== null && _query$context !== void 0 ? _query$context : 'default';
|
|
|
if (query === undefined) {
|
|
|
// If expecting a complete item, validate that completeness.
|
|
|
if (!queriedState.itemIsComplete[context]?.[key]) {
|
|
|
return undefined;
|
|
|
}
|
|
|
return queriedState.items[context][key];
|
|
|
}
|
|
|
const item = queriedState.items[context]?.[key];
|
|
|
if (item && query._fields) {
|
|
|
var _getNormalizedCommaSe;
|
|
|
const filteredItem = {};
|
|
|
const fields = (_getNormalizedCommaSe = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe !== void 0 ? _getNormalizedCommaSe : [];
|
|
|
for (let f = 0; f < fields.length; f++) {
|
|
|
const field = fields[f].split('.');
|
|
|
let value = item;
|
|
|
field.forEach(fieldName => {
|
|
|
value = value?.[fieldName];
|
|
|
});
|
|
|
setNestedValue(filteredItem, field, value);
|
|
|
}
|
|
|
return filteredItem;
|
|
|
}
|
|
|
return item;
|
|
|
}, (state, kind, name, recordId, query) => {
|
|
|
var _query$context2;
|
|
|
const context = (_query$context2 = query?.context) !== null && _query$context2 !== void 0 ? _query$context2 : 'default';
|
|
|
return [state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Normalizes `recordKey`s that look like numeric IDs to numbers.
|
|
|
*
|
|
|
* @param args EntityRecordArgs the selector arguments.
|
|
|
* @return EntityRecordArgs the normalized arguments.
|
|
|
*/
|
|
|
getEntityRecord.__unstableNormalizeArgs = args => {
|
|
|
const newArgs = [...args];
|
|
|
const recordKey = newArgs?.[2];
|
|
|
|
|
|
// If recordKey looks to be a numeric ID then coerce to number.
|
|
|
newArgs[2] = isNumericID(recordKey) ? Number(recordKey) : recordKey;
|
|
|
return newArgs;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns the Entity's record object by key. Doesn't trigger a resolver nor requests the entity records from the API if the entity record isn't available in the local state.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param key Record's key
|
|
|
*
|
|
|
* @return Record.
|
|
|
*/
|
|
|
function __experimentalGetEntityRecordNoResolver(state, kind, name, key) {
|
|
|
return getEntityRecord(state, kind, name, key);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the entity's record object by key,
|
|
|
* with its attributes mapped to their raw values.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param key Record's key.
|
|
|
*
|
|
|
* @return Object with the entity's raw attributes.
|
|
|
*/
|
|
|
const getRawEntityRecord = rememo((state, kind, name, key) => {
|
|
|
const record = getEntityRecord(state, kind, name, key);
|
|
|
return record && Object.keys(record).reduce((accumulator, _key) => {
|
|
|
if (isRawAttribute(getEntityConfig(state, kind, name), _key)) {
|
|
|
var _record$_key$raw;
|
|
|
// Because edits are the "raw" attribute values,
|
|
|
// we return those from record selectors to make rendering,
|
|
|
// comparisons, and joins with edits easier.
|
|
|
accumulator[_key] = (_record$_key$raw = record[_key]?.raw) !== null && _record$_key$raw !== void 0 ? _record$_key$raw : record[_key];
|
|
|
} else {
|
|
|
accumulator[_key] = record[_key];
|
|
|
}
|
|
|
return accumulator;
|
|
|
}, {});
|
|
|
}, (state, kind, name, recordId, query) => {
|
|
|
var _query$context3;
|
|
|
const context = (_query$context3 = query?.context) !== null && _query$context3 !== void 0 ? _query$context3 : 'default';
|
|
|
return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData?.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData?.itemIsComplete[context]?.[recordId]];
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Returns true if records have been received for the given set of parameters,
|
|
|
* or false otherwise.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param query Optional terms query. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
|
|
|
*
|
|
|
* @return Whether entity records have been received.
|
|
|
*/
|
|
|
function hasEntityRecords(state, kind, name, query) {
|
|
|
return Array.isArray(getEntityRecords(state, kind, name, query));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* GetEntityRecord is declared as a *callable interface* with
|
|
|
* two signatures to work around the fact that TypeScript doesn't
|
|
|
* allow currying generic functions.
|
|
|
*
|
|
|
* @see GetEntityRecord
|
|
|
* @see https://github.com/WordPress/gutenberg/pull/41578
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Returns the Entity's records.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param query Optional terms query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
|
|
|
*
|
|
|
* @return Records.
|
|
|
*/
|
|
|
const getEntityRecords = (state, kind, name, query) => {
|
|
|
// Queried data state is prepopulated for all known entities. If this is not
|
|
|
// assigned for the given parameters, then it is known to not exist.
|
|
|
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
|
|
|
if (!queriedState) {
|
|
|
return null;
|
|
|
}
|
|
|
return getQueriedItems(queriedState, query);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns the Entity's total available records for a given query (ignoring pagination).
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param query Optional terms query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
|
|
|
*
|
|
|
* @return number | null.
|
|
|
*/
|
|
|
const getEntityRecordsTotalItems = (state, kind, name, query) => {
|
|
|
// Queried data state is prepopulated for all known entities. If this is not
|
|
|
// assigned for the given parameters, then it is known to not exist.
|
|
|
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
|
|
|
if (!queriedState) {
|
|
|
return null;
|
|
|
}
|
|
|
return getQueriedTotalItems(queriedState, query);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns the number of available pages for the given query.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param query Optional terms query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see the [Reference](https://developer.wordpress.org/rest-api/reference/) in the REST API Handbook and select the entity kind. Then see the arguments available for "List [Entity kind]s".
|
|
|
*
|
|
|
* @return number | null.
|
|
|
*/
|
|
|
const getEntityRecordsTotalPages = (state, kind, name, query) => {
|
|
|
// Queried data state is prepopulated for all known entities. If this is not
|
|
|
// assigned for the given parameters, then it is known to not exist.
|
|
|
const queriedState = state.entities.records?.[kind]?.[name]?.queriedData;
|
|
|
if (!queriedState) {
|
|
|
return null;
|
|
|
}
|
|
|
if (query.per_page === -1) return 1;
|
|
|
const totalItems = getQueriedTotalItems(queriedState, query);
|
|
|
if (!totalItems) return totalItems;
|
|
|
return Math.ceil(totalItems / query.per_page);
|
|
|
};
|
|
|
/**
|
|
|
* Returns the list of dirty entity records.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return The list of updated records
|
|
|
*/
|
|
|
const __experimentalGetDirtyEntityRecords = rememo(state => {
|
|
|
const {
|
|
|
entities: {
|
|
|
records
|
|
|
}
|
|
|
} = state;
|
|
|
const dirtyRecords = [];
|
|
|
Object.keys(records).forEach(kind => {
|
|
|
Object.keys(records[kind]).forEach(name => {
|
|
|
const primaryKeys = Object.keys(records[kind][name].edits).filter(primaryKey =>
|
|
|
// The entity record must exist (not be deleted),
|
|
|
// and it must have edits.
|
|
|
getEntityRecord(state, kind, name, primaryKey) && hasEditsForEntityRecord(state, kind, name, primaryKey));
|
|
|
if (primaryKeys.length) {
|
|
|
const entityConfig = getEntityConfig(state, kind, name);
|
|
|
primaryKeys.forEach(primaryKey => {
|
|
|
const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
|
|
|
dirtyRecords.push({
|
|
|
// We avoid using primaryKey because it's transformed into a string
|
|
|
// when it's used as an object key.
|
|
|
key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
|
|
|
title: entityConfig?.getTitle?.(entityRecord) || '',
|
|
|
name,
|
|
|
kind
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
return dirtyRecords;
|
|
|
}, state => [state.entities.records]);
|
|
|
|
|
|
/**
|
|
|
* Returns the list of entities currently being saved.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return The list of records being saved.
|
|
|
*/
|
|
|
const __experimentalGetEntitiesBeingSaved = rememo(state => {
|
|
|
const {
|
|
|
entities: {
|
|
|
records
|
|
|
}
|
|
|
} = state;
|
|
|
const recordsBeingSaved = [];
|
|
|
Object.keys(records).forEach(kind => {
|
|
|
Object.keys(records[kind]).forEach(name => {
|
|
|
const primaryKeys = Object.keys(records[kind][name].saving).filter(primaryKey => isSavingEntityRecord(state, kind, name, primaryKey));
|
|
|
if (primaryKeys.length) {
|
|
|
const entityConfig = getEntityConfig(state, kind, name);
|
|
|
primaryKeys.forEach(primaryKey => {
|
|
|
const entityRecord = getEditedEntityRecord(state, kind, name, primaryKey);
|
|
|
recordsBeingSaved.push({
|
|
|
// We avoid using primaryKey because it's transformed into a string
|
|
|
// when it's used as an object key.
|
|
|
key: entityRecord ? entityRecord[entityConfig.key || DEFAULT_ENTITY_KEY] : undefined,
|
|
|
title: entityConfig?.getTitle?.(entityRecord) || '',
|
|
|
name,
|
|
|
kind
|
|
|
});
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
return recordsBeingSaved;
|
|
|
}, state => [state.entities.records]);
|
|
|
|
|
|
/**
|
|
|
* Returns the specified entity record's edits.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return The entity record's edits.
|
|
|
*/
|
|
|
function getEntityRecordEdits(state, kind, name, recordId) {
|
|
|
return state.entities.records?.[kind]?.[name]?.edits?.[recordId];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the specified entity record's non transient edits.
|
|
|
*
|
|
|
* Transient edits don't create an undo level, and
|
|
|
* are not considered for change detection.
|
|
|
* They are defined in the entity's config.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return The entity record's non transient edits.
|
|
|
*/
|
|
|
const getEntityRecordNonTransientEdits = rememo((state, kind, name, recordId) => {
|
|
|
const {
|
|
|
transientEdits
|
|
|
} = getEntityConfig(state, kind, name) || {};
|
|
|
const edits = getEntityRecordEdits(state, kind, name, recordId) || {};
|
|
|
if (!transientEdits) {
|
|
|
return edits;
|
|
|
}
|
|
|
return Object.keys(edits).reduce((acc, key) => {
|
|
|
if (!transientEdits[key]) {
|
|
|
acc[key] = edits[key];
|
|
|
}
|
|
|
return acc;
|
|
|
}, {});
|
|
|
}, (state, kind, name, recordId) => [state.entities.config, state.entities.records?.[kind]?.[name]?.edits?.[recordId]]);
|
|
|
|
|
|
/**
|
|
|
* Returns true if the specified entity record has edits,
|
|
|
* and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return Whether the entity record has edits or not.
|
|
|
*/
|
|
|
function hasEditsForEntityRecord(state, kind, name, recordId) {
|
|
|
return isSavingEntityRecord(state, kind, name, recordId) || Object.keys(getEntityRecordNonTransientEdits(state, kind, name, recordId)).length > 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the specified entity record, merged with its edits.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return The entity record, merged with its edits.
|
|
|
*/
|
|
|
const getEditedEntityRecord = rememo((state, kind, name, recordId) => ({
|
|
|
...getRawEntityRecord(state, kind, name, recordId),
|
|
|
...getEntityRecordEdits(state, kind, name, recordId)
|
|
|
}), (state, kind, name, recordId, query) => {
|
|
|
var _query$context4;
|
|
|
const context = (_query$context4 = query?.context) !== null && _query$context4 !== void 0 ? _query$context4 : 'default';
|
|
|
return [state.entities.config, state.entities.records?.[kind]?.[name]?.queriedData.items[context]?.[recordId], state.entities.records?.[kind]?.[name]?.queriedData.itemIsComplete[context]?.[recordId], state.entities.records?.[kind]?.[name]?.edits?.[recordId]];
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Returns true if the specified entity record is autosaving, and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return Whether the entity record is autosaving or not.
|
|
|
*/
|
|
|
function isAutosavingEntityRecord(state, kind, name, recordId) {
|
|
|
var _state$entities$recor;
|
|
|
const {
|
|
|
pending,
|
|
|
isAutosave
|
|
|
} = (_state$entities$recor = state.entities.records?.[kind]?.[name]?.saving?.[recordId]) !== null && _state$entities$recor !== void 0 ? _state$entities$recor : {};
|
|
|
return Boolean(pending && isAutosave);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if the specified entity record is saving, and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return Whether the entity record is saving or not.
|
|
|
*/
|
|
|
function isSavingEntityRecord(state, kind, name, recordId) {
|
|
|
var _state$entities$recor2;
|
|
|
return (_state$entities$recor2 = state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.pending) !== null && _state$entities$recor2 !== void 0 ? _state$entities$recor2 : false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if the specified entity record is deleting, and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return Whether the entity record is deleting or not.
|
|
|
*/
|
|
|
function isDeletingEntityRecord(state, kind, name, recordId) {
|
|
|
var _state$entities$recor3;
|
|
|
return (_state$entities$recor3 = state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.pending) !== null && _state$entities$recor3 !== void 0 ? _state$entities$recor3 : false;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the specified entity record's last save error.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return The entity record's save error.
|
|
|
*/
|
|
|
function getLastEntitySaveError(state, kind, name, recordId) {
|
|
|
return state.entities.records?.[kind]?.[name]?.saving?.[recordId]?.error;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the specified entity record's last delete error.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record ID.
|
|
|
*
|
|
|
* @return The entity record's save error.
|
|
|
*/
|
|
|
function getLastEntityDeleteError(state, kind, name, recordId) {
|
|
|
return state.entities.records?.[kind]?.[name]?.deleting?.[recordId]?.error;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the previous edit from the current undo offset
|
|
|
* for the entity records edits history, if any.
|
|
|
*
|
|
|
* @deprecated since 6.3
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return The edit.
|
|
|
*/
|
|
|
function getUndoEdit(state) {
|
|
|
external_wp_deprecated_default()("select( 'core' ).getUndoEdit()", {
|
|
|
since: '6.3'
|
|
|
});
|
|
|
return undefined;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the next edit from the current undo offset
|
|
|
* for the entity records edits history, if any.
|
|
|
*
|
|
|
* @deprecated since 6.3
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return The edit.
|
|
|
*/
|
|
|
function getRedoEdit(state) {
|
|
|
external_wp_deprecated_default()("select( 'core' ).getRedoEdit()", {
|
|
|
since: '6.3'
|
|
|
});
|
|
|
return undefined;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if there is a previous edit from the current undo offset
|
|
|
* for the entity records edits history, and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return Whether there is a previous edit or not.
|
|
|
*/
|
|
|
function hasUndo(state) {
|
|
|
return state.undoManager.hasUndo();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if there is a next edit from the current undo offset
|
|
|
* for the entity records edits history, and false otherwise.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return Whether there is a next edit or not.
|
|
|
*/
|
|
|
function hasRedo(state) {
|
|
|
return state.undoManager.hasRedo();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Return the current theme.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return The current theme.
|
|
|
*/
|
|
|
function getCurrentTheme(state) {
|
|
|
if (!state.currentTheme) {
|
|
|
return null;
|
|
|
}
|
|
|
return getEntityRecord(state, 'root', 'theme', state.currentTheme);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Return the ID of the current global styles object.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return The current global styles ID.
|
|
|
*/
|
|
|
function __experimentalGetCurrentGlobalStylesId(state) {
|
|
|
return state.currentGlobalStylesId;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Return theme supports data in the index.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return Index data.
|
|
|
*/
|
|
|
function getThemeSupports(state) {
|
|
|
var _getCurrentTheme$them;
|
|
|
return (_getCurrentTheme$them = getCurrentTheme(state)?.theme_supports) !== null && _getCurrentTheme$them !== void 0 ? _getCurrentTheme$them : EMPTY_OBJECT;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the embed preview for the given URL.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param url Embedded URL.
|
|
|
*
|
|
|
* @return Undefined if the preview has not been fetched, otherwise, the preview fetched from the embed preview API.
|
|
|
*/
|
|
|
function getEmbedPreview(state, url) {
|
|
|
return state.embedPreviews[url];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Determines if the returned preview is an oEmbed link fallback.
|
|
|
*
|
|
|
* WordPress can be configured to return a simple link to a URL if it is not embeddable.
|
|
|
* We need to be able to determine if a URL is embeddable or not, based on what we
|
|
|
* get back from the oEmbed preview API.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param url Embedded URL.
|
|
|
*
|
|
|
* @return Is the preview for the URL an oEmbed link fallback.
|
|
|
*/
|
|
|
function isPreviewEmbedFallback(state, url) {
|
|
|
const preview = state.embedPreviews[url];
|
|
|
const oEmbedLinkCheck = '<a href="' + url + '">' + url + '</a>';
|
|
|
if (!preview) {
|
|
|
return false;
|
|
|
}
|
|
|
return preview.html === oEmbedLinkCheck;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns whether the current user can perform the given action on the given
|
|
|
* REST resource.
|
|
|
*
|
|
|
* Calling this may trigger an OPTIONS request to the REST API via the
|
|
|
* `canUser()` resolver.
|
|
|
*
|
|
|
* https://developer.wordpress.org/rest-api/reference/
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param action Action to check. One of: 'create', 'read', 'update', 'delete'.
|
|
|
* @param resource REST resource to check, e.g. 'media' or 'posts'.
|
|
|
* @param id Optional ID of the rest resource to check.
|
|
|
*
|
|
|
* @return Whether or not the user can perform the action,
|
|
|
* or `undefined` if the OPTIONS request is still being made.
|
|
|
*/
|
|
|
function canUser(state, action, resource, id) {
|
|
|
const key = [action, resource, id].filter(Boolean).join('/');
|
|
|
return state.userPermissions[key];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns whether the current user can edit the given entity.
|
|
|
*
|
|
|
* Calling this may trigger an OPTIONS request to the REST API via the
|
|
|
* `canUser()` resolver.
|
|
|
*
|
|
|
* https://developer.wordpress.org/rest-api/reference/
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordId Record's id.
|
|
|
* @return Whether or not the user can edit,
|
|
|
* or `undefined` if the OPTIONS request is still being made.
|
|
|
*/
|
|
|
function canUserEditEntityRecord(state, kind, name, recordId) {
|
|
|
const entityConfig = getEntityConfig(state, kind, name);
|
|
|
if (!entityConfig) {
|
|
|
return false;
|
|
|
}
|
|
|
const resource = entityConfig.__unstable_rest_base;
|
|
|
return canUser(state, 'update', resource, recordId);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the latest autosaves for the post.
|
|
|
*
|
|
|
* May return multiple autosaves since the backend stores one autosave per
|
|
|
* author for each post.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param postType The type of the parent post.
|
|
|
* @param postId The id of the parent post.
|
|
|
*
|
|
|
* @return An array of autosaves for the post, or undefined if there is none.
|
|
|
*/
|
|
|
function getAutosaves(state, postType, postId) {
|
|
|
return state.autosaves[postId];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the autosave for the post and author.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param postType The type of the parent post.
|
|
|
* @param postId The id of the parent post.
|
|
|
* @param authorId The id of the author.
|
|
|
*
|
|
|
* @return The autosave for the post and author.
|
|
|
*/
|
|
|
function getAutosave(state, postType, postId, authorId) {
|
|
|
if (authorId === undefined) {
|
|
|
return;
|
|
|
}
|
|
|
const autosaves = state.autosaves[postId];
|
|
|
return autosaves?.find(autosave => autosave.author === authorId);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns true if the REST request for autosaves has completed.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
* @param postType The type of the parent post.
|
|
|
* @param postId The id of the parent post.
|
|
|
*
|
|
|
* @return True if the REST request was completed. False otherwise.
|
|
|
*/
|
|
|
const hasFetchedAutosaves = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => (state, postType, postId) => {
|
|
|
return select(STORE_NAME).hasFinishedResolution('getAutosaves', [postType, postId]);
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Returns a new reference when edited values have changed. This is useful in
|
|
|
* inferring where an edit has been made between states by comparison of the
|
|
|
* return values using strict equality.
|
|
|
*
|
|
|
* @example
|
|
|
*
|
|
|
* ```
|
|
|
* const hasEditOccurred = (
|
|
|
* getReferenceByDistinctEdits( beforeState ) !==
|
|
|
* getReferenceByDistinctEdits( afterState )
|
|
|
* );
|
|
|
* ```
|
|
|
*
|
|
|
* @param state Editor state.
|
|
|
*
|
|
|
* @return A value whose reference will change only when an edit occurs.
|
|
|
*/
|
|
|
function getReferenceByDistinctEdits(state) {
|
|
|
return state.editsReference;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the frontend template used for a given link.
|
|
|
*
|
|
|
* @param state Editor state.
|
|
|
* @param link Link.
|
|
|
*
|
|
|
* @return The template record.
|
|
|
*/
|
|
|
function __experimentalGetTemplateForLink(state, link) {
|
|
|
const records = getEntityRecords(state, 'postType', 'wp_template', {
|
|
|
'find-template': link
|
|
|
});
|
|
|
if (records?.length) {
|
|
|
return getEditedEntityRecord(state, 'postType', 'wp_template', records[0].id);
|
|
|
}
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the current theme's base global styles
|
|
|
*
|
|
|
* @param state Editor state.
|
|
|
*
|
|
|
* @return The Global Styles object.
|
|
|
*/
|
|
|
function __experimentalGetCurrentThemeBaseGlobalStyles(state) {
|
|
|
const currentTheme = getCurrentTheme(state);
|
|
|
if (!currentTheme) {
|
|
|
return null;
|
|
|
}
|
|
|
return state.themeBaseGlobalStyles[currentTheme.stylesheet];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Return the ID of the current global styles object.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return The current global styles ID.
|
|
|
*/
|
|
|
function __experimentalGetCurrentThemeGlobalStylesVariations(state) {
|
|
|
const currentTheme = getCurrentTheme(state);
|
|
|
if (!currentTheme) {
|
|
|
return null;
|
|
|
}
|
|
|
return state.themeGlobalStyleVariations[currentTheme.stylesheet];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the list of registered block patterns.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return Block pattern list.
|
|
|
*/
|
|
|
function getBlockPatterns(state) {
|
|
|
return state.blockPatterns;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the list of registered block pattern categories.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return Block pattern category list.
|
|
|
*/
|
|
|
function getBlockPatternCategories(state) {
|
|
|
return state.blockPatternCategories;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the registered user pattern categories.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return User patterns category array.
|
|
|
*/
|
|
|
|
|
|
function getUserPatternCategories(state) {
|
|
|
return state.userPatternCategories;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the revisions of the current global styles theme.
|
|
|
*
|
|
|
* @deprecated since WordPress 6.5.0. Callers should use `select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )` instead, where `recordKey` is the id of the global styles parent post.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
*
|
|
|
* @return The current global styles.
|
|
|
*/
|
|
|
function getCurrentThemeGlobalStylesRevisions(state) {
|
|
|
external_wp_deprecated_default()("select( 'core' ).getCurrentThemeGlobalStylesRevisions()", {
|
|
|
since: '6.5.0',
|
|
|
alternative: "select( 'core' ).getRevisions( 'root', 'globalStyles', ${ recordKey } )"
|
|
|
});
|
|
|
const currentGlobalStylesId = __experimentalGetCurrentGlobalStylesId(state);
|
|
|
if (!currentGlobalStylesId) {
|
|
|
return null;
|
|
|
}
|
|
|
return state.themeGlobalStyleRevisions[currentGlobalStylesId];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns the default template use to render a given query.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @param query Query.
|
|
|
*
|
|
|
* @return The default template id for the given query.
|
|
|
*/
|
|
|
function getDefaultTemplateId(state, query) {
|
|
|
return state.defaultTemplates[JSON.stringify(query)];
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Returns an entity's revisions.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordKey The key of the entity record whose revisions you want to fetch.
|
|
|
* @param query Optional query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [Entity kind]".
|
|
|
*
|
|
|
* @return Record.
|
|
|
*/
|
|
|
const getRevisions = (state, kind, name, recordKey, query) => {
|
|
|
const queriedStateRevisions = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
|
|
|
if (!queriedStateRevisions) {
|
|
|
return null;
|
|
|
}
|
|
|
return getQueriedItems(queriedStateRevisions, query);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Returns a single, specific revision of a parent entity.
|
|
|
*
|
|
|
* @param state State tree
|
|
|
* @param kind Entity kind.
|
|
|
* @param name Entity name.
|
|
|
* @param recordKey The key of the entity record whose revisions you want to fetch.
|
|
|
* @param revisionKey The revision's key.
|
|
|
* @param query Optional query. If requesting specific
|
|
|
* fields, fields must always include the ID. For valid query parameters see revisions schema in [the REST API Handbook](https://developer.wordpress.org/rest-api/reference/). Then see the arguments available "Retrieve a [entity kind]".
|
|
|
*
|
|
|
* @return Record.
|
|
|
*/
|
|
|
const getRevision = rememo((state, kind, name, recordKey, revisionKey, query) => {
|
|
|
var _query$context5;
|
|
|
const queriedState = state.entities.records?.[kind]?.[name]?.revisions?.[recordKey];
|
|
|
if (!queriedState) {
|
|
|
return undefined;
|
|
|
}
|
|
|
const context = (_query$context5 = query?.context) !== null && _query$context5 !== void 0 ? _query$context5 : 'default';
|
|
|
if (query === undefined) {
|
|
|
// If expecting a complete item, validate that completeness.
|
|
|
if (!queriedState.itemIsComplete[context]?.[revisionKey]) {
|
|
|
return undefined;
|
|
|
}
|
|
|
return queriedState.items[context][revisionKey];
|
|
|
}
|
|
|
const item = queriedState.items[context]?.[revisionKey];
|
|
|
if (item && query._fields) {
|
|
|
var _getNormalizedCommaSe2;
|
|
|
const filteredItem = {};
|
|
|
const fields = (_getNormalizedCommaSe2 = get_normalized_comma_separable(query._fields)) !== null && _getNormalizedCommaSe2 !== void 0 ? _getNormalizedCommaSe2 : [];
|
|
|
for (let f = 0; f < fields.length; f++) {
|
|
|
const field = fields[f].split('.');
|
|
|
let value = item;
|
|
|
field.forEach(fieldName => {
|
|
|
value = value?.[fieldName];
|
|
|
});
|
|
|
setNestedValue(filteredItem, field, value);
|
|
|
}
|
|
|
return filteredItem;
|
|
|
}
|
|
|
return item;
|
|
|
}, (state, kind, name, recordKey, revisionKey, query) => {
|
|
|
var _query$context6;
|
|
|
const context = (_query$context6 = query?.context) !== null && _query$context6 !== void 0 ? _query$context6 : 'default';
|
|
|
return [state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.items?.[context]?.[revisionKey], state.entities.records?.[kind]?.[name]?.revisions?.[recordKey]?.itemIsComplete?.[context]?.[revisionKey]];
|
|
|
});
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/private-selectors.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Returns the previous edit from the current undo offset
|
|
|
* for the entity records edits history, if any.
|
|
|
*
|
|
|
* @param state State tree.
|
|
|
*
|
|
|
* @return The undo manager.
|
|
|
*/
|
|
|
function getUndoManager(state) {
|
|
|
return state.undoManager;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Retrieve the fallback Navigation.
|
|
|
*
|
|
|
* @param state Data state.
|
|
|
* @return The ID for the fallback Navigation post.
|
|
|
*/
|
|
|
function getNavigationFallbackId(state) {
|
|
|
return state.navigationFallbackId;
|
|
|
}
|
|
|
const getBlockPatternsForPostType = (0,external_wp_data_namespaceObject.createRegistrySelector)(select => rememo((state, postType) => select(STORE_NAME).getBlockPatterns().filter(({
|
|
|
postTypes
|
|
|
}) => !postTypes || Array.isArray(postTypes) && postTypes.includes(postType)), () => [select(STORE_NAME).getBlockPatterns()]));
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/camel-case/dist.es2015/index.js
|
|
|
|
|
|
|
|
|
function camelCaseTransform(input, index) {
|
|
|
if (index === 0)
|
|
|
return input.toLowerCase();
|
|
|
return pascalCaseTransform(input, index);
|
|
|
}
|
|
|
function camelCaseTransformMerge(input, index) {
|
|
|
if (index === 0)
|
|
|
return input.toLowerCase();
|
|
|
return pascalCaseTransformMerge(input);
|
|
|
}
|
|
|
function camelCase(input, options) {
|
|
|
if (options === void 0) { options = {}; }
|
|
|
return pascalCase(input, __assign({ transform: camelCaseTransform }, options));
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: external ["wp","htmlEntities"]
|
|
|
const external_wp_htmlEntities_namespaceObject = window["wp"]["htmlEntities"];
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/utils/forward-resolver.js
|
|
|
/**
|
|
|
* Higher-order function which forward the resolution to another resolver with the same arguments.
|
|
|
*
|
|
|
* @param {string} resolverName forwarded resolver.
|
|
|
*
|
|
|
* @return {Function} Enhanced resolver.
|
|
|
*/
|
|
|
const forwardResolver = resolverName => (...args) => async ({
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
await resolveSelect[resolverName](...args);
|
|
|
};
|
|
|
/* harmony default export */ const forward_resolver = (forwardResolver);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/fetch/__experimental-fetch-link-suggestions.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Filters the search by type
|
|
|
*
|
|
|
* @typedef { 'attachment' | 'post' | 'term' | 'post-format' } WPLinkSearchType
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* A link with an id may be of kind post-type or taxonomy
|
|
|
*
|
|
|
* @typedef { 'post-type' | 'taxonomy' } WPKind
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef WPLinkSearchOptions
|
|
|
*
|
|
|
* @property {boolean} [isInitialSuggestions] Displays initial search suggestions, when true.
|
|
|
* @property {WPLinkSearchType} [type] Filters by search type.
|
|
|
* @property {string} [subtype] Slug of the post-type or taxonomy.
|
|
|
* @property {number} [page] Which page of results to return.
|
|
|
* @property {number} [perPage] Search results per page.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef WPLinkSearchResult
|
|
|
*
|
|
|
* @property {number} id Post or term id.
|
|
|
* @property {string} url Link url.
|
|
|
* @property {string} title Title of the link.
|
|
|
* @property {string} type The taxonomy or post type slug or type URL.
|
|
|
* @property {WPKind} [kind] Link kind of post-type or taxonomy
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef WPLinkSearchResultAugments
|
|
|
*
|
|
|
* @property {{kind: WPKind}} [meta] Contains kind information.
|
|
|
* @property {WPKind} [subtype] Optional subtype if it exists.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef {WPLinkSearchResult & WPLinkSearchResultAugments} WPLinkSearchResultAugmented
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* @typedef WPEditorSettings
|
|
|
*
|
|
|
* @property {boolean} [ disablePostFormats ] Disables post formats, when true.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Fetches link suggestions from the API.
|
|
|
*
|
|
|
* @async
|
|
|
* @param {string} search
|
|
|
* @param {WPLinkSearchOptions} [searchOptions]
|
|
|
* @param {WPEditorSettings} [settings]
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { __experimentalFetchLinkSuggestions as fetchLinkSuggestions } from '@wordpress/core-data';
|
|
|
*
|
|
|
* //...
|
|
|
*
|
|
|
* export function initialize( id, settings ) {
|
|
|
*
|
|
|
* settings.__experimentalFetchLinkSuggestions = (
|
|
|
* search,
|
|
|
* searchOptions
|
|
|
* ) => fetchLinkSuggestions( search, searchOptions, settings );
|
|
|
* ```
|
|
|
* @return {Promise< WPLinkSearchResult[] >} List of search suggestions
|
|
|
*/
|
|
|
const fetchLinkSuggestions = async (search, searchOptions = {}, settings = {}) => {
|
|
|
const {
|
|
|
isInitialSuggestions = false,
|
|
|
initialSuggestionsSearchOptions = undefined
|
|
|
} = searchOptions;
|
|
|
const {
|
|
|
disablePostFormats = false
|
|
|
} = settings;
|
|
|
let {
|
|
|
type = undefined,
|
|
|
subtype = undefined,
|
|
|
page = undefined,
|
|
|
perPage = isInitialSuggestions ? 3 : 20
|
|
|
} = searchOptions;
|
|
|
|
|
|
/** @type {Promise<WPLinkSearchResult>[]} */
|
|
|
const queries = [];
|
|
|
if (isInitialSuggestions && initialSuggestionsSearchOptions) {
|
|
|
type = initialSuggestionsSearchOptions.type || type;
|
|
|
subtype = initialSuggestionsSearchOptions.subtype || subtype;
|
|
|
page = initialSuggestionsSearchOptions.page || page;
|
|
|
perPage = initialSuggestionsSearchOptions.perPage || perPage;
|
|
|
}
|
|
|
if (!type || type === 'post') {
|
|
|
queries.push(external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
|
|
|
search,
|
|
|
page,
|
|
|
per_page: perPage,
|
|
|
type: 'post',
|
|
|
subtype
|
|
|
})
|
|
|
}).then(results => {
|
|
|
return results.map(result => {
|
|
|
return {
|
|
|
...result,
|
|
|
meta: {
|
|
|
kind: 'post-type',
|
|
|
subtype
|
|
|
}
|
|
|
};
|
|
|
});
|
|
|
}).catch(() => []) // Fail by returning no results.
|
|
|
);
|
|
|
}
|
|
|
if (!type || type === 'term') {
|
|
|
queries.push(external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
|
|
|
search,
|
|
|
page,
|
|
|
per_page: perPage,
|
|
|
type: 'term',
|
|
|
subtype
|
|
|
})
|
|
|
}).then(results => {
|
|
|
return results.map(result => {
|
|
|
return {
|
|
|
...result,
|
|
|
meta: {
|
|
|
kind: 'taxonomy',
|
|
|
subtype
|
|
|
}
|
|
|
};
|
|
|
});
|
|
|
}).catch(() => []) // Fail by returning no results.
|
|
|
);
|
|
|
}
|
|
|
if (!disablePostFormats && (!type || type === 'post-format')) {
|
|
|
queries.push(external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/search', {
|
|
|
search,
|
|
|
page,
|
|
|
per_page: perPage,
|
|
|
type: 'post-format',
|
|
|
subtype
|
|
|
})
|
|
|
}).then(results => {
|
|
|
return results.map(result => {
|
|
|
return {
|
|
|
...result,
|
|
|
meta: {
|
|
|
kind: 'taxonomy',
|
|
|
subtype
|
|
|
}
|
|
|
};
|
|
|
});
|
|
|
}).catch(() => []) // Fail by returning no results.
|
|
|
);
|
|
|
}
|
|
|
if (!type || type === 'attachment') {
|
|
|
queries.push(external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/media', {
|
|
|
search,
|
|
|
page,
|
|
|
per_page: perPage
|
|
|
})
|
|
|
}).then(results => {
|
|
|
return results.map(result => {
|
|
|
return {
|
|
|
...result,
|
|
|
meta: {
|
|
|
kind: 'media'
|
|
|
}
|
|
|
};
|
|
|
});
|
|
|
}).catch(() => []) // Fail by returning no results.
|
|
|
);
|
|
|
}
|
|
|
return Promise.all(queries).then(results => {
|
|
|
return results.reduce(( /** @type {WPLinkSearchResult[]} */accumulator, current) => accumulator.concat(current),
|
|
|
// Flatten list.
|
|
|
[]).filter(
|
|
|
/**
|
|
|
* @param {{ id: number }} result
|
|
|
*/
|
|
|
result => {
|
|
|
return !!result.id;
|
|
|
}).slice(0, perPage).map(( /** @type {WPLinkSearchResultAugmented} */result) => {
|
|
|
const isMedia = result.type === 'attachment';
|
|
|
return {
|
|
|
id: result.id,
|
|
|
// @ts-ignore fix when we make this a TS file
|
|
|
url: isMedia ? result.source_url : result.url,
|
|
|
title: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(isMedia ?
|
|
|
// @ts-ignore fix when we make this a TS file
|
|
|
result.title.rendered : result.title || '') || (0,external_wp_i18n_namespaceObject.__)('(no title)'),
|
|
|
type: result.subtype || result.type,
|
|
|
kind: result?.meta?.kind
|
|
|
};
|
|
|
});
|
|
|
});
|
|
|
};
|
|
|
/* harmony default export */ const _experimental_fetch_link_suggestions = (fetchLinkSuggestions);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/fetch/__experimental-fetch-url-data.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* A simple in-memory cache for requests.
|
|
|
* This avoids repeat HTTP requests which may be beneficial
|
|
|
* for those wishing to preserve low-bandwidth.
|
|
|
*/
|
|
|
const CACHE = new Map();
|
|
|
|
|
|
/**
|
|
|
* @typedef WPRemoteUrlData
|
|
|
*
|
|
|
* @property {string} title contents of the remote URL's `<title>` tag.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Fetches data about a remote URL.
|
|
|
* eg: <title> tag, favicon...etc.
|
|
|
*
|
|
|
* @async
|
|
|
* @param {string} url the URL to request details from.
|
|
|
* @param {Object?} options any options to pass to the underlying fetch.
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { __experimentalFetchUrlData as fetchUrlData } from '@wordpress/core-data';
|
|
|
*
|
|
|
* //...
|
|
|
*
|
|
|
* export function initialize( id, settings ) {
|
|
|
*
|
|
|
* settings.__experimentalFetchUrlData = (
|
|
|
* url
|
|
|
* ) => fetchUrlData( url );
|
|
|
* ```
|
|
|
* @return {Promise< WPRemoteUrlData[] >} Remote URL data.
|
|
|
*/
|
|
|
const fetchUrlData = async (url, options = {}) => {
|
|
|
const endpoint = '/wp-block-editor/v1/url-details';
|
|
|
const args = {
|
|
|
url: (0,external_wp_url_namespaceObject.prependHTTP)(url)
|
|
|
};
|
|
|
if (!(0,external_wp_url_namespaceObject.isURL)(url)) {
|
|
|
return Promise.reject(`${url} is not a valid URL.`);
|
|
|
}
|
|
|
|
|
|
// Test for "http" based URL as it is possible for valid
|
|
|
// yet unusable URLs such as `tel:123456` to be passed.
|
|
|
const protocol = (0,external_wp_url_namespaceObject.getProtocol)(url);
|
|
|
if (!protocol || !(0,external_wp_url_namespaceObject.isValidProtocol)(protocol) || !protocol.startsWith('http') || !/^https?:\/\/[^\/\s]/i.test(url)) {
|
|
|
return Promise.reject(`${url} does not have a valid protocol. URLs must be "http" based`);
|
|
|
}
|
|
|
if (CACHE.has(url)) {
|
|
|
return CACHE.get(url);
|
|
|
}
|
|
|
return external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)(endpoint, args),
|
|
|
...options
|
|
|
}).then(res => {
|
|
|
CACHE.set(url, res);
|
|
|
return res;
|
|
|
});
|
|
|
};
|
|
|
/* harmony default export */ const _experimental_fetch_url_data = (fetchUrlData);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/fetch/index.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
async function fetchBlockPatterns() {
|
|
|
const restPatterns = await external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/block-patterns/patterns'
|
|
|
});
|
|
|
if (!restPatterns) {
|
|
|
return [];
|
|
|
}
|
|
|
return restPatterns.map(pattern => Object.fromEntries(Object.entries(pattern).map(([key, value]) => [camelCase(key), value])));
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/resolvers.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Requests authors from the REST API.
|
|
|
*
|
|
|
* @param {Object|undefined} query Optional object of query parameters to
|
|
|
* include with request.
|
|
|
*/
|
|
|
const resolvers_getAuthors = query => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/users/?who=authors&per_page=100', query);
|
|
|
const users = await external_wp_apiFetch_default()({
|
|
|
path
|
|
|
});
|
|
|
dispatch.receiveUserQuery(path, users);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests the current user from the REST API.
|
|
|
*/
|
|
|
const resolvers_getCurrentUser = () => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const currentUser = await external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/users/me'
|
|
|
});
|
|
|
dispatch.receiveCurrentUser(currentUser);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests an entity's record from the REST API.
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {number|string} key Record's key
|
|
|
* @param {Object|undefined} query Optional object of query parameters to
|
|
|
* include with request. If requesting specific
|
|
|
* fields, fields must always include the ID.
|
|
|
*/
|
|
|
const resolvers_getEntityRecord = (kind, name, key = '', query) => async ({
|
|
|
select,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name, key], {
|
|
|
exclusive: false
|
|
|
});
|
|
|
try {
|
|
|
// Entity supports configs,
|
|
|
// use the sync algorithm instead of the old fetch behavior.
|
|
|
if (window.__experimentalEnableSync && entityConfig.syncConfig && !query) {
|
|
|
if (false) {}
|
|
|
} else {
|
|
|
if (query !== undefined && query._fields) {
|
|
|
// If requesting specific fields, items and query association to said
|
|
|
// records are stored by ID reference. Thus, fields must always include
|
|
|
// the ID.
|
|
|
query = {
|
|
|
...query,
|
|
|
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
|
|
|
};
|
|
|
}
|
|
|
|
|
|
// Disable reason: While true that an early return could leave `path`
|
|
|
// unused, it's important that path is derived using the query prior to
|
|
|
// additional query modifications in the condition below, since those
|
|
|
// modifications are relevant to how the data is tracked in state, and not
|
|
|
// for how the request is made to the REST API.
|
|
|
|
|
|
// eslint-disable-next-line @wordpress/no-unused-vars-before-return
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL + (key ? '/' + key : ''), {
|
|
|
...entityConfig.baseURLParams,
|
|
|
...query
|
|
|
});
|
|
|
if (query !== undefined) {
|
|
|
query = {
|
|
|
...query,
|
|
|
include: [key]
|
|
|
};
|
|
|
|
|
|
// The resolution cache won't consider query as reusable based on the
|
|
|
// fields, so it's tested here, prior to initiating the REST request,
|
|
|
// and without causing `getEntityRecords` resolution to occur.
|
|
|
const hasRecords = select.hasEntityRecords(kind, name, query);
|
|
|
if (hasRecords) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
const record = await external_wp_apiFetch_default()({
|
|
|
path
|
|
|
});
|
|
|
dispatch.receiveEntityRecords(kind, name, record, query);
|
|
|
}
|
|
|
} finally {
|
|
|
dispatch.__unstableReleaseStoreLock(lock);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests an entity's record from the REST API.
|
|
|
*/
|
|
|
const resolvers_getRawEntityRecord = forward_resolver('getEntityRecord');
|
|
|
|
|
|
/**
|
|
|
* Requests an entity's record from the REST API.
|
|
|
*/
|
|
|
const resolvers_getEditedEntityRecord = forward_resolver('getEntityRecord');
|
|
|
|
|
|
/**
|
|
|
* Requests the entity's records from the REST API.
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {Object?} query Query Object. If requesting specific fields, fields
|
|
|
* must always include the ID.
|
|
|
*/
|
|
|
const resolvers_getEntityRecords = (kind, name, query = {}) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
const lock = await dispatch.__unstableAcquireStoreLock(STORE_NAME, ['entities', 'records', kind, name], {
|
|
|
exclusive: false
|
|
|
});
|
|
|
try {
|
|
|
if (query._fields) {
|
|
|
// If requesting specific fields, items and query association to said
|
|
|
// records are stored by ID reference. Thus, fields must always include
|
|
|
// the ID.
|
|
|
query = {
|
|
|
...query,
|
|
|
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.key || DEFAULT_ENTITY_KEY])].join()
|
|
|
};
|
|
|
}
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.baseURL, {
|
|
|
...entityConfig.baseURLParams,
|
|
|
...query
|
|
|
});
|
|
|
let records, meta;
|
|
|
if (entityConfig.supportsPagination && query.per_page !== -1) {
|
|
|
const response = await external_wp_apiFetch_default()({
|
|
|
path,
|
|
|
parse: false
|
|
|
});
|
|
|
records = Object.values(await response.json());
|
|
|
meta = {
|
|
|
totalItems: parseInt(response.headers.get('X-WP-Total'))
|
|
|
};
|
|
|
} else {
|
|
|
records = Object.values(await external_wp_apiFetch_default()({
|
|
|
path
|
|
|
}));
|
|
|
}
|
|
|
|
|
|
// If we request fields but the result doesn't contain the fields,
|
|
|
// explicitly set these fields as "undefined"
|
|
|
// that way we consider the query "fulfilled".
|
|
|
if (query._fields) {
|
|
|
records = records.map(record => {
|
|
|
query._fields.split(',').forEach(field => {
|
|
|
if (!record.hasOwnProperty(field)) {
|
|
|
record[field] = undefined;
|
|
|
}
|
|
|
});
|
|
|
return record;
|
|
|
});
|
|
|
}
|
|
|
dispatch.receiveEntityRecords(kind, name, records, query, false, undefined, meta);
|
|
|
|
|
|
// When requesting all fields, the list of results can be used to
|
|
|
// resolve the `getEntityRecord` selector in addition to `getEntityRecords`.
|
|
|
// See https://github.com/WordPress/gutenberg/pull/26575
|
|
|
if (!query?._fields && !query.context) {
|
|
|
const key = entityConfig.key || DEFAULT_ENTITY_KEY;
|
|
|
const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, record[key]]);
|
|
|
dispatch({
|
|
|
type: 'START_RESOLUTIONS',
|
|
|
selectorName: 'getEntityRecord',
|
|
|
args: resolutionsArgs
|
|
|
});
|
|
|
dispatch({
|
|
|
type: 'FINISH_RESOLUTIONS',
|
|
|
selectorName: 'getEntityRecord',
|
|
|
args: resolutionsArgs
|
|
|
});
|
|
|
}
|
|
|
} finally {
|
|
|
dispatch.__unstableReleaseStoreLock(lock);
|
|
|
}
|
|
|
};
|
|
|
resolvers_getEntityRecords.shouldInvalidate = (action, kind, name) => {
|
|
|
return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && kind === action.kind && name === action.name;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests the current theme.
|
|
|
*/
|
|
|
const resolvers_getCurrentTheme = () => async ({
|
|
|
dispatch,
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
|
|
|
status: 'active'
|
|
|
});
|
|
|
dispatch.receiveCurrentTheme(activeThemes[0]);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests theme supports data from the index.
|
|
|
*/
|
|
|
const resolvers_getThemeSupports = forward_resolver('getCurrentTheme');
|
|
|
|
|
|
/**
|
|
|
* Requests a preview from the Embed API.
|
|
|
*
|
|
|
* @param {string} url URL to get the preview for.
|
|
|
*/
|
|
|
const resolvers_getEmbedPreview = url => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
try {
|
|
|
const embedProxyResponse = await external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/oembed/1.0/proxy', {
|
|
|
url
|
|
|
})
|
|
|
});
|
|
|
dispatch.receiveEmbedPreview(url, embedProxyResponse);
|
|
|
} catch (error) {
|
|
|
// Embed API 404s if the URL cannot be embedded, so we have to catch the error from the apiRequest here.
|
|
|
dispatch.receiveEmbedPreview(url, false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Checks whether the current user can perform the given action on the given
|
|
|
* REST resource.
|
|
|
*
|
|
|
* @param {string} requestedAction Action to check. One of: 'create', 'read', 'update',
|
|
|
* 'delete'.
|
|
|
* @param {string} resource REST resource to check, e.g. 'media' or 'posts'.
|
|
|
* @param {?string} id ID of the rest resource to check.
|
|
|
*/
|
|
|
const resolvers_canUser = (requestedAction, resource, id) => async ({
|
|
|
dispatch,
|
|
|
registry
|
|
|
}) => {
|
|
|
const {
|
|
|
hasStartedResolution
|
|
|
} = registry.select(STORE_NAME);
|
|
|
const resourcePath = id ? `${resource}/${id}` : resource;
|
|
|
const retrievedActions = ['create', 'read', 'update', 'delete'];
|
|
|
if (!retrievedActions.includes(requestedAction)) {
|
|
|
throw new Error(`'${requestedAction}' is not a valid action.`);
|
|
|
}
|
|
|
|
|
|
// Prevent resolving the same resource twice.
|
|
|
for (const relatedAction of retrievedActions) {
|
|
|
if (relatedAction === requestedAction) {
|
|
|
continue;
|
|
|
}
|
|
|
const isAlreadyResolving = hasStartedResolution('canUser', [relatedAction, resource, id]);
|
|
|
if (isAlreadyResolving) {
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
|
let response;
|
|
|
try {
|
|
|
response = await external_wp_apiFetch_default()({
|
|
|
path: `/wp/v2/${resourcePath}`,
|
|
|
method: 'OPTIONS',
|
|
|
parse: false
|
|
|
});
|
|
|
} catch (error) {
|
|
|
// Do nothing if our OPTIONS request comes back with an API error (4xx or
|
|
|
// 5xx). The previously determined isAllowed value will remain in the store.
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
// Optional chaining operator is used here because the API requests don't
|
|
|
// return the expected result in the native version. Instead, API requests
|
|
|
// only return the result, without including response properties like the headers.
|
|
|
const allowHeader = response.headers?.get('allow');
|
|
|
const allowedMethods = allowHeader?.allow || allowHeader || '';
|
|
|
const permissions = {};
|
|
|
const methods = {
|
|
|
create: 'POST',
|
|
|
read: 'GET',
|
|
|
update: 'PUT',
|
|
|
delete: 'DELETE'
|
|
|
};
|
|
|
for (const [actionName, methodName] of Object.entries(methods)) {
|
|
|
permissions[actionName] = allowedMethods.includes(methodName);
|
|
|
}
|
|
|
for (const action of retrievedActions) {
|
|
|
dispatch.receiveUserPermission(`${action}/${resourcePath}`, permissions[action]);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Checks whether the current user can perform the given action on the given
|
|
|
* REST resource.
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {string} recordId Record's id.
|
|
|
*/
|
|
|
const resolvers_canUserEditEntityRecord = (kind, name, recordId) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
|
|
|
if (!entityConfig) {
|
|
|
return;
|
|
|
}
|
|
|
const resource = entityConfig.__unstable_rest_base;
|
|
|
await dispatch(resolvers_canUser('update', resource, recordId));
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Request autosave data from the REST API.
|
|
|
*
|
|
|
* @param {string} postType The type of the parent post.
|
|
|
* @param {number} postId The id of the parent post.
|
|
|
*/
|
|
|
const resolvers_getAutosaves = (postType, postId) => async ({
|
|
|
dispatch,
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
const {
|
|
|
rest_base: restBase,
|
|
|
rest_namespace: restNamespace = 'wp/v2'
|
|
|
} = await resolveSelect.getPostType(postType);
|
|
|
const autosaves = await external_wp_apiFetch_default()({
|
|
|
path: `/${restNamespace}/${restBase}/${postId}/autosaves?context=edit`
|
|
|
});
|
|
|
if (autosaves && autosaves.length) {
|
|
|
dispatch.receiveAutosaves(postId, autosaves);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Request autosave data from the REST API.
|
|
|
*
|
|
|
* This resolver exists to ensure the underlying autosaves are fetched via
|
|
|
* `getAutosaves` when a call to the `getAutosave` selector is made.
|
|
|
*
|
|
|
* @param {string} postType The type of the parent post.
|
|
|
* @param {number} postId The id of the parent post.
|
|
|
*/
|
|
|
const resolvers_getAutosave = (postType, postId) => async ({
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
await resolveSelect.getAutosaves(postType, postId);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Retrieve the frontend template used for a given link.
|
|
|
*
|
|
|
* @param {string} link Link.
|
|
|
*/
|
|
|
const resolvers_experimentalGetTemplateForLink = link => async ({
|
|
|
dispatch,
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
let template;
|
|
|
try {
|
|
|
// This is NOT calling a REST endpoint but rather ends up with a response from
|
|
|
// an Ajax function which has a different shape from a WP_REST_Response.
|
|
|
template = await external_wp_apiFetch_default()({
|
|
|
url: (0,external_wp_url_namespaceObject.addQueryArgs)(link, {
|
|
|
'_wp-find-template': true
|
|
|
})
|
|
|
}).then(({
|
|
|
data
|
|
|
}) => data);
|
|
|
} catch (e) {
|
|
|
// For non-FSE themes, it is possible that this request returns an error.
|
|
|
}
|
|
|
if (!template) {
|
|
|
return;
|
|
|
}
|
|
|
const record = await resolveSelect.getEntityRecord('postType', 'wp_template', template.id);
|
|
|
if (record) {
|
|
|
dispatch.receiveEntityRecords('postType', 'wp_template', [record], {
|
|
|
'find-template': link
|
|
|
});
|
|
|
}
|
|
|
};
|
|
|
resolvers_experimentalGetTemplateForLink.shouldInvalidate = action => {
|
|
|
return (action.type === 'RECEIVE_ITEMS' || action.type === 'REMOVE_ITEMS') && action.invalidateCache && action.kind === 'postType' && action.name === 'wp_template';
|
|
|
};
|
|
|
const resolvers_experimentalGetCurrentGlobalStylesId = () => async ({
|
|
|
dispatch,
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
const activeThemes = await resolveSelect.getEntityRecords('root', 'theme', {
|
|
|
status: 'active'
|
|
|
});
|
|
|
const globalStylesURL = activeThemes?.[0]?._links?.['wp:user-global-styles']?.[0]?.href;
|
|
|
if (globalStylesURL) {
|
|
|
const globalStylesObject = await external_wp_apiFetch_default()({
|
|
|
url: globalStylesURL
|
|
|
});
|
|
|
dispatch.__experimentalReceiveCurrentGlobalStylesId(globalStylesObject.id);
|
|
|
}
|
|
|
};
|
|
|
const resolvers_experimentalGetCurrentThemeBaseGlobalStyles = () => async ({
|
|
|
resolveSelect,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const currentTheme = await resolveSelect.getCurrentTheme();
|
|
|
const themeGlobalStyles = await external_wp_apiFetch_default()({
|
|
|
path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}`
|
|
|
});
|
|
|
dispatch.__experimentalReceiveThemeBaseGlobalStyles(currentTheme.stylesheet, themeGlobalStyles);
|
|
|
};
|
|
|
const resolvers_experimentalGetCurrentThemeGlobalStylesVariations = () => async ({
|
|
|
resolveSelect,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const currentTheme = await resolveSelect.getCurrentTheme();
|
|
|
const variations = await external_wp_apiFetch_default()({
|
|
|
path: `/wp/v2/global-styles/themes/${currentTheme.stylesheet}/variations`
|
|
|
});
|
|
|
dispatch.__experimentalReceiveThemeGlobalStyleVariations(currentTheme.stylesheet, variations);
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Fetches and returns the revisions of the current global styles theme.
|
|
|
*/
|
|
|
const resolvers_getCurrentThemeGlobalStylesRevisions = () => async ({
|
|
|
resolveSelect,
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const globalStylesId = await resolveSelect.__experimentalGetCurrentGlobalStylesId();
|
|
|
const record = globalStylesId ? await resolveSelect.getEntityRecord('root', 'globalStyles', globalStylesId) : undefined;
|
|
|
const revisionsURL = record?._links?.['version-history']?.[0]?.href;
|
|
|
if (revisionsURL) {
|
|
|
const resetRevisions = await external_wp_apiFetch_default()({
|
|
|
url: revisionsURL
|
|
|
});
|
|
|
const revisions = resetRevisions?.map(revision => Object.fromEntries(Object.entries(revision).map(([key, value]) => [camelCase(key), value])));
|
|
|
dispatch.receiveThemeGlobalStyleRevisions(globalStylesId, revisions);
|
|
|
}
|
|
|
};
|
|
|
resolvers_getCurrentThemeGlobalStylesRevisions.shouldInvalidate = action => {
|
|
|
return action.type === 'SAVE_ENTITY_RECORD_FINISH' && action.kind === 'root' && !action.error && action.name === 'globalStyles';
|
|
|
};
|
|
|
const resolvers_getBlockPatterns = () => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const patterns = await fetchBlockPatterns();
|
|
|
dispatch({
|
|
|
type: 'RECEIVE_BLOCK_PATTERNS',
|
|
|
patterns
|
|
|
});
|
|
|
};
|
|
|
const resolvers_getBlockPatternCategories = () => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const categories = await external_wp_apiFetch_default()({
|
|
|
path: '/wp/v2/block-patterns/categories'
|
|
|
});
|
|
|
dispatch({
|
|
|
type: 'RECEIVE_BLOCK_PATTERN_CATEGORIES',
|
|
|
categories
|
|
|
});
|
|
|
};
|
|
|
const resolvers_getUserPatternCategories = () => async ({
|
|
|
dispatch,
|
|
|
resolveSelect
|
|
|
}) => {
|
|
|
const patternCategories = await resolveSelect.getEntityRecords('taxonomy', 'wp_pattern_category', {
|
|
|
per_page: -1,
|
|
|
_fields: 'id,name,description,slug',
|
|
|
context: 'view'
|
|
|
});
|
|
|
const mappedPatternCategories = patternCategories?.map(userCategory => ({
|
|
|
...userCategory,
|
|
|
label: (0,external_wp_htmlEntities_namespaceObject.decodeEntities)(userCategory.name),
|
|
|
name: userCategory.slug
|
|
|
})) || [];
|
|
|
dispatch({
|
|
|
type: 'RECEIVE_USER_PATTERN_CATEGORIES',
|
|
|
patternCategories: mappedPatternCategories
|
|
|
});
|
|
|
};
|
|
|
const resolvers_getNavigationFallbackId = () => async ({
|
|
|
dispatch,
|
|
|
select
|
|
|
}) => {
|
|
|
const fallback = await external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp-block-editor/v1/navigation-fallback', {
|
|
|
_embed: true
|
|
|
})
|
|
|
});
|
|
|
const record = fallback?._embedded?.self;
|
|
|
dispatch.receiveNavigationFallbackId(fallback?.id);
|
|
|
if (record) {
|
|
|
// If the fallback is already in the store, don't invalidate navigation queries.
|
|
|
// Otherwise, invalidate the cache for the scenario where there were no Navigation
|
|
|
// posts in the state and the fallback created one.
|
|
|
const existingFallbackEntityRecord = select.getEntityRecord('postType', 'wp_navigation', fallback.id);
|
|
|
const invalidateNavigationQueries = !existingFallbackEntityRecord;
|
|
|
dispatch.receiveEntityRecords('postType', 'wp_navigation', record, undefined, invalidateNavigationQueries);
|
|
|
|
|
|
// Resolve to avoid further network requests.
|
|
|
dispatch.finishResolution('getEntityRecord', ['postType', 'wp_navigation', fallback.id]);
|
|
|
}
|
|
|
};
|
|
|
const resolvers_getDefaultTemplateId = query => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const template = await external_wp_apiFetch_default()({
|
|
|
path: (0,external_wp_url_namespaceObject.addQueryArgs)('/wp/v2/templates/lookup', query)
|
|
|
});
|
|
|
if (template) {
|
|
|
dispatch.receiveDefaultTemplateId(query, template.id);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Requests an entity's revisions from the REST API.
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
|
|
|
* @param {Object|undefined} query Optional object of query parameters to
|
|
|
* include with request. If requesting specific
|
|
|
* fields, fields must always include the ID.
|
|
|
*/
|
|
|
const resolvers_getRevisions = (kind, name, recordKey, query = {}) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
if (query._fields) {
|
|
|
// If requesting specific fields, items and query association to said
|
|
|
// records are stored by ID reference. Thus, fields must always include
|
|
|
// the ID.
|
|
|
query = {
|
|
|
...query,
|
|
|
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
|
|
|
};
|
|
|
}
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey), query);
|
|
|
let records, response;
|
|
|
const meta = {};
|
|
|
const isPaginated = entityConfig.supportsPagination && query.per_page !== -1;
|
|
|
try {
|
|
|
response = await external_wp_apiFetch_default()({
|
|
|
path,
|
|
|
parse: !isPaginated
|
|
|
});
|
|
|
} catch (error) {
|
|
|
// Do nothing if our request comes back with an API error.
|
|
|
return;
|
|
|
}
|
|
|
if (response) {
|
|
|
if (isPaginated) {
|
|
|
records = Object.values(await response.json());
|
|
|
meta.totalItems = parseInt(response.headers.get('X-WP-Total'));
|
|
|
} else {
|
|
|
records = Object.values(response);
|
|
|
}
|
|
|
|
|
|
// If we request fields but the result doesn't contain the fields,
|
|
|
// explicitly set these fields as "undefined"
|
|
|
// that way we consider the query "fulfilled".
|
|
|
if (query._fields) {
|
|
|
records = records.map(record => {
|
|
|
query._fields.split(',').forEach(field => {
|
|
|
if (!record.hasOwnProperty(field)) {
|
|
|
record[field] = undefined;
|
|
|
}
|
|
|
});
|
|
|
return record;
|
|
|
});
|
|
|
}
|
|
|
dispatch.receiveRevisions(kind, name, recordKey, records, query, false, meta);
|
|
|
|
|
|
// When requesting all fields, the list of results can be used to
|
|
|
// resolve the `getRevision` selector in addition to `getRevisions`.
|
|
|
if (!query?._fields && !query.context) {
|
|
|
const key = entityConfig.key || DEFAULT_ENTITY_KEY;
|
|
|
const resolutionsArgs = records.filter(record => record[key]).map(record => [kind, name, recordKey, record[key]]);
|
|
|
dispatch({
|
|
|
type: 'START_RESOLUTIONS',
|
|
|
selectorName: 'getRevision',
|
|
|
args: resolutionsArgs
|
|
|
});
|
|
|
dispatch({
|
|
|
type: 'FINISH_RESOLUTIONS',
|
|
|
selectorName: 'getRevision',
|
|
|
args: resolutionsArgs
|
|
|
});
|
|
|
}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// Invalidate cache when a new revision is created.
|
|
|
resolvers_getRevisions.shouldInvalidate = (action, kind, name, recordKey) => action.type === 'SAVE_ENTITY_RECORD_FINISH' && name === action.name && kind === action.kind && !action.error && recordKey === action.recordId;
|
|
|
|
|
|
/**
|
|
|
* Requests a specific Entity revision from the REST API.
|
|
|
*
|
|
|
* @param {string} kind Entity kind.
|
|
|
* @param {string} name Entity name.
|
|
|
* @param {number|string} recordKey The key of the entity record whose revisions you want to fetch.
|
|
|
* @param {number|string} revisionKey The revision's key.
|
|
|
* @param {Object|undefined} query Optional object of query parameters to
|
|
|
* include with request. If requesting specific
|
|
|
* fields, fields must always include the ID.
|
|
|
*/
|
|
|
const resolvers_getRevision = (kind, name, recordKey, revisionKey, query) => async ({
|
|
|
dispatch
|
|
|
}) => {
|
|
|
const configs = await dispatch(getOrLoadEntitiesConfig(kind));
|
|
|
const entityConfig = configs.find(config => config.name === name && config.kind === kind);
|
|
|
if (!entityConfig || entityConfig?.__experimentalNoFetch) {
|
|
|
return;
|
|
|
}
|
|
|
if (query !== undefined && query._fields) {
|
|
|
// If requesting specific fields, items and query association to said
|
|
|
// records are stored by ID reference. Thus, fields must always include
|
|
|
// the ID.
|
|
|
query = {
|
|
|
...query,
|
|
|
_fields: [...new Set([...(get_normalized_comma_separable(query._fields) || []), entityConfig.revisionKey || DEFAULT_ENTITY_KEY])].join()
|
|
|
};
|
|
|
}
|
|
|
const path = (0,external_wp_url_namespaceObject.addQueryArgs)(entityConfig.getRevisionsUrl(recordKey, revisionKey), query);
|
|
|
let record;
|
|
|
try {
|
|
|
record = await external_wp_apiFetch_default()({
|
|
|
path
|
|
|
});
|
|
|
} catch (error) {
|
|
|
// Do nothing if our request comes back with an API error.
|
|
|
return;
|
|
|
}
|
|
|
if (record) {
|
|
|
dispatch.receiveRevisions(kind, name, recordKey, record, query);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/utils.js
|
|
|
function deepCopyLocksTreePath(tree, path) {
|
|
|
const newTree = {
|
|
|
...tree
|
|
|
};
|
|
|
let currentNode = newTree;
|
|
|
for (const branchName of path) {
|
|
|
currentNode.children = {
|
|
|
...currentNode.children,
|
|
|
[branchName]: {
|
|
|
locks: [],
|
|
|
children: {},
|
|
|
...currentNode.children[branchName]
|
|
|
}
|
|
|
};
|
|
|
currentNode = currentNode.children[branchName];
|
|
|
}
|
|
|
return newTree;
|
|
|
}
|
|
|
function getNode(tree, path) {
|
|
|
let currentNode = tree;
|
|
|
for (const branchName of path) {
|
|
|
const nextNode = currentNode.children[branchName];
|
|
|
if (!nextNode) {
|
|
|
return null;
|
|
|
}
|
|
|
currentNode = nextNode;
|
|
|
}
|
|
|
return currentNode;
|
|
|
}
|
|
|
function* iteratePath(tree, path) {
|
|
|
let currentNode = tree;
|
|
|
yield currentNode;
|
|
|
for (const branchName of path) {
|
|
|
const nextNode = currentNode.children[branchName];
|
|
|
if (!nextNode) {
|
|
|
break;
|
|
|
}
|
|
|
yield nextNode;
|
|
|
currentNode = nextNode;
|
|
|
}
|
|
|
}
|
|
|
function* iterateDescendants(node) {
|
|
|
const stack = Object.values(node.children);
|
|
|
while (stack.length) {
|
|
|
const childNode = stack.pop();
|
|
|
yield childNode;
|
|
|
stack.push(...Object.values(childNode.children));
|
|
|
}
|
|
|
}
|
|
|
function hasConflictingLock({
|
|
|
exclusive
|
|
|
}, locks) {
|
|
|
if (exclusive && locks.length) {
|
|
|
return true;
|
|
|
}
|
|
|
if (!exclusive && locks.filter(lock => lock.exclusive).length) {
|
|
|
return true;
|
|
|
}
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/reducer.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
const DEFAULT_STATE = {
|
|
|
requests: [],
|
|
|
tree: {
|
|
|
locks: [],
|
|
|
children: {}
|
|
|
}
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Reducer returning locks.
|
|
|
*
|
|
|
* @param {Object} state Current state.
|
|
|
* @param {Object} action Dispatched action.
|
|
|
*
|
|
|
* @return {Object} Updated state.
|
|
|
*/
|
|
|
function locks(state = DEFAULT_STATE, action) {
|
|
|
switch (action.type) {
|
|
|
case 'ENQUEUE_LOCK_REQUEST':
|
|
|
{
|
|
|
const {
|
|
|
request
|
|
|
} = action;
|
|
|
return {
|
|
|
...state,
|
|
|
requests: [request, ...state.requests]
|
|
|
};
|
|
|
}
|
|
|
case 'GRANT_LOCK_REQUEST':
|
|
|
{
|
|
|
const {
|
|
|
lock,
|
|
|
request
|
|
|
} = action;
|
|
|
const {
|
|
|
store,
|
|
|
path
|
|
|
} = request;
|
|
|
const storePath = [store, ...path];
|
|
|
const newTree = deepCopyLocksTreePath(state.tree, storePath);
|
|
|
const node = getNode(newTree, storePath);
|
|
|
node.locks = [...node.locks, lock];
|
|
|
return {
|
|
|
...state,
|
|
|
requests: state.requests.filter(r => r !== request),
|
|
|
tree: newTree
|
|
|
};
|
|
|
}
|
|
|
case 'RELEASE_LOCK':
|
|
|
{
|
|
|
const {
|
|
|
lock
|
|
|
} = action;
|
|
|
const storePath = [lock.store, ...lock.path];
|
|
|
const newTree = deepCopyLocksTreePath(state.tree, storePath);
|
|
|
const node = getNode(newTree, storePath);
|
|
|
node.locks = node.locks.filter(l => l !== lock);
|
|
|
return {
|
|
|
...state,
|
|
|
tree: newTree
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
return state;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/selectors.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
function getPendingLockRequests(state) {
|
|
|
return state.requests;
|
|
|
}
|
|
|
function isLockAvailable(state, store, path, {
|
|
|
exclusive
|
|
|
}) {
|
|
|
const storePath = [store, ...path];
|
|
|
const locks = state.tree;
|
|
|
|
|
|
// Validate all parents and the node itself
|
|
|
for (const node of iteratePath(locks, storePath)) {
|
|
|
if (hasConflictingLock({
|
|
|
exclusive
|
|
|
}, node.locks)) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// iteratePath terminates early if path is unreachable, let's
|
|
|
// re-fetch the node and check it exists in the tree.
|
|
|
const node = getNode(locks, storePath);
|
|
|
if (!node) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
// Validate all nested nodes
|
|
|
for (const descendant of iterateDescendants(node)) {
|
|
|
if (hasConflictingLock({
|
|
|
exclusive
|
|
|
}, descendant.locks)) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/engine.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
function createLocks() {
|
|
|
let state = locks(undefined, {
|
|
|
type: '@@INIT'
|
|
|
});
|
|
|
function processPendingLockRequests() {
|
|
|
for (const request of getPendingLockRequests(state)) {
|
|
|
const {
|
|
|
store,
|
|
|
path,
|
|
|
exclusive,
|
|
|
notifyAcquired
|
|
|
} = request;
|
|
|
if (isLockAvailable(state, store, path, {
|
|
|
exclusive
|
|
|
})) {
|
|
|
const lock = {
|
|
|
store,
|
|
|
path,
|
|
|
exclusive
|
|
|
};
|
|
|
state = locks(state, {
|
|
|
type: 'GRANT_LOCK_REQUEST',
|
|
|
lock,
|
|
|
request
|
|
|
});
|
|
|
notifyAcquired(lock);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
function acquire(store, path, exclusive) {
|
|
|
return new Promise(resolve => {
|
|
|
state = locks(state, {
|
|
|
type: 'ENQUEUE_LOCK_REQUEST',
|
|
|
request: {
|
|
|
store,
|
|
|
path,
|
|
|
exclusive,
|
|
|
notifyAcquired: resolve
|
|
|
}
|
|
|
});
|
|
|
processPendingLockRequests();
|
|
|
});
|
|
|
}
|
|
|
function release(lock) {
|
|
|
state = locks(state, {
|
|
|
type: 'RELEASE_LOCK',
|
|
|
lock
|
|
|
});
|
|
|
processPendingLockRequests();
|
|
|
}
|
|
|
return {
|
|
|
acquire,
|
|
|
release
|
|
|
};
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/locks/actions.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
function createLocksActions() {
|
|
|
const locks = createLocks();
|
|
|
function __unstableAcquireStoreLock(store, path, {
|
|
|
exclusive
|
|
|
}) {
|
|
|
return () => locks.acquire(store, path, exclusive);
|
|
|
}
|
|
|
function __unstableReleaseStoreLock(lock) {
|
|
|
return () => locks.release(lock);
|
|
|
}
|
|
|
return {
|
|
|
__unstableAcquireStoreLock,
|
|
|
__unstableReleaseStoreLock
|
|
|
};
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: external ["wp","privateApis"]
|
|
|
const external_wp_privateApis_namespaceObject = window["wp"]["privateApis"];
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/private-apis.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
const {
|
|
|
lock,
|
|
|
unlock
|
|
|
} = (0,external_wp_privateApis_namespaceObject.__dangerousOptInToUnstableAPIsOnlyForCoreModules)('I know using unstable features means my theme or plugin will inevitably break in the next version of WordPress.', '@wordpress/core-data');
|
|
|
|
|
|
;// CONCATENATED MODULE: external "React"
|
|
|
const external_React_namespaceObject = window["React"];
|
|
|
;// CONCATENATED MODULE: external ["wp","element"]
|
|
|
const external_wp_element_namespaceObject = window["wp"]["element"];
|
|
|
;// CONCATENATED MODULE: external ["wp","blocks"]
|
|
|
const external_wp_blocks_namespaceObject = window["wp"]["blocks"];
|
|
|
;// CONCATENATED MODULE: external ["wp","blockEditor"]
|
|
|
const external_wp_blockEditor_namespaceObject = window["wp"]["blockEditor"];
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/footnotes/get-rich-text-values-cached.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
// TODO: The following line should have been:
|
|
|
//
|
|
|
// const unlockedApis = unlock( blockEditorPrivateApis );
|
|
|
//
|
|
|
// But there are hidden circular dependencies in RNMobile code, specifically in
|
|
|
// certain native components in the `components` package that depend on
|
|
|
// `block-editor`. What follows is a workaround that defers the `unlock` call
|
|
|
// to prevent native code from failing.
|
|
|
//
|
|
|
// Fix once https://github.com/WordPress/gutenberg/issues/52692 is closed.
|
|
|
let unlockedApis;
|
|
|
const cache = new WeakMap();
|
|
|
function getRichTextValuesCached(block) {
|
|
|
if (!unlockedApis) {
|
|
|
unlockedApis = unlock(external_wp_blockEditor_namespaceObject.privateApis);
|
|
|
}
|
|
|
if (!cache.has(block)) {
|
|
|
const values = unlockedApis.getRichTextValues([block]);
|
|
|
cache.set(block, values);
|
|
|
}
|
|
|
return cache.get(block);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/footnotes/get-footnotes-order.js
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
const get_footnotes_order_cache = new WeakMap();
|
|
|
function getBlockFootnotesOrder(block) {
|
|
|
if (!get_footnotes_order_cache.has(block)) {
|
|
|
const order = [];
|
|
|
for (const value of getRichTextValuesCached(block)) {
|
|
|
if (!value) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// replacements is a sparse array, use forEach to skip empty slots.
|
|
|
value.replacements.forEach(({
|
|
|
type,
|
|
|
attributes
|
|
|
}) => {
|
|
|
if (type === 'core/footnote') {
|
|
|
order.push(attributes['data-fn']);
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
get_footnotes_order_cache.set(block, order);
|
|
|
}
|
|
|
return get_footnotes_order_cache.get(block);
|
|
|
}
|
|
|
function getFootnotesOrder(blocks) {
|
|
|
// We can only separate getting order from blocks at the root level. For
|
|
|
// deeper inner blocks, this will not work since it's possible to have both
|
|
|
// inner blocks and block attributes, so order needs to be computed from the
|
|
|
// Edit functions as a whole.
|
|
|
return blocks.flatMap(getBlockFootnotesOrder);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/footnotes/index.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
let oldFootnotes = {};
|
|
|
function updateFootnotesFromMeta(blocks, meta) {
|
|
|
const output = {
|
|
|
blocks
|
|
|
};
|
|
|
if (!meta) return output;
|
|
|
|
|
|
// If meta.footnotes is empty, it means the meta is not registered.
|
|
|
if (meta.footnotes === undefined) return output;
|
|
|
const newOrder = getFootnotesOrder(blocks);
|
|
|
const footnotes = meta.footnotes ? JSON.parse(meta.footnotes) : [];
|
|
|
const currentOrder = footnotes.map(fn => fn.id);
|
|
|
if (currentOrder.join('') === newOrder.join('')) return output;
|
|
|
const newFootnotes = newOrder.map(fnId => footnotes.find(fn => fn.id === fnId) || oldFootnotes[fnId] || {
|
|
|
id: fnId,
|
|
|
content: ''
|
|
|
});
|
|
|
function updateAttributes(attributes) {
|
|
|
// Only attempt to update attributes, if attributes is an object.
|
|
|
if (!attributes || Array.isArray(attributes) || typeof attributes !== 'object') {
|
|
|
return attributes;
|
|
|
}
|
|
|
attributes = {
|
|
|
...attributes
|
|
|
};
|
|
|
for (const key in attributes) {
|
|
|
const value = attributes[key];
|
|
|
if (Array.isArray(value)) {
|
|
|
attributes[key] = value.map(updateAttributes);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// To do, remove support for string values?
|
|
|
if (typeof value !== 'string' && !(value instanceof external_wp_richText_namespaceObject.RichTextData)) {
|
|
|
continue;
|
|
|
}
|
|
|
const richTextValue = typeof value === 'string' ? external_wp_richText_namespaceObject.RichTextData.fromHTMLString(value) : new external_wp_richText_namespaceObject.RichTextData(value);
|
|
|
richTextValue.replacements.forEach(replacement => {
|
|
|
if (replacement.type === 'core/footnote') {
|
|
|
const id = replacement.attributes['data-fn'];
|
|
|
const index = newOrder.indexOf(id);
|
|
|
// The innerHTML contains the count wrapped in a link.
|
|
|
const countValue = (0,external_wp_richText_namespaceObject.create)({
|
|
|
html: replacement.innerHTML
|
|
|
});
|
|
|
countValue.text = String(index + 1);
|
|
|
countValue.formats = Array.from({
|
|
|
length: countValue.text.length
|
|
|
}, () => countValue.formats[0]);
|
|
|
countValue.replacements = Array.from({
|
|
|
length: countValue.text.length
|
|
|
}, () => countValue.replacements[0]);
|
|
|
replacement.innerHTML = (0,external_wp_richText_namespaceObject.toHTMLString)({
|
|
|
value: countValue
|
|
|
});
|
|
|
}
|
|
|
});
|
|
|
attributes[key] = typeof value === 'string' ? richTextValue.toHTMLString() : richTextValue;
|
|
|
}
|
|
|
return attributes;
|
|
|
}
|
|
|
function updateBlocksAttributes(__blocks) {
|
|
|
return __blocks.map(block => {
|
|
|
return {
|
|
|
...block,
|
|
|
attributes: updateAttributes(block.attributes),
|
|
|
innerBlocks: updateBlocksAttributes(block.innerBlocks)
|
|
|
};
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// We need to go through all block attributes deeply and update the
|
|
|
// footnote anchor numbering (textContent) to match the new order.
|
|
|
const newBlocks = updateBlocksAttributes(blocks);
|
|
|
oldFootnotes = {
|
|
|
...oldFootnotes,
|
|
|
...footnotes.reduce((acc, fn) => {
|
|
|
if (!newOrder.includes(fn.id)) {
|
|
|
acc[fn.id] = fn;
|
|
|
}
|
|
|
return acc;
|
|
|
}, {})
|
|
|
};
|
|
|
return {
|
|
|
meta: {
|
|
|
...meta,
|
|
|
footnotes: JSON.stringify(newFootnotes)
|
|
|
},
|
|
|
blocks: newBlocks
|
|
|
};
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/entity-provider.js
|
|
|
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/** @typedef {import('@wordpress/blocks').WPBlock} WPBlock */
|
|
|
|
|
|
const EMPTY_ARRAY = [];
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
const entityContexts = {
|
|
|
...rootEntitiesConfig.reduce((acc, loader) => {
|
|
|
if (!acc[loader.kind]) {
|
|
|
acc[loader.kind] = {};
|
|
|
}
|
|
|
acc[loader.kind][loader.name] = {
|
|
|
context: (0,external_wp_element_namespaceObject.createContext)(undefined)
|
|
|
};
|
|
|
return acc;
|
|
|
}, {}),
|
|
|
...additionalEntityConfigLoaders.reduce((acc, loader) => {
|
|
|
acc[loader.kind] = {};
|
|
|
return acc;
|
|
|
}, {})
|
|
|
};
|
|
|
const getEntityContext = (kind, name) => {
|
|
|
if (!entityContexts[kind]) {
|
|
|
throw new Error(`Missing entity config for kind: ${kind}.`);
|
|
|
}
|
|
|
if (!entityContexts[kind][name]) {
|
|
|
entityContexts[kind][name] = {
|
|
|
context: (0,external_wp_element_namespaceObject.createContext)(undefined)
|
|
|
};
|
|
|
}
|
|
|
return entityContexts[kind][name].context;
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Context provider component for providing
|
|
|
* an entity for a specific entity.
|
|
|
*
|
|
|
* @param {Object} props The component's props.
|
|
|
* @param {string} props.kind The entity kind.
|
|
|
* @param {string} props.type The entity name.
|
|
|
* @param {number} props.id The entity ID.
|
|
|
* @param {*} props.children The children to wrap.
|
|
|
*
|
|
|
* @return {Object} The provided children, wrapped with
|
|
|
* the entity's context provider.
|
|
|
*/
|
|
|
function EntityProvider({
|
|
|
kind,
|
|
|
type: name,
|
|
|
id,
|
|
|
children
|
|
|
}) {
|
|
|
const Provider = getEntityContext(kind, name).Provider;
|
|
|
return (0,external_React_namespaceObject.createElement)(Provider, {
|
|
|
value: id
|
|
|
}, children);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Hook that returns the ID for the nearest
|
|
|
* provided entity of the specified type.
|
|
|
*
|
|
|
* @param {string} kind The entity kind.
|
|
|
* @param {string} name The entity name.
|
|
|
*/
|
|
|
function useEntityId(kind, name) {
|
|
|
return (0,external_wp_element_namespaceObject.useContext)(getEntityContext(kind, name));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Hook that returns the value and a setter for the
|
|
|
* specified property of the nearest provided
|
|
|
* entity of the specified type.
|
|
|
*
|
|
|
* @param {string} kind The entity kind.
|
|
|
* @param {string} name The entity name.
|
|
|
* @param {string} prop The property name.
|
|
|
* @param {string} [_id] An entity ID to use instead of the context-provided one.
|
|
|
*
|
|
|
* @return {[*, Function, *]} An array where the first item is the
|
|
|
* property value, the second is the
|
|
|
* setter and the third is the full value
|
|
|
* object from REST API containing more
|
|
|
* information like `raw`, `rendered` and
|
|
|
* `protected` props.
|
|
|
*/
|
|
|
function useEntityProp(kind, name, prop, _id) {
|
|
|
const providerId = useEntityId(kind, name);
|
|
|
const id = _id !== null && _id !== void 0 ? _id : providerId;
|
|
|
const {
|
|
|
value,
|
|
|
fullValue
|
|
|
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
|
|
|
const {
|
|
|
getEntityRecord,
|
|
|
getEditedEntityRecord
|
|
|
} = select(STORE_NAME);
|
|
|
const record = getEntityRecord(kind, name, id); // Trigger resolver.
|
|
|
const editedRecord = getEditedEntityRecord(kind, name, id);
|
|
|
return record && editedRecord ? {
|
|
|
value: editedRecord[prop],
|
|
|
fullValue: record[prop]
|
|
|
} : {};
|
|
|
}, [kind, name, id, prop]);
|
|
|
const {
|
|
|
editEntityRecord
|
|
|
} = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
|
|
|
const setValue = (0,external_wp_element_namespaceObject.useCallback)(newValue => {
|
|
|
editEntityRecord(kind, name, id, {
|
|
|
[prop]: newValue
|
|
|
});
|
|
|
}, [editEntityRecord, kind, name, id, prop]);
|
|
|
return [value, setValue, fullValue];
|
|
|
}
|
|
|
const parsedBlocksCache = new WeakMap();
|
|
|
|
|
|
/**
|
|
|
* Hook that returns block content getters and setters for
|
|
|
* the nearest provided entity of the specified type.
|
|
|
*
|
|
|
* The return value has the shape `[ blocks, onInput, onChange ]`.
|
|
|
* `onInput` is for block changes that don't create undo levels
|
|
|
* or dirty the post, non-persistent changes, and `onChange` is for
|
|
|
* persistent changes. They map directly to the props of a
|
|
|
* `BlockEditorProvider` and are intended to be used with it,
|
|
|
* or similar components or hooks.
|
|
|
*
|
|
|
* @param {string} kind The entity kind.
|
|
|
* @param {string} name The entity name.
|
|
|
* @param {Object} options
|
|
|
* @param {string} [options.id] An entity ID to use instead of the context-provided one.
|
|
|
*
|
|
|
* @return {[WPBlock[], Function, Function]} The block array and setters.
|
|
|
*/
|
|
|
function useEntityBlockEditor(kind, name, {
|
|
|
id: _id
|
|
|
} = {}) {
|
|
|
const providerId = useEntityId(kind, name);
|
|
|
const id = _id !== null && _id !== void 0 ? _id : providerId;
|
|
|
const {
|
|
|
getEntityRecord,
|
|
|
getEntityRecordEdits
|
|
|
} = (0,external_wp_data_namespaceObject.useSelect)(STORE_NAME);
|
|
|
const {
|
|
|
content,
|
|
|
editedBlocks,
|
|
|
meta
|
|
|
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
|
|
|
if (!id) {
|
|
|
return {};
|
|
|
}
|
|
|
const {
|
|
|
getEditedEntityRecord
|
|
|
} = select(STORE_NAME);
|
|
|
const editedRecord = getEditedEntityRecord(kind, name, id);
|
|
|
return {
|
|
|
editedBlocks: editedRecord.blocks,
|
|
|
content: editedRecord.content,
|
|
|
meta: editedRecord.meta
|
|
|
};
|
|
|
}, [kind, name, id]);
|
|
|
const {
|
|
|
__unstableCreateUndoLevel,
|
|
|
editEntityRecord
|
|
|
} = (0,external_wp_data_namespaceObject.useDispatch)(STORE_NAME);
|
|
|
const blocks = (0,external_wp_element_namespaceObject.useMemo)(() => {
|
|
|
if (!id) {
|
|
|
return undefined;
|
|
|
}
|
|
|
if (editedBlocks) {
|
|
|
return editedBlocks;
|
|
|
}
|
|
|
if (!content || typeof content !== 'string') {
|
|
|
return EMPTY_ARRAY;
|
|
|
}
|
|
|
|
|
|
// If there's an edit, cache the parsed blocks by the edit.
|
|
|
// If not, cache by the original enity record.
|
|
|
const edits = getEntityRecordEdits(kind, name, id);
|
|
|
const isUnedited = !edits || !Object.keys(edits).length;
|
|
|
const cackeKey = isUnedited ? getEntityRecord(kind, name, id) : edits;
|
|
|
let _blocks = parsedBlocksCache.get(cackeKey);
|
|
|
if (!_blocks) {
|
|
|
_blocks = (0,external_wp_blocks_namespaceObject.parse)(content);
|
|
|
parsedBlocksCache.set(cackeKey, _blocks);
|
|
|
}
|
|
|
return _blocks;
|
|
|
}, [kind, name, id, editedBlocks, content, getEntityRecord, getEntityRecordEdits]);
|
|
|
const updateFootnotes = (0,external_wp_element_namespaceObject.useCallback)(_blocks => updateFootnotesFromMeta(_blocks, meta), [meta]);
|
|
|
const onChange = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
|
|
|
const noChange = blocks === newBlocks;
|
|
|
if (noChange) {
|
|
|
return __unstableCreateUndoLevel(kind, name, id);
|
|
|
}
|
|
|
const {
|
|
|
selection,
|
|
|
...rest
|
|
|
} = options;
|
|
|
|
|
|
// We create a new function here on every persistent edit
|
|
|
// to make sure the edit makes the post dirty and creates
|
|
|
// a new undo level.
|
|
|
const edits = {
|
|
|
selection,
|
|
|
content: ({
|
|
|
blocks: blocksForSerialization = []
|
|
|
}) => (0,external_wp_blocks_namespaceObject.__unstableSerializeAndClean)(blocksForSerialization),
|
|
|
...updateFootnotes(newBlocks)
|
|
|
};
|
|
|
editEntityRecord(kind, name, id, edits, {
|
|
|
isCached: false,
|
|
|
...rest
|
|
|
});
|
|
|
}, [kind, name, id, blocks, updateFootnotes, __unstableCreateUndoLevel, editEntityRecord]);
|
|
|
const onInput = (0,external_wp_element_namespaceObject.useCallback)((newBlocks, options) => {
|
|
|
const {
|
|
|
selection,
|
|
|
...rest
|
|
|
} = options;
|
|
|
const footnotesChanges = updateFootnotes(newBlocks);
|
|
|
const edits = {
|
|
|
selection,
|
|
|
...footnotesChanges
|
|
|
};
|
|
|
editEntityRecord(kind, name, id, edits, {
|
|
|
isCached: true,
|
|
|
...rest
|
|
|
});
|
|
|
}, [kind, name, id, updateFootnotes, editEntityRecord]);
|
|
|
return [blocks, onInput, onChange];
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/memize/dist/index.js
|
|
|
/**
|
|
|
* Memize options object.
|
|
|
*
|
|
|
* @typedef MemizeOptions
|
|
|
*
|
|
|
* @property {number} [maxSize] Maximum size of the cache.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Internal cache entry.
|
|
|
*
|
|
|
* @typedef MemizeCacheNode
|
|
|
*
|
|
|
* @property {?MemizeCacheNode|undefined} [prev] Previous node.
|
|
|
* @property {?MemizeCacheNode|undefined} [next] Next node.
|
|
|
* @property {Array<*>} args Function arguments for cache
|
|
|
* entry.
|
|
|
* @property {*} val Function result.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Properties of the enhanced function for controlling cache.
|
|
|
*
|
|
|
* @typedef MemizeMemoizedFunction
|
|
|
*
|
|
|
* @property {()=>void} clear Clear the cache.
|
|
|
*/
|
|
|
|
|
|
/**
|
|
|
* Accepts a function to be memoized, and returns a new memoized function, with
|
|
|
* optional options.
|
|
|
*
|
|
|
* @template {(...args: any[]) => any} F
|
|
|
*
|
|
|
* @param {F} fn Function to memoize.
|
|
|
* @param {MemizeOptions} [options] Options object.
|
|
|
*
|
|
|
* @return {((...args: Parameters<F>) => ReturnType<F>) & MemizeMemoizedFunction} Memoized function.
|
|
|
*/
|
|
|
function memize(fn, options) {
|
|
|
var size = 0;
|
|
|
|
|
|
/** @type {?MemizeCacheNode|undefined} */
|
|
|
var head;
|
|
|
|
|
|
/** @type {?MemizeCacheNode|undefined} */
|
|
|
var tail;
|
|
|
|
|
|
options = options || {};
|
|
|
|
|
|
function memoized(/* ...args */) {
|
|
|
var node = head,
|
|
|
len = arguments.length,
|
|
|
args,
|
|
|
i;
|
|
|
|
|
|
searchCache: while (node) {
|
|
|
// Perform a shallow equality test to confirm that whether the node
|
|
|
// under test is a candidate for the arguments passed. Two arrays
|
|
|
// are shallowly equal if their length matches and each entry is
|
|
|
// strictly equal between the two sets. Avoid abstracting to a
|
|
|
// function which could incur an arguments leaking deoptimization.
|
|
|
|
|
|
// Check whether node arguments match arguments length
|
|
|
if (node.args.length !== arguments.length) {
|
|
|
node = node.next;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
// Check whether node arguments match arguments values
|
|
|
for (i = 0; i < len; i++) {
|
|
|
if (node.args[i] !== arguments[i]) {
|
|
|
node = node.next;
|
|
|
continue searchCache;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// At this point we can assume we've found a match
|
|
|
|
|
|
// Surface matched node to head if not already
|
|
|
if (node !== head) {
|
|
|
// As tail, shift to previous. Must only shift if not also
|
|
|
// head, since if both head and tail, there is no previous.
|
|
|
if (node === tail) {
|
|
|
tail = node.prev;
|
|
|
}
|
|
|
|
|
|
// Adjust siblings to point to each other. If node was tail,
|
|
|
// this also handles new tail's empty `next` assignment.
|
|
|
/** @type {MemizeCacheNode} */ (node.prev).next = node.next;
|
|
|
if (node.next) {
|
|
|
node.next.prev = node.prev;
|
|
|
}
|
|
|
|
|
|
node.next = head;
|
|
|
node.prev = null;
|
|
|
/** @type {MemizeCacheNode} */ (head).prev = node;
|
|
|
head = node;
|
|
|
}
|
|
|
|
|
|
// Return immediately
|
|
|
return node.val;
|
|
|
}
|
|
|
|
|
|
// No cached value found. Continue to insertion phase:
|
|
|
|
|
|
// Create a copy of arguments (avoid leaking deoptimization)
|
|
|
args = new Array(len);
|
|
|
for (i = 0; i < len; i++) {
|
|
|
args[i] = arguments[i];
|
|
|
}
|
|
|
|
|
|
node = {
|
|
|
args: args,
|
|
|
|
|
|
// Generate the result from original function
|
|
|
val: fn.apply(null, args),
|
|
|
};
|
|
|
|
|
|
// Don't need to check whether node is already head, since it would
|
|
|
// have been returned above already if it was
|
|
|
|
|
|
// Shift existing head down list
|
|
|
if (head) {
|
|
|
head.prev = node;
|
|
|
node.next = head;
|
|
|
} else {
|
|
|
// If no head, follows that there's no tail (at initial or reset)
|
|
|
tail = node;
|
|
|
}
|
|
|
|
|
|
// Trim tail if we're reached max size and are pending cache insertion
|
|
|
if (size === /** @type {MemizeOptions} */ (options).maxSize) {
|
|
|
tail = /** @type {MemizeCacheNode} */ (tail).prev;
|
|
|
/** @type {MemizeCacheNode} */ (tail).next = null;
|
|
|
} else {
|
|
|
size++;
|
|
|
}
|
|
|
|
|
|
head = node;
|
|
|
|
|
|
return node.val;
|
|
|
}
|
|
|
|
|
|
memoized.clear = function () {
|
|
|
head = null;
|
|
|
tail = null;
|
|
|
size = 0;
|
|
|
};
|
|
|
|
|
|
// Ignore reason: There's not a clear solution to create an intersection of
|
|
|
// the function with additional properties, where the goal is to retain the
|
|
|
// function signature of the incoming argument and add control properties
|
|
|
// on the return value.
|
|
|
|
|
|
// @ts-ignore
|
|
|
return memoized;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/memoize.js
|
|
|
/**
|
|
|
* External dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
// re-export due to restrictive esModuleInterop setting
|
|
|
/* harmony default export */ const memoize = (memize);
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/constants.js
|
|
|
let Status = /*#__PURE__*/function (Status) {
|
|
|
Status["Idle"] = "IDLE";
|
|
|
Status["Resolving"] = "RESOLVING";
|
|
|
Status["Error"] = "ERROR";
|
|
|
Status["Success"] = "SUCCESS";
|
|
|
return Status;
|
|
|
}({});
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/use-query-select.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
const META_SELECTORS = ['getIsResolving', 'hasStartedResolution', 'hasFinishedResolution', 'isResolving', 'getCachedResolvers'];
|
|
|
/**
|
|
|
* Like useSelect, but the selectors return objects containing
|
|
|
* both the original data AND the resolution info.
|
|
|
*
|
|
|
* @since 6.1.0 Introduced in WordPress core.
|
|
|
* @private
|
|
|
*
|
|
|
* @param {Function} mapQuerySelect see useSelect
|
|
|
* @param {Array} deps see useSelect
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useQuerySelect } from '@wordpress/data';
|
|
|
* import { store as coreDataStore } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function PageTitleDisplay( { id } ) {
|
|
|
* const { data: page, isResolving } = useQuerySelect( ( query ) => {
|
|
|
* return query( coreDataStore ).getEntityRecord( 'postType', 'page', id )
|
|
|
* }, [ id ] );
|
|
|
*
|
|
|
* if ( isResolving ) {
|
|
|
* return 'Loading...';
|
|
|
* }
|
|
|
*
|
|
|
* return page.title;
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <PageTitleDisplay id={ 10 } />
|
|
|
* ```
|
|
|
*
|
|
|
* In the above example, when `PageTitleDisplay` is rendered into an
|
|
|
* application, the page and the resolution details will be retrieved from
|
|
|
* the store state using the `mapSelect` callback on `useQuerySelect`.
|
|
|
*
|
|
|
* If the id prop changes then any page in the state for that id is
|
|
|
* retrieved. If the id prop doesn't change and other props are passed in
|
|
|
* that do change, the title will not change because the dependency is just
|
|
|
* the id.
|
|
|
* @see useSelect
|
|
|
*
|
|
|
* @return {QuerySelectResponse} Queried data.
|
|
|
*/
|
|
|
function useQuerySelect(mapQuerySelect, deps) {
|
|
|
return (0,external_wp_data_namespaceObject.useSelect)((select, registry) => {
|
|
|
const resolve = store => enrichSelectors(select(store));
|
|
|
return mapQuerySelect(resolve, registry);
|
|
|
}, deps);
|
|
|
}
|
|
|
/**
|
|
|
* Transform simple selectors into ones that return an object with the
|
|
|
* original return value AND the resolution info.
|
|
|
*
|
|
|
* @param {Object} selectors Selectors to enrich
|
|
|
* @return {EnrichedSelectors} Enriched selectors
|
|
|
*/
|
|
|
const enrichSelectors = memoize(selectors => {
|
|
|
const resolvers = {};
|
|
|
for (const selectorName in selectors) {
|
|
|
if (META_SELECTORS.includes(selectorName)) {
|
|
|
continue;
|
|
|
}
|
|
|
Object.defineProperty(resolvers, selectorName, {
|
|
|
get: () => (...args) => {
|
|
|
const {
|
|
|
getIsResolving,
|
|
|
hasFinishedResolution
|
|
|
} = selectors;
|
|
|
const isResolving = !!getIsResolving(selectorName, args);
|
|
|
const hasResolved = !isResolving && hasFinishedResolution(selectorName, args);
|
|
|
const data = selectors[selectorName](...args);
|
|
|
let status;
|
|
|
if (isResolving) {
|
|
|
status = Status.Resolving;
|
|
|
} else if (hasResolved) {
|
|
|
if (data) {
|
|
|
status = Status.Success;
|
|
|
} else {
|
|
|
status = Status.Error;
|
|
|
}
|
|
|
} else {
|
|
|
status = Status.Idle;
|
|
|
}
|
|
|
return {
|
|
|
data,
|
|
|
status,
|
|
|
isResolving,
|
|
|
hasResolved
|
|
|
};
|
|
|
}
|
|
|
});
|
|
|
}
|
|
|
return resolvers;
|
|
|
});
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/use-entity-record.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
const use_entity_record_EMPTY_OBJECT = {};
|
|
|
|
|
|
/**
|
|
|
* Resolves the specified entity record.
|
|
|
*
|
|
|
* @since 6.1.0 Introduced in WordPress core.
|
|
|
*
|
|
|
* @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
|
|
|
* @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
|
|
|
* @param recordId ID of the requested entity record.
|
|
|
* @param options Optional hook options.
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useEntityRecord } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function PageTitleDisplay( { id } ) {
|
|
|
* const { record, isResolving } = useEntityRecord( 'postType', 'page', id );
|
|
|
*
|
|
|
* if ( isResolving ) {
|
|
|
* return 'Loading...';
|
|
|
* }
|
|
|
*
|
|
|
* return record.title;
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <PageTitleDisplay id={ 1 } />
|
|
|
* ```
|
|
|
*
|
|
|
* In the above example, when `PageTitleDisplay` is rendered into an
|
|
|
* application, the page and the resolution details will be retrieved from
|
|
|
* the store state using `getEntityRecord()`, or resolved if missing.
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useCallback } from 'react';
|
|
|
* import { useDispatch } from '@wordpress/data';
|
|
|
* import { __ } from '@wordpress/i18n';
|
|
|
* import { TextControl } from '@wordpress/components';
|
|
|
* import { store as noticeStore } from '@wordpress/notices';
|
|
|
* import { useEntityRecord } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function PageRenameForm( { id } ) {
|
|
|
* const page = useEntityRecord( 'postType', 'page', id );
|
|
|
* const { createSuccessNotice, createErrorNotice } =
|
|
|
* useDispatch( noticeStore );
|
|
|
*
|
|
|
* const setTitle = useCallback( ( title ) => {
|
|
|
* page.edit( { title } );
|
|
|
* }, [ page.edit ] );
|
|
|
*
|
|
|
* if ( page.isResolving ) {
|
|
|
* return 'Loading...';
|
|
|
* }
|
|
|
*
|
|
|
* async function onRename( event ) {
|
|
|
* event.preventDefault();
|
|
|
* try {
|
|
|
* await page.save();
|
|
|
* createSuccessNotice( __( 'Page renamed.' ), {
|
|
|
* type: 'snackbar',
|
|
|
* } );
|
|
|
* } catch ( error ) {
|
|
|
* createErrorNotice( error.message, { type: 'snackbar' } );
|
|
|
* }
|
|
|
* }
|
|
|
*
|
|
|
* return (
|
|
|
* <form onSubmit={ onRename }>
|
|
|
* <TextControl
|
|
|
* label={ __( 'Name' ) }
|
|
|
* value={ page.editedRecord.title }
|
|
|
* onChange={ setTitle }
|
|
|
* />
|
|
|
* <button type="submit">{ __( 'Save' ) }</button>
|
|
|
* </form>
|
|
|
* );
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <PageRenameForm id={ 1 } />
|
|
|
* ```
|
|
|
*
|
|
|
* In the above example, updating and saving the page title is handled
|
|
|
* via the `edit()` and `save()` mutation helpers provided by
|
|
|
* `useEntityRecord()`;
|
|
|
*
|
|
|
* @return Entity record data.
|
|
|
* @template RecordType
|
|
|
*/
|
|
|
function useEntityRecord(kind, name, recordId, options = {
|
|
|
enabled: true
|
|
|
}) {
|
|
|
const {
|
|
|
editEntityRecord,
|
|
|
saveEditedEntityRecord
|
|
|
} = (0,external_wp_data_namespaceObject.useDispatch)(store);
|
|
|
const mutations = (0,external_wp_element_namespaceObject.useMemo)(() => ({
|
|
|
edit: (record, editOptions = {}) => editEntityRecord(kind, name, recordId, record, editOptions),
|
|
|
save: (saveOptions = {}) => saveEditedEntityRecord(kind, name, recordId, {
|
|
|
throwOnError: true,
|
|
|
...saveOptions
|
|
|
})
|
|
|
}), [editEntityRecord, kind, name, recordId, saveEditedEntityRecord]);
|
|
|
const {
|
|
|
editedRecord,
|
|
|
hasEdits,
|
|
|
edits
|
|
|
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
|
|
|
if (!options.enabled) {
|
|
|
return {
|
|
|
editedRecord: use_entity_record_EMPTY_OBJECT,
|
|
|
hasEdits: false,
|
|
|
edits: use_entity_record_EMPTY_OBJECT
|
|
|
};
|
|
|
}
|
|
|
return {
|
|
|
editedRecord: select(store).getEditedEntityRecord(kind, name, recordId),
|
|
|
hasEdits: select(store).hasEditsForEntityRecord(kind, name, recordId),
|
|
|
edits: select(store).getEntityRecordNonTransientEdits(kind, name, recordId)
|
|
|
};
|
|
|
}, [kind, name, recordId, options.enabled]);
|
|
|
const {
|
|
|
data: record,
|
|
|
...querySelectRest
|
|
|
} = useQuerySelect(query => {
|
|
|
if (!options.enabled) {
|
|
|
return {
|
|
|
data: null
|
|
|
};
|
|
|
}
|
|
|
return query(store).getEntityRecord(kind, name, recordId);
|
|
|
}, [kind, name, recordId, options.enabled]);
|
|
|
return {
|
|
|
record,
|
|
|
editedRecord,
|
|
|
hasEdits,
|
|
|
edits,
|
|
|
...querySelectRest,
|
|
|
...mutations
|
|
|
};
|
|
|
}
|
|
|
function __experimentalUseEntityRecord(kind, name, recordId, options) {
|
|
|
external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecord`, {
|
|
|
alternative: 'wp.data.useEntityRecord',
|
|
|
since: '6.1'
|
|
|
});
|
|
|
return useEntityRecord(kind, name, recordId, options);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/use-entity-records.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
const use_entity_records_EMPTY_ARRAY = [];
|
|
|
|
|
|
/**
|
|
|
* Resolves the specified entity records.
|
|
|
*
|
|
|
* @since 6.1.0 Introduced in WordPress core.
|
|
|
*
|
|
|
* @param kind Kind of the entity, e.g. `root` or a `postType`. See rootEntitiesConfig in ../entities.ts for a list of available kinds.
|
|
|
* @param name Name of the entity, e.g. `plugin` or a `post`. See rootEntitiesConfig in ../entities.ts for a list of available names.
|
|
|
* @param queryArgs Optional HTTP query description for how to fetch the data, passed to the requested API endpoint.
|
|
|
* @param options Optional hook options.
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useEntityRecords } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function PageTitlesList() {
|
|
|
* const { records, isResolving } = useEntityRecords( 'postType', 'page' );
|
|
|
*
|
|
|
* if ( isResolving ) {
|
|
|
* return 'Loading...';
|
|
|
* }
|
|
|
*
|
|
|
* return (
|
|
|
* <ul>
|
|
|
* {records.map(( page ) => (
|
|
|
* <li>{ page.title }</li>
|
|
|
* ))}
|
|
|
* </ul>
|
|
|
* );
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <PageTitlesList />
|
|
|
* ```
|
|
|
*
|
|
|
* In the above example, when `PageTitlesList` is rendered into an
|
|
|
* application, the list of records and the resolution details will be retrieved from
|
|
|
* the store state using `getEntityRecords()`, or resolved if missing.
|
|
|
*
|
|
|
* @return Entity records data.
|
|
|
* @template RecordType
|
|
|
*/
|
|
|
function useEntityRecords(kind, name, queryArgs = {}, options = {
|
|
|
enabled: true
|
|
|
}) {
|
|
|
// Serialize queryArgs to a string that can be safely used as a React dep.
|
|
|
// We can't just pass queryArgs as one of the deps, because if it is passed
|
|
|
// as an object literal, then it will be a different object on each call even
|
|
|
// if the values remain the same.
|
|
|
const queryAsString = (0,external_wp_url_namespaceObject.addQueryArgs)('', queryArgs);
|
|
|
const {
|
|
|
data: records,
|
|
|
...rest
|
|
|
} = useQuerySelect(query => {
|
|
|
if (!options.enabled) {
|
|
|
return {
|
|
|
// Avoiding returning a new reference on every execution.
|
|
|
data: use_entity_records_EMPTY_ARRAY
|
|
|
};
|
|
|
}
|
|
|
return query(store).getEntityRecords(kind, name, queryArgs);
|
|
|
}, [kind, name, queryAsString, options.enabled]);
|
|
|
const {
|
|
|
totalItems,
|
|
|
totalPages
|
|
|
} = (0,external_wp_data_namespaceObject.useSelect)(select => {
|
|
|
if (!options.enabled) {
|
|
|
return {
|
|
|
totalItems: null,
|
|
|
totalPages: null
|
|
|
};
|
|
|
}
|
|
|
return {
|
|
|
totalItems: select(store).getEntityRecordsTotalItems(kind, name, queryArgs),
|
|
|
totalPages: select(store).getEntityRecordsTotalPages(kind, name, queryArgs)
|
|
|
};
|
|
|
}, [kind, name, queryAsString, options.enabled]);
|
|
|
return {
|
|
|
records,
|
|
|
totalItems,
|
|
|
totalPages,
|
|
|
...rest
|
|
|
};
|
|
|
}
|
|
|
function __experimentalUseEntityRecords(kind, name, queryArgs, options) {
|
|
|
external_wp_deprecated_default()(`wp.data.__experimentalUseEntityRecords`, {
|
|
|
alternative: 'wp.data.useEntityRecords',
|
|
|
since: '6.1'
|
|
|
});
|
|
|
return useEntityRecords(kind, name, queryArgs, options);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/use-resource-permissions.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Resolves resource permissions.
|
|
|
*
|
|
|
* @since 6.1.0 Introduced in WordPress core.
|
|
|
*
|
|
|
* @param resource The resource in question, e.g. media.
|
|
|
* @param id ID of a specific resource entry, if needed, e.g. 10.
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useResourcePermissions } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function PagesList() {
|
|
|
* const { canCreate, isResolving } = useResourcePermissions( 'pages' );
|
|
|
*
|
|
|
* if ( isResolving ) {
|
|
|
* return 'Loading ...';
|
|
|
* }
|
|
|
*
|
|
|
* return (
|
|
|
* <div>
|
|
|
* {canCreate ? (<button>+ Create a new page</button>) : false}
|
|
|
* // ...
|
|
|
* </div>
|
|
|
* );
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <PagesList />
|
|
|
* ```
|
|
|
*
|
|
|
* @example
|
|
|
* ```js
|
|
|
* import { useResourcePermissions } from '@wordpress/core-data';
|
|
|
*
|
|
|
* function Page({ pageId }) {
|
|
|
* const {
|
|
|
* canCreate,
|
|
|
* canUpdate,
|
|
|
* canDelete,
|
|
|
* isResolving
|
|
|
* } = useResourcePermissions( 'pages', pageId );
|
|
|
*
|
|
|
* if ( isResolving ) {
|
|
|
* return 'Loading ...';
|
|
|
* }
|
|
|
*
|
|
|
* return (
|
|
|
* <div>
|
|
|
* {canCreate ? (<button>+ Create a new page</button>) : false}
|
|
|
* {canUpdate ? (<button>Edit page</button>) : false}
|
|
|
* {canDelete ? (<button>Delete page</button>) : false}
|
|
|
* // ...
|
|
|
* </div>
|
|
|
* );
|
|
|
* }
|
|
|
*
|
|
|
* // Rendered in the application:
|
|
|
* // <Page pageId={ 15 } />
|
|
|
* ```
|
|
|
*
|
|
|
* In the above example, when `PagesList` is rendered into an
|
|
|
* application, the appropriate permissions and the resolution details will be retrieved from
|
|
|
* the store state using `canUser()`, or resolved if missing.
|
|
|
*
|
|
|
* @return Entity records data.
|
|
|
* @template IdType
|
|
|
*/
|
|
|
function useResourcePermissions(resource, id) {
|
|
|
return useQuerySelect(resolve => {
|
|
|
const {
|
|
|
canUser
|
|
|
} = resolve(store);
|
|
|
const create = canUser('create', resource);
|
|
|
if (!id) {
|
|
|
const read = canUser('read', resource);
|
|
|
const isResolving = create.isResolving || read.isResolving;
|
|
|
const hasResolved = create.hasResolved && read.hasResolved;
|
|
|
let status = Status.Idle;
|
|
|
if (isResolving) {
|
|
|
status = Status.Resolving;
|
|
|
} else if (hasResolved) {
|
|
|
status = Status.Success;
|
|
|
}
|
|
|
return {
|
|
|
status,
|
|
|
isResolving,
|
|
|
hasResolved,
|
|
|
canCreate: create.hasResolved && create.data,
|
|
|
canRead: read.hasResolved && read.data
|
|
|
};
|
|
|
}
|
|
|
const read = canUser('read', resource, id);
|
|
|
const update = canUser('update', resource, id);
|
|
|
const _delete = canUser('delete', resource, id);
|
|
|
const isResolving = read.isResolving || create.isResolving || update.isResolving || _delete.isResolving;
|
|
|
const hasResolved = read.hasResolved && create.hasResolved && update.hasResolved && _delete.hasResolved;
|
|
|
let status = Status.Idle;
|
|
|
if (isResolving) {
|
|
|
status = Status.Resolving;
|
|
|
} else if (hasResolved) {
|
|
|
status = Status.Success;
|
|
|
}
|
|
|
return {
|
|
|
status,
|
|
|
isResolving,
|
|
|
hasResolved,
|
|
|
canRead: hasResolved && read.data,
|
|
|
canCreate: hasResolved && create.data,
|
|
|
canUpdate: hasResolved && update.data,
|
|
|
canDelete: hasResolved && _delete.data
|
|
|
};
|
|
|
}, [resource, id]);
|
|
|
}
|
|
|
function __experimentalUseResourcePermissions(resource, id) {
|
|
|
external_wp_deprecated_default()(`wp.data.__experimentalUseResourcePermissions`, {
|
|
|
alternative: 'wp.data.useResourcePermissions',
|
|
|
since: '6.1'
|
|
|
});
|
|
|
return useResourcePermissions(resource, id);
|
|
|
}
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/hooks/index.js
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;// CONCATENATED MODULE: ./node_modules/@wordpress/core-data/build-module/index.js
|
|
|
/**
|
|
|
* WordPress dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
/**
|
|
|
* Internal dependencies
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// The entity selectors/resolvers and actions are shortcuts to their generic equivalents
|
|
|
// (getEntityRecord, getEntityRecords, updateEntityRecord, updateEntityRecords)
|
|
|
// Instead of getEntityRecord, the consumer could use more user-friendly named selector: getPostType, getTaxonomy...
|
|
|
// The "kind" and the "name" of the entity are combined to generate these shortcuts.
|
|
|
|
|
|
const entitySelectors = rootEntitiesConfig.reduce((result, entity) => {
|
|
|
const {
|
|
|
kind,
|
|
|
name
|
|
|
} = entity;
|
|
|
result[getMethodName(kind, name)] = (state, key, query) => getEntityRecord(state, kind, name, key, query);
|
|
|
result[getMethodName(kind, name, 'get', true)] = (state, query) => getEntityRecords(state, kind, name, query);
|
|
|
return result;
|
|
|
}, {});
|
|
|
const entityResolvers = rootEntitiesConfig.reduce((result, entity) => {
|
|
|
const {
|
|
|
kind,
|
|
|
name
|
|
|
} = entity;
|
|
|
result[getMethodName(kind, name)] = (key, query) => resolvers_getEntityRecord(kind, name, key, query);
|
|
|
const pluralMethodName = getMethodName(kind, name, 'get', true);
|
|
|
result[pluralMethodName] = (...args) => resolvers_getEntityRecords(kind, name, ...args);
|
|
|
result[pluralMethodName].shouldInvalidate = action => resolvers_getEntityRecords.shouldInvalidate(action, kind, name);
|
|
|
return result;
|
|
|
}, {});
|
|
|
const entityActions = rootEntitiesConfig.reduce((result, entity) => {
|
|
|
const {
|
|
|
kind,
|
|
|
name
|
|
|
} = entity;
|
|
|
result[getMethodName(kind, name, 'save')] = (record, options) => saveEntityRecord(kind, name, record, options);
|
|
|
result[getMethodName(kind, name, 'delete')] = (key, query, options) => deleteEntityRecord(kind, name, key, query, options);
|
|
|
return result;
|
|
|
}, {});
|
|
|
const storeConfig = () => ({
|
|
|
reducer: build_module_reducer,
|
|
|
actions: {
|
|
|
...build_module_actions_namespaceObject,
|
|
|
...entityActions,
|
|
|
...createLocksActions()
|
|
|
},
|
|
|
selectors: {
|
|
|
...build_module_selectors_namespaceObject,
|
|
|
...entitySelectors
|
|
|
},
|
|
|
resolvers: {
|
|
|
...resolvers_namespaceObject,
|
|
|
...entityResolvers
|
|
|
}
|
|
|
});
|
|
|
|
|
|
/**
|
|
|
* Store definition for the code data namespace.
|
|
|
*
|
|
|
* @see https://github.com/WordPress/gutenberg/blob/HEAD/packages/data/README.md#createReduxStore
|
|
|
*/
|
|
|
const store = (0,external_wp_data_namespaceObject.createReduxStore)(STORE_NAME, storeConfig());
|
|
|
unlock(store).registerPrivateSelectors(private_selectors_namespaceObject);
|
|
|
(0,external_wp_data_namespaceObject.register)(store); // Register store after unlocking private selectors to allow resolvers to use them.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
})();
|
|
|
|
|
|
(window.wp = window.wp || {}).coreData = __webpack_exports__;
|
|
|
/******/ })()
|
|
|
; |