/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
import Component from 'metal-component';
import objectToFormData from './util/form/object_to_form_data.es';
function toElementHelper(elementOrSelector) {
if (typeof elementOrSelector === 'string') {
elementOrSelector = document.querySelector(elementOrSelector);
}
return elementOrSelector;
}
function isString(val) {
return typeof val === 'string';
}
/**
* Provides helper functions that simplify querying the DOM for elements related
* to a specific portlet.
*
* @abstract
* @extends {Component}
*/
class PortletBase extends Component {
/**
* Returns a Node List containing all the matching element nodes within the
* subtrees of the root object, in tree order. If there are no matching
* nodes, the method returns an empty Node List.
*
* @param {string} selectors A list of one or more CSS relative selectors.
* @param {(string|Element|Document)=} root The root node of the search. If
* not specified, the element search will start in the portlet's
* root node or in the document.
* @return {NodeList<Element>} A list of elements matching the selectors, in
* tree order.
*/
all(selectors, root) {
root = toElementHelper(root) || this.rootNode || document;
return root.querySelectorAll(
this.namespaceSelectors_(
this.portletNamespace || this.namespace,
selectors
)
);
}
/**
* Performs an HTTP POST request to the given URL with the given body.
*
* @deprecated As of Athanasius (7.3.x), replaced by `Liferay.Util.fetch`.
* @param {!string} url The URL to send the post request to.
* @param {!Object|!FormData} body The request body.
* @return {Promise} A promise.
*/
fetch(url, body) {
const requestBody = this.getRequestBody_(body);
// eslint-disable-next-line @liferay/portal/no-global-fetch
return fetch(url, {
body: requestBody,
credentials: 'include',
method: 'POST',
});
}
/**
* Transforms the given body into a valid <code>FormData</code> element.
*
* @param {!FormData|!HTMLFormElement|!Object} body The original data.
* @return {FormData} The transformed form data.
*/
getRequestBody_(body) {
let requestBody;
if (body instanceof FormData) {
requestBody = body;
}
else if (body instanceof HTMLFormElement) {
requestBody = new FormData(body);
}
else if (typeof body === 'object') {
requestBody = objectToFormData(this.ns(body));
}
else {
requestBody = body;
}
return requestBody;
}
/**
* Namespaces the list of selectors, appending the portlet namespace to the
* selectors of type ID. Selectors of other types remain unaltered.
*
* @param {string} namespace The portlet's namespace.
* @param {string} selectors A list of one or more CSS relative selectors.
* @protected
* @return {string} The namespaced ID selectors.
*/
namespaceSelectors_(namespace, selectors) {
return selectors.replace(
new RegExp('(#|\\[id=(\\"|\\\'))(?!' + namespace + ')', 'g'),
'$1' + namespace
);
}
/**
* Appends the portlet's namespace to the given string or object properties.
*
* @param {!Object|string} obj The object or string to namespace.
* @return {Object|string} An object with its properties namespaced, using
* the portlet namespace or a namespaced string.
*/
ns(object) {
return Liferay.Util.ns(this.portletNamespace || this.namespace, object);
}
/**
* Returns the first matching Element node within the subtrees of the
* root object. If there is no matching Element, the method returns null.
*
* @param {string} selectors A list of one or more CSS relative selectors.
* @param {(string|Element|Document)=} root The root node of the search. If
* not specified, the element search will start in the portlet's
* root node or in the document.
* @return {Element|null} A list of the first element matching the selectors
* or <code>null</code>.
*/
one(selectors, root) {
root = toElementHelper(root) || this.rootNode || document;
return root.querySelector(
this.namespaceSelectors_(
this.portletNamespace || this.namespace,
selectors
)
);
}
/**
* Returns the default portlet root node element. By default, this is the
* element with ID <code>p_p_id{portletNamespace}</code>.
*
* @protected
* @return {Element} The portlet's default root node element.
*/
rootNodeValueFn_() {
return document.getElementById(
`p_p_id${this.portletNamespace || this.namespace}`
);
}
}
/**
* State definition.
*
* @ignore
* @static
* @type {!Object}
*/
PortletBase.STATE = {
/**
* Portlet's namespace.
*
* @deprecated As of Judson (7.1.x)
* @instance
* @memberof PortletBase
* @type {string}
*/
namespace: {
validator: isString,
},
/**
* Portlet's namespace.
*
* @instance
* @memberof PortletBase
* @type {string}
*/
portletNamespace: {
validator: isString,
},
/**
* Portlet's root node element.
*
* @instance
* @memberof PortletBase
* @type {Element}
*/
rootNode: {
setter: toElementHelper,
valueFn: 'rootNodeValueFn_',
},
};
export default PortletBase;