carbone
Version:
Fast, Simple and Powerful report generator. Injects JSON and produces PDF, DOCX, XLSX, ODT, PPTX, ODS, ...!
575 lines (546 loc) • 18.3 kB
JavaScript
/**
* Change the default operator between conditional formatters.
*
* For example: `{d.car:ifEQ('delorean'):and(.speed):ifGT(80):show('TravelInTime'):elseShow('StayHere')}`
* means "if d.car equals 'delorean' AND d.speed is greater than 80, then it prints 'TravelInTime', otherwise
* it prints 'StayHere'
*
* @version 2.0.0
* @param {Mixed} d data
* @param {Mixed} value [optional] new value to test
* @return {Mixed} if `value` is defined, the next formatter "sees" this new value instead of the original value
*/
function and (d, value) {
this.isAndOperator = true;
if (arguments.length === 1) {
return d;
}
return value;
}
/**
* Change the default operator between conditional formatters.
*
* For example: `{d.car:ifEQ('delorean'):or(.speed):ifGT(80):show('TravelInTime'):elseShow('StayHere')}`
* means "if d.car equals 'delorean' OR d.speed is greater than 80, then it prints 'TravelInTime', otherwise
* it prints 'StayHere'
*
*
* @version 2.0.0
* @param {Mixed} d data
* @param {Mixed} value [optional] new value to test
* @return {Mixed} if `value` is defined, the next formatter "sees" this new value instead of the original value
*/
function or (d, value) {
this.isAndOperator = false;
if (arguments.length === 1) {
return d;
}
return value;
}
/**
* Update the condition according to the operator and / or.
*
* By default, we consider "or" operator.
* @private
*
* @version 2.0.0
* @param {Boolean} operator if true, the operator is AND, otherwhise it is OR
* @param {Boolean} currentConditionState the current condition state
* @param {Boolean} newValue the value coming form the previous condition
* @return {Boolean} the condition result
*/
function _updateCondition (isAndOperator, currentConditionState, newValue) {
if (isAndOperator === true) {
return currentConditionState = currentConditionState && newValue;
}
return currentConditionState = currentConditionState || newValue;
}
/**
* Matches empty values, string, arrays or objects (null, undefined, [], {}, ...), it replaces `ifEmpty`.
*
* @version 2.0.0
* @exampleContextFormatter [ null ] true
* @exampleContextFormatter [ [] ] true
* @exampleContextFormatter [ {} ] true
* @exampleContextFormatter [ "" ] true
* @exampleContextFormatter [ 0 ] false
* @exampleContextFormatter [ "homer" ] false
* @exampleContextFormatter [ [23] ] false
* @exampleContextFormatter [ {"id":3} ] false
*
* @param {Mixed} d data
*/
function ifEM (d) {
var _result = false;
if ( d === null
|| typeof(d) === 'undefined'
|| d === ''
|| d instanceof Array && d.length === 0
|| d.constructor === Object && Object.keys(d).length === 0
|| Number.isNaN(d) === true) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches not empty values, string, arrays or objects.
*
* @version 2.0.0
* @exampleContextFormatter [ 0 ] true
* @exampleContextFormatter [ "homer" ] true
* @exampleContextFormatter [ [23] ] true
* @exampleContextFormatter [ {"id":3} ] true
* @exampleContextFormatter [ null ] false
* @exampleContextFormatter [ [] ] false
* @exampleContextFormatter [ {} ] false
* @exampleContextFormatter [ "" ] false
*
* @param {Mixed} d data
*/
function ifNEM (d) {
var _result = true;
if ( d === null
|| typeof(d) === 'undefined'
|| d === ''
|| d instanceof Array && d.length === 0
|| d.constructor === Object && Object.keys(d).length === 0
|| Number.isNaN(d) === true) {
_result = false;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches all values that are equal to a specified value. It can be combined with other formatters to create conditional content. It returns the initial marker. The state of the condition is not returned.
*
* @version 2.0.0
* @exampleContextFormatter [ 100 , 100 ] true
* @exampleContextFormatter [ 100 , 101 ] false
* @exampleContextFormatter [ "homer" , "homer" ] true
* @exampleContextFormatter [ "homer" , "bart" ] false
* @exampleContextFormatter [ "" , "" ] true
* @exampleContextFormatter [ null , 100 ] false
* @exampleContextFormatter [ null , null ] true
* @exampleContextFormatter [ 0 , 100 ] false
*
* @param {String|Integer} d
* @param {String|Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifEQ (d, value) {
var _result = false;
// Convert everything in string (not strict Equal)
if (d + '' === value + '') {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches all values that are not equal to a specified value. It can be combined with other formatters to create conditional content. It returns the initial marker. The state of the condition is not returned.
*
* @version 2.0.0
* @exampleContextFormatter [ 100 , 100 ] false
* @exampleContextFormatter [ 100 , 101 ] true
* @exampleContextFormatter [ "homer" , "homer" ] false
* @exampleContextFormatter [ "homer" , "bart" ] true
* @exampleContextFormatter [ "" , "" ] false
* @exampleContextFormatter [ null , 100 ] true
* @exampleContextFormatter [ null , null ] false
* @exampleContextFormatter [ 0 , 100 ] true
*
* @param {String|Integer} d
* @param {String|Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifNE (d, value) {
var _result = true;
if (d + '' === value + '') {
_result = false;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches values that are greater than a specified value.
*
* @version 2.0.0
* @exampleContextFormatter [1234, 1] true
* @exampleContextFormatter ["50", "-29"] true
* @exampleContextFormatter ["32q", "4q2"] true
* @exampleContextFormatter ["1234Hello", "1"] true
* @exampleContextFormatter ["10", "8Hello1234"] true
* @exampleContextFormatter [-23, 19] false
* @exampleContextFormatter [1, 768] false
* @exampleContextFormatter [0, 0] false
* @exampleContextFormatter [-2891, "33Hello"] false
*
* @param {Integer} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifGT (d, value) {
var _result = false;
var _value = parseFloat(value);
var _d = parseFloat(d);
if (Number.isNaN(_d) === false && Number.isNaN(_value) === false && _d > _value) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches values that are greater than or equal to a specified value.
*
* @version 2.0.0
* @exampleContextFormatter [50, -29] true
* @exampleContextFormatter [1, 1] true
* @exampleContextFormatter [1290, 768] true
* @exampleContextFormatter ["1234", "1"] true
* @exampleContextFormatter [-23, 19] false
* @exampleContextFormatter [1, 768] false
* @exampleContextFormatter ["1" , "1234"] false
*
* @param {Integer} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifGTE (d, value) {
var _result = false;
var _value = parseFloat(value);
var _d = parseFloat(d);
if (Number.isNaN(_d) === false && Number.isNaN(_value) === false && _d >= _value) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches values that are less than a specified value.
*
* @version 2.0.0
* @exampleContextFormatter [-23, 19] true
* @exampleContextFormatter [1, 768] true
* @exampleContextFormatter ["1" , "1234"] true
* @exampleContextFormatter ["123dsf", "103123"] true
* @exampleContextFormatter [-1299283, "-2891feihuwf"] true
* @exampleContextFormatter [50, -29] false
* @exampleContextFormatter [0, 0] false
* @exampleContextFormatter [1290, 768] false
* @exampleContextFormatter ["1234", "1"] false
*
* @param {Integer} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifLT (d, value) {
var _result = false;
var _value = parseFloat(value);
var _d = parseFloat(d);
if (Number.isNaN(_d) === false && Number.isNaN(_value) === false && _d < _value) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches values that are less than or equal to a specified value.
*
* @version 2.0.0
* @exampleContextFormatter [-23, 19] true
* @exampleContextFormatter [1, 768] true
* @exampleContextFormatter [5, 5] true
* @exampleContextFormatter ["1" , "1234"] true
* @exampleContextFormatter [1290, 768] false
* @exampleContextFormatter ["1234", "1"] false
*
* @param {Integer} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifLTE (d, value) {
var _result = false;
var _value = parseFloat(value);
var _d = parseFloat(d);
if (Number.isNaN(_d) === false && Number.isNaN(_value) === false && _d <= _value) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches any of the values specified in an array or string, it replaces `ifContain`.
*
* @version 2.0.0
* @exampleContextFormatter ["car is broken", "is"] true
* @exampleContextFormatter [[1, 2, "toto"], 2] true
* @exampleContextFormatter ["car is broken", "are"] false
* @exampleContextFormatter [[1, 2, "toto"], "titi"] false
*
* @param {Integer|String|Array} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifIN (d, value) {
var _result = false;
if (value && (typeof(d) === 'string' || d instanceof Array) && d.indexOf(value) !== -1) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Matches none of the values specified in an array or string.
*
* @version 2.0.0
* @exampleContextFormatter ["car is broken", "are"] true
* @exampleContextFormatter [[1, 2, "toto"], "titi"] true
* @exampleContextFormatter ["car is broken", "is"] false
* @exampleContextFormatter [[1, 2, "toto"], 2] false
*
* @param {Integer|String|Array} d
* @param {Integer} value value to test
* @returns It returns the initial value `d`. The state of the condition is not returned.
*/
function ifNIN (d, value) {
var _result = false;
if (value && (typeof(d) === 'string' || d instanceof Array) && d.indexOf(value) === -1) {
_result = true;
}
this.isConditionTrue = _updateCondition(this.isAndOperator, this.isConditionTrue, _result);
return d;
}
/**
* Print a message if the condition is true. It should be used with other formatters to print conditional content.
*
* @version 2.0.0
* @example ["Carbone.io"]
*
* @param {Mixed} d marker
* @param {*} message message to print
*/
function show (d, message) {
if (this.isConditionTrue === true || this.isConditionTrue === null && d) {
this.stopPropagation = true;
return message;
}
return d;
}
/**
* Print a message if the condition is false. It should be used with other formatters to print conditional content.
*
* @version 2.0.0
* @param {Mixed} d marker
* @param {*} message message to print
*/
function elseShow (d, message) {
if (this.isConditionTrue === false || this.isConditionTrue === null && !d) {
this.stopPropagation = true;
return message;
}
return d;
}
/**
* Show a text block between showBegin and showEnd if the condition is true
* @version 2.0.0
* @private
* @param {*} d
*/
function showBegin (d) {
this.isHidden = 1;
if (this.isConditionTrue === true || this.isConditionTrue === null && d) {
this.stopPropagation = true;
this.isHidden = 0;
}
return '';
}
/**
* show a text block between showBegin and showEnd if the condition is true
* @version 2.0.0
* @private
*/
function showEnd () {
this.isHidden = -1;
return '';
}
/**
* hide text block between hideBegin and hideEnd if the condition is true
* @version 2.0.0
* @private
* @param {*} d
*/
function hideBegin (d) {
this.isHidden = 0;
if (this.isConditionTrue === true || this.isConditionTrue === null && d) {
this.stopPropagation = true;
this.isHidden = 1;
}
return '';
}
/**
* hide text block between hideBegin and hideEnd if the condition is true
* @version 2.0.0
* @private
*/
function hideEnd () {
this.isHidden = -1;
return '';
}
/**
* Returns the length of a string or array.
*
* @version 2.0.0
* @example ["Hello World"]
* @example [""]
* @example [[1, 2, 3, 4, 5]]
* @example [[1, "Hello"]]
*
* @param {Mixed} d Array or String
* @returns {Number} Length of the element
*/
function len (d) {
if (typeof d === 'string' || Array.isArray(d)) {
return d.length;
}
return 0;
}
/**
* Test if data is empty (null, undefined, [], {}, ...). The new formatter `ifEM` should be used instead of this one.
*
* @version 0.12.5
*
* @example [ null , "D'oh!" ]
* @example [ [] , "D'oh!" ]
* @example [ {} , "D'oh!" ]
* @example [ "" , "D'oh!" ]
* @example [ 0 , "D'oh!" ]
* @example [ "homer" , "D'oh!" ]
* @example [ [23] , "D'oh!" ]
* @example [ {"id":3} , "D'oh!" ]
*
* @param {Mixed} d data
* @param {String} message message to print if JSON data is empty
* @param {Boolean} continueOnSuccess [optional], if true, next formatter will be called even if the condition is true
* @return {Mixed} `message` if condition is true, `d` otherwise
*/
function ifEmpty (d, message, continueOnSuccess) {
if ( d === null
|| typeof(d) === 'undefined'
|| d === ''
|| d instanceof Array && d.length === 0
|| d.constructor === Object && Object.keys(d).length === 0
|| Number.isNaN(d) === true) {
if (continueOnSuccess !== true && continueOnSuccess !== 'true') {
this.stopPropagation = true;
}
return message;
}
return d;
}
/**
* Test if a value equals a variable. The new formatter `ifEQ` should be used instead of this one.
*
* @version 0.13.0
*
* @example [ 100 , 100 , "bingo" ]
* @example [ 100 , 101 , "bingo" ]
* @example [ "homer" , "homer" , "bingo" ]
* @example [ "homer" , "bart" , "bingo" ]
* @example [ "" , "" , "bingo" ]
* @example [ null , 100 , "bingo" ]
* @example [ null , null , "bingo" ]
* @example [ 0 , 100 , "bingo" ]
*
* @param {String|Integer|Boolean} d data
* @param {String|Integer|Boolean} value value to test
* @param {String} messageIfTrue message to print if the value equals JSON data
* @param {Boolean} continueOnSuccess [optional], if true, next formatter will be called even if the condition is true
* @return {Mixed} `message` if condition is true, `d` otherwise
*/
function ifEqual (d, value, messageIfTrue, continueOnSuccess) {
// Convert everything in string (not strict Equal)
if (d + '' === value + '') {
if (continueOnSuccess !== true && continueOnSuccess !== 'true') {
this.stopPropagation = true;
}
return messageIfTrue;
}
return d;
}
/**
* Test if a string or an array contains a value. The new formatter `ifIN` should be used instead of this one.
*
* @version 0.13.0
*
* @example [ "your beautiful eyes", "beauti", "bingo" ]
* @example [ "your beautiful eyes", "leg" , "bingo" ]
* @example [ "your beautiful eyes", "eyes" , "bingo" ]
* @example [ "" , "eyes" , "bingo" ]
* @example [ "your beautiful eyes", "" , "bingo" ]
* @example [ [100, 120, 20] , 120 , "bingo" ]
* @example [ [100, 120, 20] , 99 , "bingo" ]
* @example [ ["your", "eyes"] , "eyes" , "bingo" ]
* @example [ [] , "eyes" , "bingo" ]
*
* @param {String|Array} d data
* @param {String|Integer|Boolean} value value to search
* @param {String} messageIfTrue message to print if JSON data contains the value
* @param {Boolean} continueOnSuccess [optional], if true, next formatter will be called even if the condition is true
* @return {Mixed} `message` if condition is true, `d` otherwise
*/
function ifContain (d, value, messageIfTrue, continueOnSuccess) {
if ((typeof(d) === 'string' || d instanceof Array) && d.indexOf(value) !== -1) {
if (continueOnSuccess !== true && continueOnSuccess !== 'true') {
this.stopPropagation = true;
}
return messageIfTrue;
}
return d;
}
/**
* Detect conditional block begin/end
*
* @private
* @param {String} marker
* @return {Boolean} true if there is a showEnd/hideEnd formatter
*/
function _isConditionalBlockEndMarker (marker) {
return /:(?:showEnd|hideEnd)/.test(marker.replace(/\s/g, ''));
}
/**
* Detect conditional block begin/end
*
* @private
* @param {String} marker
* @return {Boolean} true if there is a showBegin/hideBegin formatter
*/
function _isConditionalBlockBeginMarker (marker) {
return /:(?:showBegin|hideBegin)/.test(marker.replace(/\s/g, ''));
}
module.exports = {
_isConditionalBlockEndMarker,
_isConditionalBlockBeginMarker,
ifContain,
ifEmpty,
ifEqual,
ifEM,
ifNEM,
ifEQ,
ifNE,
ifGT,
ifGTE,
ifLT,
ifLTE,
ifIN,
ifNIN,
hideBegin,
hideEnd,
showBegin,
showEnd,
show,
elseShow,
and,
or,
len
};