Home Reference Source

application/util/strings.js

import moment from 'moment';
import diff from 'htmldiff/src/htmldiff.js';
import {Html5Entities} from 'html-entities';
import queryString from 'query-string';

/**
 * Convert a string into a URL slug
 * @param  {string} str
 * @param  {string} allowTrailing Allows preservation of trailing slash. Useful when live editing
 * @return {string}
 */
export const sluggify = (str, allowTrailing = false) => {
    str = str.replace(/[^a-zA-Z0-9\._\-\%\& ]/g, '')
              .replace(/\s{2,}/g, ' ')
              .replace(/\.{2,}/g, '.')
              .replace(/ /g, '-')
              .replace(/(\-){2,}/, '-')
              .toLowerCase();

    if (str.indexOf('-') === 0) {
        str = str.substr(1);
    }
    if (!allowTrailing && str.lastIndexOf('-') === str.length-1) {
        str = str.substr(0, str.length-1);
    }

    return str;
};

/**
 * Ensure a string is URL friendly. Unlike sluggify, it will not remove
 * forward slashes (but will deduplicate them).
 * @param {string} str
 * @param {boolean} strip start and end slashes (default is TRUE)
 * @return {string}
 */
export const urlify = (str, stripSlashes = true) => {
    let newStr = str.replace(/\/{2,}/g, '/');
    newStr = sluggify(newStr.replace(/\//g, '%slash%'), true).replace(/%slash%/g, '/');

    if (stripSlashes && newStr.indexOf('/') === 0) {
        newStr = newStr.substr(1);
    }
    if (stripSlashes && newStr.lastIndexOf('/') === newStr.length-1) {
        newStr = newStr.substr(0, newStr.length-1);
    }

    return newStr;

}


/**
 * Convert hash into HTTP parameter string.
 *
 * Adapted from
 * http://stackoverflow.com/questions/1714786/querystring-encoding-of-a-javascript-object
 * @param {object} obj Hash
 * @param {string} prefix Used in recursion
 * @return {string}
 */
export const parameterize = (obj, prefix = null) => {
    let str;
    if (prefix === null) {
        str = queryString.stringify(obj, {arrayFormat: 'bracket'});
        if (str.indexOf('object%20Object') === -1) {
            return str;
        }
    }

    str = [];
    for(let p in obj) {
        if (obj.hasOwnProperty(p)) {
            let k = prefix ? prefix + "[" + p + "]" : p, v = obj[p];
            str.push(typeof v == "object" ? parameterize(v, k) : encodeURIComponent(k) + "=" + encodeURIComponent(v));
        }
    }

    return str.join("&");

};

/**
 * Convert time to local string.
 * The server stores and returns timestamps as UTC, this converts them
 * to local time and formats
 * @param  {string} time Time
 * @param  {string} fmt  Format, default M/DD/YYYY HH:MM:P
 * @return {string}
 */
export const timeToFormat = (time, fmt) => {
    if (!fmt) {
        fmt = 'l LT';
    }

    return moment.utc(time).local().format(fmt);
};

/**
 * Parse a SRN into its component parts
 * @param  {string} srn SRN
 * @return {object}     Mapped SRN
 */
export const parseSrn = (srn) => {
    let parts = srn.split(':');

    parts.shift();

    let data = {
        'client': parts.shift(),
        'app': parts.shift(),
        'uuid': parts.shift()
    };

    data.extra = parts.join(':');

    parts = data.app.split('/');

    data.app = parts[0];
    data.model = parts[1];

    return data;
};

/**
 * HTML String diff
 * @param  {string} strA String A
 * @param  {string} strB String B
 * @return {string}      Diffed, tagged, HTML string
 */
export const htmlDiff = (strA, strB) => {
    return diff(strA, strB);
};

export const degraf = (str) => {
    return str.replace(/<p>(<br( ?\/?)>|&nbsp;)<\/p>(\n)?/g, '').trim();
}

/**
 * HTML String decoder
 * Decode HTML5 entities
 * @param {string} str
 * @return {string} decoded string
 */
export const htmlDecode = (str) => {
    return Html5Entities.decode(str);
}

/**
 * Truncate a string at character count, regardless of length or punctuation.
 * @param {string} str
 * @param {integer} length Truncate length
 * @param {string} trail Trailing string, false to remove
 */
export const truncate = (str, length = 50, trail = '...') => {
    if (str.length < length) {
        return str;
    }

    let pad = 0;
    if (trail && trail.length) {
        pad = trail.length;
    }
    let returnString = str.substr(0, (length - pad));
    if (trail) {
        returnString += trail;
    }

    return returnString;
}

/**
 * Generate random alpha numeric string.
 * **This is not cryptographically secure**
 * @param {integer} Max length
 */
export const randomString = (len = 8) => {
    const getToken = () => {
        const src = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        const max = src.length;

        return src[Math.floor(Math.random() * (max-1))];
    };
    let tok = getToken();
    while (tok.length < len) {
        tok = tok+getToken();
    }

    return tok.substring(0, len);
};

/**
 * Reduce slashes in an escaped string.
 * @param {string} str string to reduce
 */
export const reduceSlashes = (str) => {
    return str.replace(/\\"/g, '"').replace(/\\{2,}/g, "\\");
};