/** @module util */
import $ from 'jquery';
import addUrlParam from './addUrlParam';
import hooks from './hooks';
import rmlOpts from 'rmlopts';
import wpApiSettings from 'wpApiSettings';
import { Icon } from 'react-aiot';
import T from 'i18n-react';
import { TreeNode } from 'react-aiot';
import './wpRfc';
/**
* Creates a React component (span) with the translated markdown.
*
* @param {string} key The key in rmlOpts.lang
* @param {object} [params] The parameters
* @param {object|string('maxWidth')} [spanWrapperProps] Wraps an additinal span wrapper with custom attributes
* @see https://github.com/alexdrel/i18n-react
* @returns {React.Element} Or null if key not found
*/
export function i18n(key, params, spanWrapperProps) {
if (rmlOpts && rmlOpts.lang && rmlOpts.lang[key]) { // @TODO rmlOpts.lang check remove
const span = <T.span text={rmlOpts.lang[key]} {...params} />;
// Predefined span wrapper props
if (typeof spanWrapperProps === 'string') {
switch (spanWrapperProps) {
case 'maxWidth':
spanWrapperProps = { style: { display: 'inline-block', maxWidth: 200 } };
break;
default: break;
}
}
return spanWrapperProps ? <span {...spanWrapperProps}>{ span }</span> : span;
}
return key;
}
/**
* Get URL parameter of current url.
*
* @param {string} name The parameter name
* @param {string} [url=window.location.href]
* @returns {string|null}
*/
export function urlParam(name, url = window.location.href){
const results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(url);
return results && results[1] || null;
}
/**
* Execute a jQuery request with X-WP-Nonce header.
*
* @param {string} url The url appended to ".../wp-json/realmedialibrary/v1/"
* @param {object} [settings] The options for jQuery.ajax
* @param {string} [url='realmedialibrary/v1'] The API namespace
* @returns Result of jQuery.ajax
*/
export function ajax(url, settings = {}, urlNamespace = 'realmedialibrary/v1') {
const apiUrlRoot = wpApiSettings.root, lang = urlParam('lang', apiUrlRoot),
apiUrl = apiUrlRoot.split('?')[0];
let useUrl = apiUrl + urlNamespace + '/' + url;
if (lang) {
useUrl = addUrlParam(useUrl, 'lang', lang.replace('/', ''));
}
return $.ajax(useUrl, $.extend(true, settings, {
headers: {
'X-WP-Nonce': wpApiSettings.nonce
}
}));
}
/**
* Icon showing a opened folder.
*
* @type React.Element
*/
export const ICON_OBJ_FOLDER_OPEN = <Icon type="folder-open" />;
/**
* Icon showing a closed folder.
*
* @type React.Element
*/
export const ICON_OBJ_FOLDER_CLOSED = <Icon type="folder" />;
/**
* Icon showing a home icon for Unorganized.
*
* @type React.Element
*/
export const ICON_OBJ_FOLDER_ROOT = <Icon type="home" />;
/**
* Icon showing a collection.
*
* @type React.Element
*/
export const ICON_OBJ_FOLDER_COLLECTION = <i className="rmlicon-collection" />;
/**
* Icon showing a gallery.
*
* @type React.Element
*/
export const ICON_OBJ_FOLDER_GALLERY = <i className="rmlicon-gallery" />;
/**
* Handle tree node defaults for loaded folder items and new items.
*
* @param {object[]} folders The folders
* @returns object[]
*/
export function applyNodeDefaults(arr) {
return arr.map(({
id,
name,
cnt,
children,
contentCustomOrder,
lastOrderBy,
orderAutomatically,
...rest
}) => (node => {
// Update node
switch (node.properties.type) {
case 0:
node.iconActive = ICON_OBJ_FOLDER_OPEN;
break;
case 1:
node.icon = ICON_OBJ_FOLDER_COLLECTION;
break;
case 2:
node.icon = ICON_OBJ_FOLDER_GALLERY;
break;
default: break;
}
/**
* A tree node is fetched from the server and should be prepared
* for the {@link module:store/TreeNode~TreeNode} class.
*
* @event module:util/hooks#tree/node
* @param {object} node The node object
*/
hooks.call('tree/node', [node]);
return node;
})($.extend({}, TreeNode.defaultProps, { // Default node
id,
title: name,
icon: ICON_OBJ_FOLDER_CLOSED,
count: cnt,
childNodes: children ? applyNodeDefaults(children) : [],
properties: rest,
className: {},
contentCustomOrder,
lastOrderBy: !!lastOrderBy ? lastOrderBy : "",
orderAutomatically: !!orderAutomatically,
$visible: true
})));
}
/**
* Execute the REST query to fetch the category tree.
*
* @param {object} [settings] Additional options for jQuery.ajax
* @returns {object} The original AJAX result and the tree result prepared for AIO
*/
export async function fetchTree(settings) {
const { tree, ...rest } = await ajax('tree', settings);
return { tree: applyNodeDefaults(tree), ...rest };
}
/**
* Allows you to find an object path.
*
* @param {object} obj The object
* @param {string} path The path
* @returns {mixed|undefined}
*/
export function findDeep(obj, path) {
const paths = path.split('.');
let current = obj;
for (var i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
/**
* Transform bytes to humand readable string.
*
* @param {int} bytes The bytes
* @returns {string}
* @see http://stackoverflow.com/questions/10420352/converting-file-size-in-bytes-to-human-readable
*/
export function humanFileSize(bytes, si = true) {
const thresh = si ? 1000 : 1024;
if (Math.abs(bytes) < thresh) {
return bytes + ' B';
}
const units = si
? ['kB','MB','GB','TB','PB','EB','ZB','YB']
: ['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB'];
let u = -1;
do {
bytes /= thresh;
++u;
} while(Math.abs(bytes) >= thresh && u < units.length - 1);
return bytes.toFixed(1)+' '+units[u];
}
/**
* Transform seconds to readable HH:mm:ss.
*
* @param {int} totalSec The seconds
* @returns {string}
*/
export function secondsFormat(totalSec) {
const hours = Math.floor(totalSec / 3600),
minutes = Math.floor((totalSec - (hours * 3600)) / 60),
seconds = totalSec - (hours * 3600) - (minutes * 60);
return (hours < 10 ? '0' + hours : hours) + ':' + (minutes < 10 ? '0' + minutes : minutes) + ':' + (seconds < 10 ? '0' + seconds : seconds);
}
/**
* Export Data URI to blob instance.
*
* @param {string} sUri
* @returns {Blob}
*/
export function dataUriToBlob(sUri) {
// convert base64/URLEncoded data component to raw binary data held in a string
let byteString;
if (sUri.split(",")[0].indexOf("base64") >= 0) {
byteString = window.atob(sUri.split(',')[1]);
} else {
byteString = unescape(sUri.split(',')[1]);
}
// separate out the mime component
const type = sUri.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
const ia = new Uint8Array(byteString.length);
for (let i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new window.Blob([ia], { type });
}
export {
/**
* @type module:util/addUrlParam
*/
addUrlParam,
/**
* @type module:util/hooks
*/
hooks,
/**
* The localized Real Media Library script object.
*
* @type object
*/
rmlOpts
};