cloudinary-core
Version:
Cloudinary Client Side JS library. Cloudinary streamlines your web application’s image manipulation needs. Cloudinary's cloud-based servers automate image uploading, resizing, cropping, optimizing, sprite generation and more.
345 lines (315 loc) • 9.52 kB
JavaScript
import Expression from './expression';
import Transformation from "./transformation";
import {
allStrings,
identity,
isArray,
isEmpty,
isFunction,
isPlainObject,
isString,
withCamelCaseKeys
} from './util';
import Layer from './layer/layer';
import TextLayer from './layer/textlayer';
import SubtitlesLayer from './layer/subtitleslayer';
import FetchLayer from './layer/fetchlayer';
/**
* Transformation parameters
* Depends on 'util', 'transformation'
*/
class Param {
/**
* Represents a single parameter.
* @class Param
* @param {string} name - The name of the parameter in snake_case
* @param {string} shortName - The name of the serialized form of the parameter.
* If a value is not provided, the parameter will not be serialized.
* @param {function} [process=Util.identity ] - Manipulate origValue when value is called
* @ignore
*/
constructor(name, shortName, process = identity) {
/**
* The name of the parameter in snake_case
* @member {string} Param#name
*/
this.name = name;
/**
* The name of the serialized form of the parameter
* @member {string} Param#shortName
*/
this.shortName = shortName;
/**
* Manipulate origValue when value is called
* @member {function} Param#process
*/
this.process = process;
}
/**
* Set a (unprocessed) value for this parameter
* @function Param#set
* @param {*} origValue - the value of the parameter
* @return {Param} self for chaining
*/
set(origValue) {
this.origValue = origValue;
return this;
}
/**
* Generate the serialized form of the parameter
* @function Param#serialize
* @return {string} the serialized form of the parameter
*/
serialize() {
var val, valid;
val = this.value();
valid = isArray(val) || isPlainObject(val) || isString(val) ? !isEmpty(val) : val != null;
if ((this.shortName != null) && valid) {
return `${this.shortName}_${val}`;
} else {
return '';
}
}
/**
* Return the processed value of the parameter
* @function Param#value
*/
value() {
return this.process(this.origValue);
}
static norm_color(value) {
return value != null ? value.replace(/^#/, 'rgb:') : void 0;
}
static build_array(arg) {
if(arg == null) {
return [];
} else if (isArray(arg)) {
return arg;
} else {
return [arg];
}
}
/**
* Covert value to video codec string.
*
* If the parameter is an object,
* @param {(string|Object)} param - the video codec as either a String or a Hash
* @return {string} the video codec string in the format codec:profile:level:b_frames
* @example
* vc_[ :profile : [level : [b_frames]]]
* or
{ codec: 'h264', profile: 'basic', level: '3.1', b_frames: false }
* @ignore
*/
static process_video_params(param) {
var video;
switch (param.constructor) {
case Object:
video = "";
if ('codec' in param) {
video = param.codec;
if ('profile' in param) {
video += ":" + param.profile;
if ('level' in param) {
video += ":" + param.level;
if ('b_frames' in param && param.b_frames === false) {
video += ":bframes_no";
}
}
}
}
return video;
case String:
return param;
default:
return null;
}
}
}
class ArrayParam extends Param {
/**
* A parameter that represents an array.
* @param {string} name - The name of the parameter in snake_case.
* @param {string} shortName - The name of the serialized form of the parameter
* If a value is not provided, the parameter will not be serialized.
* @param {string} [sep='.'] - The separator to use when joining the array elements together
* @param {function} [process=Util.identity ] - Manipulate origValue when value is called
* @class ArrayParam
* @extends Param
* @ignore
*/
constructor(name, shortName, sep = '.', process = undefined) {
super(name, shortName, process);
this.sep = sep;
}
serialize() {
if (this.shortName != null) {
let arrayValue = this.value();
if (isEmpty(arrayValue)) {
return '';
} else if (isString(arrayValue)) {
return `${this.shortName}_${arrayValue}`;
} else {
let flat = arrayValue.map(t=>isFunction(t.serialize) ? t.serialize() : t).join(this.sep);
return `${this.shortName}_${flat}`;
}
} else {
return '';
}
}
value() {
if (isArray(this.origValue)) {
return this.origValue.map(v=>this.process(v));
} else {
return this.process(this.origValue);
}
}
set(origValue) {
if ((origValue == null) || isArray(origValue)) {
return super.set(origValue);
} else {
return super.set([origValue]);
}
}
}
class TransformationParam extends Param {
/**
* A parameter that represents a transformation
* @param {string} name - The name of the parameter in snake_case
* @param {string} [shortName='t'] - The name of the serialized form of the parameter
* @param {string} [sep='.'] - The separator to use when joining the array elements together
* @param {function} [process=Util.identity ] - Manipulate origValue when value is called
* @class TransformationParam
* @extends Param
* @ignore
*/
constructor(name, shortName = "t", sep = '.', process = undefined) {
super(name, shortName, process);
this.sep = sep;
}
/**
* Generate string representations of the transformation.
* @returns {*} Returns either the transformation as a string, or an array of string representations.
*/
serialize() {
let result = '';
const val = this.value();
if (isEmpty(val)) {
return result;
}
// val is an array of strings so join them
if (allStrings(val)) {
const joined = val.join(this.sep); // creates t1.t2.t3 in case multiple named transformations were configured
if (!isEmpty(joined)) {
// in case options.transformation was not set with an empty string (val != ['']);
result = `${this.shortName}_${joined}`;
}
} else { // Convert val to an array of strings
result = val.map(t => {
if (isString(t) && !isEmpty(t)) {
return `${this.shortName}_${t}`;
}
if (isFunction(t.serialize)) {
return t.serialize();
}
if (isPlainObject(t) && !isEmpty(t)) {
return new Transformation(t).serialize();
}
return undefined;
}).filter(t=>t);
}
return result;
}
set(origValue1) {
this.origValue = origValue1;
if (isArray(this.origValue)) {
return super.set(this.origValue);
} else {
return super.set([this.origValue]);
}
}
}
const number_pattern = "([0-9]*)\\.([0-9]+)|([0-9]+)";
const offset_any_pattern = "(" + number_pattern + ")([%pP])?";
class RangeParam extends Param {
/**
* A parameter that represents a range
* @param {string} name - The name of the parameter in snake_case
* @param {string} shortName - The name of the serialized form of the parameter
* If a value is not provided, the parameter will not be serialized.
* @param {function} [process=norm_range_value ] - Manipulate origValue when value is called
* @class RangeParam
* @extends Param
* @ignore
*/
constructor(name, shortName, process = RangeParam.norm_range_value) {
super(name, shortName, process);
}
static norm_range_value(value) {
let offset = String(value).match(new RegExp('^' + offset_any_pattern + '$'));
if (offset) {
let modifier = offset[5] != null ? 'p' : '';
value = (offset[1] || offset[4]) + modifier;
}
return Expression.normalize(value);
}
}
class RawParam extends Param {
constructor(name, shortName, process = identity) {
super(name, shortName, process);
}
serialize() {
return this.value();
}
}
class LayerParam extends Param {
// Parse layer options
// @return [string] layer transformation string
// @private
value() {
if (this.origValue == null) {
return '';
}
let result;
if (this.origValue instanceof Layer) {
result = this.origValue;
} else if (isPlainObject(this.origValue)) {
let layerOptions = withCamelCaseKeys(this.origValue);
if (layerOptions.resourceType === "text" || (layerOptions.text != null)) {
result = new TextLayer(layerOptions);
} else if (layerOptions.resourceType === "subtitles") {
result = new SubtitlesLayer(layerOptions);
} else if (layerOptions.resourceType === "fetch" || (layerOptions.url != null)) {
result = new FetchLayer(layerOptions);
} else {
result = new Layer(layerOptions);
}
} else if (isString(this.origValue)) {
if (/^fetch:.+/.test(this.origValue)) {
result = new FetchLayer(this.origValue.substr(6));
} else {
result = this.origValue;
}
} else {
result = '';
}
return result.toString();
}
static textStyle(layer) {
return (new TextLayer(layer)).textStyleIdentifier();
}
}
class ExpressionParam extends Param {
serialize() {
return Expression.normalize(super.serialize());
}
}
export {
Param,
ArrayParam,
TransformationParam,
RangeParam,
RawParam,
LayerParam,
ExpressionParam
};