Source: portlet/portlet_util.es.js

  1. /**
  2. * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
  3. *
  4. * This library is free software; you can redistribute it and/or modify it under
  5. * the terms of the GNU Lesser General Public License as published by the Free
  6. * Software Foundation; either version 2.1 of the License, or (at your option)
  7. * any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but WITHOUT
  10. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  11. * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
  12. * details.
  13. */
  14. // Constants for URL generation
  15. const AJAX_ACTION_VALUE = '0';
  16. const CACHE_LEVEL_KEY = 'p_p_cacheability';
  17. const HUB_ACTION_KEY = 'p_p_hub';
  18. const PARTIAL_ACTION_VALUE = '1';
  19. const PORTLET_MODE_KEY = 'p_p_mode';
  20. const PUBLIC_RENDER_PARAM_KEY = 'p_r_p_';
  21. const RENDER_PARAM_KEY = 'priv_r_p_';
  22. const RESOURCE_ID_KEY = 'p_p_resource_id';
  23. const TOKEN_DELIM = '&';
  24. const VALUE_ARRAY_EMPTY = '';
  25. const VALUE_DELIM = '=';
  26. const VALUE_NULL = '';
  27. const WINDOW_STATE_KEY = 'p_p_state';
  28. /**
  29. * Compares two parameters and returns a boolean indicating if they're equal
  30. * or not.
  31. * @param {?Array.<string>} parameter1 The first parameter to compare.
  32. * @param {?Array.<string>} parameter2 The second parameter to compare.
  33. * @return {boolean}
  34. * @review
  35. */
  36. const isParameterEqual = function (parameter1, parameter2) {
  37. let result = false;
  38. // The values are either string arrays or undefined.
  39. if (parameter1 === undefined && parameter2 === undefined) {
  40. result = true;
  41. }
  42. if (parameter1 === undefined || parameter2 === undefined) {
  43. result = false;
  44. }
  45. if (parameter1.length !== parameter2.length) {
  46. result = false;
  47. }
  48. for (let i = parameter1.length - 1; i >= 0; i--) {
  49. if (parameter1[i] !== parameter2[i]) {
  50. result = false;
  51. }
  52. }
  53. return result;
  54. };
  55. /**
  56. * Returns true if input state differs from the current page state.
  57. * Throws exception if input state is malformed.
  58. * @param {Object} pageRenderState The (current) page render state.
  59. * @param {RenderState} newState The new state to be set.
  60. * @param {string} portletId The portlet ID.
  61. * @return {boolean} True if the two state are different.
  62. * @review
  63. */
  64. const stateChanged = function (pageRenderState, newState, portletId) {
  65. let result = false;
  66. if (pageRenderState && pageRenderState.portlets) {
  67. const portletData = pageRenderState.portlets[portletId];
  68. if (portletData) {
  69. const oldState = pageRenderState.portlets[portletId].state;
  70. if (
  71. !newState.portletMode ||
  72. !newState.windowState ||
  73. !newState.parameters
  74. ) {
  75. throw new Error(`Error decoding state: ${newState}`);
  76. }
  77. if (
  78. newState.porletMode !== oldState.portletMode ||
  79. newState.windowState !== oldState.windowState
  80. ) {
  81. result = true;
  82. }
  83. else {
  84. // Has a parameter changed or been added?
  85. const newKeys = Object.keys(newState.parameters);
  86. newKeys.forEach((key) => {
  87. const newParameter = newState.parameters[key];
  88. const oldParameter = oldState.parameters[key];
  89. if (!isParameterEqual(newParameter, oldParameter)) {
  90. result = true;
  91. }
  92. });
  93. // Make sure no parameter was deleted
  94. const oldKeys = Object.keys(oldState.parameters);
  95. oldKeys.forEach((key) => {
  96. if (!newState.parameters[key]) {
  97. result = true;
  98. }
  99. });
  100. }
  101. }
  102. }
  103. return result;
  104. };
  105. /**
  106. * Decodes the update strings.
  107. * The update string is a JSON object containing the entire page state.
  108. * This decoder returns an object containing the portlet data for portlets whose
  109. * state has changed as compared to the current page state.
  110. * @param {Object} pageRenderState The page render state.
  111. * @param {string} updateString The update string to decode.
  112. * @return {Object}
  113. * @review
  114. */
  115. const decodeUpdateString = function (pageRenderState, updateString) {
  116. const portlets =
  117. pageRenderState && pageRenderState.portlets
  118. ? pageRenderState.portlets
  119. : {};
  120. try {
  121. const newRenderState = JSON.parse(updateString);
  122. if (newRenderState.portlets) {
  123. const keys = Object.keys(portlets);
  124. keys.forEach((key) => {
  125. const newState = newRenderState.portlets[key].state;
  126. const oldState = portlets[key].state;
  127. if (!newState || !oldState) {
  128. throw new Error(
  129. `Invalid update string.\nold state=${oldState}\nnew state=${newState}`
  130. );
  131. }
  132. if (stateChanged(pageRenderState, newState, key)) {
  133. portlets[key] = newRenderState.portlets[key];
  134. }
  135. });
  136. }
  137. }
  138. catch (e) {
  139. // Do nothing
  140. }
  141. return portlets;
  142. };
  143. /**
  144. * Function to extract data from form and encode
  145. * it as an 'application/x-www-form-urlencoded' string.
  146. * @param {string} portletId The portlet ID.
  147. * @param {HTMLFormElement} form Form to be submitted.
  148. * @review
  149. */
  150. const encodeFormAsString = function (portletId, form) {
  151. const parameters = [];
  152. for (let i = 0; i < form.elements.length; i++) {
  153. const element = form.elements[i];
  154. const name = element.name;
  155. const tag = element.nodeName.toUpperCase();
  156. const type = tag === 'INPUT' ? element.type.toUpperCase() : '';
  157. const value = element.value;
  158. if (name && !element.disabled && type !== 'FILE') {
  159. if (tag === 'SELECT' && element.multiple) {
  160. const options = [...element.options];
  161. options.forEach((opt) => {
  162. if (opt.checked) {
  163. const value = opt.value;
  164. const parameter =
  165. encodeURIComponent(portletId + name) +
  166. '=' +
  167. encodeURIComponent(value);
  168. parameters.push(parameter);
  169. }
  170. });
  171. }
  172. else if (
  173. (type !== 'CHECKBOX' && type !== 'RADIO') ||
  174. element.checked
  175. ) {
  176. const param =
  177. encodeURIComponent(portletId + name) +
  178. '=' +
  179. encodeURIComponent(value);
  180. parameters.push(param);
  181. }
  182. }
  183. }
  184. return parameters.join('&');
  185. };
  186. /**
  187. * Helper for encoding a multi valued parameter.
  188. * @param {string} name The parameter's name.
  189. * @param {Array.<string>} values The parameter's value.
  190. * @return {string}
  191. * @review
  192. */
  193. const encodeParameter = function (name, values) {
  194. let str = '';
  195. if (Array.isArray(values)) {
  196. if (values.length === 0) {
  197. str +=
  198. TOKEN_DELIM +
  199. encodeURIComponent(name) +
  200. VALUE_DELIM +
  201. VALUE_ARRAY_EMPTY;
  202. }
  203. else {
  204. values.forEach((value) => {
  205. str += TOKEN_DELIM + encodeURIComponent(name);
  206. if (value === null) {
  207. str += VALUE_DELIM + VALUE_NULL;
  208. }
  209. else {
  210. str += VALUE_DELIM + encodeURIComponent(value);
  211. }
  212. });
  213. }
  214. }
  215. return str;
  216. };
  217. /**
  218. * Generates the required options for an action URL request
  219. * according to the portletId, action URL and optional form element.
  220. *
  221. * @param {string} portletId The id of the portlet.
  222. * @param {string} url The action url.
  223. * @param {HTMLFormElement} The form element.
  224. * @return {Object}
  225. * @review
  226. */
  227. const generateActionUrl = function (portletId, url, form) {
  228. const request = {
  229. credentials: 'same-origin',
  230. method: 'POST',
  231. url,
  232. };
  233. if (form) {
  234. const enctype = form.enctype;
  235. if (enctype === 'multipart/form-data') {
  236. const formData = new FormData(form);
  237. request.body = formData;
  238. }
  239. else {
  240. const formAsString = encodeFormAsString(portletId, form);
  241. const method = form.method ? form.method.toUpperCase() : 'GET';
  242. if (method === 'GET') {
  243. if (url.indexOf('?') >= 0) {
  244. url += `&${formAsString}`;
  245. }
  246. else {
  247. url += `?${formAsString}`;
  248. }
  249. request.url = url;
  250. }
  251. else {
  252. request.body = formAsString;
  253. request.headers = {
  254. 'Content-Type': 'application/x-www-form-urlencoded',
  255. };
  256. }
  257. }
  258. }
  259. return request;
  260. };
  261. /**
  262. * Helper for generating parameter strings for the URL
  263. * @param {Object} pageRenderState The page render state.
  264. * @param {string} portletId The portlet ID.
  265. * @param {string} name The parameter's name.
  266. * @param {string} type The parameter's type.
  267. * @param {string} group The parameter's group.
  268. * @review
  269. */
  270. const generateParameterString = function (
  271. pageRenderState,
  272. portletId,
  273. name,
  274. type,
  275. group
  276. ) {
  277. let str = '';
  278. if (pageRenderState.portlets && pageRenderState.portlets[portletId]) {
  279. const portletData = pageRenderState.portlets[portletId];
  280. if (portletData && portletData.state && portletData.state.parameters) {
  281. const values = portletData.state.parameters[name];
  282. if (values !== undefined) {
  283. // If values are present, encode the mutlivalued parameter string
  284. if (type === PUBLIC_RENDER_PARAM_KEY) {
  285. str += encodeParameter(group, values);
  286. }
  287. else if (type === RENDER_PARAM_KEY) {
  288. str += encodeParameter(
  289. portletId + RENDER_PARAM_KEY + name,
  290. values
  291. );
  292. }
  293. else {
  294. str += encodeParameter(portletId + name, values);
  295. }
  296. }
  297. }
  298. }
  299. return str;
  300. };
  301. /**
  302. * Helper for generating portlet mode & window state strings for the URL.
  303. * @param {Object} pageRenderState The page render state.
  304. * @param {string} portletId The portlet ID.
  305. * @return {string}
  306. * @review
  307. */
  308. const generatePortletModeAndWindowStateString = function (
  309. pageRenderState,
  310. portletId
  311. ) {
  312. let str = '';
  313. if (pageRenderState.portlets) {
  314. const portletData = pageRenderState.portlets[portletId];
  315. if (portletData.state) {
  316. const state = portletData.state;
  317. str +=
  318. TOKEN_DELIM +
  319. PORTLET_MODE_KEY +
  320. VALUE_DELIM +
  321. encodeURIComponent(state.portletMode);
  322. str +=
  323. TOKEN_DELIM +
  324. WINDOW_STATE_KEY +
  325. VALUE_DELIM +
  326. encodeURIComponent(state.windowState);
  327. }
  328. }
  329. return str;
  330. };
  331. /**
  332. * Compares the values of the named parameter in the new render state
  333. * with the values of that parameter in the current state.
  334. * @param {Object} pageRenderState The page render state.
  335. * @param {string} portletId The portlet ID.
  336. * @param {RenderState} state The new render state.
  337. * @param {string} name The name of the parameter to check.
  338. * @return {boolean} True if the new parameter's value is different from the current value.
  339. * @review
  340. */
  341. const isParameterInStateEqual = function (
  342. pageRenderState,
  343. portletId,
  344. state,
  345. name
  346. ) {
  347. let result = false;
  348. if (pageRenderState && pageRenderState.portlets) {
  349. const portletData = pageRenderState.portlets[portletId];
  350. if (state.parameters[name] && portletData.state.parameters[name]) {
  351. const newParameter = state.parameters[name];
  352. const oldParameter = portletData.state.parameters[name];
  353. result = isParameterEqual(newParameter, oldParameter);
  354. }
  355. }
  356. return result;
  357. };
  358. /**
  359. * Gets the updated public parameters for the given portlet ID and new render state.
  360. * Returns an object whose properties are the group indexes of the
  361. * updated public parameters. The values are the new public parameter values.
  362. * @param {Object} pageRenderState The page render state.
  363. * @param {string} portletId The portlet ID.
  364. * @param {RenderState} state The new render state.
  365. * @return {Object} Object containing the updated public render parameters.
  366. * @review
  367. */
  368. const getUpdatedPublicRenderParameters = function (
  369. pageRenderState,
  370. portletId,
  371. state
  372. ) {
  373. const publicRenderParameters = {};
  374. if (pageRenderState && pageRenderState.portlets) {
  375. const portletData = pageRenderState.portlets[portletId];
  376. if (portletData && portletData.pubParms) {
  377. const portletPublicParameters = portletData.pubParms;
  378. const keys = Object.keys(portletPublicParameters);
  379. keys.forEach((key) => {
  380. if (
  381. !isParameterInStateEqual(
  382. pageRenderState,
  383. portletId,
  384. state,
  385. key
  386. )
  387. ) {
  388. const group = portletPublicParameters[key];
  389. publicRenderParameters[group] = state.parameters[key];
  390. }
  391. });
  392. }
  393. }
  394. return publicRenderParameters;
  395. };
  396. /**
  397. * Function for checking if a parameter is public.
  398. * @param {Object} pageRenderState The page render state.
  399. * @param {string} portletId The portlet ID.
  400. * @param {string} name The name of the parameter to check.
  401. * @return {boolean}
  402. * @review
  403. */
  404. const isPublicParameter = function (pageRenderState, portletId, name) {
  405. let result = false;
  406. if (pageRenderState && pageRenderState.portlets) {
  407. const portletData = pageRenderState.portlets[portletId];
  408. if (portletData && portletData.pubParms) {
  409. const keys = Object.keys(portletData.pubParms);
  410. result = keys.includes(name);
  411. }
  412. }
  413. return result;
  414. };
  415. /**
  416. * Returns a URL of the specified type.
  417. * @param {Object} pageRenderState The page render state.
  418. * @param {string} type The URL type.
  419. * @param {string} portletId The portlet ID.
  420. * @param {Object} parameters Additional parameters. May be <code>null</code>.
  421. * @param {string} cache Cacheability. Must be present if type = "RESOURCE". May be <code>null</code>.
  422. * @param {string} resourceId Resource ID. May be present if type = "RESOURCE". May be <code>null</code>.
  423. * @return {Promise} A promise that resolves the generated URL.
  424. * @review
  425. */
  426. const getUrl = function (
  427. pageRenderState,
  428. type,
  429. portletId,
  430. parameters,
  431. cache,
  432. resourceId
  433. ) {
  434. let cacheability = 'cacheLevelPage';
  435. let str = '';
  436. let url = '';
  437. if (pageRenderState && pageRenderState.portlets) {
  438. // If target portlet not defined for render URL, set it to null
  439. if (type === 'RENDER' && portletId === undefined) {
  440. portletId = null;
  441. }
  442. const portletData = pageRenderState.portlets[portletId];
  443. if (portletData) {
  444. if (type === 'RESOURCE') {
  445. url = decodeURIComponent(portletData.encodedResourceURL);
  446. if (cache) {
  447. cacheability = cache;
  448. }
  449. url +=
  450. TOKEN_DELIM +
  451. CACHE_LEVEL_KEY +
  452. VALUE_DELIM +
  453. encodeURIComponent(cacheability);
  454. if (resourceId) {
  455. url +=
  456. TOKEN_DELIM +
  457. RESOURCE_ID_KEY +
  458. VALUE_DELIM +
  459. encodeURIComponent(resourceId);
  460. }
  461. }
  462. else if (type === 'RENDER' && portletId !== null) {
  463. url = decodeURIComponent(portletData.encodedRenderURL);
  464. }
  465. else if (type === 'RENDER') {
  466. url = decodeURIComponent(pageRenderState.encodedCurrentURL);
  467. }
  468. else if (type === 'ACTION') {
  469. url = decodeURIComponent(portletData.encodedActionURL);
  470. url +=
  471. TOKEN_DELIM +
  472. HUB_ACTION_KEY +
  473. VALUE_DELIM +
  474. encodeURIComponent(AJAX_ACTION_VALUE);
  475. }
  476. else if (type === 'PARTIAL_ACTION') {
  477. url = decodeURIComponent(portletData.encodedActionURL);
  478. url +=
  479. TOKEN_DELIM +
  480. HUB_ACTION_KEY +
  481. VALUE_DELIM +
  482. encodeURIComponent(PARTIAL_ACTION_VALUE);
  483. }
  484. // Now add the state to the URL, taking into account cacheability if
  485. // we're dealing with a resource URL.
  486. // Put the private & public parameters on the URL if cacheability != FULL
  487. if (type !== 'RESOURCE' || cacheability !== 'cacheLevelFull') {
  488. // Add the state for the target portlet, if there is one.
  489. // (for the render URL, pid can be null, and the state will have
  490. // been added previously)
  491. if (portletId) {
  492. url += generatePortletModeAndWindowStateString(
  493. pageRenderState,
  494. portletId
  495. );
  496. }
  497. // Add the state for the target portlet, if there is one.
  498. // (for the render URL, pid can be null, and the state will have
  499. // been added previously)
  500. if (portletId) {
  501. str = '';
  502. if (portletData.state && portletData.state.parameters) {
  503. const stateParameters = portletData.state.parameters;
  504. const keys = Object.keys(stateParameters);
  505. keys.forEach((key) => {
  506. if (
  507. !isPublicParameter(
  508. pageRenderState,
  509. portletId,
  510. key
  511. )
  512. ) {
  513. str += generateParameterString(
  514. pageRenderState,
  515. portletId,
  516. key,
  517. RENDER_PARAM_KEY
  518. );
  519. }
  520. });
  521. url += str;
  522. }
  523. }
  524. // Add the public render parameters for all portlets
  525. if (pageRenderState.prpMap) {
  526. str = '';
  527. const publicRenderParameters = {};
  528. const mapKeys = Object.keys(pageRenderState.prpMap);
  529. mapKeys.forEach((mapKey) => {
  530. const groupKeys = Object.keys(
  531. pageRenderState.prpMap[mapKey]
  532. );
  533. groupKeys.forEach((groupKey) => {
  534. const groupName =
  535. pageRenderState.prpMap[mapKey][groupKey];
  536. const parts = groupName.split('|');
  537. // Only need to add parameter once, since it is shared
  538. if (
  539. !Object.hasOwnProperty.call(
  540. publicRenderParameters,
  541. mapKey
  542. )
  543. ) {
  544. publicRenderParameters[
  545. mapKey
  546. ] = generateParameterString(
  547. pageRenderState,
  548. parts[0],
  549. parts[1],
  550. PUBLIC_RENDER_PARAM_KEY,
  551. mapKey
  552. );
  553. str += publicRenderParameters[mapKey];
  554. }
  555. });
  556. });
  557. url += str;
  558. }
  559. }
  560. }
  561. }
  562. // Encode resource or action parameters
  563. if (parameters) {
  564. str = '';
  565. const parameterKeys = Object.keys(parameters);
  566. parameterKeys.forEach((parameterKey) => {
  567. str += encodeParameter(
  568. portletId + parameterKey,
  569. parameters[parameterKey]
  570. );
  571. });
  572. url += str;
  573. }
  574. return Promise.resolve(url);
  575. };
  576. /**
  577. * Used by the portlet hub methods to check the number and types of the
  578. * arguments.
  579. *
  580. * @param {string[]} args The argument list to be checked.
  581. * @param {number} min The minimum number of arguments.
  582. * @param {number} max The maximum number of arguments. If this value is
  583. * undefined, the function can take any number of arguments greater
  584. * than max.
  585. * @param {string[]} types An array containing the expected parameter types in the
  586. * order of occurrance in the argument array.
  587. * @throws {TypeError} Thrown if the parameters are in some manner incorrect.
  588. * @review
  589. */
  590. const validateArguments = function (args = [], min = 0, max = 1, types = []) {
  591. if (args.length < min) {
  592. throw new TypeError(
  593. `Too few arguments provided: Number of arguments: ${args.length}`
  594. );
  595. }
  596. else if (args.length > max) {
  597. throw new TypeError(
  598. `Too many arguments provided: ${[].join.call(args, ', ')}`
  599. );
  600. }
  601. else if (Array.isArray(types)) {
  602. let i = Math.min(args.length, types.length) - 1;
  603. for (i; i >= 0; i--) {
  604. if (typeof args[i] !== types[i]) {
  605. throw new TypeError(
  606. `Parameter ${i} is of type ${typeof args[
  607. i
  608. ]} rather than the expected type ${types[i]}`
  609. );
  610. }
  611. if (args[i] === null || args[i] === undefined) {
  612. throw new TypeError(`Argument is ${typeof args[i]}`);
  613. }
  614. }
  615. }
  616. };
  617. /**
  618. * Validates an HTMLFormElement
  619. * @param {?HTMLFormElement} form The form element to be validated.
  620. * @throws {TypeError} Thrown if the form is not an HTMLFormElement.
  621. * @throws {TypeError} Thrown if the form's method attribute is not valid.
  622. * @throws {TypeError} Thrown if the form's enctype attribute is not valid.
  623. * @throws {TypeError} Thrown if the form's enctype attribute is not valid.
  624. * @review
  625. */
  626. const validateForm = function (form) {
  627. if (!(form instanceof HTMLFormElement)) {
  628. throw new TypeError('Element must be an HTMLFormElement');
  629. }
  630. const method = form.method ? form.method.toUpperCase() : undefined;
  631. if (method && method !== 'GET' && method !== 'POST') {
  632. throw new TypeError(
  633. `Invalid form method ${method}. Allowed methods are GET & POST`
  634. );
  635. }
  636. const enctype = form.enctype;
  637. if (
  638. enctype &&
  639. enctype !== 'application/x-www-form-urlencoded' &&
  640. enctype !== 'multipart/form-data'
  641. ) {
  642. throw new TypeError(
  643. `Invalid form enctype ${enctype}. Allowed: 'application/x-www-form-urlencoded' & 'multipart/form-data'`
  644. );
  645. }
  646. if (enctype && enctype === 'multipart/form-data' && method !== 'POST') {
  647. throw new TypeError(
  648. 'Invalid method with multipart/form-data. Must be POST'
  649. );
  650. }
  651. if (!enctype || enctype === 'application/x-www-form-urlencoded') {
  652. const l = form.elements.length;
  653. for (let i = 0; i < l; i++) {
  654. if (
  655. form.elements[i].nodeName.toUpperCase() === 'INPUT' &&
  656. form.elements[i].type.toUpperCase() === 'FILE'
  657. ) {
  658. throw new TypeError(
  659. "Must use enctype = 'multipart/form-data' with input type FILE."
  660. );
  661. }
  662. }
  663. }
  664. };
  665. /**
  666. * Verifies that the input parameters are in valid format.
  667. *
  668. * Parameters must be an object containing parameter names. It may also
  669. * contain no property names which represents the case of having no
  670. * parameters.
  671. *
  672. * If properties are present, each property must refer to an array of string
  673. * values. The array length must be at least 1, because each parameter must
  674. * have a value. However, a value of 'null' may appear in any array entry.
  675. *
  676. * To represent a <code>null</code> value, the property value must equal [null].
  677. *
  678. * @param {Object} parameters The parameters to check.
  679. * @throws {TypeError} Thrown if the parameters are incorrect.
  680. * @review
  681. */
  682. const validateParameters = function (parameters) {
  683. if (!(parameters !== undefined && parameters !== null)) {
  684. throw new TypeError(`The parameter object is: ${typeof parameters}`);
  685. }
  686. const keys = Object.keys(parameters);
  687. keys.forEach((key) => {
  688. if (!Array.isArray(parameters[key])) {
  689. throw new TypeError(`${key} parameter is not an array`);
  690. }
  691. if (!parameters[key].length) {
  692. throw new TypeError(`${key} parameter is an empty array`);
  693. }
  694. });
  695. };
  696. /**
  697. * Validates the specificed portletId against the list
  698. * of current portlet in the pageRenderState.
  699. *
  700. * @param {string} portletId The ID of the portlet to be registered.
  701. * @param {Object} pageRenderState The current pageRenderState.
  702. * @return {boolean} A flag indicating if the specified portlet id is valid.
  703. * @review
  704. */
  705. const validatePortletId = function (pageRenderState = {}, portletId = '') {
  706. return (
  707. pageRenderState.portlets &&
  708. Object.keys(pageRenderState.portlets).includes(portletId)
  709. );
  710. };
  711. /**
  712. * Verifies that the input parameters are in valid format, that the portlet
  713. * mode and window state values are allowed for the portlet.
  714. * @param {RenderState} state The render state object to check.
  715. * @param {Object} portletData The porltet render state.
  716. * @throws {TypeError} Thrown if any component of the state is incorrect.
  717. * @review
  718. */
  719. const validateState = function (state = {}, portletData = {}) {
  720. validateParameters(state.parameters);
  721. const portletMode = state.portletMode;
  722. if (typeof portletMode !== 'string') {
  723. throw new TypeError(
  724. `Invalid parameters. portletMode is ${typeof portletMode}`
  725. );
  726. }
  727. else {
  728. const allowedPortletModes = portletData.allowedPM;
  729. if (!allowedPortletModes.includes(portletMode.toLowerCase())) {
  730. throw new TypeError(
  731. `Invalid portletMode=${portletMode} is not in ${allowedPortletModes}`
  732. );
  733. }
  734. }
  735. const windowState = state.windowState;
  736. if (typeof windowState !== 'string') {
  737. throw new TypeError(
  738. `Invalid parameters. windowState is ${typeof windowState}`
  739. );
  740. }
  741. else {
  742. const allowedWindowStates = portletData.allowedWS;
  743. if (!allowedWindowStates.includes(windowState.toLowerCase())) {
  744. throw new TypeError(
  745. `Invalid windowState=${windowState} is not in ${allowedWindowStates}`
  746. );
  747. }
  748. }
  749. };
  750. export {
  751. decodeUpdateString,
  752. encodeFormAsString,
  753. generateActionUrl,
  754. generatePortletModeAndWindowStateString,
  755. getUpdatedPublicRenderParameters,
  756. getUrl,
  757. validateArguments,
  758. validateForm,
  759. validateParameters,
  760. validatePortletId,
  761. validateState,
  762. };