2022-07-28 07:33:25 -07:00
/ * *
2023-02-16 21:17:00 -05:00
* Jspreadsheet v4 . 11.1
2022-07-28 07:33:25 -07:00
*
* Website : https : //bossanova.uk/jspreadsheet/
* Description : Create amazing web based spreadsheets .
*
* This software is distribute under MIT License
* /
2023-02-16 21:17:00 -05:00
var formula = ( function ( ) {
// Based on sutoiku work (https://github.com/sutoiku)
var error = ( function ( ) {
var exports = { } ;
exports . nil = new Error ( "#NULL!" ) ;
exports . div0 = new Error ( "#DIV/0!" ) ;
exports . value = new Error ( "#VALUE!" ) ;
exports . ref = new Error ( "#REF!" ) ;
exports . name = new Error ( "#NAME?" ) ;
exports . num = new Error ( "#NUM!" ) ;
exports . na = new Error ( "#N/A" ) ;
exports . error = new Error ( "#ERROR!" ) ;
exports . data = new Error ( "#GETTING_DATA" ) ;
return exports ;
} ) ( ) ;
var utils = ( function ( ) {
var exports = { } ;
exports . flattenShallow = function ( array ) {
if ( ! array || ! array . reduce ) {
return array ;
}
return array . reduce ( function ( a , b ) {
var aIsArray = Array . isArray ( a ) ;
var bIsArray = Array . isArray ( b ) ;
if ( aIsArray && bIsArray ) {
return a . concat ( b ) ;
}
if ( aIsArray ) {
a . push ( b ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return a ;
}
if ( bIsArray ) {
return [ a ] . concat ( b ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return [ a , b ] ;
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . isFlat = function ( array ) {
if ( ! array ) {
return false ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < array . length ; ++ i ) {
if ( Array . isArray ( array [ i ] ) ) {
return false ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return true ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . flatten = function ( ) {
var result = exports . argsToArray . apply ( null , arguments ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
while ( ! exports . isFlat ( result ) ) {
result = exports . flattenShallow ( result ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return result ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . argsToArray = function ( args ) {
var result = [ ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . arrayEach ( args , function ( value ) {
result . push ( value ) ;
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return result ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . numbers = function ( ) {
var possibleNumbers = this . flatten . apply ( null , arguments ) ;
return possibleNumbers . filter ( function ( el ) {
return typeof el === "number" ;
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . cleanFloat = function ( number ) {
var power = 1e14 ;
return Math . round ( number * power ) / power ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . parseBool = function ( bool ) {
if ( typeof bool === "boolean" ) {
return bool ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( bool instanceof Error ) {
return bool ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( typeof bool === "number" ) {
return bool !== 0 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( typeof bool === "string" ) {
var up = bool . toUpperCase ( ) ;
if ( up === "TRUE" ) {
return true ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( up === "FALSE" ) {
return false ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( bool instanceof Date && ! isNaN ( bool ) ) {
return true ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return error . value ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . parseNumber = function ( string ) {
if ( string === undefined || string === "" ) {
return error . value ;
}
if ( ! isNaN ( string ) ) {
return parseFloat ( string ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return error . value ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . parseNumberArray = function ( arr ) {
var len ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! arr || ( len = arr . length ) === 0 ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var parsed ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
while ( len -- ) {
parsed = exports . parseNumber ( arr [ len ] ) ;
if ( parsed === error . value ) {
return parsed ;
}
arr [ len ] = parsed ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return arr ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . parseMatrix = function ( matrix ) {
var n ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! matrix || ( n = matrix . length ) === 0 ) {
return error . value ;
}
var pnarr ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < matrix . length ; i ++ ) {
pnarr = exports . parseNumberArray ( matrix [ i ] ) ;
matrix [ i ] = pnarr ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( pnarr instanceof Error ) {
return pnarr ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return matrix ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var d1900 = new Date ( Date . UTC ( 1900 , 0 , 1 ) ) ;
exports . parseDate = function ( date ) {
if ( ! isNaN ( date ) ) {
if ( date instanceof Date ) {
return new Date ( date ) ;
}
var d = parseInt ( date , 10 ) ;
if ( d < 0 ) {
return error . num ;
}
if ( d <= 60 ) {
return new Date ( d1900 . getTime ( ) + ( d - 1 ) * 86400000 ) ;
}
return new Date ( d1900 . getTime ( ) + ( d - 2 ) * 86400000 ) ;
}
if ( typeof date === "string" ) {
date = new Date ( date ) ;
if ( ! isNaN ( date ) ) {
return date ;
}
}
return error . value ;
} ;
exports . parseDateArray = function ( arr ) {
var len = arr . length ;
var parsed ;
while ( len -- ) {
parsed = this . parseDate ( arr [ len ] ) ;
if ( parsed === error . value ) {
return parsed ;
}
arr [ len ] = parsed ;
}
return arr ;
} ;
exports . anyIsError = function ( ) {
var n = arguments . length ;
while ( n -- ) {
if ( arguments [ n ] instanceof Error ) {
return true ;
}
}
return false ;
} ;
exports . arrayValuesToNumbers = function ( arr ) {
var n = arr . length ;
var el ;
while ( n -- ) {
el = arr [ n ] ;
if ( typeof el === "number" ) {
continue ;
}
if ( el === true ) {
arr [ n ] = 1 ;
continue ;
}
if ( el === false ) {
arr [ n ] = 0 ;
continue ;
}
if ( typeof el === "string" ) {
var number = this . parseNumber ( el ) ;
if ( number instanceof Error ) {
arr [ n ] = 0 ;
} else {
arr [ n ] = number ;
}
}
}
return arr ;
} ;
exports . rest = function ( array , idx ) {
idx = idx || 1 ;
if ( ! array || typeof array . slice !== "function" ) {
return array ;
}
return array . slice ( idx ) ;
} ;
exports . initial = function ( array , idx ) {
idx = idx || 1 ;
if ( ! array || typeof array . slice !== "function" ) {
return array ;
}
return array . slice ( 0 , array . length - idx ) ;
} ;
exports . arrayEach = function ( array , iteratee ) {
var index = - 1 ,
length = array . length ;
while ( ++ index < length ) {
if ( iteratee ( array [ index ] , index , array ) === false ) {
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return array ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . transpose = function ( matrix ) {
if ( ! matrix ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return matrix [ 0 ] . map ( function ( col , i ) {
return matrix . map ( function ( row ) {
return row [ i ] ;
} ) ;
} ) ;
} ;
return exports ;
} ) ( ) ;
var met = { } ;
met . datetime = ( function ( ) {
var exports = { } ;
var d1900 = new Date ( 1900 , 0 , 1 ) ;
var WEEK _STARTS = [
undefined ,
0 ,
1 ,
undefined ,
undefined ,
undefined ,
undefined ,
undefined ,
undefined ,
undefined ,
undefined ,
undefined ,
1 ,
2 ,
3 ,
4 ,
5 ,
6 ,
0 ,
] ;
var WEEK _TYPES = [
[ ] ,
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ,
[ 7 , 1 , 2 , 3 , 4 , 5 , 6 ] ,
[ 6 , 0 , 1 , 2 , 3 , 4 , 5 ] ,
[ ] ,
[ ] ,
[ ] ,
[ ] ,
[ ] ,
[ ] ,
[ ] ,
[ 7 , 1 , 2 , 3 , 4 , 5 , 6 ] ,
[ 6 , 7 , 1 , 2 , 3 , 4 , 5 ] ,
[ 5 , 6 , 7 , 1 , 2 , 3 , 4 ] ,
[ 4 , 5 , 6 , 7 , 1 , 2 , 3 ] ,
[ 3 , 4 , 5 , 6 , 7 , 1 , 2 ] ,
[ 2 , 3 , 4 , 5 , 6 , 7 , 1 ] ,
[ 1 , 2 , 3 , 4 , 5 , 6 , 7 ] ,
] ;
var WEEKEND _TYPES = [
[ ] ,
[ 6 , 0 ] ,
[ 0 , 1 ] ,
[ 1 , 2 ] ,
[ 2 , 3 ] ,
[ 3 , 4 ] ,
[ 4 , 5 ] ,
[ 5 , 6 ] ,
undefined ,
undefined ,
undefined ,
[ 0 , 0 ] ,
[ 1 , 1 ] ,
[ 2 , 2 ] ,
[ 3 , 3 ] ,
[ 4 , 4 ] ,
[ 5 , 5 ] ,
[ 6 , 6 ] ,
] ;
exports . DATE = function ( year , month , day ) {
year = utils . parseNumber ( year ) ;
month = utils . parseNumber ( month ) ;
day = utils . parseNumber ( day ) ;
if ( utils . anyIsError ( year , month , day ) ) {
return error . value ;
}
if ( year < 0 || month < 0 || day < 0 ) {
return error . num ;
}
var date = new Date ( year , month - 1 , day ) ;
return date ;
} ;
exports . DATEVALUE = function ( date _text ) {
if ( typeof date _text !== "string" ) {
return error . value ;
}
var date = Date . parse ( date _text ) ;
if ( isNaN ( date ) ) {
return error . value ;
}
if ( date <= - 2203891200000 ) {
return ( date - d1900 ) / 86400000 + 1 ;
}
return ( date - d1900 ) / 86400000 + 2 ;
} ;
exports . DAY = function ( serial _number ) {
var date = utils . parseDate ( serial _number ) ;
if ( date instanceof Error ) {
return date ;
}
return date . getDate ( ) ;
} ;
exports . DAYS = function ( end _date , start _date ) {
end _date = utils . parseDate ( end _date ) ;
start _date = utils . parseDate ( start _date ) ;
if ( end _date instanceof Error ) {
return end _date ;
}
if ( start _date instanceof Error ) {
return start _date ;
}
return serial ( end _date ) - serial ( start _date ) ;
} ;
exports . DAYS360 = function ( start _date , end _date , method ) { } ;
exports . EDATE = function ( start _date , months ) {
start _date = utils . parseDate ( start _date ) ;
if ( start _date instanceof Error ) {
return start _date ;
}
if ( isNaN ( months ) ) {
return error . value ;
}
months = parseInt ( months , 10 ) ;
start _date . setMonth ( start _date . getMonth ( ) + months ) ;
return serial ( start _date ) ;
} ;
exports . EOMONTH = function ( start _date , months ) {
start _date = utils . parseDate ( start _date ) ;
if ( start _date instanceof Error ) {
return start _date ;
}
if ( isNaN ( months ) ) {
return error . value ;
}
months = parseInt ( months , 10 ) ;
return serial (
new Date (
start _date . getFullYear ( ) ,
start _date . getMonth ( ) + months + 1 ,
0
)
) ;
} ;
exports . HOUR = function ( serial _number ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
return serial _number . getHours ( ) ;
} ;
exports . INTERVAL = function ( second ) {
if ( typeof second !== "number" && typeof second !== "string" ) {
return error . value ;
} else {
second = parseInt ( second , 10 ) ;
}
var year = Math . floor ( second / 946080000 ) ;
second = second % 946080000 ;
var month = Math . floor ( second / 2592000 ) ;
second = second % 2592000 ;
var day = Math . floor ( second / 86400 ) ;
second = second % 86400 ;
var hour = Math . floor ( second / 3600 ) ;
second = second % 3600 ;
var min = Math . floor ( second / 60 ) ;
second = second % 60 ;
var sec = second ;
year = year > 0 ? year + "Y" : "" ;
month = month > 0 ? month + "M" : "" ;
day = day > 0 ? day + "D" : "" ;
hour = hour > 0 ? hour + "H" : "" ;
min = min > 0 ? min + "M" : "" ;
sec = sec > 0 ? sec + "S" : "" ;
return "P" + year + month + day + "T" + hour + min + sec ;
} ;
exports . ISOWEEKNUM = function ( date ) {
date = utils . parseDate ( date ) ;
if ( date instanceof Error ) {
return date ;
}
date . setHours ( 0 , 0 , 0 ) ;
date . setDate ( date . getDate ( ) + 4 - ( date . getDay ( ) || 7 ) ) ;
var yearStart = new Date ( date . getFullYear ( ) , 0 , 1 ) ;
return Math . ceil ( ( ( date - yearStart ) / 86400000 + 1 ) / 7 ) ;
} ;
exports . MINUTE = function ( serial _number ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
return serial _number . getMinutes ( ) ;
} ;
exports . MONTH = function ( serial _number ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
return serial _number . getMonth ( ) + 1 ;
} ;
exports . NETWORKDAYS = function ( start _date , end _date , holidays ) { } ;
exports . NETWORKDAYS . INTL = function (
start _date ,
end _date ,
weekend ,
holidays
) { } ;
exports . NOW = function ( ) {
return new Date ( ) ;
} ;
exports . SECOND = function ( serial _number ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
return serial _number . getSeconds ( ) ;
} ;
exports . TIME = function ( hour , minute , second ) {
hour = utils . parseNumber ( hour ) ;
minute = utils . parseNumber ( minute ) ;
second = utils . parseNumber ( second ) ;
if ( utils . anyIsError ( hour , minute , second ) ) {
return error . value ;
}
if ( hour < 0 || minute < 0 || second < 0 ) {
return error . num ;
}
return ( 3600 * hour + 60 * minute + second ) / 86400 ;
} ;
exports . TIMEVALUE = function ( time _text ) {
time _text = utils . parseDate ( time _text ) ;
if ( time _text instanceof Error ) {
return time _text ;
}
return (
( 3600 * time _text . getHours ( ) +
60 * time _text . getMinutes ( ) +
time _text . getSeconds ( ) ) /
86400
) ;
} ;
exports . TODAY = function ( ) {
return new Date ( ) ;
} ;
exports . WEEKDAY = function ( serial _number , return _type ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
if ( return _type === undefined ) {
return _type = 1 ;
}
var day = serial _number . getDay ( ) ;
return WEEK _TYPES [ return _type ] [ day ] ;
} ;
exports . WEEKNUM = function ( serial _number , return _type ) { } ;
exports . WORKDAY = function ( start _date , days , holidays ) { } ;
exports . WORKDAY . INTL = function ( start _date , days , weekend , holidays ) { } ;
exports . YEAR = function ( serial _number ) {
serial _number = utils . parseDate ( serial _number ) ;
if ( serial _number instanceof Error ) {
return serial _number ;
}
return serial _number . getFullYear ( ) ;
} ;
function isLeapYear ( year ) {
return new Date ( year , 1 , 29 ) . getMonth ( ) === 1 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . YEARFRAC = function ( start _date , end _date , basis ) { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
function serial ( date ) {
var addOn = date > - 2203891200000 ? 2 : 1 ;
return ( date - d1900 ) / 86400000 + addOn ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return exports ;
} ) ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
met . database = ( function ( ) {
var exports = { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
function compact ( array ) {
if ( ! array ) {
return array ;
}
var result = [ ] ;
for ( var i = 0 ; i < array . length ; ++ i ) {
if ( ! array [ i ] ) {
continue ;
}
result . push ( array [ i ] ) ;
}
return result ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . FINDFIELD = function ( database , title ) {
var index = null ;
for ( var i = 0 ; i < database . length ; i ++ ) {
if ( database [ i ] [ 0 ] === title ) {
index = i ;
break ;
}
}
// Return error if the input field title is incorrect
if ( index == null ) {
return error . value ;
}
return index ;
} ;
function findResultIndex ( database , criterias ) {
var matches = { } ;
for ( var i = 1 ; i < database [ 0 ] . length ; ++ i ) {
matches [ i ] = true ;
}
var maxCriteriaLength = criterias [ 0 ] . length ;
for ( i = 1 ; i < criterias . length ; ++ i ) {
if ( criterias [ i ] . length > maxCriteriaLength ) {
maxCriteriaLength = criterias [ i ] . length ;
}
}
for ( var k = 1 ; k < database . length ; ++ k ) {
for ( var l = 1 ; l < database [ k ] . length ; ++ l ) {
var currentCriteriaResult = false ;
var hasMatchingCriteria = false ;
for ( var j = 0 ; j < criterias . length ; ++ j ) {
var criteria = criterias [ j ] ;
if ( criteria . length < maxCriteriaLength ) {
continue ;
}
var criteriaField = criteria [ 0 ] ;
if ( database [ k ] [ 0 ] !== criteriaField ) {
continue ;
}
hasMatchingCriteria = true ;
for ( var p = 1 ; p < criteria . length ; ++ p ) {
currentCriteriaResult =
currentCriteriaResult || eval ( database [ k ] [ l ] + criteria [ p ] ) ; // jshint
// ignore:line
}
}
if ( hasMatchingCriteria ) {
matches [ l ] = matches [ l ] && currentCriteriaResult ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var result = [ ] ;
for ( var n = 0 ; n < database [ 0 ] . length ; ++ n ) {
if ( matches [ n ] ) {
result . push ( n - 1 ) ;
}
}
return result ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Database functions
exports . DAVERAGE = function ( database , field , criteria ) {
// Return error if field is not a number and not a string
if ( isNaN ( field ) && typeof field !== "string" ) {
return error . value ;
}
var resultIndexes = findResultIndex ( database , criteria ) ;
var targetFields = [ ] ;
if ( typeof field === "string" ) {
var index = exports . FINDFIELD ( database , field ) ;
targetFields = utils . rest ( database [ index ] ) ;
} else {
targetFields = utils . rest ( database [ field ] ) ;
}
var sum = 0 ;
for ( var i = 0 ; i < resultIndexes . length ; i ++ ) {
sum += targetFields [ resultIndexes [ i ] ] ;
}
return resultIndexes . length === 0
? error . div0
: sum / resultIndexes . length ;
} ;
exports . DCOUNT = function ( database , field , criteria ) { } ;
exports . DCOUNTA = function ( database , field , criteria ) { } ;
exports . DGET = function ( database , field , criteria ) {
// Return error if field is not a number and not a string
if ( isNaN ( field ) && typeof field !== "string" ) {
return error . value ;
}
var resultIndexes = findResultIndex ( database , criteria ) ;
var targetFields = [ ] ;
if ( typeof field === "string" ) {
var index = exports . FINDFIELD ( database , field ) ;
targetFields = utils . rest ( database [ index ] ) ;
} else {
targetFields = utils . rest ( database [ field ] ) ;
}
// Return error if no record meets the criteria
if ( resultIndexes . length === 0 ) {
return error . value ;
}
// Returns the #NUM! error value because more than one record meets the
// criteria
if ( resultIndexes . length > 1 ) {
return error . num ;
}
return targetFields [ resultIndexes [ 0 ] ] ;
} ;
exports . DMAX = function ( database , field , criteria ) {
// Return error if field is not a number and not a string
if ( isNaN ( field ) && typeof field !== "string" ) {
return error . value ;
}
var resultIndexes = findResultIndex ( database , criteria ) ;
var targetFields = [ ] ;
if ( typeof field === "string" ) {
var index = exports . FINDFIELD ( database , field ) ;
targetFields = utils . rest ( database [ index ] ) ;
} else {
targetFields = utils . rest ( database [ field ] ) ;
}
var maxValue = targetFields [ resultIndexes [ 0 ] ] ;
for ( var i = 1 ; i < resultIndexes . length ; i ++ ) {
if ( maxValue < targetFields [ resultIndexes [ i ] ] ) {
maxValue = targetFields [ resultIndexes [ i ] ] ;
}
}
return maxValue ;
} ;
exports . DMIN = function ( database , field , criteria ) {
// Return error if field is not a number and not a string
if ( isNaN ( field ) && typeof field !== "string" ) {
return error . value ;
}
var resultIndexes = findResultIndex ( database , criteria ) ;
var targetFields = [ ] ;
if ( typeof field === "string" ) {
var index = exports . FINDFIELD ( database , field ) ;
targetFields = utils . rest ( database [ index ] ) ;
} else {
targetFields = utils . rest ( database [ field ] ) ;
}
var minValue = targetFields [ resultIndexes [ 0 ] ] ;
for ( var i = 1 ; i < resultIndexes . length ; i ++ ) {
if ( minValue > targetFields [ resultIndexes [ i ] ] ) {
minValue = targetFields [ resultIndexes [ i ] ] ;
}
}
return minValue ;
} ;
exports . DPRODUCT = function ( database , field , criteria ) {
// Return error if field is not a number and not a string
if ( isNaN ( field ) && typeof field !== "string" ) {
return error . value ;
}
var resultIndexes = findResultIndex ( database , criteria ) ;
var targetFields = [ ] ;
if ( typeof field === "string" ) {
var index = exports . FINDFIELD ( database , field ) ;
targetFields = utils . rest ( database [ index ] ) ;
} else {
targetFields = utils . rest ( database [ field ] ) ;
}
var targetValues = [ ] ;
for ( var i = 0 ; i < resultIndexes . length ; i ++ ) {
targetValues [ i ] = targetFields [ resultIndexes [ i ] ] ;
}
targetValues = compact ( targetValues ) ;
var result = 1 ;
for ( i = 0 ; i < targetValues . length ; i ++ ) {
result *= targetValues [ i ] ;
}
return result ;
} ;
exports . DSTDEV = function ( database , field , criteria ) { } ;
exports . DSTDEVP = function ( database , field , criteria ) { } ;
exports . DSUM = function ( database , field , criteria ) { } ;
exports . DVAR = function ( database , field , criteria ) { } ;
exports . DVARP = function ( database , field , criteria ) { } ;
exports . MATCH = function ( lookupValue , lookupArray , matchType ) {
if ( ! lookupValue && ! lookupArray ) {
return error . na ;
}
if ( arguments . length === 2 ) {
matchType = 1 ;
}
if ( ! ( lookupArray instanceof Array ) ) {
return error . na ;
}
if ( matchType !== - 1 && matchType !== 0 && matchType !== 1 ) {
return error . na ;
}
var index ;
var indexValue ;
for ( var idx = 0 ; idx < lookupArray . length ; idx ++ ) {
if ( matchType === 1 ) {
if ( lookupArray [ idx ] === lookupValue ) {
return idx + 1 ;
} else if ( lookupArray [ idx ] < lookupValue ) {
if ( ! indexValue ) {
index = idx + 1 ;
indexValue = lookupArray [ idx ] ;
} else if ( lookupArray [ idx ] > indexValue ) {
index = idx + 1 ;
indexValue = lookupArray [ idx ] ;
}
}
} else if ( matchType === 0 ) {
if ( typeof lookupValue === "string" ) {
lookupValue = lookupValue . replace ( /\?/g , "." ) ;
if (
lookupArray [ idx ] . toLowerCase ( ) . match ( lookupValue . toLowerCase ( ) )
) {
return idx + 1 ;
}
} else {
if ( lookupArray [ idx ] === lookupValue ) {
return idx + 1 ;
}
}
} else if ( matchType === - 1 ) {
if ( lookupArray [ idx ] === lookupValue ) {
return idx + 1 ;
} else if ( lookupArray [ idx ] > lookupValue ) {
if ( ! indexValue ) {
index = idx + 1 ;
indexValue = lookupArray [ idx ] ;
} else if ( lookupArray [ idx ] < indexValue ) {
index = idx + 1 ;
indexValue = lookupArray [ idx ] ;
}
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return index ? index : error . na ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return exports ;
} ) ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
met . engineering = ( function ( ) {
var exports = { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
function isValidBinaryNumber ( number ) {
return /^[01]{1,10}$/ . test ( number ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . BESSELI = function ( x , n ) { } ;
exports . BESSELJ = function ( x , n ) { } ;
exports . BESSELK = function ( x , n ) { } ;
exports . BESSELY = function ( x , n ) { } ;
exports . BIN2DEC = function ( number ) {
// Return error if number is not binary or contains more than 10
// characters (10 digits)
if ( ! isValidBinaryNumber ( number ) ) {
return error . num ;
}
// Convert binary number to decimal
var result = parseInt ( number , 2 ) ;
// Handle negative numbers
var stringified = number . toString ( ) ;
if ( stringified . length === 10 && stringified . substring ( 0 , 1 ) === "1" ) {
return parseInt ( stringified . substring ( 1 ) , 2 ) - 512 ;
} else {
return result ;
}
} ;
exports . BIN2HEX = function ( number , places ) {
// Return error if number is not binary or contains more than 10
// characters (10 digits)
if ( ! isValidBinaryNumber ( number ) ) {
return error . num ;
}
// Ignore places and return a 10-character hexadecimal number if number
// is negative
var stringified = number . toString ( ) ;
if ( stringified . length === 10 && stringified . substring ( 0 , 1 ) === "1" ) {
return ( 1099511627264 + parseInt ( stringified . substring ( 1 ) , 2 ) ) . toString (
16
) ;
}
// Convert binary number to hexadecimal
var result = parseInt ( number , 2 ) . toString ( 16 ) ;
// Return hexadecimal number using the minimum number of characters
// necessary if places is undefined
if ( places === undefined ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . BIN2OCT = function ( number , places ) {
// Return error if number is not binary or contains more than 10
// characters (10 digits)
if ( ! isValidBinaryNumber ( number ) ) {
return error . num ;
}
// Ignore places and return a 10-character octal number if number is
// negative
var stringified = number . toString ( ) ;
if ( stringified . length === 10 && stringified . substring ( 0 , 1 ) === "1" ) {
return ( 1073741312 + parseInt ( stringified . substring ( 1 ) , 2 ) ) . toString ( 8 ) ;
}
// Convert binary number to octal
var result = parseInt ( number , 2 ) . toString ( 8 ) ;
// Return octal number using the minimum number of characters necessary
// if places is undefined
if ( places === undefined ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . BITAND = function ( number1 , number2 ) {
// Return error if either number is a non-numeric value
number1 = utils . parseNumber ( number1 ) ;
number2 = utils . parseNumber ( number2 ) ;
if ( utils . anyIsError ( number1 , number2 ) ) {
return error . value ;
}
// Return error if either number is less than 0
if ( number1 < 0 || number2 < 0 ) {
return error . num ;
}
// Return error if either number is a non-integer
if ( Math . floor ( number1 ) !== number1 || Math . floor ( number2 ) !== number2 ) {
return error . num ;
}
// Return error if either number is greater than (2^48)-1
if ( number1 > 281474976710655 || number2 > 281474976710655 ) {
return error . num ;
}
// Return bitwise AND of two numbers
return number1 & number2 ;
} ;
exports . BITLSHIFT = function ( number , shift ) {
number = utils . parseNumber ( number ) ;
shift = utils . parseNumber ( shift ) ;
if ( utils . anyIsError ( number , shift ) ) {
return error . value ;
}
// Return error if number is less than 0
if ( number < 0 ) {
return error . num ;
}
// Return error if number is a non-integer
if ( Math . floor ( number ) !== number ) {
return error . num ;
}
// Return error if number is greater than (2^48)-1
if ( number > 281474976710655 ) {
return error . num ;
}
// Return error if the absolute value of shift is greater than 53
if ( Math . abs ( shift ) > 53 ) {
return error . num ;
}
// Return number shifted by shift bits to the left or to the right if
// shift is negative
return shift >= 0 ? number << shift : number >> - shift ;
} ;
exports . BITOR = function ( number1 , number2 ) {
number1 = utils . parseNumber ( number1 ) ;
number2 = utils . parseNumber ( number2 ) ;
if ( utils . anyIsError ( number1 , number2 ) ) {
return error . value ;
}
// Return error if either number is less than 0
if ( number1 < 0 || number2 < 0 ) {
return error . num ;
}
// Return error if either number is a non-integer
if ( Math . floor ( number1 ) !== number1 || Math . floor ( number2 ) !== number2 ) {
return error . num ;
}
// Return error if either number is greater than (2^48)-1
if ( number1 > 281474976710655 || number2 > 281474976710655 ) {
return error . num ;
}
// Return bitwise OR of two numbers
return number1 | number2 ;
} ;
exports . BITRSHIFT = function ( number , shift ) {
number = utils . parseNumber ( number ) ;
shift = utils . parseNumber ( shift ) ;
if ( utils . anyIsError ( number , shift ) ) {
return error . value ;
}
// Return error if number is less than 0
if ( number < 0 ) {
return error . num ;
}
// Return error if number is a non-integer
if ( Math . floor ( number ) !== number ) {
return error . num ;
}
// Return error if number is greater than (2^48)-1
if ( number > 281474976710655 ) {
return error . num ;
}
// Return error if the absolute value of shift is greater than 53
if ( Math . abs ( shift ) > 53 ) {
return error . num ;
}
// Return number shifted by shift bits to the right or to the left if
// shift is negative
return shift >= 0 ? number >> shift : number << - shift ;
} ;
exports . BITXOR = function ( number1 , number2 ) {
number1 = utils . parseNumber ( number1 ) ;
number2 = utils . parseNumber ( number2 ) ;
if ( utils . anyIsError ( number1 , number2 ) ) {
return error . value ;
}
// Return error if either number is less than 0
if ( number1 < 0 || number2 < 0 ) {
return error . num ;
}
// Return error if either number is a non-integer
if ( Math . floor ( number1 ) !== number1 || Math . floor ( number2 ) !== number2 ) {
return error . num ;
}
// Return error if either number is greater than (2^48)-1
if ( number1 > 281474976710655 || number2 > 281474976710655 ) {
return error . num ;
}
// Return bitwise XOR of two numbers
return number1 ^ number2 ;
} ;
exports . COMPLEX = function ( real , imaginary , suffix ) {
real = utils . parseNumber ( real ) ;
imaginary = utils . parseNumber ( imaginary ) ;
if ( utils . anyIsError ( real , imaginary ) ) {
return real ;
}
// Set suffix
suffix = suffix === undefined ? "i" : suffix ;
// Return error if suffix is neither "i" nor "j"
if ( suffix !== "i" && suffix !== "j" ) {
return error . value ;
}
// Return complex number
if ( real === 0 && imaginary === 0 ) {
return 0 ;
} else if ( real === 0 ) {
return imaginary === 1 ? suffix : imaginary . toString ( ) + suffix ;
} else if ( imaginary === 0 ) {
return real . toString ( ) ;
} else {
var sign = imaginary > 0 ? "+" : "" ;
return (
real . toString ( ) +
sign +
( imaginary === 1 ? suffix : imaginary . toString ( ) + suffix )
) ;
}
} ;
exports . CONVERT = function ( number , from _unit , to _unit ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
// List of units supported by CONVERT and units defined by the
// International System of Units
// [Name, Symbol, Alternate symbols, Quantity, ISU, CONVERT, Conversion
// ratio]
var units = [
[
"a.u. of action" ,
"?" ,
null ,
"action" ,
false ,
false ,
1.05457168181818 e - 34 ,
] ,
[
"a.u. of charge" ,
"e" ,
null ,
"electric_charge" ,
false ,
false ,
1.60217653141414 e - 19 ,
] ,
[
"a.u. of energy" ,
"Eh" ,
null ,
"energy" ,
false ,
false ,
4.35974417757576 e - 18 ,
] ,
[
"a.u. of length" ,
"a?" ,
null ,
"length" ,
false ,
false ,
5.29177210818182 e - 11 ,
] ,
[
"a.u. of mass" ,
"m?" ,
null ,
"mass" ,
false ,
false ,
9.10938261616162 e - 31 ,
] ,
[
"a.u. of time" ,
"?/Eh" ,
null ,
"time" ,
false ,
false ,
2.41888432650516 e - 17 ,
] ,
[ "admiralty knot" , "admkn" , null , "speed" , false , true , 0.514773333 ] ,
[ "ampere" , "A" , null , "electric_current" , true , false , 1 ] ,
[
"ampere per meter" ,
"A/m" ,
null ,
"magnetic_field_intensity" ,
true ,
false ,
1 ,
] ,
[ "ångström" , "Å" , [ "ang" ] , "length" , false , true , 1e-10 ] ,
[ "are" , "ar" , null , "area" , false , true , 100 ] ,
[
"astronomical unit" ,
"ua" ,
null ,
"length" ,
false ,
false ,
1.49597870691667 e - 11 ,
] ,
[ "bar" , "bar" , null , "pressure" , false , false , 100000 ] ,
[ "barn" , "b" , null , "area" , false , false , 1e-28 ] ,
[ "becquerel" , "Bq" , null , "radioactivity" , true , false , 1 ] ,
[ "bit" , "bit" , [ "b" ] , "information" , false , true , 1 ] ,
[ "btu" , "BTU" , [ "btu" ] , "energy" , false , true , 1055.05585262 ] ,
[ "byte" , "byte" , null , "information" , false , true , 8 ] ,
[ "candela" , "cd" , null , "luminous_intensity" , true , false , 1 ] ,
[
"candela per square metre" ,
"cd/m?" ,
null ,
"luminance" ,
true ,
false ,
1 ,
] ,
[ "coulomb" , "C" , null , "electric_charge" , true , false , 1 ] ,
[ "cubic ångström" , "ang3" , [ "ang^3" ] , "volume" , false , true , 1e-30 ] ,
[ "cubic foot" , "ft3" , [ "ft^3" ] , "volume" , false , true , 0.028316846592 ] ,
[ "cubic inch" , "in3" , [ "in^3" ] , "volume" , false , true , 0.000016387064 ] ,
[
"cubic light-year" ,
"ly3" ,
[ "ly^3" ] ,
"volume" ,
false ,
true ,
8.46786664623715 e - 47 ,
] ,
[ "cubic metre" , "m?" , null , "volume" , true , true , 1 ] ,
[
"cubic mile" ,
"mi3" ,
[ "mi^3" ] ,
"volume" ,
false ,
true ,
4168181825.44058 ,
] ,
[
"cubic nautical mile" ,
"Nmi3" ,
[ "Nmi^3" ] ,
"volume" ,
false ,
true ,
6352182208 ,
] ,
[
"cubic Pica" ,
"Pica3" ,
[ "Picapt3" , "Pica^3" , "Picapt^3" ] ,
"volume" ,
false ,
true ,
7.58660370370369 e - 8 ,
] ,
[ "cubic yard" , "yd3" , [ "yd^3" ] , "volume" , false , true , 0.764554857984 ] ,
[ "cup" , "cup" , null , "volume" , false , true , 0.0002365882365 ] ,
[ "dalton" , "Da" , [ "u" ] , "mass" , false , false , 1.66053886282828 e - 27 ] ,
[ "day" , "d" , [ "day" ] , "time" , false , true , 86400 ] ,
[ "degree" , "°" , null , "angle" , false , false , 0.0174532925199433 ] ,
[
"degrees Rankine" ,
"Rank" ,
null ,
"temperature" ,
false ,
true ,
0.555555555555556 ,
] ,
[ "dyne" , "dyn" , [ "dy" ] , "force" , false , true , 0.00001 ] ,
[ "electronvolt" , "eV" , [ "ev" ] , "energy" , false , true , 1.60217656514141 ] ,
[ "ell" , "ell" , null , "length" , false , true , 1.143 ] ,
[ "erg" , "erg" , [ "e" ] , "energy" , false , true , 1e-7 ] ,
[ "farad" , "F" , null , "electric_capacitance" , true , false , 1 ] ,
[ "fluid ounce" , "oz" , null , "volume" , false , true , 0.0000295735295625 ] ,
[ "foot" , "ft" , null , "length" , false , true , 0.3048 ] ,
[ "foot-pound" , "flb" , null , "energy" , false , true , 1.3558179483314 ] ,
[ "gal" , "Gal" , null , "acceleration" , false , false , 0.01 ] ,
[ "gallon" , "gal" , null , "volume" , false , true , 0.003785411784 ] ,
[ "gauss" , "G" , [ "ga" ] , "magnetic_flux_density" , false , true , 1 ] ,
[ "grain" , "grain" , null , "mass" , false , true , 0.0000647989 ] ,
[ "gram" , "g" , null , "mass" , false , true , 0.001 ] ,
[ "gray" , "Gy" , null , "absorbed_dose" , true , false , 1 ] ,
[
"gross registered ton" ,
"GRT" ,
[ "regton" ] ,
"volume" ,
false ,
true ,
2.8316846592 ,
] ,
[ "hectare" , "ha" , null , "area" , false , true , 10000 ] ,
[ "henry" , "H" , null , "inductance" , true , false , 1 ] ,
[ "hertz" , "Hz" , null , "frequency" , true , false , 1 ] ,
[ "horsepower" , "HP" , [ "h" ] , "power" , false , true , 745.69987158227 ] ,
[
"horsepower-hour" ,
"HPh" ,
[ "hh" , "hph" ] ,
"energy" ,
false ,
true ,
2684519.538 ,
] ,
[ "hour" , "h" , [ "hr" ] , "time" , false , true , 3600 ] ,
[
"imperial gallon (U.K.)" ,
"uk_gal" ,
null ,
"volume" ,
false ,
true ,
0.00454609 ,
] ,
[
"imperial hundredweight" ,
"lcwt" ,
[ "uk_cwt" , "hweight" ] ,
"mass" ,
false ,
true ,
50.802345 ,
] ,
[
"imperial quart (U.K)" ,
"uk_qt" ,
null ,
"volume" ,
false ,
true ,
0.0011365225 ,
] ,
[
"imperial ton" ,
"brton" ,
[ "uk_ton" , "LTON" ] ,
"mass" ,
false ,
true ,
1016.046909 ,
] ,
[ "inch" , "in" , null , "length" , false , true , 0.0254 ] ,
[
"international acre" ,
"uk_acre" ,
null ,
"area" ,
false ,
true ,
4046.8564224 ,
] ,
[ "IT calorie" , "cal" , null , "energy" , false , true , 4.1868 ] ,
[ "joule" , "J" , null , "energy" , true , true , 1 ] ,
[ "katal" , "kat" , null , "catalytic_activity" , true , false , 1 ] ,
[ "kelvin" , "K" , [ "kel" ] , "temperature" , true , true , 1 ] ,
[ "kilogram" , "kg" , null , "mass" , true , true , 1 ] ,
[ "knot" , "kn" , null , "speed" , false , true , 0.514444444444444 ] ,
[ "light-year" , "ly" , null , "length" , false , true , 9460730472580800 ] ,
[ "litre" , "L" , [ "l" , "lt" ] , "volume" , false , true , 0.001 ] ,
[ "lumen" , "lm" , null , "luminous_flux" , true , false , 1 ] ,
[ "lux" , "lx" , null , "illuminance" , true , false , 1 ] ,
[ "maxwell" , "Mx" , null , "magnetic_flux" , false , false , 1e-18 ] ,
[ "measurement ton" , "MTON" , null , "volume" , false , true , 1.13267386368 ] ,
[
"meter per hour" ,
"m/h" ,
[ "m/hr" ] ,
"speed" ,
false ,
true ,
0.00027777777777778 ,
] ,
[ "meter per second" , "m/s" , [ "m/sec" ] , "speed" , true , true , 1 ] ,
[
"meter per second squared" ,
"m?s??" ,
null ,
"acceleration" ,
true ,
false ,
1 ,
] ,
[ "parsec" , "pc" , [ "parsec" ] , "length" , false , true , 30856775814671900 ] ,
[
"meter squared per second" ,
"m?/s" ,
null ,
"kinematic_viscosity" ,
true ,
false ,
1 ,
] ,
[ "metre" , "m" , null , "length" , true , true , 1 ] ,
[ "miles per hour" , "mph" , null , "speed" , false , true , 0.44704 ] ,
[
"millimetre of mercury" ,
"mmHg" ,
null ,
"pressure" ,
false ,
false ,
133.322 ,
] ,
[ "minute" , "?" , null , "angle" , false , false , 0.000290888208665722 ] ,
[ "minute" , "min" , [ "mn" ] , "time" , false , true , 60 ] ,
[ "modern teaspoon" , "tspm" , null , "volume" , false , true , 0.000005 ] ,
[ "mole" , "mol" , null , "amount_of_substance" , true , false , 1 ] ,
[ "morgen" , "Morgen" , null , "area" , false , true , 2500 ] ,
[
"n.u. of action" ,
"?" ,
null ,
"action" ,
false ,
false ,
1.05457168181818 e - 34 ,
] ,
[
"n.u. of mass" ,
"m?" ,
null ,
"mass" ,
false ,
false ,
9.10938261616162 e - 31 ,
] ,
[ "n.u. of speed" , "c?" , null , "speed" , false , false , 299792458 ] ,
[
"n.u. of time" ,
"?/(me?c??)" ,
null ,
"time" ,
false ,
false ,
1.28808866778687 e - 21 ,
] ,
[ "nautical mile" , "M" , [ "Nmi" ] , "length" , false , true , 1852 ] ,
[ "newton" , "N" , null , "force" , true , true , 1 ] ,
[
"œrsted" ,
"Oe " ,
null ,
"magnetic_field_intensity" ,
false ,
false ,
79.5774715459477 ,
] ,
[ "ohm" , "Ω" , null , "electric_resistance" , true , false , 1 ] ,
[ "ounce mass" , "ozm" , null , "mass" , false , true , 0.028349523125 ] ,
[ "pascal" , "Pa" , null , "pressure" , true , false , 1 ] ,
[ "pascal second" , "Pa?s" , null , "dynamic_viscosity" , true , false , 1 ] ,
[ "pferdestärke" , "PS" , null , "power" , false , true , 735.49875 ] ,
[ "phot" , "ph" , null , "illuminance" , false , false , 0.0001 ] ,
[
"pica (1/6 inch)" ,
"pica" ,
null ,
"length" ,
false ,
true ,
0.00035277777777778 ,
] ,
[
"pica (1/72 inch)" ,
"Pica" ,
[ "Picapt" ] ,
"length" ,
false ,
true ,
0.00423333333333333 ,
] ,
[ "poise" , "P" , null , "dynamic_viscosity" , false , false , 0.1 ] ,
[ "pond" , "pond" , null , "force" , false , true , 0.00980665 ] ,
[ "pound force" , "lbf" , null , "force" , false , true , 4.4482216152605 ] ,
[ "pound mass" , "lbm" , null , "mass" , false , true , 0.45359237 ] ,
[ "quart" , "qt" , null , "volume" , false , true , 0.000946352946 ] ,
[ "radian" , "rad" , null , "angle" , true , false , 1 ] ,
[ "second" , "?" , null , "angle" , false , false , 0.00000484813681109536 ] ,
[ "second" , "s" , [ "sec" ] , "time" , true , true , 1 ] ,
[
"short hundredweight" ,
"cwt" ,
[ "shweight" ] ,
"mass" ,
false ,
true ,
45.359237 ,
] ,
[ "siemens" , "S" , null , "electrical_conductance" , true , false , 1 ] ,
[ "sievert" , "Sv" , null , "equivalent_dose" , true , false , 1 ] ,
[ "slug" , "sg" , null , "mass" , false , true , 14.59390294 ] ,
[ "square ångström" , "ang2" , [ "ang^2" ] , "area" , false , true , 1e-20 ] ,
[ "square foot" , "ft2" , [ "ft^2" ] , "area" , false , true , 0.09290304 ] ,
[ "square inch" , "in2" , [ "in^2" ] , "area" , false , true , 0.00064516 ] ,
[
"square light-year" ,
"ly2" ,
[ "ly^2" ] ,
"area" ,
false ,
true ,
8.95054210748189 e31 ,
] ,
[ "square meter" , "m?" , null , "area" , true , true , 1 ] ,
[ "square mile" , "mi2" , [ "mi^2" ] , "area" , false , true , 2589988.110336 ] ,
[
"square nautical mile" ,
"Nmi2" ,
[ "Nmi^2" ] ,
"area" ,
false ,
true ,
3429904 ,
] ,
[
"square Pica" ,
"Pica2" ,
[ "Picapt2" , "Pica^2" , "Picapt^2" ] ,
"area" ,
false ,
true ,
0.00001792111111111 ,
] ,
[ "square yard" , "yd2" , [ "yd^2" ] , "area" , false , true , 0.83612736 ] ,
[ "statute mile" , "mi" , null , "length" , false , true , 1609.344 ] ,
[ "steradian" , "sr" , null , "solid_angle" , true , false , 1 ] ,
[ "stilb" , "sb" , null , "luminance" , false , false , 0.0001 ] ,
[ "stokes" , "St" , null , "kinematic_viscosity" , false , false , 0.0001 ] ,
[ "stone" , "stone" , null , "mass" , false , true , 6.35029318 ] ,
[ "tablespoon" , "tbs" , null , "volume" , false , true , 0.0000147868 ] ,
[ "teaspoon" , "tsp" , null , "volume" , false , true , 0.00000492892 ] ,
[ "tesla" , "T" , null , "magnetic_flux_density" , true , true , 1 ] ,
[ "thermodynamic calorie" , "c" , null , "energy" , false , true , 4.184 ] ,
[ "ton" , "ton" , null , "mass" , false , true , 907.18474 ] ,
[ "tonne" , "t" , null , "mass" , false , false , 1000 ] ,
[ "U.K. pint" , "uk_pt" , null , "volume" , false , true , 0.00056826125 ] ,
[ "U.S. bushel" , "bushel" , null , "volume" , false , true , 0.03523907 ] ,
[ "U.S. oil barrel" , "barrel" , null , "volume" , false , true , 0.158987295 ] ,
[ "U.S. pint" , "pt" , [ "us_pt" ] , "volume" , false , true , 0.000473176473 ] ,
[
"U.S. survey mile" ,
"survey_mi" ,
null ,
"length" ,
false ,
true ,
1609.347219 ,
] ,
[
"U.S. survey/statute acre" ,
"us_acre" ,
null ,
"area" ,
false ,
true ,
4046.87261 ,
] ,
[ "volt" , "V" , null , "voltage" , true , false , 1 ] ,
[ "watt" , "W" , null , "power" , true , true , 1 ] ,
[ "watt-hour" , "Wh" , [ "wh" ] , "energy" , false , true , 3600 ] ,
[ "weber" , "Wb" , null , "magnetic_flux" , true , false , 1 ] ,
[ "yard" , "yd" , null , "length" , false , true , 0.9144 ] ,
[ "year" , "yr" , null , "time" , false , true , 31557600 ] ,
] ;
// Binary prefixes
// [Name, Prefix power of 2 value, Previx value, Abbreviation, Derived
// from]
var binary _prefixes = {
Yi : [ "yobi" , 80 , 1208925819614629174706176 , "Yi" , "yotta" ] ,
Zi : [ "zebi" , 70 , 1180591620717411303424 , "Zi" , "zetta" ] ,
Ei : [ "exbi" , 60 , 1152921504606846976 , "Ei" , "exa" ] ,
Pi : [ "pebi" , 50 , 1125899906842624 , "Pi" , "peta" ] ,
Ti : [ "tebi" , 40 , 1099511627776 , "Ti" , "tera" ] ,
Gi : [ "gibi" , 30 , 1073741824 , "Gi" , "giga" ] ,
Mi : [ "mebi" , 20 , 1048576 , "Mi" , "mega" ] ,
ki : [ "kibi" , 10 , 1024 , "ki" , "kilo" ] ,
} ;
// Unit prefixes
// [Name, Multiplier, Abbreviation]
var unit _prefixes = {
Y : [ "yotta" , 1e24 , "Y" ] ,
Z : [ "zetta" , 1e21 , "Z" ] ,
E : [ "exa" , 1e18 , "E" ] ,
P : [ "peta" , 1e15 , "P" ] ,
T : [ "tera" , 1e12 , "T" ] ,
G : [ "giga" , 1e9 , "G" ] ,
M : [ "mega" , 1e6 , "M" ] ,
k : [ "kilo" , 1e3 , "k" ] ,
h : [ "hecto" , 1e2 , "h" ] ,
e : [ "dekao" , 1e1 , "e" ] ,
d : [ "deci" , 1e-1 , "d" ] ,
c : [ "centi" , 1e-2 , "c" ] ,
m : [ "milli" , 1e-3 , "m" ] ,
u : [ "micro" , 1e-6 , "u" ] ,
n : [ "nano" , 1e-9 , "n" ] ,
p : [ "pico" , 1e-12 , "p" ] ,
f : [ "femto" , 1e-15 , "f" ] ,
a : [ "atto" , 1e-18 , "a" ] ,
z : [ "zepto" , 1e-21 , "z" ] ,
y : [ "yocto" , 1e-24 , "y" ] ,
} ;
// Initialize units and multipliers
var from = null ;
var to = null ;
var base _from _unit = from _unit ;
var base _to _unit = to _unit ;
var from _multiplier = 1 ;
var to _multiplier = 1 ;
var alt ;
// Lookup from and to units
for ( var i = 0 ; i < units . length ; i ++ ) {
alt = units [ i ] [ 2 ] === null ? [ ] : units [ i ] [ 2 ] ;
if (
units [ i ] [ 1 ] === base _from _unit ||
alt . indexOf ( base _from _unit ) >= 0
) {
from = units [ i ] ;
}
if ( units [ i ] [ 1 ] === base _to _unit || alt . indexOf ( base _to _unit ) >= 0 ) {
to = units [ i ] ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Lookup from prefix
if ( from === null ) {
var from _binary _prefix = binary _prefixes [ from _unit . substring ( 0 , 2 ) ] ;
var from _unit _prefix = unit _prefixes [ from _unit . substring ( 0 , 1 ) ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Handle dekao unit prefix (only unit prefix with two characters)
if ( from _unit . substring ( 0 , 2 ) === "da" ) {
from _unit _prefix = [ "dekao" , 1e1 , "da" ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Handle binary prefixes first (so that 'Yi' is processed before
// 'Y')
if ( from _binary _prefix ) {
from _multiplier = from _binary _prefix [ 2 ] ;
base _from _unit = from _unit . substring ( 2 ) ;
} else if ( from _unit _prefix ) {
from _multiplier = from _unit _prefix [ 1 ] ;
base _from _unit = from _unit . substring ( from _unit _prefix [ 2 ] . length ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Lookup from unit
for ( var j = 0 ; j < units . length ; j ++ ) {
alt = units [ j ] [ 2 ] === null ? [ ] : units [ j ] [ 2 ] ;
if (
units [ j ] [ 1 ] === base _from _unit ||
alt . indexOf ( base _from _unit ) >= 0
) {
from = units [ j ] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Lookup to prefix
if ( to === null ) {
var to _binary _prefix = binary _prefixes [ to _unit . substring ( 0 , 2 ) ] ;
var to _unit _prefix = unit _prefixes [ to _unit . substring ( 0 , 1 ) ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Handle dekao unit prefix (only unit prefix with two characters)
if ( to _unit . substring ( 0 , 2 ) === "da" ) {
to _unit _prefix = [ "dekao" , 1e1 , "da" ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Handle binary prefixes first (so that 'Yi' is processed before
// 'Y')
if ( to _binary _prefix ) {
to _multiplier = to _binary _prefix [ 2 ] ;
base _to _unit = to _unit . substring ( 2 ) ;
} else if ( to _unit _prefix ) {
to _multiplier = to _unit _prefix [ 1 ] ;
base _to _unit = to _unit . substring ( to _unit _prefix [ 2 ] . length ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Lookup to unit
for ( var k = 0 ; k < units . length ; k ++ ) {
alt = units [ k ] [ 2 ] === null ? [ ] : units [ k ] [ 2 ] ;
if ( units [ k ] [ 1 ] === base _to _unit || alt . indexOf ( base _to _unit ) >= 0 ) {
to = units [ k ] ;
}
}
}
// Return error if a unit does not exist
if ( from === null || to === null ) {
return error . na ;
}
// Return error if units represent different quantities
if ( from [ 3 ] !== to [ 3 ] ) {
return error . na ;
}
// Return converted number
return ( number * from [ 6 ] * from _multiplier ) / ( to [ 6 ] * to _multiplier ) ;
} ;
exports . DEC2BIN = function ( number , places ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
// Return error if number is not decimal, is lower than -512, or is
// greater than 511
if ( ! /^-?[0-9]{1,3}$/ . test ( number ) || number < - 512 || number > 511 ) {
return error . num ;
}
// Ignore places and return a 10-character binary number if number is
// negative
if ( number < 0 ) {
return (
"1" +
REPT ( "0" , 9 - ( 512 + number ) . toString ( 2 ) . length ) +
( 512 + number ) . toString ( 2 )
) ;
}
// Convert decimal number to binary
var result = parseInt ( number , 10 ) . toString ( 2 ) ;
// Return binary number using the minimum number of characters necessary
// if places is undefined
if ( typeof places === "undefined" ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . DEC2HEX = function ( number , places ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
// Return error if number is not decimal, is lower than -549755813888,
// or is greater than 549755813887
if (
! /^-?[0-9]{1,12}$/ . test ( number ) ||
number < - 549755813888 ||
number > 549755813887
) {
return error . num ;
}
// Ignore places and return a 10-character hexadecimal number if number
// is negative
if ( number < 0 ) {
return ( 1099511627776 + number ) . toString ( 16 ) ;
}
// Convert decimal number to hexadecimal
var result = parseInt ( number , 10 ) . toString ( 16 ) ;
// Return hexadecimal number using the minimum number of characters
// necessary if places is undefined
if ( typeof places === "undefined" ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . DEC2OCT = function ( number , places ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
// Return error if number is not decimal, is lower than -549755813888,
// or is greater than 549755813887
if (
! /^-?[0-9]{1,9}$/ . test ( number ) ||
number < - 536870912 ||
number > 536870911
) {
return error . num ;
}
// Ignore places and return a 10-character octal number if number is
// negative
if ( number < 0 ) {
return ( 1073741824 + number ) . toString ( 8 ) ;
}
// Convert decimal number to octal
var result = parseInt ( number , 10 ) . toString ( 8 ) ;
// Return octal number using the minimum number of characters necessary
// if places is undefined
if ( typeof places === "undefined" ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . DELTA = function ( number1 , number2 ) {
// Set number2 to zero if undefined
number2 = number2 === undefined ? 0 : number2 ;
number1 = utils . parseNumber ( number1 ) ;
number2 = utils . parseNumber ( number2 ) ;
if ( utils . anyIsError ( number1 , number2 ) ) {
return error . value ;
}
// Return delta
return number1 === number2 ? 1 : 0 ;
} ;
exports . ERF = function ( lower _bound , upper _bound ) { } ;
exports . ERF . PRECISE = function ( ) { } ;
exports . ERFC = function ( x ) { } ;
exports . ERFC . PRECISE = function ( ) { } ;
exports . GESTEP = function ( number , step ) {
step = step || 0 ;
number = utils . parseNumber ( number ) ;
if ( utils . anyIsError ( step , number ) ) {
return number ;
}
// Return delta
return number >= step ? 1 : 0 ;
} ;
exports . HEX2BIN = function ( number , places ) {
// Return error if number is not hexadecimal or contains more than ten
// characters (10 digits)
if ( ! /^[0-9A-Fa-f]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Check if number is negative
var negative =
number . length === 10 && number . substring ( 0 , 1 ) . toLowerCase ( ) === "f"
? true
: false ;
// Convert hexadecimal number to decimal
var decimal = negative
? parseInt ( number , 16 ) - 1099511627776
: parseInt ( number , 16 ) ;
// Return error if number is lower than -512 or greater than 511
if ( decimal < - 512 || decimal > 511 ) {
return error . num ;
}
// Ignore places and return a 10-character binary number if number is
// negative
if ( negative ) {
return (
"1" +
REPT ( "0" , 9 - ( 512 + decimal ) . toString ( 2 ) . length ) +
( 512 + decimal ) . toString ( 2 )
) ;
}
// Convert decimal number to binary
var result = decimal . toString ( 2 ) ;
// Return binary number using the minimum number of characters necessary
// if places is undefined
if ( places === undefined ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . HEX2DEC = function ( number ) {
// Return error if number is not hexadecimal or contains more than ten
// characters (10 digits)
if ( ! /^[0-9A-Fa-f]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Convert hexadecimal number to decimal
var decimal = parseInt ( number , 16 ) ;
// Return decimal number
return decimal >= 549755813888 ? decimal - 1099511627776 : decimal ;
} ;
exports . HEX2OCT = function ( number , places ) {
// Return error if number is not hexadecimal or contains more than ten
// characters (10 digits)
if ( ! /^[0-9A-Fa-f]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Convert hexadecimal number to decimal
var decimal = parseInt ( number , 16 ) ;
// Return error if number is positive and greater than 0x1fffffff
// (536870911)
if ( decimal > 536870911 && decimal < 1098974756864 ) {
return error . num ;
}
// Ignore places and return a 10-character octal number if number is
// negative
if ( decimal >= 1098974756864 ) {
return ( decimal - 1098437885952 ) . toString ( 8 ) ;
}
// Convert decimal number to octal
var result = decimal . toString ( 8 ) ;
// Return octal number using the minimum number of characters necessary
// if places is undefined
if ( places === undefined ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . IMABS = function ( inumber ) {
// Lookup real and imaginary coefficients using exports.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
// Return error if either coefficient is not a number
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return absolute value of complex number
return Math . sqrt ( Math . pow ( x , 2 ) + Math . pow ( y , 2 ) ) ;
} ;
exports . IMAGINARY = function ( inumber ) {
if ( inumber === undefined || inumber === true || inumber === false ) {
return error . value ;
}
// Return 0 if inumber is equal to 0
if ( inumber === 0 || inumber === "0" ) {
return 0 ;
}
// Handle special cases
if ( [ "i" , "j" ] . indexOf ( inumber ) >= 0 ) {
return 1 ;
}
// Normalize imaginary coefficient
inumber = inumber
. replace ( "+i" , "+1i" )
. replace ( "-i" , "-1i" )
. replace ( "+j" , "+1j" )
. replace ( "-j" , "-1j" ) ;
// Lookup sign
var plus = inumber . indexOf ( "+" ) ;
var minus = inumber . indexOf ( "-" ) ;
if ( plus === 0 ) {
plus = inumber . indexOf ( "+" , 1 ) ;
}
if ( minus === 0 ) {
minus = inumber . indexOf ( "-" , 1 ) ;
}
// Lookup imaginary unit
var last = inumber . substring ( inumber . length - 1 , inumber . length ) ;
var unit = last === "i" || last === "j" ;
if ( plus >= 0 || minus >= 0 ) {
// Return error if imaginary unit is neither i nor j
if ( ! unit ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return imaginary coefficient of complex number
if ( plus >= 0 ) {
return isNaN ( inumber . substring ( 0 , plus ) ) ||
isNaN ( inumber . substring ( plus + 1 , inumber . length - 1 ) )
? error . num
: Number ( inumber . substring ( plus + 1 , inumber . length - 1 ) ) ;
} else {
return isNaN ( inumber . substring ( 0 , minus ) ) ||
isNaN ( inumber . substring ( minus + 1 , inumber . length - 1 ) )
? error . num
: - Number ( inumber . substring ( minus + 1 , inumber . length - 1 ) ) ;
}
} else {
if ( unit ) {
return isNaN ( inumber . substring ( 0 , inumber . length - 1 ) )
? error . num
: inumber . substring ( 0 , inumber . length - 1 ) ;
} else {
return isNaN ( inumber ) ? error . num : 0 ;
}
}
} ;
exports . IMARGUMENT = function ( inumber ) {
// Lookup real and imaginary coefficients using exports.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
// Return error if either coefficient is not a number
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return error if inumber is equal to zero
if ( x === 0 && y === 0 ) {
return error . div0 ;
}
// Return PI/2 if x is equal to zero and y is positive
if ( x === 0 && y > 0 ) {
return Math . PI / 2 ;
}
// Return -PI/2 if x is equal to zero and y is negative
if ( x === 0 && y < 0 ) {
return - Math . PI / 2 ;
}
// Return zero if x is negative and y is equal to zero
if ( y === 0 && x > 0 ) {
return 0 ;
}
// Return zero if x is negative and y is equal to zero
if ( y === 0 && x < 0 ) {
return - Math . PI ;
}
// Return argument of complex number
if ( x > 0 ) {
return Math . atan ( y / x ) ;
} else if ( x < 0 && y >= 0 ) {
return Math . atan ( y / x ) + Math . PI ;
} else {
return Math . atan ( y / x ) - Math . PI ;
}
} ;
exports . IMCONJUGATE = function ( inumber ) {
// Lookup real and imaginary coefficients using exports.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return conjugate of complex number
return y !== 0 ? exports . COMPLEX ( x , - y , unit ) : inumber ;
} ;
exports . IMCOS = function ( inumber ) {
// Lookup real and imaginary coefficients using exports.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return cosine of complex number
return exports . COMPLEX (
( Math . cos ( x ) * ( Math . exp ( y ) + Math . exp ( - y ) ) ) / 2 ,
( - Math . sin ( x ) * ( Math . exp ( y ) - Math . exp ( - y ) ) ) / 2 ,
unit
) ;
} ;
exports . IMCOSH = function ( inumber ) {
// Lookup real and imaginary coefficients using exports.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return hyperbolic cosine of complex number
return exports . COMPLEX (
( Math . cos ( y ) * ( Math . exp ( x ) + Math . exp ( - x ) ) ) / 2 ,
( Math . sin ( y ) * ( Math . exp ( x ) - Math . exp ( - x ) ) ) / 2 ,
unit
) ;
} ;
exports . IMCOT = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return cotangent of complex number
return exports . IMDIV ( exports . IMCOS ( inumber ) , exports . IMSIN ( inumber ) ) ;
} ;
exports . IMDIV = function ( inumber1 , inumber2 ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var a = exports . IMREAL ( inumber1 ) ;
var b = exports . IMAGINARY ( inumber1 ) ;
var c = exports . IMREAL ( inumber2 ) ;
var d = exports . IMAGINARY ( inumber2 ) ;
if ( utils . anyIsError ( a , b , c , d ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit1 = inumber1 . substring ( inumber1 . length - 1 ) ;
var unit2 = inumber2 . substring ( inumber2 . length - 1 ) ;
var unit = "i" ;
if ( unit1 === "j" ) {
unit = "j" ;
} else if ( unit2 === "j" ) {
unit = "j" ;
}
// Return error if inumber2 is null
if ( c === 0 && d === 0 ) {
return error . num ;
}
// Return exponential of complex number
var den = c * c + d * d ;
return exports . COMPLEX (
( a * c + b * d ) / den ,
( b * c - a * d ) / den ,
unit
) ;
} ;
exports . IMEXP = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return exponential of complex number
var e = Math . exp ( x ) ;
return exports . COMPLEX ( e * Math . cos ( y ) , e * Math . sin ( y ) , unit ) ;
} ;
exports . IMLN = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return exponential of complex number
return exports . COMPLEX (
Math . log ( Math . sqrt ( x * x + y * y ) ) ,
Math . atan ( y / x ) ,
unit
) ;
} ;
exports . IMLOG10 = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return exponential of complex number
return exports . COMPLEX (
Math . log ( Math . sqrt ( x * x + y * y ) ) / Math . log ( 10 ) ,
Math . atan ( y / x ) / Math . log ( 10 ) ,
unit
) ;
} ;
exports . IMLOG2 = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return exponential of complex number
return exports . COMPLEX (
Math . log ( Math . sqrt ( x * x + y * y ) ) / Math . log ( 2 ) ,
Math . atan ( y / x ) / Math . log ( 2 ) ,
unit
) ;
} ;
exports . IMPOWER = function ( inumber , number ) {
number = utils . parseNumber ( number ) ;
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( number , x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Calculate power of modulus
var p = Math . pow ( exports . IMABS ( inumber ) , number ) ;
// Calculate argument
var t = exports . IMARGUMENT ( inumber ) ;
// Return exponential of complex number
return exports . COMPLEX (
p * Math . cos ( number * t ) ,
p * Math . sin ( number * t ) ,
unit
) ;
} ;
exports . IMPRODUCT = function ( ) {
// Initialize result
var result = arguments [ 0 ] ;
// Loop on all numbers
for ( var i = 1 ; i < arguments . length ; i ++ ) {
// Lookup coefficients of two complex numbers
var a = exports . IMREAL ( result ) ;
var b = exports . IMAGINARY ( result ) ;
var c = exports . IMREAL ( arguments [ i ] ) ;
var d = exports . IMAGINARY ( arguments [ i ] ) ;
if ( utils . anyIsError ( a , b , c , d ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Complute product of two complex numbers
result = exports . COMPLEX ( a * c - b * d , a * d + b * c ) ;
}
// Return product of complex numbers
return result ;
} ;
exports . IMREAL = function ( inumber ) {
if ( inumber === undefined || inumber === true || inumber === false ) {
return error . value ;
}
// Return 0 if inumber is equal to 0
if ( inumber === 0 || inumber === "0" ) {
return 0 ;
}
// Handle special cases
if (
[
"i" ,
"+i" ,
"1i" ,
"+1i" ,
"-i" ,
"-1i" ,
"j" ,
"+j" ,
"1j" ,
"+1j" ,
"-j" ,
"-1j" ,
] . indexOf ( inumber ) >= 0
) {
return 0 ;
}
// Lookup sign
var plus = inumber . indexOf ( "+" ) ;
var minus = inumber . indexOf ( "-" ) ;
if ( plus === 0 ) {
plus = inumber . indexOf ( "+" , 1 ) ;
}
if ( minus === 0 ) {
minus = inumber . indexOf ( "-" , 1 ) ;
}
// Lookup imaginary unit
var last = inumber . substring ( inumber . length - 1 , inumber . length ) ;
var unit = last === "i" || last === "j" ;
if ( plus >= 0 || minus >= 0 ) {
// Return error if imaginary unit is neither i nor j
if ( ! unit ) {
return error . num ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return real coefficient of complex number
if ( plus >= 0 ) {
return isNaN ( inumber . substring ( 0 , plus ) ) ||
isNaN ( inumber . substring ( plus + 1 , inumber . length - 1 ) )
? error . num
: Number ( inumber . substring ( 0 , plus ) ) ;
} else {
return isNaN ( inumber . substring ( 0 , minus ) ) ||
isNaN ( inumber . substring ( minus + 1 , inumber . length - 1 ) )
? error . num
: Number ( inumber . substring ( 0 , minus ) ) ;
}
} else {
if ( unit ) {
return isNaN ( inumber . substring ( 0 , inumber . length - 1 ) )
? error . num
: 0 ;
} else {
return isNaN ( inumber ) ? error . num : inumber ;
}
}
} ;
exports . IMSEC = function ( inumber ) {
// Return error if inumber is a logical value
if ( inumber === true || inumber === false ) {
return error . value ;
}
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return secant of complex number
return exports . IMDIV ( "1" , exports . IMCOS ( inumber ) ) ;
} ;
exports . IMSECH = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return hyperbolic secant of complex number
return exports . IMDIV ( "1" , exports . IMCOSH ( inumber ) ) ;
} ;
exports . IMSIN = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return sine of complex number
return exports . COMPLEX (
( Math . sin ( x ) * ( Math . exp ( y ) + Math . exp ( - y ) ) ) / 2 ,
( Math . cos ( x ) * ( Math . exp ( y ) - Math . exp ( - y ) ) ) / 2 ,
unit
) ;
} ;
exports . IMSINH = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Return hyperbolic sine of complex number
return exports . COMPLEX (
( Math . cos ( y ) * ( Math . exp ( x ) - Math . exp ( - x ) ) ) / 2 ,
( Math . sin ( y ) * ( Math . exp ( x ) + Math . exp ( - x ) ) ) / 2 ,
unit
) ;
} ;
exports . IMSQRT = function ( inumber ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit = inumber . substring ( inumber . length - 1 ) ;
unit = unit === "i" || unit === "j" ? unit : "i" ;
// Calculate power of modulus
var s = Math . sqrt ( exports . IMABS ( inumber ) ) ;
// Calculate argument
var t = exports . IMARGUMENT ( inumber ) ;
// Return exponential of complex number
return exports . COMPLEX ( s * Math . cos ( t / 2 ) , s * Math . sin ( t / 2 ) , unit ) ;
} ;
exports . IMCSC = function ( inumber ) {
// Return error if inumber is a logical value
if ( inumber === true || inumber === false ) {
return error . value ;
}
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
// Return error if either coefficient is not a number
if ( utils . anyIsError ( x , y ) ) {
return error . num ;
}
// Return cosecant of complex number
return exports . IMDIV ( "1" , exports . IMSIN ( inumber ) ) ;
} ;
exports . IMCSCH = function ( inumber ) {
// Return error if inumber is a logical value
if ( inumber === true || inumber === false ) {
return error . value ;
}
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
// Return error if either coefficient is not a number
if ( utils . anyIsError ( x , y ) ) {
return error . num ;
}
// Return hyperbolic cosecant of complex number
return exports . IMDIV ( "1" , exports . IMSINH ( inumber ) ) ;
} ;
exports . IMSUB = function ( inumber1 , inumber2 ) {
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var a = this . IMREAL ( inumber1 ) ;
var b = this . IMAGINARY ( inumber1 ) ;
var c = this . IMREAL ( inumber2 ) ;
var d = this . IMAGINARY ( inumber2 ) ;
if ( utils . anyIsError ( a , b , c , d ) ) {
return error . value ;
}
// Lookup imaginary unit
var unit1 = inumber1 . substring ( inumber1 . length - 1 ) ;
var unit2 = inumber2 . substring ( inumber2 . length - 1 ) ;
var unit = "i" ;
if ( unit1 === "j" ) {
unit = "j" ;
} else if ( unit2 === "j" ) {
unit = "j" ;
}
// Return _ of two complex numbers
return this . COMPLEX ( a - c , b - d , unit ) ;
} ;
exports . IMSUM = function ( ) {
var args = utils . flatten ( arguments ) ;
// Initialize result
var result = args [ 0 ] ;
// Loop on all numbers
for ( var i = 1 ; i < args . length ; i ++ ) {
// Lookup coefficients of two complex numbers
var a = this . IMREAL ( result ) ;
var b = this . IMAGINARY ( result ) ;
var c = this . IMREAL ( args [ i ] ) ;
var d = this . IMAGINARY ( args [ i ] ) ;
if ( utils . anyIsError ( a , b , c , d ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Complute product of two complex numbers
result = this . COMPLEX ( a + c , b + d ) ;
}
// Return sum of complex numbers
return result ;
} ;
exports . IMTAN = function ( inumber ) {
// Return error if inumber is a logical value
if ( inumber === true || inumber === false ) {
return error . value ;
}
// Lookup real and imaginary coefficients using Formula.js
// [http://formulajs.org]
var x = exports . IMREAL ( inumber ) ;
var y = exports . IMAGINARY ( inumber ) ;
if ( utils . anyIsError ( x , y ) ) {
return error . value ;
}
// Return tangent of complex number
return this . IMDIV ( this . IMSIN ( inumber ) , this . IMCOS ( inumber ) ) ;
} ;
exports . OCT2BIN = function ( number , places ) {
// Return error if number is not hexadecimal or contains more than ten
// characters (10 digits)
if ( ! /^[0-7]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Check if number is negative
var negative =
number . length === 10 && number . substring ( 0 , 1 ) === "7" ? true : false ;
// Convert octal number to decimal
var decimal = negative
? parseInt ( number , 8 ) - 1073741824
: parseInt ( number , 8 ) ;
// Return error if number is lower than -512 or greater than 511
if ( decimal < - 512 || decimal > 511 ) {
return error . num ;
}
// Ignore places and return a 10-character binary number if number is
// negative
if ( negative ) {
return (
"1" +
REPT ( "0" , 9 - ( 512 + decimal ) . toString ( 2 ) . length ) +
( 512 + decimal ) . toString ( 2 )
) ;
}
// Convert decimal number to binary
var result = decimal . toString ( 2 ) ;
// Return binary number using the minimum number of characters necessary
// if places is undefined
if ( typeof places === "undefined" ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
exports . OCT2DEC = function ( number ) {
// Return error if number is not octal or contains more than ten
// characters (10 digits)
if ( ! /^[0-7]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Convert octal number to decimal
var decimal = parseInt ( number , 8 ) ;
// Return decimal number
return decimal >= 536870912 ? decimal - 1073741824 : decimal ;
} ;
exports . OCT2HEX = function ( number , places ) {
// Return error if number is not octal or contains more than ten
// characters (10 digits)
if ( ! /^[0-7]{1,10}$/ . test ( number ) ) {
return error . num ;
}
// Convert octal number to decimal
var decimal = parseInt ( number , 8 ) ;
// Ignore places and return a 10-character octal number if number is
// negative
if ( decimal >= 536870912 ) {
return "ff" + ( decimal + 3221225472 ) . toString ( 16 ) ;
}
// Convert decimal number to hexadecimal
var result = decimal . toString ( 16 ) ;
// Return hexadecimal number using the minimum number of characters
// necessary if places is undefined
if ( places === undefined ) {
return result ;
} else {
// Return error if places is nonnumeric
if ( isNaN ( places ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return error if places is negative
if ( places < 0 ) {
return error . num ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Truncate places in case it is not an integer
places = Math . floor ( places ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Pad return value with leading 0s (zeros) if necessary (using
// Underscore.string)
return places >= result . length
? REPT ( "0" , places - result . length ) + result
: error . num ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return exports ;
} ) ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
met . financial = ( function ( ) {
var exports = { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
function validDate ( d ) {
return d && d . getTime && ! isNaN ( d . getTime ( ) ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
function ensureDate ( d ) {
return d instanceof Date ? d : new Date ( d ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . ACCRINT = function (
issue ,
first ,
settlement ,
rate ,
par ,
frequency ,
basis
) {
// Return error if either date is invalid
issue = ensureDate ( issue ) ;
first = ensureDate ( first ) ;
settlement = ensureDate ( settlement ) ;
if ( ! validDate ( issue ) || ! validDate ( first ) || ! validDate ( settlement ) ) {
return "#VALUE!" ;
}
// Return error if either rate or par are lower than or equal to zero
if ( rate <= 0 || par <= 0 ) {
return "#NUM!" ;
}
// Return error if frequency is neither 1, 2, or 4
if ( [ 1 , 2 , 4 ] . indexOf ( frequency ) === - 1 ) {
return "#NUM!" ;
}
// Return error if basis is neither 0, 1, 2, 3, or 4
if ( [ 0 , 1 , 2 , 3 , 4 ] . indexOf ( basis ) === - 1 ) {
return "#NUM!" ;
}
// Return error if settlement is before or equal to issue
if ( settlement <= issue ) {
return "#NUM!" ;
}
// Set default values
par = par || 0 ;
basis = basis || 0 ;
// Compute accrued interest
return par * rate * YEARFRAC ( issue , settlement , basis ) ;
} ;
exports . ACCRINTM = null ;
exports . AMORDEGRC = null ;
exports . AMORLINC = null ;
exports . COUPDAYBS = null ;
exports . COUPDAYS = null ;
exports . COUPDAYSNC = null ;
exports . COUPNCD = null ;
exports . COUPNUM = null ;
exports . COUPPCD = null ;
exports . CUMIPMT = function ( rate , periods , value , start , end , type ) {
// Credits: algorithm inspired by Apache OpenOffice
// Credits: Hannes Stiebitzhofer for the translations of function and
// variable names
// Requires exports.FV() and exports.PMT() from exports.js
// [http://stoic.com/exports/]
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
value = utils . parseNumber ( value ) ;
if ( utils . anyIsError ( rate , periods , value ) ) {
return error . value ;
}
// Return error if either rate, periods, or value are lower than or
// equal to zero
if ( rate <= 0 || periods <= 0 || value <= 0 ) {
return error . num ;
}
// Return error if start < 1, end < 1, or start > end
if ( start < 1 || end < 1 || start > end ) {
return error . num ;
}
// Return error if type is neither 0 nor 1
if ( type !== 0 && type !== 1 ) {
return error . num ;
}
// Compute cumulative interest
var payment = exports . PMT ( rate , periods , value , 0 , type ) ;
var interest = 0 ;
if ( start === 1 ) {
if ( type === 0 ) {
interest = - value ;
start ++ ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = start ; i <= end ; i ++ ) {
if ( type === 1 ) {
interest += exports . FV ( rate , i - 2 , payment , value , 1 ) - payment ;
} else {
interest += exports . FV ( rate , i - 1 , payment , value , 0 ) ;
}
}
interest *= rate ;
// Return cumulative interest
return interest ;
} ;
exports . CUMPRINC = function ( rate , periods , value , start , end , type ) {
// Credits: algorithm inspired by Apache OpenOffice
// Credits: Hannes Stiebitzhofer for the translations of function and
// variable names
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
value = utils . parseNumber ( value ) ;
if ( utils . anyIsError ( rate , periods , value ) ) {
return error . value ;
}
// Return error if either rate, periods, or value are lower than or
// equal to zero
if ( rate <= 0 || periods <= 0 || value <= 0 ) {
return error . num ;
}
// Return error if start < 1, end < 1, or start > end
if ( start < 1 || end < 1 || start > end ) {
return error . num ;
}
// Return error if type is neither 0 nor 1
if ( type !== 0 && type !== 1 ) {
return error . num ;
}
// Compute cumulative principal
var payment = exports . PMT ( rate , periods , value , 0 , type ) ;
var principal = 0 ;
if ( start === 1 ) {
if ( type === 0 ) {
principal = payment + value * rate ;
} else {
principal = payment ;
}
start ++ ;
}
for ( var i = start ; i <= end ; i ++ ) {
if ( type > 0 ) {
principal +=
payment -
( exports . FV ( rate , i - 2 , payment , value , 1 ) - payment ) * rate ;
} else {
principal +=
payment - exports . FV ( rate , i - 1 , payment , value , 0 ) * rate ;
}
}
// Return cumulative principal
return principal ;
} ;
exports . DB = function ( cost , salvage , life , period , month ) {
// Initialize month
month = month === undefined ? 12 : month ;
cost = utils . parseNumber ( cost ) ;
salvage = utils . parseNumber ( salvage ) ;
life = utils . parseNumber ( life ) ;
period = utils . parseNumber ( period ) ;
month = utils . parseNumber ( month ) ;
if ( utils . anyIsError ( cost , salvage , life , period , month ) ) {
return error . value ;
}
// Return error if any of the parameters is negative
if ( cost < 0 || salvage < 0 || life < 0 || period < 0 ) {
return error . num ;
}
// Return error if month is not an integer between 1 and 12
if ( [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ] . indexOf ( month ) === - 1 ) {
return error . num ;
}
// Return error if period is greater than life
if ( period > life ) {
return error . num ;
}
// Return 0 (zero) if salvage is greater than or equal to cost
if ( salvage >= cost ) {
return 0 ;
}
// Rate is rounded to three decimals places
var rate = ( 1 - Math . pow ( salvage / cost , 1 / life ) ) . toFixed ( 3 ) ;
// Compute initial depreciation
var initial = ( cost * rate * month ) / 12 ;
// Compute total depreciation
var total = initial ;
var current = 0 ;
var ceiling = period === life ? life - 1 : period ;
for ( var i = 2 ; i <= ceiling ; i ++ ) {
current = ( cost - total ) * rate ;
total += current ;
}
// Depreciation for the first and last periods are special cases
if ( period === 1 ) {
// First period
return initial ;
} else if ( period === life ) {
// Last period
return ( cost - total ) * rate ;
} else {
return current ;
}
} ;
exports . DDB = function ( cost , salvage , life , period , factor ) {
// Initialize factor
factor = factor === undefined ? 2 : factor ;
cost = utils . parseNumber ( cost ) ;
salvage = utils . parseNumber ( salvage ) ;
life = utils . parseNumber ( life ) ;
period = utils . parseNumber ( period ) ;
factor = utils . parseNumber ( factor ) ;
if ( utils . anyIsError ( cost , salvage , life , period , factor ) ) {
return error . value ;
}
// Return error if any of the parameters is negative or if factor is
// null
if ( cost < 0 || salvage < 0 || life < 0 || period < 0 || factor <= 0 ) {
return error . num ;
}
// Return error if period is greater than life
if ( period > life ) {
return error . num ;
}
// Return 0 (zero) if salvage is greater than or equal to cost
if ( salvage >= cost ) {
return 0 ;
}
// Compute depreciation
var total = 0 ;
var current = 0 ;
for ( var i = 1 ; i <= period ; i ++ ) {
current = Math . min (
( cost - total ) * ( factor / life ) ,
cost - salvage - total
) ;
total += current ;
}
// Return depreciation
return current ;
} ;
exports . DISC = null ;
exports . DOLLARDE = function ( dollar , fraction ) {
// Credits: algorithm inspired by Apache OpenOffice
dollar = utils . parseNumber ( dollar ) ;
fraction = utils . parseNumber ( fraction ) ;
if ( utils . anyIsError ( dollar , fraction ) ) {
return error . value ;
}
// Return error if fraction is negative
if ( fraction < 0 ) {
return error . num ;
}
// Return error if fraction is greater than or equal to 0 and less than
// 1
if ( fraction >= 0 && fraction < 1 ) {
return error . div0 ;
}
// Truncate fraction if it is not an integer
fraction = parseInt ( fraction , 10 ) ;
// Compute integer part
var result = parseInt ( dollar , 10 ) ;
// Add decimal part
result +=
( ( dollar % 1 ) *
Math . pow ( 10 , Math . ceil ( Math . log ( fraction ) / Math . LN10 ) ) ) /
fraction ;
// Round result
var power = Math . pow ( 10 , Math . ceil ( Math . log ( fraction ) / Math . LN2 ) + 1 ) ;
result = Math . round ( result * power ) / power ;
// Return converted dollar price
return result ;
} ;
exports . DOLLARFR = function ( dollar , fraction ) {
// Credits: algorithm inspired by Apache OpenOffice
dollar = utils . parseNumber ( dollar ) ;
fraction = utils . parseNumber ( fraction ) ;
if ( utils . anyIsError ( dollar , fraction ) ) {
return error . value ;
}
// Return error if fraction is negative
if ( fraction < 0 ) {
return error . num ;
}
// Return error if fraction is greater than or equal to 0 and less than
// 1
if ( fraction >= 0 && fraction < 1 ) {
return error . div0 ;
}
// Truncate fraction if it is not an integer
fraction = parseInt ( fraction , 10 ) ;
// Compute integer part
var result = parseInt ( dollar , 10 ) ;
// Add decimal part
result +=
( dollar % 1 ) *
Math . pow ( 10 , - Math . ceil ( Math . log ( fraction ) / Math . LN10 ) ) *
fraction ;
// Return converted dollar price
return result ;
} ;
exports . DURATION = null ;
exports . EFFECT = function ( rate , periods ) {
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
if ( utils . anyIsError ( rate , periods ) ) {
return error . value ;
}
// Return error if rate <=0 or periods < 1
if ( rate <= 0 || periods < 1 ) {
return error . num ;
}
// Truncate periods if it is not an integer
periods = parseInt ( periods , 10 ) ;
// Return effective annual interest rate
return Math . pow ( 1 + rate / periods , periods ) - 1 ;
} ;
exports . FV = function ( rate , periods , payment , value , type ) {
// Credits: algorithm inspired by Apache OpenOffice
value = value || 0 ;
type = type || 0 ;
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
payment = utils . parseNumber ( payment ) ;
value = utils . parseNumber ( value ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , periods , payment , value , type ) ) {
return error . value ;
}
// Return future value
var result ;
if ( rate === 0 ) {
result = value + payment * periods ;
} else {
var term = Math . pow ( 1 + rate , periods ) ;
if ( type === 1 ) {
result = value * term + ( payment * ( 1 + rate ) * ( term - 1 ) ) / rate ;
} else {
result = value * term + ( payment * ( term - 1 ) ) / rate ;
}
}
return - result ;
} ;
exports . FVSCHEDULE = function ( principal , schedule ) {
principal = utils . parseNumber ( principal ) ;
schedule = utils . parseNumberArray ( utils . flatten ( schedule ) ) ;
if ( utils . anyIsError ( principal , schedule ) ) {
return error . value ;
}
var n = schedule . length ;
var future = principal ;
// Apply all interests in schedule
for ( var i = 0 ; i < n ; i ++ ) {
// Apply scheduled interest
future *= 1 + schedule [ i ] ;
}
// Return future value
return future ;
} ;
exports . INTRATE = null ;
exports . IPMT = function ( rate , period , periods , present , future , type ) {
// Credits: algorithm inspired by Apache OpenOffice
future = future || 0 ;
type = type || 0 ;
rate = utils . parseNumber ( rate ) ;
period = utils . parseNumber ( period ) ;
periods = utils . parseNumber ( periods ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , period , periods , present , future , type ) ) {
return error . value ;
}
// Compute payment
var payment = exports . PMT ( rate , periods , present , future , type ) ;
// Compute interest
var interest ;
if ( period === 1 ) {
if ( type === 1 ) {
interest = 0 ;
} else {
interest = - present ;
}
} else {
if ( type === 1 ) {
interest =
exports . FV ( rate , period - 2 , payment , present , 1 ) - payment ;
} else {
interest = exports . FV ( rate , period - 1 , payment , present , 0 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Return interest
return interest * rate ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . IRR = function ( values , guess ) {
// Credits: algorithm inspired by Apache OpenOffice
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
guess = guess || 0 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
values = utils . parseNumberArray ( utils . flatten ( values ) ) ;
guess = utils . parseNumber ( guess ) ;
if ( utils . anyIsError ( values , guess ) ) {
return error . value ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Calculates the resulting amount
var irrResult = function ( values , dates , rate ) {
var r = rate + 1 ;
var result = values [ 0 ] ;
for ( var i = 1 ; i < values . length ; i ++ ) {
result += values [ i ] / Math . pow ( r , ( dates [ i ] - dates [ 0 ] ) / 365 ) ;
}
return result ;
} ;
// Calculates the first derivation
var irrResultDeriv = function ( values , dates , rate ) {
var r = rate + 1 ;
var result = 0 ;
for ( var i = 1 ; i < values . length ; i ++ ) {
var frac = ( dates [ i ] - dates [ 0 ] ) / 365 ;
result -= ( frac * values [ i ] ) / Math . pow ( r , frac + 1 ) ;
}
return result ;
} ;
// Initialize dates and check that values contains at least one positive
// value and one negative value
var dates = [ ] ;
var positive = false ;
var negative = false ;
for ( var i = 0 ; i < values . length ; i ++ ) {
dates [ i ] = i === 0 ? 0 : dates [ i - 1 ] + 365 ;
if ( values [ i ] > 0 ) {
positive = true ;
}
if ( values [ i ] < 0 ) {
negative = true ;
}
}
// Return error if values does not contain at least one positive value
// and one negative value
if ( ! positive || ! negative ) {
return error . num ;
}
// Initialize guess and resultRate
guess = guess === undefined ? 0.1 : guess ;
var resultRate = guess ;
// Set maximum epsilon for end of iteration
var epsMax = 1e-10 ;
// Implement Newton's method
var newRate , epsRate , resultValue ;
var contLoop = true ;
do {
resultValue = irrResult ( values , dates , resultRate ) ;
newRate =
resultRate - resultValue / irrResultDeriv ( values , dates , resultRate ) ;
epsRate = Math . abs ( newRate - resultRate ) ;
resultRate = newRate ;
contLoop = epsRate > epsMax && Math . abs ( resultValue ) > epsMax ;
} while ( contLoop ) ;
// Return internal rate of return
return resultRate ;
} ;
exports . ISPMT = function ( rate , period , periods , value ) {
rate = utils . parseNumber ( rate ) ;
period = utils . parseNumber ( period ) ;
periods = utils . parseNumber ( periods ) ;
value = utils . parseNumber ( value ) ;
if ( utils . anyIsError ( rate , period , periods , value ) ) {
return error . value ;
}
// Return interest
return value * rate * ( period / periods - 1 ) ;
} ;
exports . MDURATION = null ;
exports . MIRR = function ( values , finance _rate , reinvest _rate ) {
values = utils . parseNumberArray ( utils . flatten ( values ) ) ;
finance _rate = utils . parseNumber ( finance _rate ) ;
reinvest _rate = utils . parseNumber ( reinvest _rate ) ;
if ( utils . anyIsError ( values , finance _rate , reinvest _rate ) ) {
return error . value ;
}
// Initialize number of values
var n = values . length ;
// Lookup payments (negative values) and incomes (positive values)
var payments = [ ] ;
var incomes = [ ] ;
for ( var i = 0 ; i < n ; i ++ ) {
if ( values [ i ] < 0 ) {
payments . push ( values [ i ] ) ;
} else {
incomes . push ( values [ i ] ) ;
}
}
// Return modified internal rate of return
var num =
- exports . NPV ( reinvest _rate , incomes ) *
Math . pow ( 1 + reinvest _rate , n - 1 ) ;
var den = exports . NPV ( finance _rate , payments ) * ( 1 + finance _rate ) ;
return Math . pow ( num / den , 1 / ( n - 1 ) ) - 1 ;
} ;
exports . NOMINAL = function ( rate , periods ) {
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
if ( utils . anyIsError ( rate , periods ) ) {
return error . value ;
}
// Return error if rate <=0 or periods < 1
if ( rate <= 0 || periods < 1 ) {
return error . num ;
}
// Truncate periods if it is not an integer
periods = parseInt ( periods , 10 ) ;
// Return nominal annual interest rate
return ( Math . pow ( rate + 1 , 1 / periods ) - 1 ) * periods ;
} ;
exports . NPER = function ( rate , payment , present , future , type ) {
type = type === undefined ? 0 : type ;
future = future === undefined ? 0 : future ;
rate = utils . parseNumber ( rate ) ;
payment = utils . parseNumber ( payment ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , payment , present , future , type ) ) {
return error . value ;
}
// Return number of periods
var num = payment * ( 1 + rate * type ) - future * rate ;
var den = present * rate + payment * ( 1 + rate * type ) ;
return Math . log ( num / den ) / Math . log ( 1 + rate ) ;
} ;
exports . NPV = function ( ) {
var args = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( args instanceof Error ) {
return args ;
}
// Lookup rate
var rate = args [ 0 ] ;
// Initialize net present value
var value = 0 ;
// Loop on all values
for ( var j = 1 ; j < args . length ; j ++ ) {
value += args [ j ] / Math . pow ( 1 + rate , j ) ;
}
// Return net present value
return value ;
} ;
exports . ODDFPRICE = null ;
exports . ODDFYIELD = null ;
exports . ODDLPRICE = null ;
exports . ODDLYIELD = null ;
exports . PDURATION = function ( rate , present , future ) {
rate = utils . parseNumber ( rate ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
if ( utils . anyIsError ( rate , present , future ) ) {
return error . value ;
}
// Return error if rate <=0
if ( rate <= 0 ) {
return error . num ;
}
// Return number of periods
return ( Math . log ( future ) - Math . log ( present ) ) / Math . log ( 1 + rate ) ;
} ;
exports . PMT = function ( rate , periods , present , future , type ) {
// Credits: algorithm inspired by Apache OpenOffice
future = future || 0 ;
type = type || 0 ;
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , periods , present , future , type ) ) {
return error . value ;
}
// Return payment
var result ;
if ( rate === 0 ) {
result = ( present + future ) / periods ;
} else {
var term = Math . pow ( 1 + rate , periods ) ;
if ( type === 1 ) {
result =
( ( future * rate ) / ( term - 1 ) + ( present * rate ) / ( 1 - 1 / term ) ) /
( 1 + rate ) ;
} else {
result =
( future * rate ) / ( term - 1 ) + ( present * rate ) / ( 1 - 1 / term ) ;
}
}
return - result ;
} ;
exports . PPMT = function ( rate , period , periods , present , future , type ) {
future = future || 0 ;
type = type || 0 ;
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , periods , present , future , type ) ) {
return error . value ;
}
return (
exports . PMT ( rate , periods , present , future , type ) -
exports . IPMT ( rate , period , periods , present , future , type )
) ;
} ;
exports . PRICE = null ;
exports . PRICEDISC = null ;
exports . PRICEMAT = null ;
exports . PV = function ( rate , periods , payment , future , type ) {
future = future || 0 ;
type = type || 0 ;
rate = utils . parseNumber ( rate ) ;
periods = utils . parseNumber ( periods ) ;
payment = utils . parseNumber ( payment ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
if ( utils . anyIsError ( rate , periods , payment , future , type ) ) {
return error . value ;
}
// Return present value
if ( rate === 0 ) {
return - payment * periods - future ;
} else {
return (
( ( ( 1 - Math . pow ( 1 + rate , periods ) ) / rate ) *
payment *
( 1 + rate * type ) -
future ) /
Math . pow ( 1 + rate , periods )
) ;
}
} ;
exports . RATE = function ( periods , payment , present , future , type , guess ) {
// Credits: rabugento
guess = guess === undefined ? 0.01 : guess ;
future = future === undefined ? 0 : future ;
type = type === undefined ? 0 : type ;
periods = utils . parseNumber ( periods ) ;
payment = utils . parseNumber ( payment ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
type = utils . parseNumber ( type ) ;
guess = utils . parseNumber ( guess ) ;
if ( utils . anyIsError ( periods , payment , present , future , type , guess ) ) {
return error . value ;
}
// Set maximum epsilon for end of iteration
var epsMax = 1e-6 ;
// Set maximum number of iterations
var iterMax = 100 ;
var iter = 0 ;
var close = false ;
var rate = guess ;
while ( iter < iterMax && ! close ) {
var t1 = Math . pow ( rate + 1 , periods ) ;
var t2 = Math . pow ( rate + 1 , periods - 1 ) ;
var f1 =
future +
t1 * present +
( payment * ( t1 - 1 ) * ( rate * type + 1 ) ) / rate ;
var f2 =
periods * t2 * present -
( payment * ( t1 - 1 ) * ( rate * type + 1 ) ) / Math . pow ( rate , 2 ) ;
var f3 =
( periods * payment * t2 * ( rate * type + 1 ) ) / rate +
( payment * ( t1 - 1 ) * type ) / rate ;
var newRate = rate - f1 / ( f2 + f3 ) ;
if ( Math . abs ( newRate - rate ) < epsMax ) close = true ;
iter ++ ;
rate = newRate ;
}
if ( ! close ) return Number . NaN + rate ;
return rate ;
} ;
// TODO
exports . RECEIVED = null ;
exports . RRI = function ( periods , present , future ) {
periods = utils . parseNumber ( periods ) ;
present = utils . parseNumber ( present ) ;
future = utils . parseNumber ( future ) ;
if ( utils . anyIsError ( periods , present , future ) ) {
return error . value ;
}
// Return error if periods or present is equal to 0 (zero)
if ( periods === 0 || present === 0 ) {
return error . num ;
}
// Return equivalent interest rate
return Math . pow ( future / present , 1 / periods ) - 1 ;
} ;
exports . SLN = function ( cost , salvage , life ) {
cost = utils . parseNumber ( cost ) ;
salvage = utils . parseNumber ( salvage ) ;
life = utils . parseNumber ( life ) ;
if ( utils . anyIsError ( cost , salvage , life ) ) {
return error . value ;
}
// Return error if life equal to 0 (zero)
if ( life === 0 ) {
return error . num ;
}
// Return straight-line depreciation
return ( cost - salvage ) / life ;
} ;
exports . SYD = function ( cost , salvage , life , period ) {
// Return error if any of the parameters is not a number
cost = utils . parseNumber ( cost ) ;
salvage = utils . parseNumber ( salvage ) ;
life = utils . parseNumber ( life ) ;
period = utils . parseNumber ( period ) ;
if ( utils . anyIsError ( cost , salvage , life , period ) ) {
return error . value ;
}
// Return error if life equal to 0 (zero)
if ( life === 0 ) {
return error . num ;
}
// Return error if period is lower than 1 or greater than life
if ( period < 1 || period > life ) {
return error . num ;
}
// Truncate period if it is not an integer
period = parseInt ( period , 10 ) ;
// Return straight-line depreciation
return ( ( cost - salvage ) * ( life - period + 1 ) * 2 ) / ( life * ( life + 1 ) ) ;
} ;
exports . TBILLEQ = function ( settlement , maturity , discount ) {
settlement = utils . parseDate ( settlement ) ;
maturity = utils . parseDate ( maturity ) ;
discount = utils . parseNumber ( discount ) ;
if ( utils . anyIsError ( settlement , maturity , discount ) ) {
return error . value ;
}
// Return error if discount is lower than or equal to zero
if ( discount <= 0 ) {
return error . num ;
}
// Return error if settlement is greater than maturity
if ( settlement > maturity ) {
return error . num ;
}
// Return error if maturity is more than one year after settlement
if ( maturity - settlement > 365 * 24 * 60 * 60 * 1000 ) {
return error . num ;
}
// Return bond-equivalent yield
return (
( 365 * discount ) /
( 360 - discount * DAYS360 ( settlement , maturity , false ) )
) ;
} ;
exports . TBILLPRICE = function ( settlement , maturity , discount ) {
settlement = utils . parseDate ( settlement ) ;
maturity = utils . parseDate ( maturity ) ;
discount = utils . parseNumber ( discount ) ;
if ( utils . anyIsError ( settlement , maturity , discount ) ) {
return error . value ;
}
// Return error if discount is lower than or equal to zero
if ( discount <= 0 ) {
return error . num ;
}
// Return error if settlement is greater than maturity
if ( settlement > maturity ) {
return error . num ;
}
// Return error if maturity is more than one year after settlement
if ( maturity - settlement > 365 * 24 * 60 * 60 * 1000 ) {
return error . num ;
}
// Return bond-equivalent yield
return (
100 * ( 1 - ( discount * DAYS360 ( settlement , maturity , false ) ) / 360 )
) ;
} ;
exports . TBILLYIELD = function ( settlement , maturity , price ) {
settlement = utils . parseDate ( settlement ) ;
maturity = utils . parseDate ( maturity ) ;
price = utils . parseNumber ( price ) ;
if ( utils . anyIsError ( settlement , maturity , price ) ) {
return error . value ;
}
// Return error if price is lower than or equal to zero
if ( price <= 0 ) {
return error . num ;
}
// Return error if settlement is greater than maturity
if ( settlement > maturity ) {
return error . num ;
}
// Return error if maturity is more than one year after settlement
if ( maturity - settlement > 365 * 24 * 60 * 60 * 1000 ) {
return error . num ;
}
// Return bond-equivalent yield
return (
( ( 100 - price ) * 360 ) / ( price * DAYS360 ( settlement , maturity , false ) )
) ;
} ;
exports . VDB = null ;
exports . XIRR = function ( values , dates , guess ) {
// Credits: algorithm inspired by Apache OpenOffice
values = utils . parseNumberArray ( utils . flatten ( values ) ) ;
dates = utils . parseDateArray ( utils . flatten ( dates ) ) ;
guess = utils . parseNumber ( guess ) ;
if ( utils . anyIsError ( values , dates , guess ) ) {
return error . value ;
}
// Calculates the resulting amount
var irrResult = function ( values , dates , rate ) {
var r = rate + 1 ;
var result = values [ 0 ] ;
for ( var i = 1 ; i < values . length ; i ++ ) {
result += values [ i ] / Math . pow ( r , DAYS ( dates [ i ] , dates [ 0 ] ) / 365 ) ;
}
return result ;
} ;
// Calculates the first derivation
var irrResultDeriv = function ( values , dates , rate ) {
var r = rate + 1 ;
var result = 0 ;
for ( var i = 1 ; i < values . length ; i ++ ) {
var frac = DAYS ( dates [ i ] , dates [ 0 ] ) / 365 ;
result -= ( frac * values [ i ] ) / Math . pow ( r , frac + 1 ) ;
}
return result ;
} ;
// Check that values contains at least one positive value and one
// negative value
var positive = false ;
var negative = false ;
for ( var i = 0 ; i < values . length ; i ++ ) {
if ( values [ i ] > 0 ) {
positive = true ;
}
if ( values [ i ] < 0 ) {
negative = true ;
}
}
// Return error if values does not contain at least one positive value
// and one negative value
if ( ! positive || ! negative ) {
return error . num ;
}
// Initialize guess and resultRate
guess = guess || 0.1 ;
var resultRate = guess ;
// Set maximum epsilon for end of iteration
var epsMax = 1e-10 ;
// Implement Newton's method
var newRate , epsRate , resultValue ;
var contLoop = true ;
do {
resultValue = irrResult ( values , dates , resultRate ) ;
newRate =
resultRate - resultValue / irrResultDeriv ( values , dates , resultRate ) ;
epsRate = Math . abs ( newRate - resultRate ) ;
resultRate = newRate ;
contLoop = epsRate > epsMax && Math . abs ( resultValue ) > epsMax ;
} while ( contLoop ) ;
// Return internal rate of return
return resultRate ;
} ;
exports . XNPV = function ( rate , values , dates ) {
rate = utils . parseNumber ( rate ) ;
values = utils . parseNumberArray ( utils . flatten ( values ) ) ;
dates = utils . parseDateArray ( utils . flatten ( dates ) ) ;
if ( utils . anyIsError ( rate , values , dates ) ) {
return error . value ;
}
var result = 0 ;
for ( var i = 0 ; i < values . length ; i ++ ) {
result +=
values [ i ] / Math . pow ( 1 + rate , DAYS ( dates [ i ] , dates [ 0 ] ) / 365 ) ;
}
return result ;
} ;
exports . YIELD = null ;
exports . YIELDDISC = null ;
exports . YIELDMAT = null ;
return exports ;
} ) ( ) ;
met . information = ( function ( ) {
var exports = { } ;
exports . CELL = null ;
exports . ERROR = { } ;
exports . ERROR . TYPE = function ( error _val ) {
switch ( error _val ) {
case error . nil :
return 1 ;
case error . div0 :
return 2 ;
case error . value :
return 3 ;
case error . ref :
return 4 ;
case error . name :
return 5 ;
case error . num :
return 6 ;
case error . na :
return 7 ;
case error . data :
return 8 ;
}
return error . na ;
} ;
exports . INFO = null ;
exports . ISBLANK = function ( value ) {
return value === null ;
} ;
exports . ISBINARY = function ( number ) {
return /^[01]{1,10}$/ . test ( number ) ;
} ;
exports . ISERR = function ( value ) {
return (
[
error . value ,
error . ref ,
error . div0 ,
error . num ,
error . name ,
error . nil ,
] . indexOf ( value ) >= 0 ||
( typeof value === "number" && ( isNaN ( value ) || ! isFinite ( value ) ) )
) ;
} ;
exports . ISERROR = function ( value ) {
return exports . ISERR ( value ) || value === error . na ;
} ;
exports . ISEVEN = function ( number ) {
return Math . floor ( Math . abs ( number ) ) & 1 ? false : true ;
} ;
// TODO
exports . ISFORMULA = null ;
exports . ISLOGICAL = function ( value ) {
return value === true || value === false ;
} ;
exports . ISNA = function ( value ) {
return value === error . na ;
} ;
exports . ISNONTEXT = function ( value ) {
return typeof value !== "string" ;
} ;
exports . ISNUMBER = function ( value ) {
return typeof value === "number" && ! isNaN ( value ) && isFinite ( value ) ;
} ;
exports . ISODD = function ( number ) {
return Math . floor ( Math . abs ( number ) ) & 1 ? true : false ;
} ;
exports . ISREF = null ;
exports . ISTEXT = function ( value ) {
return typeof value === "string" ;
} ;
exports . N = function ( value ) {
if ( this . ISNUMBER ( value ) ) {
return value ;
}
if ( value instanceof Date ) {
return value . getTime ( ) ;
}
if ( value === true ) {
return 1 ;
}
if ( value === false ) {
return 0 ;
}
if ( this . ISERROR ( value ) ) {
return value ;
}
return 0 ;
} ;
exports . NA = function ( ) {
return error . na ;
} ;
exports . SHEET = null ;
exports . SHEETS = null ;
exports . TYPE = function ( value ) {
if ( this . ISNUMBER ( value ) ) {
return 1 ;
}
if ( this . ISTEXT ( value ) ) {
return 2 ;
}
if ( this . ISLOGICAL ( value ) ) {
return 4 ;
}
if ( this . ISERROR ( value ) ) {
return 16 ;
}
if ( Array . isArray ( value ) ) {
return 64 ;
}
} ;
return exports ;
} ) ( ) ;
met . logical = ( function ( ) {
var exports = { } ;
exports . AND = function ( ) {
var args = utils . flatten ( arguments ) ;
var result = true ;
for ( var i = 0 ; i < args . length ; i ++ ) {
if ( ! args [ i ] ) {
result = false ;
}
}
return result ;
} ;
exports . CHOOSE = function ( ) {
if ( arguments . length < 2 ) {
return error . na ;
}
var index = arguments [ 0 ] ;
if ( index < 1 || index > 254 ) {
return error . value ;
}
if ( arguments . length < index + 1 ) {
return error . value ;
}
return arguments [ index ] ;
} ;
exports . FALSE = function ( ) {
return false ;
} ;
exports . IF = function ( test , then _value , otherwise _value ) {
return test ? then _value : otherwise _value ;
} ;
exports . IFERROR = function ( value , valueIfError ) {
if ( ISERROR ( value ) ) {
return valueIfError ;
}
return value ;
} ;
exports . IFNA = function ( value , value _if _na ) {
return value === error . na ? value _if _na : value ;
} ;
exports . NOT = function ( logical ) {
return ! logical ;
} ;
exports . OR = function ( ) {
var args = utils . flatten ( arguments ) ;
var result = false ;
for ( var i = 0 ; i < args . length ; i ++ ) {
if ( args [ i ] ) {
result = true ;
}
}
return result ;
} ;
exports . TRUE = function ( ) {
return true ;
} ;
exports . XOR = function ( ) {
var args = utils . flatten ( arguments ) ;
var result = 0 ;
for ( var i = 0 ; i < args . length ; i ++ ) {
if ( args [ i ] ) {
result ++ ;
}
}
return Math . floor ( Math . abs ( result ) ) & 1 ? true : false ;
} ;
exports . SWITCH = function ( ) {
var result ;
if ( arguments . length > 0 ) {
var targetValue = arguments [ 0 ] ;
var argc = arguments . length - 1 ;
var switchCount = Math . floor ( argc / 2 ) ;
var switchSatisfied = false ;
var defaultClause =
argc % 2 === 0 ? null : arguments [ arguments . length - 1 ] ;
if ( switchCount ) {
for ( var index = 0 ; index < switchCount ; index ++ ) {
if ( targetValue === arguments [ index * 2 + 1 ] ) {
result = arguments [ index * 2 + 2 ] ;
switchSatisfied = true ;
break ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! switchSatisfied && defaultClause ) {
result = defaultClause ;
}
}
return result ;
} ;
return exports ;
} ) ( ) ;
met . math = ( function ( ) {
var exports = { } ;
exports . ABS = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . abs ( utils . parseNumber ( number ) ) ;
} ;
exports . ACOS = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . acos ( number ) ;
} ;
exports . ACOSH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . log ( number + Math . sqrt ( number * number - 1 ) ) ;
} ;
exports . ACOT = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . atan ( 1 / number ) ;
} ;
exports . ACOTH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 0.5 * Math . log ( ( number + 1 ) / ( number - 1 ) ) ;
} ;
exports . AGGREGATE = null ;
exports . ARABIC = function ( text ) {
// Credits: Rafa? Kukawski
if (
! /^M*(?:D?C{0,3}|C[MD])(?:L?X{0,3}|X[CL])(?:V?I{0,3}|I[XV])$/ . test ( text )
) {
return error . value ;
}
var r = 0 ;
text . replace ( /[MDLV]|C[MD]?|X[CL]?|I[XV]?/g , function ( i ) {
r += {
M : 1000 ,
CM : 900 ,
D : 500 ,
CD : 400 ,
C : 100 ,
XC : 90 ,
L : 50 ,
XL : 40 ,
X : 10 ,
IX : 9 ,
V : 5 ,
IV : 4 ,
I : 1 ,
} [ i ] ;
} ) ;
return r ;
} ;
exports . ASIN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . asin ( number ) ;
} ;
exports . ASINH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . log ( number + Math . sqrt ( number * number + 1 ) ) ;
} ;
exports . ATAN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . atan ( number ) ;
} ;
exports . ATAN2 = function ( number _x , number _y ) {
number _x = utils . parseNumber ( number _x ) ;
number _y = utils . parseNumber ( number _y ) ;
if ( utils . anyIsError ( number _x , number _y ) ) {
return error . value ;
}
return Math . atan2 ( number _x , number _y ) ;
} ;
exports . ATANH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . log ( ( 1 + number ) / ( 1 - number ) ) / 2 ;
} ;
exports . BASE = function ( number , radix , min _length ) {
min _length = min _length || 0 ;
number = utils . parseNumber ( number ) ;
radix = utils . parseNumber ( radix ) ;
min _length = utils . parseNumber ( min _length ) ;
if ( utils . anyIsError ( number , radix , min _length ) ) {
return error . value ;
}
min _length = min _length === undefined ? 0 : min _length ;
var result = number . toString ( radix ) ;
return (
new Array ( Math . max ( min _length + 1 - result . length , 0 ) ) . join ( "0" ) +
result
) ;
} ;
exports . CEILING = function ( number , significance , mode ) {
significance = significance === undefined ? 1 : significance ;
mode = mode === undefined ? 0 : mode ;
number = utils . parseNumber ( number ) ;
significance = utils . parseNumber ( significance ) ;
mode = utils . parseNumber ( mode ) ;
if ( utils . anyIsError ( number , significance , mode ) ) {
return error . value ;
}
if ( significance === 0 ) {
return 0 ;
}
significance = Math . abs ( significance ) ;
if ( number >= 0 ) {
return Math . ceil ( number / significance ) * significance ;
} else {
if ( mode === 0 ) {
return (
- 1 * Math . floor ( Math . abs ( number ) / significance ) * significance
) ;
} else {
return - 1 * Math . ceil ( Math . abs ( number ) / significance ) * significance ;
}
}
} ;
exports . CEILING . MATH = exports . CEILING ;
exports . CEILING . PRECISE = exports . CEILING ;
exports . COMBIN = function ( number , number _chosen ) {
number = utils . parseNumber ( number ) ;
number _chosen = utils . parseNumber ( number _chosen ) ;
if ( utils . anyIsError ( number , number _chosen ) ) {
return error . value ;
}
return (
exports . FACT ( number ) /
( exports . FACT ( number _chosen ) * exports . FACT ( number - number _chosen ) )
) ;
} ;
exports . COMBINA = function ( number , number _chosen ) {
number = utils . parseNumber ( number ) ;
number _chosen = utils . parseNumber ( number _chosen ) ;
if ( utils . anyIsError ( number , number _chosen ) ) {
return error . value ;
}
return number === 0 && number _chosen === 0
? 1
: exports . COMBIN ( number + number _chosen - 1 , number - 1 ) ;
} ;
exports . COS = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . cos ( number ) ;
} ;
exports . COSH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return ( Math . exp ( number ) + Math . exp ( - number ) ) / 2 ;
} ;
exports . COT = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 1 / Math . tan ( number ) ;
} ;
exports . COTH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
var e2 = Math . exp ( 2 * number ) ;
return ( e2 + 1 ) / ( e2 - 1 ) ;
} ;
exports . CSC = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 1 / Math . sin ( number ) ;
} ;
exports . CSCH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 2 / ( Math . exp ( number ) - Math . exp ( - number ) ) ;
} ;
exports . DECIMAL = function ( number , radix ) {
if ( arguments . length < 1 ) {
return error . value ;
}
return parseInt ( number , radix ) ;
} ;
exports . DEGREES = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return ( number * 180 ) / Math . PI ;
} ;
exports . EVEN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return exports . CEILING ( number , - 2 , - 1 ) ;
} ;
exports . EXP = Math . exp ;
var MEMOIZED _FACT = [ ] ;
exports . FACT = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
var n = Math . floor ( number ) ;
if ( n === 0 || n === 1 ) {
return 1 ;
} else if ( MEMOIZED _FACT [ n ] > 0 ) {
return MEMOIZED _FACT [ n ] ;
} else {
MEMOIZED _FACT [ n ] = exports . FACT ( n - 1 ) * n ;
return MEMOIZED _FACT [ n ] ;
}
} ;
exports . FACTDOUBLE = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
var n = Math . floor ( number ) ;
if ( n <= 0 ) {
return 1 ;
} else {
return n * exports . FACTDOUBLE ( n - 2 ) ;
}
} ;
exports . FLOOR = function ( number , significance , mode ) {
significance = significance === undefined ? 1 : significance ;
mode = mode === undefined ? 0 : mode ;
number = utils . parseNumber ( number ) ;
significance = utils . parseNumber ( significance ) ;
mode = utils . parseNumber ( mode ) ;
if ( utils . anyIsError ( number , significance , mode ) ) {
return error . value ;
}
if ( significance === 0 ) {
return 0 ;
}
significance = Math . abs ( significance ) ;
if ( number >= 0 ) {
return Math . floor ( number / significance ) * significance ;
} else {
if ( mode === 0 ) {
return - 1 * Math . ceil ( Math . abs ( number ) / significance ) * significance ;
} else {
return (
- 1 * Math . floor ( Math . abs ( number ) / significance ) * significance
) ;
}
}
} ;
exports . FLOOR . MATH = exports . FLOOR ;
exports . GCD = null ;
exports . INT = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . floor ( number ) ;
} ;
exports . LCM = function ( ) {
// Credits: Jonas Raoni Soares Silva
var o = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( o instanceof Error ) {
return o ;
}
for ( var i , j , n , d , r = 1 ; ( n = o . pop ( ) ) !== undefined ; ) {
while ( n > 1 ) {
if ( n % 2 ) {
for ( i = 3 , j = Math . floor ( Math . sqrt ( n ) ) ; i <= j && n % i ; i += 2 ) {
// empty
}
d = i <= j ? i : n ;
} else {
d = 2 ;
}
for (
n /= d , r *= d , i = o . length ;
i ;
o [ -- i ] % d === 0 && ( o [ i ] /= d ) === 1 && o . splice ( i , 1 )
) {
// empty
}
}
}
return r ;
} ;
exports . LN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . log ( number ) ;
} ;
exports . LOG = function ( number , base ) {
number = utils . parseNumber ( number ) ;
base = base === undefined ? 10 : utils . parseNumber ( base ) ;
if ( utils . anyIsError ( number , base ) ) {
return error . value ;
}
return Math . log ( number ) / Math . log ( base ) ;
} ;
exports . LOG10 = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . log ( number ) / Math . log ( 10 ) ;
} ;
exports . MDETERM = null ;
exports . MINVERSE = null ;
exports . MMULT = null ;
exports . MOD = function ( dividend , divisor ) {
dividend = utils . parseNumber ( dividend ) ;
divisor = utils . parseNumber ( divisor ) ;
if ( utils . anyIsError ( dividend , divisor ) ) {
return error . value ;
}
if ( divisor === 0 ) {
return error . div0 ;
}
var modulus = Math . abs ( dividend % divisor ) ;
return divisor > 0 ? modulus : - modulus ;
} ;
exports . MROUND = function ( number , multiple ) {
number = utils . parseNumber ( number ) ;
multiple = utils . parseNumber ( multiple ) ;
if ( utils . anyIsError ( number , multiple ) ) {
return error . value ;
}
if ( number * multiple < 0 ) {
return error . num ;
}
return Math . round ( number / multiple ) * multiple ;
} ;
exports . MULTINOMIAL = function ( ) {
var args = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( args instanceof Error ) {
return args ;
}
var sum = 0 ;
var divisor = 1 ;
for ( var i = 0 ; i < args . length ; i ++ ) {
sum += args [ i ] ;
divisor *= exports . FACT ( args [ i ] ) ;
}
return exports . FACT ( sum ) / divisor ;
} ;
exports . MUNIT = null ;
exports . ODD = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
var temp = Math . ceil ( Math . abs ( number ) ) ;
temp = temp & 1 ? temp : temp + 1 ;
return number > 0 ? temp : - temp ;
} ;
exports . PI = function ( ) {
return Math . PI ;
} ;
exports . POWER = function ( number , power ) {
number = utils . parseNumber ( number ) ;
power = utils . parseNumber ( power ) ;
if ( utils . anyIsError ( number , power ) ) {
return error . value ;
}
var result = Math . pow ( number , power ) ;
if ( isNaN ( result ) ) {
return error . num ;
}
return result ;
} ;
exports . PRODUCT = function ( ) {
var args = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( args instanceof Error ) {
return args ;
}
var result = 1 ;
for ( var i = 0 ; i < args . length ; i ++ ) {
result *= args [ i ] ;
}
return result ;
} ;
exports . QUOTIENT = function ( numerator , denominator ) {
numerator = utils . parseNumber ( numerator ) ;
denominator = utils . parseNumber ( denominator ) ;
if ( utils . anyIsError ( numerator , denominator ) ) {
return error . value ;
}
return parseInt ( numerator / denominator , 10 ) ;
} ;
exports . RADIANS = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return ( number * Math . PI ) / 180 ;
} ;
exports . RAND = function ( ) {
return Math . random ( ) ;
} ;
exports . RANDBETWEEN = function ( bottom , top ) {
bottom = utils . parseNumber ( bottom ) ;
top = utils . parseNumber ( top ) ;
if ( utils . anyIsError ( bottom , top ) ) {
return error . value ;
}
// Creative Commons Attribution 3.0 License
// Copyright (c) 2012 eqcode
return bottom + Math . ceil ( ( top - bottom + 1 ) * Math . random ( ) ) - 1 ;
} ;
exports . ROMAN = null ;
exports . ROUND = function ( number , digits ) {
number = utils . parseNumber ( number ) ;
digits = utils . parseNumber ( digits ) ;
if ( utils . anyIsError ( number , digits ) ) {
return error . value ;
}
return Math . round ( number * Math . pow ( 10 , digits ) ) / Math . pow ( 10 , digits ) ;
} ;
exports . ROUNDDOWN = function ( number , digits ) {
number = utils . parseNumber ( number ) ;
digits = utils . parseNumber ( digits ) ;
if ( utils . anyIsError ( number , digits ) ) {
return error . value ;
}
var sign = number > 0 ? 1 : - 1 ;
return (
( sign * Math . floor ( Math . abs ( number ) * Math . pow ( 10 , digits ) ) ) /
Math . pow ( 10 , digits )
) ;
} ;
exports . ROUNDUP = function ( number , digits ) {
number = utils . parseNumber ( number ) ;
digits = utils . parseNumber ( digits ) ;
if ( utils . anyIsError ( number , digits ) ) {
return error . value ;
}
var sign = number > 0 ? 1 : - 1 ;
return (
( sign * Math . ceil ( Math . abs ( number ) * Math . pow ( 10 , digits ) ) ) /
Math . pow ( 10 , digits )
) ;
} ;
exports . SEC = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 1 / Math . cos ( number ) ;
} ;
exports . SECH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return 2 / ( Math . exp ( number ) + Math . exp ( - number ) ) ;
} ;
exports . SERIESSUM = function ( x , n , m , coefficients ) {
x = utils . parseNumber ( x ) ;
n = utils . parseNumber ( n ) ;
m = utils . parseNumber ( m ) ;
coefficients = utils . parseNumberArray ( coefficients ) ;
if ( utils . anyIsError ( x , n , m , coefficients ) ) {
return error . value ;
}
var result = coefficients [ 0 ] * Math . pow ( x , n ) ;
for ( var i = 1 ; i < coefficients . length ; i ++ ) {
result += coefficients [ i ] * Math . pow ( x , n + i * m ) ;
}
return result ;
} ;
exports . SIGN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
if ( number < 0 ) {
return - 1 ;
} else if ( number === 0 ) {
return 0 ;
} else {
return 1 ;
}
} ;
exports . SIN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . sin ( number ) ;
} ;
exports . SINH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return ( Math . exp ( number ) - Math . exp ( - number ) ) / 2 ;
} ;
exports . SQRT = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
if ( number < 0 ) {
return error . num ;
}
return Math . sqrt ( number ) ;
} ;
exports . SQRTPI = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . sqrt ( number * Math . PI ) ;
} ;
exports . SUBTOTAL = null ;
exports . ADD = function ( num1 , num2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
num1 = utils . parseNumber ( num1 ) ;
num2 = utils . parseNumber ( num2 ) ;
if ( utils . anyIsError ( num1 , num2 ) ) {
return error . value ;
}
return num1 + num2 ;
} ;
exports . MINUS = function ( num1 , num2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
num1 = utils . parseNumber ( num1 ) ;
num2 = utils . parseNumber ( num2 ) ;
if ( utils . anyIsError ( num1 , num2 ) ) {
return error . value ;
}
return num1 - num2 ;
} ;
exports . DIVIDE = function ( dividend , divisor ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
dividend = utils . parseNumber ( dividend ) ;
divisor = utils . parseNumber ( divisor ) ;
if ( utils . anyIsError ( dividend , divisor ) ) {
return error . value ;
}
if ( divisor === 0 ) {
return error . div0 ;
}
return dividend / divisor ;
} ;
exports . MULTIPLY = function ( factor1 , factor2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
factor1 = utils . parseNumber ( factor1 ) ;
factor2 = utils . parseNumber ( factor2 ) ;
if ( utils . anyIsError ( factor1 , factor2 ) ) {
return error . value ;
}
return factor1 * factor2 ;
} ;
exports . GTE = function ( num1 , num2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
num1 = utils . parseNumber ( num1 ) ;
num2 = utils . parseNumber ( num2 ) ;
if ( utils . anyIsError ( num1 , num2 ) ) {
return error . error ;
}
return num1 >= num2 ;
} ;
exports . LT = function ( num1 , num2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
num1 = utils . parseNumber ( num1 ) ;
num2 = utils . parseNumber ( num2 ) ;
if ( utils . anyIsError ( num1 , num2 ) ) {
return error . error ;
}
return num1 < num2 ;
} ;
exports . LTE = function ( num1 , num2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
num1 = utils . parseNumber ( num1 ) ;
num2 = utils . parseNumber ( num2 ) ;
if ( utils . anyIsError ( num1 , num2 ) ) {
return error . error ;
}
return num1 <= num2 ;
} ;
exports . EQ = function ( value1 , value2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
return value1 === value2 ;
} ;
exports . NE = function ( value1 , value2 ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
return value1 !== value2 ;
} ;
exports . POW = function ( base , exponent ) {
if ( arguments . length !== 2 ) {
return error . na ;
}
base = utils . parseNumber ( base ) ;
exponent = utils . parseNumber ( exponent ) ;
if ( utils . anyIsError ( base , exponent ) ) {
return error . error ;
}
return exports . POWER ( base , exponent ) ;
} ;
exports . SUM = function ( ) {
var result = 0 ;
var argsKeys = Object . keys ( arguments ) ;
for ( var i = 0 ; i < argsKeys . length ; ++ i ) {
var elt = arguments [ argsKeys [ i ] ] ;
if ( typeof elt === "number" ) {
result += elt ;
} else if ( typeof elt === "string" ) {
var parsed = parseFloat ( elt ) ;
! isNaN ( parsed ) && ( result += parsed ) ;
} else if ( Array . isArray ( elt ) ) {
result += exports . SUM . apply ( null , elt ) ;
}
}
return result ;
} ;
exports . SUMIF = function ( ) {
var args = utils . argsToArray ( arguments ) ;
var criteria = args . pop ( ) ;
var range = utils . parseNumberArray ( utils . flatten ( args ) ) ;
if ( range instanceof Error ) {
return range ;
}
var result = 0 ;
for ( var i = 0 ; i < range . length ; i ++ ) {
result += eval ( range [ i ] + criteria ) ? range [ i ] : 0 ; // jshint ignore:line
}
return result ;
} ;
exports . SUMIFS = function ( ) {
var args = utils . argsToArray ( arguments ) ;
var range = utils . parseNumberArray ( utils . flatten ( args . shift ( ) ) ) ;
if ( range instanceof Error ) {
return range ;
}
var criteria = args ;
var n _range _elements = range . length ;
var n _criterias = criteria . length ;
var result = 0 ;
for ( var i = 0 ; i < n _range _elements ; i ++ ) {
var el = range [ i ] ;
var condition = "" ;
for ( var c = 0 ; c < n _criterias ; c += 2 ) {
if ( isNaN ( criteria [ c ] [ i ] ) ) {
condition += '"' + criteria [ c ] [ i ] + '"' + criteria [ c + 1 ] ;
} else {
condition += criteria [ c ] [ i ] + criteria [ c + 1 ] ;
}
if ( c !== n _criterias - 1 ) {
condition += " && " ;
}
}
condition = condition . slice ( 0 , - 4 ) ;
if ( eval ( condition ) ) {
// jshint ignore:line
result += el ;
}
}
return result ;
} ;
exports . SUMPRODUCT = null ;
exports . SUMSQ = function ( ) {
var numbers = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( numbers instanceof Error ) {
return numbers ;
}
var result = 0 ;
var length = numbers . length ;
for ( var i = 0 ; i < length ; i ++ ) {
result += ISNUMBER ( numbers [ i ] ) ? numbers [ i ] * numbers [ i ] : 0 ;
}
return result ;
} ;
exports . SUMX2MY2 = function ( array _x , array _y ) {
array _x = utils . parseNumberArray ( utils . flatten ( array _x ) ) ;
array _y = utils . parseNumberArray ( utils . flatten ( array _y ) ) ;
if ( utils . anyIsError ( array _x , array _y ) ) {
return error . value ;
}
var result = 0 ;
for ( var i = 0 ; i < array _x . length ; i ++ ) {
result += array _x [ i ] * array _x [ i ] - array _y [ i ] * array _y [ i ] ;
}
return result ;
} ;
exports . SUMX2PY2 = function ( array _x , array _y ) {
array _x = utils . parseNumberArray ( utils . flatten ( array _x ) ) ;
array _y = utils . parseNumberArray ( utils . flatten ( array _y ) ) ;
if ( utils . anyIsError ( array _x , array _y ) ) {
return error . value ;
}
var result = 0 ;
array _x = utils . parseNumberArray ( utils . flatten ( array _x ) ) ;
array _y = utils . parseNumberArray ( utils . flatten ( array _y ) ) ;
for ( var i = 0 ; i < array _x . length ; i ++ ) {
result += array _x [ i ] * array _x [ i ] + array _y [ i ] * array _y [ i ] ;
}
return result ;
} ;
exports . SUMXMY2 = function ( array _x , array _y ) {
array _x = utils . parseNumberArray ( utils . flatten ( array _x ) ) ;
array _y = utils . parseNumberArray ( utils . flatten ( array _y ) ) ;
if ( utils . anyIsError ( array _x , array _y ) ) {
return error . value ;
}
var result = 0 ;
array _x = utils . flatten ( array _x ) ;
array _y = utils . flatten ( array _y ) ;
for ( var i = 0 ; i < array _x . length ; i ++ ) {
result += Math . pow ( array _x [ i ] - array _y [ i ] , 2 ) ;
}
return result ;
} ;
exports . TAN = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return Math . tan ( number ) ;
} ;
exports . TANH = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
var e2 = Math . exp ( 2 * number ) ;
return ( e2 - 1 ) / ( e2 + 1 ) ;
} ;
exports . TRUNC = function ( number , digits ) {
digits = digits === undefined ? 0 : digits ;
number = utils . parseNumber ( number ) ;
digits = utils . parseNumber ( digits ) ;
if ( utils . anyIsError ( number , digits ) ) {
return error . value ;
}
var sign = number > 0 ? 1 : - 1 ;
return (
( sign * Math . floor ( Math . abs ( number ) * Math . pow ( 10 , digits ) ) ) /
Math . pow ( 10 , digits )
) ;
} ;
return exports ;
} ) ( ) ;
met . misc = ( function ( ) {
var exports = { } ;
exports . UNIQUE = function ( ) {
var result = [ ] ;
for ( var i = 0 ; i < arguments . length ; ++ i ) {
var hasElement = false ;
var element = arguments [ i ] ;
// Check if we've already seen this element.
for ( var j = 0 ; j < result . length ; ++ j ) {
hasElement = result [ j ] === element ;
if ( hasElement ) {
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// If we did not find it, add it to the result.
if ( ! hasElement ) {
result . push ( element ) ;
}
}
return result ;
} ;
exports . FLATTEN = utils . flatten ;
exports . ARGS2ARRAY = function ( ) {
return Array . prototype . slice . call ( arguments , 0 ) ;
} ;
exports . REFERENCE = function ( context , reference ) {
try {
var path = reference . split ( "." ) ;
var result = context ;
for ( var i = 0 ; i < path . length ; ++ i ) {
var step = path [ i ] ;
if ( step [ step . length - 1 ] === "]" ) {
var opening = step . indexOf ( "[" ) ;
var index = step . substring ( opening + 1 , step . length - 1 ) ;
result = result [ step . substring ( 0 , opening ) ] [ index ] ;
} else {
result = result [ step ] ;
}
}
return result ;
} catch ( error ) { }
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . JOIN = function ( array , separator ) {
return array . join ( separator ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . NUMBERS = function ( ) {
var possibleNumbers = utils . flatten ( arguments ) ;
return possibleNumbers . filter ( function ( el ) {
return typeof el === "number" ;
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . NUMERAL = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return exports ;
} ) ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
met . text = ( function ( ) {
var exports = { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . ASC = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . BAHTTEXT = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . CHAR = function ( number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return String . fromCharCode ( number ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . CLEAN = function ( text ) {
text = text || "" ;
var re = /[\0-\x1F]/g ;
return text . replace ( re , "" ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . CODE = function ( text ) {
text = text || "" ;
return text . charCodeAt ( 0 ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . CONCATENATE = function ( ) {
var args = utils . flatten ( arguments ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var trueFound = 0 ;
while ( ( trueFound = args . indexOf ( true ) ) > - 1 ) {
args [ trueFound ] = "TRUE" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var falseFound = 0 ;
while ( ( falseFound = args . indexOf ( false ) ) > - 1 ) {
args [ falseFound ] = "FALSE" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return args . join ( "" ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . DBCS = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . DOLLAR = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . EXACT = function ( text1 , text2 ) {
return text1 === text2 ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . FIND = function ( find _text , within _text , position ) {
position = position === undefined ? 0 : position ;
return within _text
? within _text . indexOf ( find _text , position - 1 ) + 1
: null ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . FIXED = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
exports . HTML2TEXT = function ( value ) {
var result = "" ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( value ) {
if ( value instanceof Array ) {
value . forEach ( function ( line ) {
if ( result !== "" ) {
result += "\n" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
result += line . replace ( /<(?:.|\n)*?>/gm , "" ) ;
} ) ;
} else {
result = value . replace ( /<(?:.|\n)*?>/gm , "" ) ;
}
}
return result ;
} ;
exports . LEFT = function ( text , number ) {
number = number === undefined ? 1 : number ;
number = utils . parseNumber ( number ) ;
if ( number instanceof Error || typeof text !== "string" ) {
return error . value ;
}
return text ? text . substring ( 0 , number ) : null ;
} ;
exports . LEN = function ( text ) {
if ( arguments . length === 0 ) {
return error . error ;
}
if ( typeof text === "string" ) {
return text ? text . length : 0 ;
}
if ( text . length ) {
return text . length ;
}
if ( text == null ) {
return 0 ;
}
return error . value ;
} ;
exports . LOWER = function ( text ) {
if ( typeof text !== "string" ) {
return error . value ;
}
return text ? text . toLowerCase ( ) : text ;
} ;
exports . MID = function ( text , start , number ) {
start = utils . parseNumber ( start ) ;
number = utils . parseNumber ( number ) ;
if ( utils . anyIsError ( start , number ) || typeof text !== "string" ) {
return number ;
}
var begin = start - 1 ;
var end = begin + number ;
return text . substring ( begin , end ) ;
} ;
exports . NUMBERVALUE = null ;
exports . PRONETIC = null ;
exports . PROPER = function ( text ) {
if ( text === undefined || text . length === 0 ) {
return error . value ;
}
if ( text === true ) {
text = "TRUE" ;
}
if ( text === false ) {
text = "FALSE" ;
}
if ( isNaN ( text ) && typeof text === "number" ) {
return error . value ;
}
if ( typeof text === "number" ) {
text = "" + text ;
}
return text . replace ( /\w\S*/g , function ( txt ) {
return txt . charAt ( 0 ) . toUpperCase ( ) + txt . substr ( 1 ) . toLowerCase ( ) ;
} ) ;
} ;
exports . REGEXEXTRACT = function ( text , regular _expression ) {
var match = text . match ( new RegExp ( regular _expression ) ) ;
return match ? match [ match . length > 1 ? match . length - 1 : 0 ] : null ;
} ;
exports . REGEXMATCH = function ( text , regular _expression , full ) {
var match = text . match ( new RegExp ( regular _expression ) ) ;
return full ? match : ! ! match ;
} ;
exports . REGEXREPLACE = function ( text , regular _expression , replacement ) {
return text . replace ( new RegExp ( regular _expression ) , replacement ) ;
} ;
exports . REPLACE = function ( text , position , length , new _text ) {
position = utils . parseNumber ( position ) ;
length = utils . parseNumber ( length ) ;
if (
utils . anyIsError ( position , length ) ||
typeof text !== "string" ||
typeof new _text !== "string"
) {
return error . value ;
}
return (
text . substr ( 0 , position - 1 ) +
new _text +
text . substr ( position - 1 + length )
) ;
} ;
exports . REPT = function ( text , number ) {
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return new Array ( number + 1 ) . join ( text ) ;
} ;
exports . RIGHT = function ( text , number ) {
number = number === undefined ? 1 : number ;
number = utils . parseNumber ( number ) ;
if ( number instanceof Error ) {
return number ;
}
return text ? text . substring ( text . length - number ) : null ;
} ;
exports . SEARCH = function ( find _text , within _text , position ) {
var foundAt ;
if ( typeof find _text !== "string" || typeof within _text !== "string" ) {
return error . value ;
}
position = position === undefined ? 0 : position ;
foundAt =
within _text
. toLowerCase ( )
. indexOf ( find _text . toLowerCase ( ) , position - 1 ) + 1 ;
return foundAt === 0 ? error . value : foundAt ;
} ;
exports . SPLIT = function ( text , separator ) {
return text . split ( separator ) ;
} ;
exports . SUBSTITUTE = function ( text , old _text , new _text , occurrence ) {
if ( ! text || ! old _text || ! new _text ) {
return text ;
} else if ( occurrence === undefined ) {
return text . replace ( new RegExp ( old _text , "g" ) , new _text ) ;
} else {
var index = 0 ;
var i = 0 ;
while ( text . indexOf ( old _text , index ) > 0 ) {
index = text . indexOf ( old _text , index + 1 ) ;
i ++ ;
if ( i === occurrence ) {
return (
text . substring ( 0 , index ) +
new _text +
text . substring ( index + old _text . length )
) ;
}
}
}
} ;
exports . T = function ( value ) {
return typeof value === "string" ? value : "" ;
} ;
exports . TEXT = null ;
exports . TRIM = function ( text ) {
if ( typeof text !== "string" ) {
return error . value ;
}
return text . replace ( / +/g , " " ) . trim ( ) ;
} ;
exports . UNICHAR = exports . CHAR ;
exports . UNICODE = exports . CODE ;
exports . UPPER = function ( text ) {
if ( typeof text !== "string" ) {
return error . value ;
}
return text . toUpperCase ( ) ;
} ;
exports . VALUE = null ;
return exports ;
} ) ( ) ;
met . stats = ( function ( ) {
var exports = { } ;
var SQRT2PI = 2.5066282746310002 ;
exports . AVEDEV = null ;
exports . AVERAGE = function ( ) {
var range = utils . numbers ( utils . flatten ( arguments ) ) ;
var n = range . length ;
var sum = 0 ;
var count = 0 ;
for ( var i = 0 ; i < n ; i ++ ) {
sum += range [ i ] ;
count += 1 ;
}
return sum / count ;
} ;
exports . AVERAGEA = function ( ) {
var range = utils . flatten ( arguments ) ;
var n = range . length ;
var sum = 0 ;
var count = 0 ;
for ( var i = 0 ; i < n ; i ++ ) {
var el = range [ i ] ;
if ( typeof el === "number" ) {
sum += el ;
}
if ( el === true ) {
sum ++ ;
}
if ( el !== null ) {
count ++ ;
}
}
return sum / count ;
} ;
exports . AVERAGEIF = function ( range , criteria , average _range ) {
average _range = average _range || range ;
range = utils . flatten ( range ) ;
average _range = utils . parseNumberArray ( utils . flatten ( average _range ) ) ;
if ( average _range instanceof Error ) {
return average _range ;
}
var average _count = 0 ;
var result = 0 ;
for ( var i = 0 ; i < range . length ; i ++ ) {
if ( eval ( range [ i ] + criteria ) ) {
// jshint ignore:line
result += average _range [ i ] ;
average _count ++ ;
}
}
return result / average _count ;
} ;
exports . AVERAGEIFS = null ;
exports . COUNT = function ( ) {
return utils . numbers ( utils . flatten ( arguments ) ) . length ;
} ;
exports . COUNTA = function ( ) {
var range = utils . flatten ( arguments ) ;
return range . length - exports . COUNTBLANK ( range ) ;
} ;
exports . COUNTIN = function ( range , value ) {
var result = 0 ;
for ( var i = 0 ; i < range . length ; i ++ ) {
if ( range [ i ] === value ) {
result ++ ;
}
}
return result ;
} ;
exports . COUNTBLANK = function ( ) {
var range = utils . flatten ( arguments ) ;
var blanks = 0 ;
var element ;
for ( var i = 0 ; i < range . length ; i ++ ) {
element = range [ i ] ;
if ( element === null || element === "" ) {
blanks ++ ;
}
}
return blanks ;
} ;
exports . COUNTIF = function ( ) {
var args = utils . argsToArray ( arguments ) ;
var criteria = args . pop ( ) ;
var range = utils . flatten ( args ) ;
if ( ! /[<>=!]/ . test ( criteria ) ) {
criteria = '=="' + criteria + '"' ;
}
var matches = 0 ;
for ( var i = 0 ; i < range . length ; i ++ ) {
if ( typeof range [ i ] !== "string" ) {
if ( eval ( range [ i ] + criteria ) ) {
// jshint ignore:line
matches ++ ;
}
} else {
if ( eval ( '"' + range [ i ] + '"' + criteria ) ) {
// jshint ignore:line
matches ++ ;
}
}
}
return matches ;
} ;
exports . COUNTIFS = function ( ) {
var args = utils . argsToArray ( arguments ) ;
var results = new Array ( utils . flatten ( args [ 0 ] ) . length ) ;
for ( var i = 0 ; i < results . length ; i ++ ) {
results [ i ] = true ;
}
for ( i = 0 ; i < args . length ; i += 2 ) {
var range = utils . flatten ( args [ i ] ) ;
var criteria = args [ i + 1 ] ;
if ( ! /[<>=!]/ . test ( criteria ) ) {
criteria = '=="' + criteria + '"' ;
}
for ( var j = 0 ; j < range . length ; j ++ ) {
if ( typeof range [ j ] !== "string" ) {
results [ j ] = results [ j ] && eval ( range [ j ] + criteria ) ; // jshint ignore:line
} else {
results [ j ] = results [ j ] && eval ( '"' + range [ j ] + '"' + criteria ) ; // jshint ignore:line
}
}
}
var result = 0 ;
for ( i = 0 ; i < results . length ; i ++ ) {
if ( results [ i ] ) {
result ++ ;
}
}
return result ;
} ;
exports . COUNTUNIQUE = function ( ) {
return UNIQUE . apply ( null , utils . flatten ( arguments ) ) . length ;
} ;
exports . FISHER = function ( x ) {
x = utils . parseNumber ( x ) ;
if ( x instanceof Error ) {
return x ;
}
return Math . log ( ( 1 + x ) / ( 1 - x ) ) / 2 ;
} ;
exports . FISHERINV = function ( y ) {
y = utils . parseNumber ( y ) ;
if ( y instanceof Error ) {
return y ;
}
var e2y = Math . exp ( 2 * y ) ;
return ( e2y - 1 ) / ( e2y + 1 ) ;
} ;
exports . FREQUENCY = function ( data , bins ) {
data = utils . parseNumberArray ( utils . flatten ( data ) ) ;
bins = utils . parseNumberArray ( utils . flatten ( bins ) ) ;
if ( utils . anyIsError ( data , bins ) ) {
return error . value ;
}
var n = data . length ;
var b = bins . length ;
var r = [ ] ;
for ( var i = 0 ; i <= b ; i ++ ) {
r [ i ] = 0 ;
for ( var j = 0 ; j < n ; j ++ ) {
if ( i === 0 ) {
if ( data [ j ] <= bins [ 0 ] ) {
r [ 0 ] += 1 ;
}
} else if ( i < b ) {
if ( data [ j ] > bins [ i - 1 ] && data [ j ] <= bins [ i ] ) {
r [ i ] += 1 ;
}
} else if ( i === b ) {
if ( data [ j ] > bins [ b - 1 ] ) {
r [ b ] += 1 ;
}
}
}
}
return r ;
} ;
exports . LARGE = function ( range , k ) {
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
k = utils . parseNumber ( k ) ;
if ( utils . anyIsError ( range , k ) ) {
return range ;
}
return range . sort ( function ( a , b ) {
return b - a ;
} ) [ k - 1 ] ;
} ;
exports . MAX = function ( ) {
var range = utils . numbers ( utils . flatten ( arguments ) ) ;
return range . length === 0 ? 0 : Math . max . apply ( Math , range ) ;
} ;
exports . MAXA = function ( ) {
var range = utils . arrayValuesToNumbers ( utils . flatten ( arguments ) ) ;
return range . length === 0 ? 0 : Math . max . apply ( Math , range ) ;
} ;
exports . MIN = function ( ) {
var range = utils . numbers ( utils . flatten ( arguments ) ) ;
return range . length === 0 ? 0 : Math . min . apply ( Math , range ) ;
} ;
exports . MINA = function ( ) {
var range = utils . arrayValuesToNumbers ( utils . flatten ( arguments ) ) ;
return range . length === 0 ? 0 : Math . min . apply ( Math , range ) ;
} ;
exports . MODE = { } ;
exports . MODE . MULT = function ( ) {
// Credits: Roönaän
var range = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( range instanceof Error ) {
return range ;
}
var n = range . length ;
var count = { } ;
var maxItems = [ ] ;
var max = 0 ;
var currentItem ;
for ( var i = 0 ; i < n ; i ++ ) {
currentItem = range [ i ] ;
count [ currentItem ] = count [ currentItem ] ? count [ currentItem ] + 1 : 1 ;
if ( count [ currentItem ] > max ) {
max = count [ currentItem ] ;
maxItems = [ ] ;
}
if ( count [ currentItem ] === max ) {
maxItems [ maxItems . length ] = currentItem ;
}
}
return maxItems ;
} ;
exports . MODE . SNGL = function ( ) {
var range = utils . parseNumberArray ( utils . flatten ( arguments ) ) ;
if ( range instanceof Error ) {
return range ;
}
return exports . MODE . MULT ( range ) . sort ( function ( a , b ) {
return a - b ;
} ) [ 0 ] ;
} ;
exports . PERCENTILE = { } ;
exports . PERCENTILE . EXC = function ( array , k ) {
array = utils . parseNumberArray ( utils . flatten ( array ) ) ;
k = utils . parseNumber ( k ) ;
if ( utils . anyIsError ( array , k ) ) {
return error . value ;
}
array = array . sort ( function ( a , b ) {
{
return a - b ;
}
} ) ;
var n = array . length ;
if ( k < 1 / ( n + 1 ) || k > 1 - 1 / ( n + 1 ) ) {
return error . num ;
}
var l = k * ( n + 1 ) - 1 ;
var fl = Math . floor ( l ) ;
return utils . cleanFloat (
l === fl ? array [ l ] : array [ fl ] + ( l - fl ) * ( array [ fl + 1 ] - array [ fl ] )
) ;
} ;
exports . PERCENTILE . INC = function ( array , k ) {
array = utils . parseNumberArray ( utils . flatten ( array ) ) ;
k = utils . parseNumber ( k ) ;
if ( utils . anyIsError ( array , k ) ) {
return error . value ;
}
array = array . sort ( function ( a , b ) {
return a - b ;
} ) ;
var n = array . length ;
var l = k * ( n - 1 ) ;
var fl = Math . floor ( l ) ;
return utils . cleanFloat (
l === fl ? array [ l ] : array [ fl ] + ( l - fl ) * ( array [ fl + 1 ] - array [ fl ] )
) ;
} ;
exports . PERCENTRANK = { } ;
exports . PERCENTRANK . EXC = function ( array , x , significance ) {
significance = significance === undefined ? 3 : significance ;
array = utils . parseNumberArray ( utils . flatten ( array ) ) ;
x = utils . parseNumber ( x ) ;
significance = utils . parseNumber ( significance ) ;
if ( utils . anyIsError ( array , x , significance ) ) {
return error . value ;
}
array = array . sort ( function ( a , b ) {
return a - b ;
} ) ;
var uniques = UNIQUE . apply ( null , array ) ;
var n = array . length ;
var m = uniques . length ;
var power = Math . pow ( 10 , significance ) ;
var result = 0 ;
var match = false ;
var i = 0 ;
while ( ! match && i < m ) {
if ( x === uniques [ i ] ) {
result = ( array . indexOf ( uniques [ i ] ) + 1 ) / ( n + 1 ) ;
match = true ;
} else if ( x >= uniques [ i ] && ( x < uniques [ i + 1 ] || i === m - 1 ) ) {
result =
( array . indexOf ( uniques [ i ] ) +
1 +
( x - uniques [ i ] ) / ( uniques [ i + 1 ] - uniques [ i ] ) ) /
( n + 1 ) ;
match = true ;
}
i ++ ;
}
return Math . floor ( result * power ) / power ;
} ;
exports . PERCENTRANK . INC = function ( array , x , significance ) {
significance = significance === undefined ? 3 : significance ;
array = utils . parseNumberArray ( utils . flatten ( array ) ) ;
x = utils . parseNumber ( x ) ;
significance = utils . parseNumber ( significance ) ;
if ( utils . anyIsError ( array , x , significance ) ) {
return error . value ;
}
array = array . sort ( function ( a , b ) {
return a - b ;
} ) ;
var uniques = UNIQUE . apply ( null , array ) ;
var n = array . length ;
var m = uniques . length ;
var power = Math . pow ( 10 , significance ) ;
var result = 0 ;
var match = false ;
var i = 0 ;
while ( ! match && i < m ) {
if ( x === uniques [ i ] ) {
result = array . indexOf ( uniques [ i ] ) / ( n - 1 ) ;
match = true ;
} else if ( x >= uniques [ i ] && ( x < uniques [ i + 1 ] || i === m - 1 ) ) {
result =
( array . indexOf ( uniques [ i ] ) +
( x - uniques [ i ] ) / ( uniques [ i + 1 ] - uniques [ i ] ) ) /
( n - 1 ) ;
match = true ;
}
i ++ ;
}
return Math . floor ( result * power ) / power ;
} ;
exports . PERMUT = function ( number , number _chosen ) {
number = utils . parseNumber ( number ) ;
number _chosen = utils . parseNumber ( number _chosen ) ;
if ( utils . anyIsError ( number , number _chosen ) ) {
return error . value ;
}
return FACT ( number ) / FACT ( number - number _chosen ) ;
} ;
exports . PERMUTATIONA = function ( number , number _chosen ) {
number = utils . parseNumber ( number ) ;
number _chosen = utils . parseNumber ( number _chosen ) ;
if ( utils . anyIsError ( number , number _chosen ) ) {
return error . value ;
}
return Math . pow ( number , number _chosen ) ;
} ;
exports . PHI = function ( x ) {
x = utils . parseNumber ( x ) ;
if ( x instanceof Error ) {
return error . value ;
}
return Math . exp ( - 0.5 * x * x ) / SQRT2PI ;
} ;
exports . PROB = function ( range , probability , lower , upper ) {
if ( lower === undefined ) {
return 0 ;
}
upper = upper === undefined ? lower : upper ;
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
probability = utils . parseNumberArray ( utils . flatten ( probability ) ) ;
lower = utils . parseNumber ( lower ) ;
upper = utils . parseNumber ( upper ) ;
if ( utils . anyIsError ( range , probability , lower , upper ) ) {
return error . value ;
}
if ( lower === upper ) {
return range . indexOf ( lower ) >= 0
? probability [ range . indexOf ( lower ) ]
: 0 ;
}
var sorted = range . sort ( function ( a , b ) {
return a - b ;
} ) ;
var n = sorted . length ;
var result = 0 ;
for ( var i = 0 ; i < n ; i ++ ) {
if ( sorted [ i ] >= lower && sorted [ i ] <= upper ) {
result += probability [ range . indexOf ( sorted [ i ] ) ] ;
}
}
return result ;
} ;
exports . QUARTILE = { } ;
exports . QUARTILE . EXC = function ( range , quart ) {
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
quart = utils . parseNumber ( quart ) ;
if ( utils . anyIsError ( range , quart ) ) {
return error . value ;
}
switch ( quart ) {
case 1 :
return exports . PERCENTILE . EXC ( range , 0.25 ) ;
case 2 :
return exports . PERCENTILE . EXC ( range , 0.5 ) ;
case 3 :
return exports . PERCENTILE . EXC ( range , 0.75 ) ;
default :
return error . num ;
}
} ;
exports . QUARTILE . INC = function ( range , quart ) {
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
quart = utils . parseNumber ( quart ) ;
if ( utils . anyIsError ( range , quart ) ) {
return error . value ;
}
switch ( quart ) {
case 1 :
return exports . PERCENTILE . INC ( range , 0.25 ) ;
case 2 :
return exports . PERCENTILE . INC ( range , 0.5 ) ;
case 3 :
return exports . PERCENTILE . INC ( range , 0.75 ) ;
default :
return error . num ;
}
} ;
exports . RANK = { } ;
exports . RANK . AVG = function ( number , range , order ) {
number = utils . parseNumber ( number ) ;
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
if ( utils . anyIsError ( number , range ) ) {
return error . value ;
}
range = utils . flatten ( range ) ;
order = order || false ;
var sort = order
? function ( a , b ) {
return a - b ;
}
: function ( a , b ) {
return b - a ;
} ;
range = range . sort ( sort ) ;
var length = range . length ;
var count = 0 ;
for ( var i = 0 ; i < length ; i ++ ) {
if ( range [ i ] === number ) {
count ++ ;
}
}
return count > 1
? ( 2 * range . indexOf ( number ) + count + 1 ) / 2
: range . indexOf ( number ) + 1 ;
} ;
exports . RANK . EQ = function ( number , range , order ) {
number = utils . parseNumber ( number ) ;
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
if ( utils . anyIsError ( number , range ) ) {
return error . value ;
}
order = order || false ;
var sort = order
? function ( a , b ) {
return a - b ;
}
: function ( a , b ) {
return b - a ;
} ;
range = range . sort ( sort ) ;
return range . indexOf ( number ) + 1 ;
} ;
exports . RSQ = function ( data _x , data _y ) {
// no need to flatten here, PEARSON will take care of that
data _x = utils . parseNumberArray ( utils . flatten ( data _x ) ) ;
data _y = utils . parseNumberArray ( utils . flatten ( data _y ) ) ;
if ( utils . anyIsError ( data _x , data _y ) ) {
return error . value ;
}
return Math . pow ( exports . PEARSON ( data _x , data _y ) , 2 ) ;
} ;
exports . SMALL = function ( range , k ) {
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
k = utils . parseNumber ( k ) ;
if ( utils . anyIsError ( range , k ) ) {
return range ;
}
return range . sort ( function ( a , b ) {
return a - b ;
} ) [ k - 1 ] ;
} ;
exports . STANDARDIZE = function ( x , mean , sd ) {
x = utils . parseNumber ( x ) ;
mean = utils . parseNumber ( mean ) ;
sd = utils . parseNumber ( sd ) ;
if ( utils . anyIsError ( x , mean , sd ) ) {
return error . value ;
}
return ( x - mean ) / sd ;
} ;
exports . STDEV = { } ;
exports . STDEV . P = function ( ) {
var v = exports . VAR . P . apply ( this , arguments ) ;
return Math . sqrt ( v ) ;
} ;
exports . STDEV . S = function ( ) {
var v = exports . VAR . S . apply ( this , arguments ) ;
return Math . sqrt ( v ) ;
} ;
exports . STDEVA = function ( ) {
var v = exports . VARA . apply ( this , arguments ) ;
return Math . sqrt ( v ) ;
} ;
exports . STDEVPA = function ( ) {
var v = exports . VARPA . apply ( this , arguments ) ;
return Math . sqrt ( v ) ;
} ;
exports . VAR = { } ;
exports . VAR . P = function ( ) {
var range = utils . numbers ( utils . flatten ( arguments ) ) ;
var n = range . length ;
var sigma = 0 ;
var mean = exports . AVERAGE ( range ) ;
for ( var i = 0 ; i < n ; i ++ ) {
sigma += Math . pow ( range [ i ] - mean , 2 ) ;
}
return sigma / n ;
} ;
exports . VAR . S = function ( ) {
var range = utils . numbers ( utils . flatten ( arguments ) ) ;
var n = range . length ;
var sigma = 0 ;
var mean = exports . AVERAGE ( range ) ;
for ( var i = 0 ; i < n ; i ++ ) {
sigma += Math . pow ( range [ i ] - mean , 2 ) ;
}
return sigma / ( n - 1 ) ;
} ;
exports . VARA = function ( ) {
var range = utils . flatten ( arguments ) ;
var n = range . length ;
var sigma = 0 ;
var count = 0 ;
var mean = exports . AVERAGEA ( range ) ;
for ( var i = 0 ; i < n ; i ++ ) {
var el = range [ i ] ;
if ( typeof el === "number" ) {
sigma += Math . pow ( el - mean , 2 ) ;
} else if ( el === true ) {
sigma += Math . pow ( 1 - mean , 2 ) ;
} else {
sigma += Math . pow ( 0 - mean , 2 ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( el !== null ) {
count ++ ;
}
}
return sigma / ( count - 1 ) ;
} ;
exports . VARPA = function ( ) {
var range = utils . flatten ( arguments ) ;
var n = range . length ;
var sigma = 0 ;
var count = 0 ;
var mean = exports . AVERAGEA ( range ) ;
for ( var i = 0 ; i < n ; i ++ ) {
var el = range [ i ] ;
if ( typeof el === "number" ) {
sigma += Math . pow ( el - mean , 2 ) ;
} else if ( el === true ) {
sigma += Math . pow ( 1 - mean , 2 ) ;
} else {
sigma += Math . pow ( 0 - mean , 2 ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( el !== null ) {
count ++ ;
}
}
return sigma / count ;
} ;
exports . WEIBULL = { } ;
exports . WEIBULL . DIST = function ( x , alpha , beta , cumulative ) {
x = utils . parseNumber ( x ) ;
alpha = utils . parseNumber ( alpha ) ;
beta = utils . parseNumber ( beta ) ;
if ( utils . anyIsError ( x , alpha , beta ) ) {
return error . value ;
}
return cumulative
? 1 - Math . exp ( - Math . pow ( x / beta , alpha ) )
: ( Math . pow ( x , alpha - 1 ) *
Math . exp ( - Math . pow ( x / beta , alpha ) ) *
alpha ) /
Math . pow ( beta , alpha ) ;
} ;
exports . Z = { } ;
exports . Z . TEST = function ( range , x , sd ) {
range = utils . parseNumberArray ( utils . flatten ( range ) ) ;
x = utils . parseNumber ( x ) ;
if ( utils . anyIsError ( range , x ) ) {
return error . value ;
}
sd = sd || exports . STDEV . S ( range ) ;
var n = range . length ;
return (
1 -
exports . NORM . S . DIST (
( exports . AVERAGE ( range ) - x ) / ( sd / Math . sqrt ( n ) ) ,
true
)
) ;
} ;
return exports ;
} ) ( ) ;
met . utils = ( function ( ) {
var exports = { } ;
exports . PROGRESS = function ( p , c ) {
var color = c ? c : "red" ;
var value = p ? p : "0" ;
return (
'<div style="width:' +
value +
"%;height:4px;background-color:" +
color +
';margin-top:1px;"></div>'
) ;
} ;
exports . RATING = function ( v ) {
var html = '<div class="jrating">' ;
for ( var i = 0 ; i < 5 ; i ++ ) {
if ( i < v ) {
html += '<div class="jrating-selected"></div>' ;
} else {
html += "<div></div>" ;
}
}
html += "</div>" ;
return html ;
} ;
return exports ;
} ) ( ) ;
for ( var i = 0 ; i < Object . keys ( met ) . length ; i ++ ) {
var methods = met [ Object . keys ( met ) [ i ] ] ;
var keys = Object . keys ( methods ) ;
for ( var j = 0 ; j < keys . length ; j ++ ) {
if ( ! methods [ keys [ j ] ] ) {
window [ keys [ j ] ] = function ( ) {
return keys [ j ] + "Not implemented" ;
} ;
} else if (
typeof methods [ keys [ j ] ] == "function" ||
typeof methods [ keys [ j ] ] == "object"
) {
window [ keys [ j ] ] = methods [ keys [ j ] ] ;
window [ keys [ j ] ] . toString = function ( ) {
return "#ERROR" ;
} ;
if ( typeof methods [ keys [ j ] ] == "object" ) {
var tmp = Object . keys ( methods [ keys [ j ] ] ) ;
for ( var z = 0 ; z < tmp . length ; z ++ ) {
window [ keys [ j ] ] [ tmp [ z ] ] . toString = function ( ) {
return "#ERROR" ;
} ;
}
}
} else {
window [ keys [ j ] ] = function ( ) {
return keys [ j ] + "Not implemented" ;
} ;
}
}
}
/ * *
* Instance execution helpers
* /
var x = null ;
var y = null ;
var instance = null ;
window [ "TABLE" ] = function ( ) {
return instance ;
} ;
window [ "COLUMN" ] = window [ "COL" ] = function ( ) {
return parseInt ( x ) + 1 ;
} ;
window [ "ROW" ] = function ( ) {
return parseInt ( y ) + 1 ;
} ;
window [ "CELL" ] = function ( ) {
return F . getColumnNameFromCoords ( x , y ) ;
} ;
window [ "VALUE" ] = function ( col , row , processed ) {
return instance . getValueFromCoords (
parseInt ( col ) - 1 ,
parseInt ( row ) - 1 ,
processed
) ;
} ;
window [ "THISROWCELL" ] = function ( col ) {
return instance . getValueFromCoords ( parseInt ( col ) - 1 , parseInt ( y ) ) ;
} ;
// Secure formula
var secureFormula = function ( oldValue , runtime ) {
var newValue = "" ;
var inside = 0 ;
var special = [ "=" , "!" , ">" , "<" ] ;
for ( var i = 0 ; i < oldValue . length ; i ++ ) {
if ( oldValue [ i ] == '"' ) {
if ( inside == 0 ) {
inside = 1 ;
} else {
inside = 0 ;
}
}
if ( inside == 1 ) {
newValue += oldValue [ i ] ;
} else {
newValue += oldValue [ i ] . toUpperCase ( ) ;
if ( runtime == true ) {
if (
i > 0 &&
oldValue [ i ] == "=" &&
special . indexOf ( oldValue [ i - 1 ] ) == - 1 &&
special . indexOf ( oldValue [ i + 1 ] ) == - 1
) {
newValue += "=" ;
}
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Adapt to JS
newValue = newValue . replace ( /\^/g , "**" ) ;
newValue = newValue . replace ( /\<\>/g , "!=" ) ;
newValue = newValue . replace ( /\&/g , "+" ) ;
newValue = newValue . replace ( /\$/g , "" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return newValue ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Convert range tokens
var tokensUpdate = function ( tokens , e ) {
for ( var index = 0 ; index < tokens . length ; index ++ ) {
var f = F . getTokensFromRange ( tokens [ index ] ) ;
e = e . replace ( tokens [ index ] , "[" + f . join ( "," ) + "]" ) ;
}
return e ;
} ;
var F = function ( expression , variables , i , j , obj ) {
// Global helpers
instance = obj ;
x = i ;
y = j ;
// String
var s = "" ;
var keys = Object . keys ( variables ) ;
if ( keys . length ) {
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( keys [ i ] . indexOf ( "." ) == - 1 && keys [ i ] . indexOf ( "!" ) == - 1 ) {
s += "var " + keys [ i ] + " = " + variables [ keys [ i ] ] + ";\n" ;
} else {
s += keys [ i ] + " = " + variables [ keys [ i ] ] + ";\n" ;
}
}
}
// Remove $
expression = expression . replace ( /\$/g , "" ) ;
// Replace ! per dot
expression = expression . replace ( /\!/g , "." ) ;
// Adapt to JS
expression = secureFormula ( expression , true ) ;
// Update range
var tokens = expression . match (
/([A-Z]+[0-9]*\.)?(\$?[A-Z]+\$?[0-9]+):(\$?[A-Z]+\$?[0-9]+)?/g
) ;
if ( tokens && tokens . length ) {
expression = tokensUpdate ( tokens , expression ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Calculate
return new Function ( s + "; return " + expression ) ( ) ;
} ;
/ * *
* Get letter based on a number
* @ param { number } i
* @ return { string }
* /
var getColumnName = function ( i ) {
var letter = "" ;
if ( i > 701 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 676 ) ) ;
letter += String . fromCharCode ( 64 + parseInt ( ( i % 676 ) / 26 ) ) ;
} else if ( i > 25 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 26 ) ) ;
}
letter += String . fromCharCode ( 65 + ( i % 26 ) ) ;
return letter ;
} ;
/ * *
* Get column name from coords
* /
F . getColumnNameFromCoords = function ( x , y ) {
return getColumnName ( parseInt ( x ) ) + ( parseInt ( y ) + 1 ) ;
} ;
F . getCoordsFromColumnName = function ( columnName ) {
// Get the letters
var t = /^[a-zA-Z]+/ . exec ( columnName ) ;
if ( t ) {
// Base 26 calculation
var code = 0 ;
for ( var i = 0 ; i < t [ 0 ] . length ; i ++ ) {
code +=
parseInt ( t [ 0 ] . charCodeAt ( i ) - 64 ) * Math . pow ( 26 , t [ 0 ] . length - 1 - i ) ;
}
code -- ;
// Make sure jspreadsheet starts on zero
if ( code < 0 ) {
code = 0 ;
}
// Number
var number = parseInt ( /[0-9]+$/ . exec ( columnName ) ) || null ;
if ( number > 0 ) {
number -- ;
}
return [ code , number ] ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
F . getRangeFromTokens = function ( tokens ) {
tokens = tokens . filter ( function ( v ) {
return v != "#REF!" ;
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var d = "" ;
var t = "" ;
for ( var i = 0 ; i < tokens . length ; i ++ ) {
if ( tokens [ i ] . indexOf ( "." ) >= 0 ) {
d = "." ;
} else if ( tokens [ i ] . indexOf ( "!" ) >= 0 ) {
d = "!" ;
}
if ( d ) {
t = tokens [ i ] . split ( d ) ;
tokens [ i ] = t [ 1 ] ;
t = t [ 0 ] + d ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
tokens . sort ( function ( a , b ) {
var t1 = Helpers . getCoordsFromColumnName ( a ) ;
var t2 = Helpers . getCoordsFromColumnName ( b ) ;
if ( t1 [ 1 ] > t2 [ 1 ] ) {
return 1 ;
} else if ( t1 [ 1 ] < t2 [ 1 ] ) {
return - 1 ;
} else {
if ( t1 [ 0 ] > t2 [ 0 ] ) {
return 1 ;
} else if ( t1 [ 0 ] < t2 [ 0 ] ) {
return - 1 ;
} else {
return 0 ;
}
}
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! tokens . length ) {
return "#REF!" ;
} else {
return t + ( tokens [ 0 ] + ":" + tokens [ tokens . length - 1 ] ) ;
}
} ;
F . getTokensFromRange = function ( range ) {
if ( range . indexOf ( "." ) > 0 ) {
var t = range . split ( "." ) ;
range = t [ 1 ] ;
t = t [ 0 ] + "." ;
} else if ( range . indexOf ( "!" ) > 0 ) {
var t = range . split ( "!" ) ;
range = t [ 1 ] ;
t = t [ 0 ] + "!" ;
} else {
var t = "" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var range = range . split ( ":" ) ;
var e1 = F . getCoordsFromColumnName ( range [ 0 ] ) ;
var e2 = F . getCoordsFromColumnName ( range [ 1 ] ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( e1 [ 0 ] <= e2 [ 0 ] ) {
var x1 = e1 [ 0 ] ;
var x2 = e2 [ 0 ] ;
} else {
var x1 = e2 [ 0 ] ;
var x2 = e1 [ 0 ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( e1 [ 1 ] === null && e2 [ 1 ] == null ) {
var y1 = null ;
var y2 = null ;
var k = Object . keys ( vars ) ;
for ( var i = 0 ; i < k . length ; i ++ ) {
var tmp = F . getCoordsFromColumnName ( k [ i ] ) ;
if ( tmp [ 0 ] === e1 [ 0 ] ) {
if ( y1 === null || tmp [ 1 ] < y1 ) {
y1 = tmp [ 1 ] ;
}
}
if ( tmp [ 0 ] === e2 [ 0 ] ) {
if ( y2 === null || tmp [ 1 ] > y2 ) {
y2 = tmp [ 1 ] ;
}
}
}
} else {
if ( e1 [ 1 ] <= e2 [ 1 ] ) {
var y1 = e1 [ 1 ] ;
var y2 = e2 [ 1 ] ;
} else {
var y1 = e2 [ 1 ] ;
var y2 = e1 [ 1 ] ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var f = [ ] ;
for ( var j = y1 ; j <= y2 ; j ++ ) {
var line = [ ] ;
for ( var i = x1 ; i <= x2 ; i ++ ) {
line . push ( t + F . getColumnNameFromCoords ( i , j ) ) ;
}
f . push ( line ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return f ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
F . setFormula = function ( o ) {
var k = Object . keys ( o ) ;
for ( var i = 0 ; i < k . length ; i ++ ) {
if ( typeof o [ k [ i ] ] == "function" ) {
window [ k [ i ] ] = o [ k [ i ] ] ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return F ;
} ) ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! jSuites && typeof require === "function" ) {
var jSuites = require ( "jsuites" ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
( function ( global , factory ) {
typeof exports === "object" && typeof module !== "undefined"
? ( module . exports = factory ( ) )
: typeof define === "function" && define . amd
? define ( factory )
: ( global . jspreadsheet = global . jexcel = factory ( ) ) ;
} ) ( this , function ( ) {
"use strict" ;
// Basic version information
var Version = ( function ( ) {
// Information
var info = {
title : "Jspreadsheet" ,
version : "4.11.1" ,
type : "CE" ,
host : "https://bossanova.uk/jspreadsheet" ,
license : "MIT" ,
print : function ( ) {
return [
this . title + " " + this . type + " " + this . version ,
this . host ,
this . license ,
] . join ( "\r\n" ) ;
} ,
} ;
return function ( ) {
return info ;
} ;
} ) ( ) ;
/ * *
* The value is a formula
* /
var isFormula = function ( value ) {
var v = ( "" + value ) [ 0 ] ;
return v == "=" || v == "#" ? true : false ;
} ;
/ * *
* Get the mask in the jSuites . mask format
* /
var getMask = function ( o ) {
if ( o . format || o . mask || o . locale ) {
var opt = { } ;
if ( o . mask ) {
opt . mask = o . mask ;
} else if ( o . format ) {
opt . mask = o . format ;
} else {
opt . locale = o . locale ;
opt . options = o . options ;
}
if ( o . decimal ) {
if ( ! opt . options ) {
opt . options = { } ;
}
opt . options = { decimal : o . decimal } ;
}
return opt ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return null ;
} ;
// Jspreadsheet core object
var jexcel = function ( el , options ) {
// Create jspreadsheet object
var obj = { } ;
obj . options = { } ;
if ( ! ( el instanceof Element || el instanceof HTMLDocument ) ) {
console . error ( "Jspreadsheet: el is not a valid DOM element" ) ;
return false ;
} else if ( el . tagName == "TABLE" ) {
if ( ( options = jexcel . createFromTable ( el , options ) ) ) {
var div = document . createElement ( "div" ) ;
el . parentNode . insertBefore ( div , el ) ;
el . remove ( ) ;
el = div ;
} else {
console . error ( "Jspreadsheet: el is not a valid DOM element" ) ;
return false ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Loading default configuration
var defaults = {
// External data
url : null ,
// Ajax options
method : "GET" ,
requestVariables : null ,
// Data
data : null ,
// Custom sorting handler
sorting : null ,
// Copy behavior
copyCompatibility : false ,
root : null ,
// Rows and columns definitions
rows : [ ] ,
columns : [ ] ,
// Deprected legacy options
colHeaders : [ ] ,
colWidths : [ ] ,
colAlignments : [ ] ,
nestedHeaders : null ,
// Column width that is used by default
defaultColWidth : 50 ,
defaultColAlign : "center" ,
// Rows height default
defaultRowHeight : null ,
// Spare rows and columns
minSpareRows : 0 ,
minSpareCols : 0 ,
// Minimal table dimensions
minDimensions : [ 0 , 0 ] ,
// Allow Export
allowExport : true ,
// @type {boolean} - Include the header titles on download
includeHeadersOnDownload : false ,
// @type {boolean} - Include the header titles on copy
includeHeadersOnCopy : false ,
// Allow column sorting
columnSorting : true ,
// Allow column dragging
columnDrag : false ,
// Allow column resizing
columnResize : true ,
// Allow row resizing
rowResize : false ,
// Allow row dragging
rowDrag : true ,
// Allow table edition
editable : true ,
// Allow new rows
allowInsertRow : true ,
// Allow new rows
allowManualInsertRow : true ,
// Allow new columns
allowInsertColumn : true ,
// Allow new rows
allowManualInsertColumn : true ,
// Allow row delete
allowDeleteRow : true ,
// Allow deleting of all rows
allowDeletingAllRows : false ,
// Allow column delete
allowDeleteColumn : true ,
// Allow rename column
allowRenameColumn : true ,
// Allow comments
allowComments : false ,
// Global wrap
wordWrap : false ,
// Image options
imageOptions : null ,
// CSV source
csv : null ,
// Filename
csvFileName : "jspreadsheet" ,
// Consider first line as header
csvHeaders : true ,
// Delimiters
csvDelimiter : "," ,
// First row as header
parseTableFirstRowAsHeader : false ,
parseTableAutoCellType : false ,
// Disable corner selection
selectionCopy : true ,
// Merged cells
mergeCells : { } ,
// Create toolbar
toolbar : null ,
// Allow search
search : false ,
// Create pagination
pagination : false ,
paginationOptions : null ,
// Full screen
fullscreen : false ,
// Lazy loading
lazyLoading : false ,
loadingSpin : false ,
// Table overflow
tableOverflow : false ,
tableHeight : "300px" ,
tableWidth : null ,
textOverflow : false ,
// Meta
meta : null ,
// Style
style : null ,
classes : null ,
// Execute formulas
parseFormulas : true ,
autoIncrement : true ,
autoCasting : true ,
// Security
secureFormulas : true ,
stripHTML : true ,
stripHTMLOnCopy : false ,
// Filters
filters : false ,
footers : null ,
// Event handles
onundo : null ,
onredo : null ,
onload : null ,
onchange : null ,
oncomments : null ,
onbeforechange : null ,
onafterchanges : null ,
onbeforeinsertrow : null ,
oninsertrow : null ,
onbeforeinsertcolumn : null ,
oninsertcolumn : null ,
onbeforedeleterow : null ,
ondeleterow : null ,
onbeforedeletecolumn : null ,
ondeletecolumn : null ,
onmoverow : null ,
onmovecolumn : null ,
onresizerow : null ,
onresizecolumn : null ,
onsort : null ,
onselection : null ,
oncopy : null ,
onpaste : null ,
onbeforepaste : null ,
onmerge : null ,
onfocus : null ,
onblur : null ,
onchangeheader : null ,
oncreateeditor : null ,
oneditionstart : null ,
oneditionend : null ,
onchangestyle : null ,
onchangemeta : null ,
onchangepage : null ,
onbeforesave : null ,
onsave : null ,
// Global event dispatcher
onevent : null ,
// Persistance
persistance : false ,
// Customize any cell behavior
updateTable : null ,
// Detach the HTML table when calling updateTable
detachForUpdates : false ,
freezeColumns : null ,
// Texts
text : {
noRecordsFound : "No records found" ,
showingPage : "Showing page {0} of {1} entries" ,
show : "Show " ,
search : "Search" ,
entries : " entries" ,
columnName : "Column name" ,
insertANewColumnBefore : "Insert a new column before" ,
insertANewColumnAfter : "Insert a new column after" ,
deleteSelectedColumns : "Delete selected columns" ,
renameThisColumn : "Rename this column" ,
orderAscending : "Order ascending" ,
orderDescending : "Order descending" ,
insertANewRowBefore : "Insert a new row before" ,
insertANewRowAfter : "Insert a new row after" ,
deleteSelectedRows : "Delete selected rows" ,
editComments : "Edit comments" ,
addComments : "Add comments" ,
comments : "Comments" ,
clearComments : "Clear comments" ,
copy : "Copy..." ,
paste : "Paste..." ,
saveAs : "Save as..." ,
about : "About" ,
areYouSureToDeleteTheSelectedRows :
"Are you sure to delete the selected rows?" ,
areYouSureToDeleteTheSelectedColumns :
"Are you sure to delete the selected columns?" ,
thisActionWillDestroyAnyExistingMergedCellsAreYouSure :
"This action will destroy any existing merged cells. Are you sure?" ,
thisActionWillClearYourSearchResultsAreYouSure :
"This action will clear your search results. Are you sure?" ,
thereIsAConflictWithAnotherMergedCell :
"There is a conflict with another merged cell" ,
invalidMergeProperties : "Invalid merged properties" ,
cellAlreadyMerged : "Cell already merged" ,
noCellsSelected : "No cells selected" ,
} ,
// About message
about : true ,
} ;
// Loading initial configuration from user
for ( var property in defaults ) {
if ( options && options . hasOwnProperty ( property ) ) {
if ( property === "text" ) {
obj . options [ property ] = defaults [ property ] ;
for ( var textKey in options [ property ] ) {
if ( options [ property ] . hasOwnProperty ( textKey ) ) {
obj . options [ property ] [ textKey ] = options [ property ] [ textKey ] ;
}
}
} else {
obj . options [ property ] = options [ property ] ;
}
} else {
obj . options [ property ] = defaults [ property ] ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Global elements
obj . el = el ;
obj . corner = null ;
obj . contextMenu = null ;
obj . textarea = null ;
obj . ads = null ;
obj . content = null ;
obj . table = null ;
obj . thead = null ;
obj . tbody = null ;
obj . rows = [ ] ;
obj . results = null ;
obj . searchInput = null ;
obj . toolbar = null ;
obj . pagination = null ;
obj . pageNumber = null ;
obj . headerContainer = null ;
obj . colgroupContainer = null ;
// Containers
obj . headers = [ ] ;
obj . records = [ ] ;
obj . history = [ ] ;
obj . formula = [ ] ;
obj . colgroup = [ ] ;
obj . selection = [ ] ;
obj . highlighted = [ ] ;
obj . selectedCell = null ;
obj . selectedContainer = null ;
obj . style = [ ] ;
obj . data = null ;
obj . filter = null ;
obj . filters = [ ] ;
// Internal controllers
obj . cursor = null ;
obj . historyIndex = - 1 ;
obj . ignoreEvents = false ;
obj . ignoreHistory = false ;
obj . edition = null ;
obj . hashString = null ;
obj . resizing = null ;
obj . dragging = null ;
// Lazy loading
if (
obj . options . lazyLoading == true &&
obj . options . tableOverflow == false &&
obj . options . fullscreen == false
) {
console . error (
"Jspreadsheet: The lazyloading only works when tableOverflow = yes or fullscreen = yes"
) ;
obj . options . lazyLoading = false ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Activate / Disable fullscreen
* use programmatically : table . fullscreen ( ) ; or table . fullscreen ( true ) ; or table . fullscreen ( false ) ;
* @ Param { boolean } activate
* /
obj . fullscreen = function ( activate ) {
// If activate not defined, get reverse options.fullscreen
if ( activate == null ) {
activate = ! obj . options . fullscreen ;
}
// If change
if ( obj . options . fullscreen != activate ) {
obj . options . fullscreen = activate ;
// Test LazyLoading conflict
if ( activate == true ) {
el . classList . add ( "fullscreen" ) ;
} else {
el . classList . remove ( "fullscreen" ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Trigger events
* /
obj . dispatch = function ( event ) {
// Dispatch events
if ( ! obj . ignoreEvents ) {
// Call global event
if ( typeof obj . options . onevent == "function" ) {
var ret = obj . options . onevent . apply ( this , arguments ) ;
}
// Call specific events
if ( typeof obj . options [ event ] == "function" ) {
var ret = obj . options [ event ] . apply (
this ,
Array . prototype . slice . call ( arguments , 1 )
) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Persistance
if ( event == "onafterchanges" && obj . options . persistance ) {
var url =
obj . options . persistance == true
? obj . options . url
: obj . options . persistance ;
var data = obj . prepareJson ( arguments [ 2 ] ) ;
obj . save ( url , data ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return ret ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Prepare the jspreadsheet table
*
* @ Param config
* /
obj . prepareTable = function ( ) {
// Loading initial data from remote sources
var results = [ ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Number of columns
var size = obj . options . columns . length ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . data && typeof obj . options . data [ 0 ] !== "undefined" ) {
// Data keys
var keys = Object . keys ( obj . options . data [ 0 ] ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( keys . length > size ) {
size = keys . length ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Minimal dimensions
if ( obj . options . minDimensions [ 0 ] > size ) {
size = obj . options . minDimensions [ 0 ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Requests
var multiple = [ ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Preparations
for ( var i = 0 ; i < size ; i ++ ) {
// Deprected options. You should use only columns
if ( ! obj . options . colHeaders [ i ] ) {
obj . options . colHeaders [ i ] = "" ;
}
if ( ! obj . options . colWidths [ i ] ) {
obj . options . colWidths [ i ] = obj . options . defaultColWidth ;
}
if ( ! obj . options . colAlignments [ i ] ) {
obj . options . colAlignments [ i ] = obj . options . defaultColAlign ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Default column description
if ( ! obj . options . columns [ i ] ) {
obj . options . columns [ i ] = { type : "text" } ;
} else if ( ! obj . options . columns [ i ] . type ) {
obj . options . columns [ i ] . type = "text" ;
}
if ( ! obj . options . columns [ i ] . name ) {
obj . options . columns [ i ] . name = keys && keys [ i ] ? keys [ i ] : i ;
}
if ( ! obj . options . columns [ i ] . source ) {
obj . options . columns [ i ] . source = [ ] ;
}
if ( ! obj . options . columns [ i ] . options ) {
obj . options . columns [ i ] . options = [ ] ;
}
if ( ! obj . options . columns [ i ] . editor ) {
obj . options . columns [ i ] . editor = null ;
}
if ( ! obj . options . columns [ i ] . allowEmpty ) {
obj . options . columns [ i ] . allowEmpty = false ;
}
if ( ! obj . options . columns [ i ] . title ) {
obj . options . columns [ i ] . title = obj . options . colHeaders [ i ]
? obj . options . colHeaders [ i ]
: "" ;
}
if ( ! obj . options . columns [ i ] . width ) {
obj . options . columns [ i ] . width = obj . options . colWidths [ i ]
? obj . options . colWidths [ i ]
: obj . options . defaultColWidth ;
}
if ( ! obj . options . columns [ i ] . align ) {
obj . options . columns [ i ] . align = obj . options . colAlignments [ i ]
? obj . options . colAlignments [ i ]
: "center" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Pre-load initial source for json autocomplete
if (
obj . options . columns [ i ] . type == "autocomplete" ||
obj . options . columns [ i ] . type == "dropdown"
) {
// if remote content
if ( obj . options . columns [ i ] . url ) {
multiple . push ( {
url : obj . options . columns [ i ] . url ,
index : i ,
method : "GET" ,
dataType : "json" ,
success : function ( data ) {
var source = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ ) {
obj . options . columns [ this . index ] . source . push ( data [ i ] ) ;
}
} ,
} ) ;
}
} else if ( obj . options . columns [ i ] . type == "calendar" ) {
// Default format for date columns
if ( ! obj . options . columns [ i ] . options . format ) {
obj . options . columns [ i ] . options . format = "DD/MM/YYYY" ;
}
}
}
// Create the table when is ready
if ( ! multiple . length ) {
obj . createTable ( ) ;
} else {
jSuites . ajax ( multiple , function ( ) {
obj . createTable ( ) ;
} ) ;
}
} ;
obj . createTable = function ( ) {
// Elements
obj . table = document . createElement ( "table" ) ;
obj . thead = document . createElement ( "thead" ) ;
obj . tbody = document . createElement ( "tbody" ) ;
// Create headers controllers
obj . headers = [ ] ;
obj . colgroup = [ ] ;
// Create table container
obj . content = document . createElement ( "div" ) ;
obj . content . classList . add ( "jexcel_content" ) ;
obj . content . onscroll = function ( e ) {
obj . scrollControls ( e ) ;
} ;
obj . content . onwheel = function ( e ) {
obj . wheelControls ( e ) ;
} ;
// Create toolbar object
obj . toolbar = document . createElement ( "div" ) ;
obj . toolbar . classList . add ( "jexcel_toolbar" ) ;
// Search
var searchContainer = document . createElement ( "div" ) ;
var searchText = document . createTextNode ( obj . options . text . search + ": " ) ;
obj . searchInput = document . createElement ( "input" ) ;
obj . searchInput . classList . add ( "jexcel_search" ) ;
searchContainer . appendChild ( searchText ) ;
searchContainer . appendChild ( obj . searchInput ) ;
obj . searchInput . onfocus = function ( ) {
obj . resetSelection ( ) ;
} ;
// Pagination select option
var paginationUpdateContainer = document . createElement ( "div" ) ;
if (
obj . options . pagination > 0 &&
obj . options . paginationOptions &&
obj . options . paginationOptions . length > 0
) {
obj . paginationDropdown = document . createElement ( "select" ) ;
obj . paginationDropdown . classList . add ( "jexcel_pagination_dropdown" ) ;
obj . paginationDropdown . onchange = function ( ) {
obj . options . pagination = parseInt ( this . value ) ;
obj . page ( 0 ) ;
} ;
for ( var i = 0 ; i < obj . options . paginationOptions . length ; i ++ ) {
var temp = document . createElement ( "option" ) ;
temp . value = obj . options . paginationOptions [ i ] ;
temp . innerHTML = obj . options . paginationOptions [ i ] ;
obj . paginationDropdown . appendChild ( temp ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Set initial pagination value
obj . paginationDropdown . value = obj . options . pagination ;
paginationUpdateContainer . appendChild (
document . createTextNode ( obj . options . text . show )
) ;
paginationUpdateContainer . appendChild ( obj . paginationDropdown ) ;
paginationUpdateContainer . appendChild (
document . createTextNode ( obj . options . text . entries )
) ;
}
// Filter and pagination container
var filter = document . createElement ( "div" ) ;
filter . classList . add ( "jexcel_filter" ) ;
filter . appendChild ( paginationUpdateContainer ) ;
filter . appendChild ( searchContainer ) ;
// Colsgroup
obj . colgroupContainer = document . createElement ( "colgroup" ) ;
var tempCol = document . createElement ( "col" ) ;
tempCol . setAttribute ( "width" , "50" ) ;
obj . colgroupContainer . appendChild ( tempCol ) ;
// Nested
if ( obj . options . nestedHeaders && obj . options . nestedHeaders . length > 0 ) {
// Flexible way to handle nestedheaders
if ( obj . options . nestedHeaders [ 0 ] && obj . options . nestedHeaders [ 0 ] [ 0 ] ) {
for ( var j = 0 ; j < obj . options . nestedHeaders . length ; j ++ ) {
obj . thead . appendChild (
obj . createNestedHeader ( obj . options . nestedHeaders [ j ] )
) ;
}
} else {
obj . thead . appendChild (
obj . createNestedHeader ( obj . options . nestedHeaders )
) ;
}
}
// Row
obj . headerContainer = document . createElement ( "tr" ) ;
var tempCol = document . createElement ( "td" ) ;
tempCol . classList . add ( "jexcel_selectall" ) ;
obj . headerContainer . appendChild ( tempCol ) ;
for ( var i = 0 ; i < obj . options . columns . length ; i ++ ) {
// Create header
obj . createCellHeader ( i ) ;
// Append cell to the container
obj . headerContainer . appendChild ( obj . headers [ i ] ) ;
obj . colgroupContainer . appendChild ( obj . colgroup [ i ] ) ;
}
obj . thead . appendChild ( obj . headerContainer ) ;
// Filters
if ( obj . options . filters == true ) {
obj . filter = document . createElement ( "tr" ) ;
var td = document . createElement ( "td" ) ;
obj . filter . appendChild ( td ) ;
for ( var i = 0 ; i < obj . options . columns . length ; i ++ ) {
var td = document . createElement ( "td" ) ;
td . innerHTML = " " ;
td . setAttribute ( "data-x" , i ) ;
td . className = "jexcel_column_filter" ;
if ( obj . options . columns [ i ] . type == "hidden" ) {
td . style . display = "none" ;
}
obj . filter . appendChild ( td ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . thead . appendChild ( obj . filter ) ;
}
// Content table
obj . table = document . createElement ( "table" ) ;
obj . table . classList . add ( "jexcel" ) ;
obj . table . setAttribute ( "cellpadding" , "0" ) ;
obj . table . setAttribute ( "cellspacing" , "0" ) ;
obj . table . setAttribute ( "unselectable" , "yes" ) ;
//obj.table.setAttribute('onselectstart', 'return false');
obj . table . appendChild ( obj . colgroupContainer ) ;
obj . table . appendChild ( obj . thead ) ;
obj . table . appendChild ( obj . tbody ) ;
if ( ! obj . options . textOverflow ) {
obj . table . classList . add ( "jexcel_overflow" ) ;
}
// Spreadsheet corner
obj . corner = document . createElement ( "div" ) ;
obj . corner . className = "jexcel_corner" ;
obj . corner . setAttribute ( "unselectable" , "on" ) ;
obj . corner . setAttribute ( "onselectstart" , "return false" ) ;
if ( obj . options . selectionCopy == false ) {
obj . corner . style . display = "none" ;
}
// Textarea helper
obj . textarea = document . createElement ( "textarea" ) ;
obj . textarea . className = "jexcel_textarea" ;
obj . textarea . id = "jexcel_textarea" ;
obj . textarea . tabIndex = "-1" ;
// Contextmenu container
obj . contextMenu = document . createElement ( "div" ) ;
obj . contextMenu . className = "jexcel_contextmenu" ;
// Create element
jSuites . contextmenu ( obj . contextMenu , {
onclick : function ( ) {
obj . contextMenu . contextmenu . close ( false ) ;
} ,
} ) ;
// Powered by Jspreadsheet
var ads = document . createElement ( "a" ) ;
ads . setAttribute ( "href" , "https://bossanova.uk/jspreadsheet/" ) ;
obj . ads = document . createElement ( "div" ) ;
obj . ads . className = "jexcel_about" ;
try {
if (
typeof sessionStorage !== "undefined" &&
! sessionStorage . getItem ( "jexcel" )
) {
sessionStorage . setItem ( "jexcel" , true ) ;
var img = document . createElement ( "img" ) ;
img . src = "//bossanova.uk/jspreadsheet/logo.png" ;
ads . appendChild ( img ) ;
}
} catch ( exception ) { }
var span = document . createElement ( "span" ) ;
span . innerHTML = "Jspreadsheet CE" ;
ads . appendChild ( span ) ;
obj . ads . appendChild ( ads ) ;
// Create table container TODO: frozen columns
var container = document . createElement ( "div" ) ;
container . classList . add ( "jexcel_table" ) ;
// Pagination
obj . pagination = document . createElement ( "div" ) ;
obj . pagination . classList . add ( "jexcel_pagination" ) ;
var paginationInfo = document . createElement ( "div" ) ;
var paginationPages = document . createElement ( "div" ) ;
obj . pagination . appendChild ( paginationInfo ) ;
obj . pagination . appendChild ( paginationPages ) ;
// Hide pagination if not in use
if ( ! obj . options . pagination ) {
obj . pagination . style . display = "none" ;
}
// Append containers to the table
if ( obj . options . search == true ) {
el . appendChild ( filter ) ;
}
// Elements
obj . content . appendChild ( obj . table ) ;
obj . content . appendChild ( obj . corner ) ;
obj . content . appendChild ( obj . textarea ) ;
el . appendChild ( obj . toolbar ) ;
el . appendChild ( obj . content ) ;
el . appendChild ( obj . pagination ) ;
el . appendChild ( obj . contextMenu ) ;
el . appendChild ( obj . ads ) ;
el . classList . add ( "jexcel_container" ) ;
// Create toolbar
if ( obj . options . toolbar && obj . options . toolbar . length ) {
obj . createToolbar ( ) ;
}
// Fullscreen
if ( obj . options . fullscreen == true ) {
el . classList . add ( "fullscreen" ) ;
} else {
// Overflow
if ( obj . options . tableOverflow == true ) {
if ( obj . options . tableHeight ) {
obj . content . style [ "overflow-y" ] = "auto" ;
obj . content . style [ "box-shadow" ] =
"rgb(221 221 221) 2px 2px 5px 0.1px" ;
obj . content . style . maxHeight = obj . options . tableHeight ;
}
if ( obj . options . tableWidth ) {
obj . content . style [ "overflow-x" ] = "auto" ;
obj . content . style . width = obj . options . tableWidth ;
}
}
}
// With toolbars
if ( obj . options . tableOverflow != true && obj . options . toolbar ) {
el . classList . add ( "with-toolbar" ) ;
}
// Actions
if ( obj . options . columnDrag == true ) {
obj . thead . classList . add ( "draggable" ) ;
}
if ( obj . options . columnResize == true ) {
obj . thead . classList . add ( "resizable" ) ;
}
if ( obj . options . rowDrag == true ) {
obj . tbody . classList . add ( "draggable" ) ;
}
if ( obj . options . rowResize == true ) {
obj . tbody . classList . add ( "resizable" ) ;
}
// Load data
obj . setData ( ) ;
// Style
if ( obj . options . style ) {
obj . setStyle ( obj . options . style , null , null , 1 , 1 ) ;
}
// Classes
if ( obj . options . classes ) {
var k = Object . keys ( obj . options . classes ) ;
for ( var i = 0 ; i < k . length ; i ++ ) {
var cell = jexcel . getIdFromColumnName ( k [ i ] , true ) ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . classList . add (
obj . options . classes [ k [ i ] ]
) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Refresh the data
*
* @ return void
* /
obj . refresh = function ( ) {
if ( obj . options . url ) {
// Loading
if ( obj . options . loadingSpin == true ) {
jSuites . loading . show ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jSuites . ajax ( {
url : obj . options . url ,
method : obj . options . method ,
data : obj . options . requestVariables ,
dataType : "json" ,
success : function ( result ) {
// Data
obj . options . data = result . data ? result . data : result ;
// Prepare table
obj . setData ( ) ;
// Hide spin
if ( obj . options . loadingSpin == true ) {
jSuites . loading . hide ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} ,
} ) ;
} else {
obj . setData ( ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set data
*
* @ param array data In case no data is sent , default is reloaded
* @ return void
* /
obj . setData = function ( data ) {
// Update data
if ( data ) {
if ( typeof data == "string" ) {
data = JSON . parse ( data ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . options . data = data ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Data
if ( ! obj . options . data ) {
obj . options . data = [ ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Prepare data
if ( obj . options . data && obj . options . data [ 0 ] ) {
if ( ! Array . isArray ( obj . options . data [ 0 ] ) ) {
var data = [ ] ;
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
var row = [ ] ;
for ( var i = 0 ; i < obj . options . columns . length ; i ++ ) {
row [ i ] = obj . options . data [ j ] [ obj . options . columns [ i ] . name ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
data . push ( row ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . options . data = data ;
}
}
// Adjust minimal dimensions
var j = 0 ;
var i = 0 ;
var size _i = obj . options . columns . length ;
var size _j = obj . options . data . length ;
var min _i = obj . options . minDimensions [ 0 ] ;
var min _j = obj . options . minDimensions [ 1 ] ;
var max _i = min _i > size _i ? min _i : size _i ;
var max _j = min _j > size _j ? min _j : size _j ;
for ( j = 0 ; j < max _j ; j ++ ) {
for ( i = 0 ; i < max _i ; i ++ ) {
if ( obj . options . data [ j ] == undefined ) {
obj . options . data [ j ] = [ ] ;
}
if ( obj . options . data [ j ] [ i ] == undefined ) {
obj . options . data [ j ] [ i ] = "" ;
}
}
}
// Reset containers
obj . rows = [ ] ;
obj . results = null ;
obj . records = [ ] ;
obj . history = [ ] ;
// Reset internal controllers
obj . historyIndex = - 1 ;
// Reset data
obj . tbody . innerHTML = "" ;
// Lazy loading
if ( obj . options . lazyLoading == true ) {
// Load only 100 records
var startNumber = 0 ;
var finalNumber =
obj . options . data . length < 100 ? obj . options . data . length : 100 ;
if ( obj . options . pagination ) {
obj . options . pagination = false ;
console . error (
"Jspreadsheet: Pagination will be disable due the lazyLoading"
) ;
}
} else if ( obj . options . pagination ) {
// Pagination
if ( ! obj . pageNumber ) {
obj . pageNumber = 0 ;
}
var quantityPerPage = obj . options . pagination ;
startNumber = obj . options . pagination * obj . pageNumber ;
finalNumber =
obj . options . pagination * obj . pageNumber + obj . options . pagination ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . data . length < finalNumber ) {
finalNumber = obj . options . data . length ;
}
} else {
var startNumber = 0 ;
var finalNumber = obj . options . data . length ;
}
// Append nodes to the HTML
for ( j = 0 ; j < obj . options . data . length ; j ++ ) {
// Create row
var tr = obj . createRow ( j , obj . options . data [ j ] ) ;
// Append line to the table
if ( j >= startNumber && j < finalNumber ) {
obj . tbody . appendChild ( tr ) ;
}
}
if ( obj . options . lazyLoading == true ) {
// Do not create pagination with lazyloading activated
} else if ( obj . options . pagination ) {
obj . updatePagination ( ) ;
}
// Merge cells
if ( obj . options . mergeCells ) {
var keys = Object . keys ( obj . options . mergeCells ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var num = obj . options . mergeCells [ keys [ i ] ] ;
obj . setMerge ( keys [ i ] , num [ 0 ] , num [ 1 ] , 1 ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Updata table with custom configurations if applicable
obj . updateTable ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Onload
obj . dispatch ( "onload" , el , obj ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the whole table data
*
* @ param bool get highlighted cells only
* @ return array data
* /
obj . getData = function ( highlighted , dataOnly ) {
// Control vars
var dataset = [ ] ;
var px = 0 ;
var py = 0 ;
// Data type
var dataType =
dataOnly == true || obj . options . copyCompatibility == false
? true
: false ;
// Column and row length
var x = obj . options . columns . length ;
var y = obj . options . data . length ;
// Go through the columns to get the data
for ( var j = 0 ; j < y ; j ++ ) {
px = 0 ;
for ( var i = 0 ; i < x ; i ++ ) {
// Cell selected or fullset
if (
! highlighted ||
obj . records [ j ] [ i ] . classList . contains ( "highlight" )
) {
// Get value
if ( ! dataset [ py ] ) {
dataset [ py ] = [ ] ;
}
if ( ! dataType ) {
dataset [ py ] [ px ] = obj . records [ j ] [ i ] . innerHTML ;
} else {
dataset [ py ] [ px ] = obj . options . data [ j ] [ i ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
px ++ ;
}
}
if ( px > 0 ) {
py ++ ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return dataset ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get json data by row number
*
* @ param integer row number
* @ return object
* /
obj . getJsonRow = function ( rowNumber ) {
var rowData = obj . options . data [ rowNumber ] ;
var x = obj . options . columns . length ;
var row = { } ;
for ( var i = 0 ; i < x ; i ++ ) {
if ( ! obj . options . columns [ i ] . name ) {
obj . options . columns [ i ] . name = i ;
}
row [ obj . options . columns [ i ] . name ] = rowData [ i ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return row ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the whole table data
*
* @ param bool highlighted cells only
* @ return string value
* /
obj . getJson = function ( highlighted ) {
// Control vars
var data = [ ] ;
// Column and row length
var x = obj . options . columns . length ;
var y = obj . options . data . length ;
// Go through the columns to get the data
for ( var j = 0 ; j < y ; j ++ ) {
var row = null ;
for ( var i = 0 ; i < x ; i ++ ) {
if (
! highlighted ||
obj . records [ j ] [ i ] . classList . contains ( "highlight" )
) {
if ( row == null ) {
row = { } ;
}
if ( ! obj . options . columns [ i ] . name ) {
obj . options . columns [ i ] . name = i ;
}
row [ obj . options . columns [ i ] . name ] = obj . options . data [ j ] [ i ] ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( row != null ) {
data . push ( row ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return data ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Prepare JSON in the correct format
* /
obj . prepareJson = function ( data ) {
var rows = [ ] ;
for ( var i = 0 ; i < data . length ; i ++ ) {
var x = data [ i ] . x ;
var y = data [ i ] . y ;
var k = obj . options . columns [ x ] . name ? obj . options . columns [ x ] . name : x ;
// Create row
if ( ! rows [ y ] ) {
rows [ y ] = {
row : y ,
data : { } ,
} ;
}
rows [ y ] . data [ k ] = data [ i ] . newValue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Filter rows
return rows . filter ( function ( el ) {
return el != null ;
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Post json to a remote server
* /
obj . save = function ( url , data ) {
// Parse anything in the data before sending to the server
var ret = obj . dispatch ( "onbeforesave" , el , obj , data ) ;
if ( ret ) {
var data = ret ;
} else {
if ( ret === false ) {
return false ;
}
}
// Remove update
jSuites . ajax ( {
url : url ,
method : "POST" ,
dataType : "json" ,
data : { data : JSON . stringify ( data ) } ,
success : function ( result ) {
// Event
obj . dispatch ( "onsave" , el , obj , data ) ;
} ,
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get a row data by rowNumber
* /
obj . getRowData = function ( rowNumber ) {
return obj . options . data [ rowNumber ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set a row data by rowNumber
* /
obj . setRowData = function ( rowNumber , data ) {
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
// Update cell
var columnName = jexcel . getColumnNameFromId ( [ i , rowNumber ] ) ;
// Set value
if ( data [ i ] != null ) {
obj . setValue ( columnName , data [ i ] ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get a column data by columnNumber
* /
obj . getColumnData = function ( columnNumber ) {
var dataset = [ ] ;
// Go through the rows to get the data
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
dataset . push ( obj . options . data [ j ] [ columnNumber ] ) ;
}
return dataset ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set a column data by colNumber
* /
obj . setColumnData = function ( colNumber , data ) {
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
// Update cell
var columnName = jexcel . getColumnNameFromId ( [ colNumber , j ] ) ;
// Set value
if ( data [ j ] != null ) {
obj . setValue ( columnName , data [ j ] ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Create row
* /
obj . createRow = function ( j , data ) {
// Create container
if ( ! obj . records [ j ] ) {
obj . records [ j ] = [ ] ;
}
// Default data
if ( ! data ) {
var data = obj . options . data [ j ] ;
}
// New line of data to be append in the table
obj . rows [ j ] = document . createElement ( "tr" ) ;
obj . rows [ j ] . setAttribute ( "data-y" , j ) ;
// Index
var index = null ;
// Set default row height
if ( obj . options . defaultRowHeight ) {
obj . rows [ j ] . style . height = obj . options . defaultRowHeight + "px" ;
}
// Definitions
if ( obj . options . rows [ j ] ) {
if ( obj . options . rows [ j ] . height ) {
obj . rows [ j ] . style . height = obj . options . rows [ j ] . height ;
}
if ( obj . options . rows [ j ] . title ) {
index = obj . options . rows [ j ] . title ;
}
}
if ( ! index ) {
index = parseInt ( j + 1 ) ;
}
// Row number label
var td = document . createElement ( "td" ) ;
td . innerHTML = index ;
td . setAttribute ( "data-y" , j ) ;
td . className = "jexcel_row" ;
obj . rows [ j ] . appendChild ( td ) ;
// Data columns
for ( var i = 0 ; i < obj . options . columns . length ; i ++ ) {
// New column of data to be append in the line
obj . records [ j ] [ i ] = obj . createCell ( i , j , data [ i ] ) ;
// Add column to the row
obj . rows [ j ] . appendChild ( obj . records [ j ] [ i ] ) ;
}
// Add row to the table body
return obj . rows [ j ] ;
} ;
obj . parseValue = function ( i , j , value , cell ) {
if (
( "" + value ) . substr ( 0 , 1 ) == "=" &&
obj . options . parseFormulas == true
) {
value = obj . executeFormula ( value , i , j ) ;
}
// Column options
var options = obj . options . columns [ i ] ;
if ( options && ! isFormula ( value ) ) {
// Mask options
var opt = null ;
if ( ( opt = getMask ( options ) ) ) {
if ( value && value == Number ( value ) ) {
value = Number ( value ) ;
}
// Process the decimals to match the mask
var masked = jSuites . mask . render ( value , opt , true ) ;
// Negative indication
if ( cell ) {
if ( opt . mask ) {
var t = opt . mask . split ( ";" ) ;
if ( t [ 1 ] ) {
var t1 = t [ 1 ] . match ( new RegExp ( "\\[Red\\]" , "gi" ) ) ;
if ( t1 ) {
if ( value < 0 ) {
cell . classList . add ( "red" ) ;
} else {
cell . classList . remove ( "red" ) ;
}
}
var t2 = t [ 1 ] . match ( new RegExp ( "\\(" , "gi" ) ) ;
if ( t2 ) {
if ( value < 0 ) {
masked = "(" + masked + ")" ;
}
}
}
}
}
if ( masked ) {
value = masked ;
}
}
}
return value ;
} ;
var validDate = function ( date ) {
date = "" + date ;
if ( date . substr ( 4 , 1 ) == "-" && date . substr ( 7 , 1 ) == "-" ) {
return true ;
} else {
date = date . split ( "-" ) ;
if (
date [ 0 ] . length == 4 &&
date [ 0 ] == Number ( date [ 0 ] ) &&
date [ 1 ] . length == 2 &&
date [ 1 ] == Number ( date [ 1 ] )
) {
return true ;
}
}
return false ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Create cell
* /
obj . createCell = function ( i , j , value ) {
// Create cell and properties
var td = document . createElement ( "td" ) ;
td . setAttribute ( "data-x" , i ) ;
td . setAttribute ( "data-y" , j ) ;
// Security
if (
( "" + value ) . substr ( 0 , 1 ) == "=" &&
obj . options . secureFormulas == true
) {
var val = secureFormula ( value ) ;
if ( val != value ) {
// Update the data container
value = val ;
}
}
// Custom column
if ( obj . options . columns [ i ] . editor ) {
if (
obj . options . stripHTML === false ||
obj . options . columns [ i ] . stripHTML === false
) {
td . innerHTML = value ;
} else {
td . textContent = value ;
}
if ( typeof obj . options . columns [ i ] . editor . createCell == "function" ) {
td = obj . options . columns [ i ] . editor . createCell ( td ) ;
}
} else {
// Hidden column
if ( obj . options . columns [ i ] . type == "hidden" ) {
td . style . display = "none" ;
td . textContent = value ;
} else if (
obj . options . columns [ i ] . type == "checkbox" ||
obj . options . columns [ i ] . type == "radio"
) {
// Create input
var element = document . createElement ( "input" ) ;
element . type = obj . options . columns [ i ] . type ;
element . name = "c" + i ;
element . checked =
value == 1 || value == true || value == "true" ? true : false ;
element . onclick = function ( ) {
obj . setValue ( td , this . checked ) ;
} ;
if (
obj . options . columns [ i ] . readOnly == true ||
obj . options . editable == false
) {
element . setAttribute ( "disabled" , "disabled" ) ;
}
// Append to the table
td . appendChild ( element ) ;
// Make sure the values are correct
obj . options . data [ j ] [ i ] = element . checked ;
} else if ( obj . options . columns [ i ] . type == "calendar" ) {
// Try formatted date
var formatted = null ;
if ( ! validDate ( value ) ) {
var tmp = jSuites . calendar . extractDateFromString (
value ,
obj . options . columns [ i ] . options . format
) ;
if ( tmp ) {
formatted = tmp ;
}
}
// Create calendar cell
td . textContent = jSuites . calendar . getDateString (
formatted ? formatted : value ,
obj . options . columns [ i ] . options . format
) ;
} else if (
obj . options . columns [ i ] . type == "dropdown" ||
obj . options . columns [ i ] . type == "autocomplete"
) {
// Create dropdown cell
td . classList . add ( "jexcel_dropdown" ) ;
td . textContent = obj . getDropDownValue ( i , value ) ;
} else if ( obj . options . columns [ i ] . type == "color" ) {
if ( obj . options . columns [ i ] . render == "square" ) {
var color = document . createElement ( "div" ) ;
color . className = "color" ;
color . style . backgroundColor = value ;
td . appendChild ( color ) ;
} else {
td . style . color = value ;
td . textContent = value ;
}
} else if ( obj . options . columns [ i ] . type == "image" ) {
if ( value && value . substr ( 0 , 10 ) == "data:image" ) {
var img = document . createElement ( "img" ) ;
img . src = value ;
td . appendChild ( img ) ;
}
} else {
if ( obj . options . columns [ i ] . type == "html" ) {
td . innerHTML = stripScript ( obj . parseValue ( i , j , value , td ) ) ;
} else {
if (
obj . options . stripHTML === false ||
obj . options . columns [ i ] . stripHTML === false
) {
td . innerHTML = stripScript ( obj . parseValue ( i , j , value , td ) ) ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
td . textContent = obj . parseValue ( i , j , value , td ) ;
}
}
}
}
// Readonly
if ( obj . options . columns [ i ] . readOnly == true ) {
td . className = "readonly" ;
}
// Text align
var colAlign = obj . options . columns [ i ] . align
? obj . options . columns [ i ] . align
: "center" ;
td . style . textAlign = colAlign ;
// Wrap option
if (
obj . options . columns [ i ] . wordWrap != false &&
( obj . options . wordWrap == true ||
obj . options . columns [ i ] . wordWrap == true ||
td . innerHTML . length > 200 )
) {
td . style . whiteSpace = "pre-wrap" ;
}
// Overflow
if ( i > 0 ) {
if ( this . options . textOverflow == true ) {
if ( value || td . innerHTML ) {
obj . records [ j ] [ i - 1 ] . style . overflow = "hidden" ;
} else {
if ( i == obj . options . columns . length - 1 ) {
td . style . overflow = "hidden" ;
}
}
}
}
return td ;
} ;
obj . createCellHeader = function ( colNumber ) {
// Create col global control
var colWidth = obj . options . columns [ colNumber ] . width
? obj . options . columns [ colNumber ] . width
: obj . options . defaultColWidth ;
var colAlign = obj . options . columns [ colNumber ] . align
? obj . options . columns [ colNumber ] . align
: obj . options . defaultColAlign ;
// Create header cell
obj . headers [ colNumber ] = document . createElement ( "td" ) ;
if ( obj . options . stripHTML ) {
obj . headers [ colNumber ] . textContent = obj . options . columns [ colNumber ]
. title
? obj . options . columns [ colNumber ] . title
: jexcel . getColumnName ( colNumber ) ;
} else {
obj . headers [ colNumber ] . innerHTML = obj . options . columns [ colNumber ] . title
? obj . options . columns [ colNumber ] . title
: jexcel . getColumnName ( colNumber ) ;
}
obj . headers [ colNumber ] . setAttribute ( "data-x" , colNumber ) ;
obj . headers [ colNumber ] . style . textAlign = colAlign ;
if ( obj . options . columns [ colNumber ] . title ) {
obj . headers [ colNumber ] . setAttribute (
"title" ,
obj . options . columns [ colNumber ] . title
) ;
}
if ( obj . options . columns [ colNumber ] . id ) {
obj . headers [ colNumber ] . setAttribute (
"id" ,
obj . options . columns [ colNumber ] . id
) ;
}
// Width control
obj . colgroup [ colNumber ] = document . createElement ( "col" ) ;
obj . colgroup [ colNumber ] . setAttribute ( "width" , colWidth ) ;
// Hidden column
if ( obj . options . columns [ colNumber ] . type == "hidden" ) {
obj . headers [ colNumber ] . style . display = "none" ;
obj . colgroup [ colNumber ] . style . display = "none" ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update a nested header title
* /
obj . updateNestedHeader = function ( x , y , title ) {
if ( obj . options . nestedHeaders [ y ] [ x ] . title ) {
obj . options . nestedHeaders [ y ] [ x ] . title = title ;
obj . options . nestedHeaders [ y ] . element . children [ x + 1 ] . textContent =
title ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Create a nested header object
* /
obj . createNestedHeader = function ( nestedInformation ) {
var tr = document . createElement ( "tr" ) ;
tr . classList . add ( "jexcel_nested" ) ;
var td = document . createElement ( "td" ) ;
tr . appendChild ( td ) ;
// Element
nestedInformation . element = tr ;
var headerIndex = 0 ;
for ( var i = 0 ; i < nestedInformation . length ; i ++ ) {
// Default values
if ( ! nestedInformation [ i ] . colspan ) {
nestedInformation [ i ] . colspan = 1 ;
}
if ( ! nestedInformation [ i ] . align ) {
nestedInformation [ i ] . align = "center" ;
}
if ( ! nestedInformation [ i ] . title ) {
nestedInformation [ i ] . title = "" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Number of columns
var numberOfColumns = nestedInformation [ i ] . colspan ;
// Classes container
var column = [ ] ;
// Header classes for this cell
for ( var x = 0 ; x < numberOfColumns ; x ++ ) {
if (
obj . options . columns [ headerIndex ] &&
obj . options . columns [ headerIndex ] . type == "hidden"
) {
numberOfColumns ++ ;
}
column . push ( headerIndex ) ;
headerIndex ++ ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Created the nested cell
var td = document . createElement ( "td" ) ;
td . setAttribute ( "data-column" , column . join ( "," ) ) ;
td . setAttribute ( "colspan" , nestedInformation [ i ] . colspan ) ;
td . setAttribute ( "align" , nestedInformation [ i ] . align ) ;
td . textContent = nestedInformation [ i ] . title ;
tr . appendChild ( td ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return tr ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Create toolbar
* /
obj . createToolbar = function ( toolbar ) {
if ( toolbar ) {
obj . options . toolbar = toolbar ;
} else {
var toolbar = obj . options . toolbar ;
}
for ( var i = 0 ; i < toolbar . length ; i ++ ) {
if ( toolbar [ i ] . type == "i" ) {
var toolbarItem = document . createElement ( "i" ) ;
toolbarItem . classList . add ( "jexcel_toolbar_item" ) ;
toolbarItem . classList . add ( "material-icons" ) ;
toolbarItem . setAttribute ( "data-k" , toolbar [ i ] . k ) ;
toolbarItem . setAttribute ( "data-v" , toolbar [ i ] . v ) ;
toolbarItem . setAttribute ( "id" , toolbar [ i ] . id ) ;
// Tooltip
if ( toolbar [ i ] . tooltip ) {
toolbarItem . setAttribute ( "title" , toolbar [ i ] . tooltip ) ;
}
// Handle click
if ( toolbar [ i ] . onclick && typeof toolbar [ i ] . onclick ) {
toolbarItem . onclick = ( function ( a ) {
var b = a ;
return function ( ) {
toolbar [ b ] . onclick ( el , obj , this ) ;
} ;
} ) ( i ) ;
} else {
toolbarItem . onclick = function ( ) {
var k = this . getAttribute ( "data-k" ) ;
var v = this . getAttribute ( "data-v" ) ;
obj . setStyle ( obj . highlighted , k , v ) ;
} ;
}
// Append element
toolbarItem . textContent = toolbar [ i ] . content ;
obj . toolbar . appendChild ( toolbarItem ) ;
} else if ( toolbar [ i ] . type == "select" ) {
var toolbarItem = document . createElement ( "select" ) ;
toolbarItem . classList . add ( "jexcel_toolbar_item" ) ;
toolbarItem . setAttribute ( "data-k" , toolbar [ i ] . k ) ;
// Tooltip
if ( toolbar [ i ] . tooltip ) {
toolbarItem . setAttribute ( "title" , toolbar [ i ] . tooltip ) ;
}
// Handle onchange
if ( toolbar [ i ] . onchange && typeof toolbar [ i ] . onchange ) {
toolbarItem . onchange = toolbar [ i ] . onchange ;
} else {
toolbarItem . onchange = function ( ) {
var k = this . getAttribute ( "data-k" ) ;
obj . setStyle ( obj . highlighted , k , this . value ) ;
} ;
}
// Add options to the dropdown
for ( var j = 0 ; j < toolbar [ i ] . v . length ; j ++ ) {
var toolbarDropdownOption = document . createElement ( "option" ) ;
toolbarDropdownOption . value = toolbar [ i ] . v [ j ] ;
toolbarDropdownOption . textContent = toolbar [ i ] . v [ j ] ;
toolbarItem . appendChild ( toolbarDropdownOption ) ;
}
obj . toolbar . appendChild ( toolbarItem ) ;
} else if ( toolbar [ i ] . type == "color" ) {
var toolbarItem = document . createElement ( "i" ) ;
toolbarItem . classList . add ( "jexcel_toolbar_item" ) ;
toolbarItem . classList . add ( "material-icons" ) ;
toolbarItem . setAttribute ( "data-k" , toolbar [ i ] . k ) ;
toolbarItem . setAttribute ( "data-v" , "" ) ;
// Tooltip
if ( toolbar [ i ] . tooltip ) {
toolbarItem . setAttribute ( "title" , toolbar [ i ] . tooltip ) ;
}
obj . toolbar . appendChild ( toolbarItem ) ;
toolbarItem . textContent = toolbar [ i ] . content ;
jSuites . color ( toolbarItem , {
onchange : function ( o , v ) {
var k = o . getAttribute ( "data-k" ) ;
obj . setStyle ( obj . highlighted , k , v ) ;
} ,
} ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Merge cells
* @ param cellName
* @ param colspan
* @ param rowspan
* @ param ignoreHistoryAndEvents
* /
obj . setMerge = function (
cellName ,
colspan ,
rowspan ,
ignoreHistoryAndEvents
) {
var test = false ;
if ( ! cellName ) {
if ( ! obj . highlighted . length ) {
alert ( obj . options . text . noCellsSelected ) ;
return null ;
} else {
var x1 = parseInt ( obj . highlighted [ 0 ] . getAttribute ( "data-x" ) ) ;
var y1 = parseInt ( obj . highlighted [ 0 ] . getAttribute ( "data-y" ) ) ;
var x2 = parseInt (
obj . highlighted [ obj . highlighted . length - 1 ] . getAttribute ( "data-x" )
) ;
var y2 = parseInt (
obj . highlighted [ obj . highlighted . length - 1 ] . getAttribute ( "data-y" )
) ;
var cellName = jexcel . getColumnNameFromId ( [ x1 , y1 ] ) ;
var colspan = x2 - x1 + 1 ;
var rowspan = y2 - y1 + 1 ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var cell = jexcel . getIdFromColumnName ( cellName , true ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . mergeCells [ cellName ] ) {
if ( obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "data-merged" ) ) {
test = obj . options . text . cellAlreadyMerged ;
}
} else if ( ( ! colspan || colspan < 2 ) && ( ! rowspan || rowspan < 2 ) ) {
test = obj . options . text . invalidMergeProperties ;
} else {
var cells = [ ] ;
for ( var j = cell [ 1 ] ; j < cell [ 1 ] + rowspan ; j ++ ) {
for ( var i = cell [ 0 ] ; i < cell [ 0 ] + colspan ; i ++ ) {
var columnName = jexcel . getColumnNameFromId ( [ i , j ] ) ;
if ( obj . records [ j ] [ i ] . getAttribute ( "data-merged" ) ) {
test = obj . options . text . thereIsAConflictWithAnotherMergedCell ;
}
}
}
}
if ( test ) {
alert ( test ) ;
} else {
// Add property
if ( colspan > 1 ) {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute ( "colspan" , colspan ) ;
} else {
colspan = 1 ;
}
if ( rowspan > 1 ) {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute ( "rowspan" , rowspan ) ;
} else {
rowspan = 1 ;
}
// Keep links to the existing nodes
obj . options . mergeCells [ cellName ] = [ colspan , rowspan , [ ] ] ;
// Mark cell as merged
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute ( "data-merged" , "true" ) ;
// Overflow
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . style . overflow = "hidden" ;
// History data
var data = [ ] ;
// Adjust the nodes
for ( var y = cell [ 1 ] ; y < cell [ 1 ] + rowspan ; y ++ ) {
for ( var x = cell [ 0 ] ; x < cell [ 0 ] + colspan ; x ++ ) {
if ( ! ( cell [ 0 ] == x && cell [ 1 ] == y ) ) {
data . push ( obj . options . data [ y ] [ x ] ) ;
obj . updateCell ( x , y , "" , true ) ;
obj . options . mergeCells [ cellName ] [ 2 ] . push ( obj . records [ y ] [ x ] ) ;
obj . records [ y ] [ x ] . style . display = "none" ;
obj . records [ y ] [ x ] = obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] ;
}
}
}
// In the initialization is not necessary keep the history
obj . updateSelection ( obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] ) ;
if ( ! ignoreHistoryAndEvents ) {
obj . setHistory ( {
action : "setMerge" ,
column : cellName ,
colspan : colspan ,
rowspan : rowspan ,
data : data ,
} ) ;
obj . dispatch ( "onmerge" , el , cellName , colspan , rowspan ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Merge cells
* @ param cellName
* @ param colspan
* @ param rowspan
* @ param ignoreHistoryAndEvents
* /
obj . getMerge = function ( cellName ) {
var data = { } ;
if ( cellName ) {
if ( obj . options . mergeCells [ cellName ] ) {
data = [
obj . options . mergeCells [ cellName ] [ 0 ] ,
obj . options . mergeCells [ cellName ] [ 1 ] ,
] ;
} else {
data = null ;
}
} else {
if ( obj . options . mergeCells ) {
var mergedCells = obj . options . mergeCells ;
var keys = Object . keys ( obj . options . mergeCells ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
data [ keys [ i ] ] = [
obj . options . mergeCells [ keys [ i ] ] [ 0 ] ,
obj . options . mergeCells [ keys [ i ] ] [ 1 ] ,
] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return data ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Remove merge by cellname
* @ param cellName
* /
obj . removeMerge = function ( cellName , data , keepOptions ) {
if ( obj . options . mergeCells [ cellName ] ) {
var cell = jexcel . getIdFromColumnName ( cellName , true ) ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . removeAttribute ( "colspan" ) ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . removeAttribute ( "rowspan" ) ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . removeAttribute ( "data-merged" ) ;
var info = obj . options . mergeCells [ cellName ] ;
var index = 0 ;
for ( var j = 0 ; j < info [ 1 ] ; j ++ ) {
for ( var i = 0 ; i < info [ 0 ] ; i ++ ) {
if ( j > 0 || i > 0 ) {
obj . records [ cell [ 1 ] + j ] [ cell [ 0 ] + i ] = info [ 2 ] [ index ] ;
obj . records [ cell [ 1 ] + j ] [ cell [ 0 ] + i ] . style . display = "" ;
// Recover data
if ( data && data [ index ] ) {
obj . updateCell ( cell [ 0 ] + i , cell [ 1 ] + j , data [ index ] ) ;
}
index ++ ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update selection
obj . updateSelection (
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] ,
obj . records [ cell [ 1 ] + j - 1 ] [ cell [ 0 ] + i - 1 ]
) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! keepOptions ) {
delete obj . options . mergeCells [ cellName ] ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Remove all merged cells
* /
obj . destroyMerged = function ( keepOptions ) {
// Remove any merged cells
if ( obj . options . mergeCells ) {
var mergedCells = obj . options . mergeCells ;
var keys = Object . keys ( obj . options . mergeCells ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
obj . removeMerge ( keys [ i ] , null , keepOptions ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Is column merged
* /
obj . isColMerged = function ( x , insertBefore ) {
var cols = [ ] ;
// Remove any merged cells
if ( obj . options . mergeCells ) {
var keys = Object . keys ( obj . options . mergeCells ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var info = jexcel . getIdFromColumnName ( keys [ i ] , true ) ;
var colspan = obj . options . mergeCells [ keys [ i ] ] [ 0 ] ;
var x1 = info [ 0 ] ;
var x2 = info [ 0 ] + ( colspan > 1 ? colspan - 1 : 0 ) ;
if ( insertBefore == null ) {
if ( x1 <= x && x2 >= x ) {
cols . push ( keys [ i ] ) ;
}
} else {
if ( insertBefore ) {
if ( x1 < x && x2 >= x ) {
cols . push ( keys [ i ] ) ;
}
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
if ( x1 <= x && x2 > x ) {
cols . push ( keys [ i ] ) ;
}
}
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return cols ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Is rows merged
* /
obj . isRowMerged = function ( y , insertBefore ) {
var rows = [ ] ;
// Remove any merged cells
if ( obj . options . mergeCells ) {
var keys = Object . keys ( obj . options . mergeCells ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var info = jexcel . getIdFromColumnName ( keys [ i ] , true ) ;
var rowspan = obj . options . mergeCells [ keys [ i ] ] [ 1 ] ;
var y1 = info [ 1 ] ;
var y2 = info [ 1 ] + ( rowspan > 1 ? rowspan - 1 : 0 ) ;
if ( insertBefore == null ) {
if ( y1 <= y && y2 >= y ) {
rows . push ( keys [ i ] ) ;
}
} else {
if ( insertBefore ) {
if ( y1 < y && y2 >= y ) {
rows . push ( keys [ i ] ) ;
}
} else {
if ( y1 <= y && y2 > y ) {
rows . push ( keys [ i ] ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return rows ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Open the column filter
* /
obj . openFilter = function ( columnId ) {
if ( ! obj . options . filters ) {
console . log ( "Jspreadsheet: filters not enabled." ) ;
} else {
// Make sure is integer
columnId = parseInt ( columnId ) ;
// Reset selection
obj . resetSelection ( ) ;
// Load options
var optionsFiltered = [ ] ;
if ( obj . options . columns [ columnId ] . type == "checkbox" ) {
optionsFiltered . push ( { id : "true" , name : "True" } ) ;
optionsFiltered . push ( { id : "false" , name : "False" } ) ;
} else {
var options = [ ] ;
var hasBlanks = false ;
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
var k = obj . options . data [ j ] [ columnId ] ;
var v = obj . records [ j ] [ columnId ] . innerHTML ;
if ( k && v ) {
options [ k ] = v ;
} else {
var hasBlanks = true ;
}
}
var keys = Object . keys ( options ) ;
var optionsFiltered = [ ] ;
for ( var j = 0 ; j < keys . length ; j ++ ) {
optionsFiltered . push ( { id : keys [ j ] , name : options [ keys [ j ] ] } ) ;
}
// Has blank options
if ( hasBlanks ) {
optionsFiltered . push ( { value : "" , id : "" , name : "(Blanks)" } ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Create dropdown
var div = document . createElement ( "div" ) ;
obj . filter . children [ columnId + 1 ] . innerHTML = "" ;
obj . filter . children [ columnId + 1 ] . appendChild ( div ) ;
obj . filter . children [ columnId + 1 ] . style . paddingLeft = "0px" ;
obj . filter . children [ columnId + 1 ] . style . paddingRight = "0px" ;
obj . filter . children [ columnId + 1 ] . style . overflow = "initial" ;
var opt = {
data : optionsFiltered ,
multiple : true ,
autocomplete : true ,
opened : true ,
value :
obj . filters [ columnId ] !== undefined ? obj . filters [ columnId ] : null ,
width : "100%" ,
position :
obj . options . tableOverflow == true || obj . options . fullscreen == true
? true
: false ,
onclose : function ( o ) {
obj . resetFilters ( ) ;
obj . filters [ columnId ] = o . dropdown . getValue ( true ) ;
obj . filter . children [ columnId + 1 ] . innerHTML = o . dropdown . getText ( ) ;
obj . filter . children [ columnId + 1 ] . style . paddingLeft = "" ;
obj . filter . children [ columnId + 1 ] . style . paddingRight = "" ;
obj . filter . children [ columnId + 1 ] . style . overflow = "" ;
obj . closeFilter ( columnId ) ;
obj . refreshSelection ( ) ;
} ,
2022-07-28 07:33:25 -07:00
} ;
2023-02-16 21:17:00 -05:00
// Dynamic dropdown
jSuites . dropdown ( div , opt ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . resetFilters = function ( ) {
if ( obj . options . filters ) {
for ( var i = 0 ; i < obj . filter . children . length ; i ++ ) {
obj . filter . children [ i ] . innerHTML = " " ;
obj . filters [ i ] = null ;
}
}
obj . results = null ;
obj . updateResult ( ) ;
} ;
obj . closeFilter = function ( columnId ) {
if ( ! columnId ) {
for ( var i = 0 ; i < obj . filter . children . length ; i ++ ) {
if ( obj . filters [ i ] ) {
columnId = i ;
}
}
}
// Search filter
var search = function ( query , x , y ) {
for ( var i = 0 ; i < query . length ; i ++ ) {
var value = "" + obj . options . data [ y ] [ x ] ;
var label = "" + obj . records [ y ] [ x ] . innerHTML ;
if ( query [ i ] == value || query [ i ] == label ) {
return true ;
}
}
return false ;
} ;
var query = obj . filters [ columnId ] ;
obj . results = [ ] ;
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
if ( search ( query , columnId , j ) ) {
obj . results . push ( j ) ;
}
}
if ( ! obj . results . length ) {
obj . results = null ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . updateResult ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Open the editor
*
* @ param object cell
* @ return void
* /
obj . openEditor = function ( cell , empty , e ) {
// Get cell position
var y = cell . getAttribute ( "data-y" ) ;
var x = cell . getAttribute ( "data-x" ) ;
// On edition start
obj . dispatch ( "oneditionstart" , el , cell , x , y ) ;
// Overflow
if ( x > 0 ) {
obj . records [ y ] [ x - 1 ] . style . overflow = "hidden" ;
}
// Create editor
var createEditor = function ( type ) {
// Cell information
var info = cell . getBoundingClientRect ( ) ;
// Create dropdown
var editor = document . createElement ( type ) ;
editor . style . width = info . width + "px" ;
editor . style . height = info . height - 2 + "px" ;
editor . style . minHeight = info . height - 2 + "px" ;
// Edit cell
cell . classList . add ( "editor" ) ;
cell . innerHTML = "" ;
cell . appendChild ( editor ) ;
// On edition start
obj . dispatch ( "oncreateeditor" , el , cell , x , y , editor ) ;
return editor ;
} ;
// Readonly
if ( cell . classList . contains ( "readonly" ) == true ) {
// Do nothing
} else {
// Holder
obj . edition = [ obj . records [ y ] [ x ] , obj . records [ y ] [ x ] . innerHTML , x , y ] ;
// If there is a custom editor for it
if ( obj . options . columns [ x ] . editor ) {
// Custom editors
obj . options . columns [ x ] . editor . openEditor ( cell , el , empty , e ) ;
} else {
// Native functions
if ( obj . options . columns [ x ] . type == "hidden" ) {
// Do nothing
} else if (
obj . options . columns [ x ] . type == "checkbox" ||
obj . options . columns [ x ] . type == "radio"
) {
// Get value
var value = cell . children [ 0 ] . checked ? false : true ;
// Toogle value
obj . setValue ( cell , value ) ;
// Do not keep edition open
obj . edition = null ;
} else if (
obj . options . columns [ x ] . type == "dropdown" ||
obj . options . columns [ x ] . type == "autocomplete"
) {
// Get current value
var value = obj . options . data [ y ] [ x ] ;
if ( obj . options . columns [ x ] . multiple && ! Array . isArray ( value ) ) {
value = value . split ( ";" ) ;
}
// Create dropdown
if ( typeof obj . options . columns [ x ] . filter == "function" ) {
var source = obj . options . columns [ x ] . filter (
el ,
cell ,
x ,
y ,
obj . options . columns [ x ] . source
) ;
} else {
var source = obj . options . columns [ x ] . source ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Do not change the original source
var data = [ ] ;
for ( var j = 0 ; j < source . length ; j ++ ) {
data . push ( source [ j ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Create editor
var editor = createEditor ( "div" ) ;
var options = {
data : data ,
multiple : obj . options . columns [ x ] . multiple ? true : false ,
autocomplete :
obj . options . columns [ x ] . autocomplete ||
obj . options . columns [ x ] . type == "autocomplete"
? true
: false ,
opened : true ,
value : value ,
width : "100%" ,
height : editor . style . minHeight ,
position :
obj . options . tableOverflow == true ||
obj . options . fullscreen == true
? true
: false ,
onclose : function ( ) {
obj . closeEditor ( cell , true ) ;
} ,
} ;
if (
obj . options . columns [ x ] . options &&
obj . options . columns [ x ] . options . type
) {
options . type = obj . options . columns [ x ] . options . type ;
}
jSuites . dropdown ( editor , options ) ;
} else if (
obj . options . columns [ x ] . type == "calendar" ||
obj . options . columns [ x ] . type == "color"
) {
// Value
var value = obj . options . data [ y ] [ x ] ;
// Create editor
var editor = createEditor ( "input" ) ;
editor . value = value ;
if (
obj . options . tableOverflow == true ||
obj . options . fullscreen == true
) {
obj . options . columns [ x ] . options . position = true ;
}
obj . options . columns [ x ] . options . value = obj . options . data [ y ] [ x ] ;
obj . options . columns [ x ] . options . opened = true ;
obj . options . columns [ x ] . options . onclose = function ( el , value ) {
obj . closeEditor ( cell , true ) ;
} ;
// Current value
if ( obj . options . columns [ x ] . type == "color" ) {
jSuites . color ( editor , obj . options . columns [ x ] . options ) ;
} else {
jSuites . calendar ( editor , obj . options . columns [ x ] . options ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Focus on editor
editor . focus ( ) ;
} else if ( obj . options . columns [ x ] . type == "html" ) {
var value = obj . options . data [ y ] [ x ] ;
// Create editor
var editor = createEditor ( "div" ) ;
editor . style . position = "relative" ;
var div = document . createElement ( "div" ) ;
div . classList . add ( "jexcel_richtext" ) ;
editor . appendChild ( div ) ;
jSuites . editor ( div , {
focus : true ,
value : value ,
} ) ;
var rect = cell . getBoundingClientRect ( ) ;
var rectContent = div . getBoundingClientRect ( ) ;
if ( window . innerHeight < rect . bottom + rectContent . height ) {
div . style . top = rect . top - ( rectContent . height + 2 ) + "px" ;
} else {
div . style . top = rect . top + "px" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else if ( obj . options . columns [ x ] . type == "image" ) {
// Value
var img = cell . children [ 0 ] ;
// Create editor
var editor = createEditor ( "div" ) ;
editor . style . position = "relative" ;
var div = document . createElement ( "div" ) ;
div . classList . add ( "jclose" ) ;
if ( img && img . src ) {
div . appendChild ( img ) ;
}
editor . appendChild ( div ) ;
jSuites . image ( div , obj . options . imageOptions ) ;
var rect = cell . getBoundingClientRect ( ) ;
var rectContent = div . getBoundingClientRect ( ) ;
if ( window . innerHeight < rect . bottom + rectContent . height ) {
div . style . top = rect . top - ( rectContent . height + 2 ) + "px" ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
div . style . top = rect . top + "px" ;
}
} else {
// Value
var value = empty == true ? "" : obj . options . data [ y ] [ x ] ;
// Basic editor
if (
obj . options . columns [ x ] . wordWrap != false &&
( obj . options . wordWrap == true ||
obj . options . columns [ x ] . wordWrap == true )
) {
var editor = createEditor ( "textarea" ) ;
} else {
var editor = createEditor ( "input" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
editor . focus ( ) ;
editor . value = value ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Column options
var options = obj . options . columns [ x ] ;
// Format
var opt = null ;
// Apply format when is not a formula
if ( ! isFormula ( value ) ) {
// Format
if ( ( opt = getMask ( options ) ) ) {
// Masking
if ( ! options . disabledMaskOnEdition ) {
if ( options . mask ) {
var m = options . mask . split ( ";" ) ;
editor . setAttribute ( "data-mask" , m [ 0 ] ) ;
} else if ( options . locale ) {
editor . setAttribute ( "data-locale" , options . locale ) ;
}
}
// Input
opt . input = editor ;
// Configuration
editor . mask = opt ;
// Do not treat the decimals
jSuites . mask . render ( value , opt , false ) ;
}
}
editor . onblur = function ( ) {
obj . closeEditor ( cell , true ) ;
} ;
editor . scrollLeft = editor . scrollWidth ;
}
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Close the editor and save the information
*
* @ param object cell
* @ param boolean save
* @ return void
* /
obj . closeEditor = function ( cell , save ) {
var x = parseInt ( cell . getAttribute ( "data-x" ) ) ;
var y = parseInt ( cell . getAttribute ( "data-y" ) ) ;
// Get cell properties
if ( save == true ) {
// If custom editor
if ( obj . options . columns [ x ] . editor ) {
// Custom editor
var value = obj . options . columns [ x ] . editor . closeEditor ( cell , save ) ;
} else {
// Native functions
if (
obj . options . columns [ x ] . type == "checkbox" ||
obj . options . columns [ x ] . type == "radio" ||
obj . options . columns [ x ] . type == "hidden"
) {
// Do nothing
} else if (
obj . options . columns [ x ] . type == "dropdown" ||
obj . options . columns [ x ] . type == "autocomplete"
) {
var value = cell . children [ 0 ] . dropdown . close ( true ) ;
} else if ( obj . options . columns [ x ] . type == "calendar" ) {
var value = cell . children [ 0 ] . calendar . close ( true ) ;
} else if ( obj . options . columns [ x ] . type == "color" ) {
var value = cell . children [ 0 ] . color . close ( true ) ;
} else if ( obj . options . columns [ x ] . type == "html" ) {
var value = cell . children [ 0 ] . children [ 0 ] . editor . getData ( ) ;
} else if ( obj . options . columns [ x ] . type == "image" ) {
var img = cell . children [ 0 ] . children [ 0 ] . children [ 0 ] ;
var value = img && img . tagName == "IMG" ? img . src : "" ;
} else if ( obj . options . columns [ x ] . type == "numeric" ) {
var value = cell . children [ 0 ] . value ;
if ( ( "" + value ) . substr ( 0 , 1 ) != "=" ) {
if ( value == "" ) {
value = obj . options . columns [ x ] . allowEmpty ? "" : 0 ;
}
}
cell . children [ 0 ] . onblur = null ;
} else {
var value = cell . children [ 0 ] . value ;
cell . children [ 0 ] . onblur = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Column options
var options = obj . options . columns [ x ] ;
// Format
var opt = null ;
if ( ( opt = getMask ( options ) ) ) {
// Keep numeric in the raw data
if (
value !== "" &&
! isFormula ( value ) &&
typeof value !== "number"
) {
var t = jSuites . mask . extract ( value , opt , true ) ;
if ( t && t . value !== "" ) {
value = t . value ;
}
}
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Ignore changes if the value is the same
if ( obj . options . data [ y ] [ x ] == value ) {
cell . innerHTML = obj . edition [ 1 ] ;
} else {
obj . setValue ( cell , value ) ;
}
} else {
if ( obj . options . columns [ x ] . editor ) {
// Custom editor
obj . options . columns [ x ] . editor . closeEditor ( cell , save ) ;
} else {
if (
obj . options . columns [ x ] . type == "dropdown" ||
obj . options . columns [ x ] . type == "autocomplete"
) {
cell . children [ 0 ] . dropdown . close ( true ) ;
} else if ( obj . options . columns [ x ] . type == "calendar" ) {
cell . children [ 0 ] . calendar . close ( true ) ;
} else if ( obj . options . columns [ x ] . type == "color" ) {
cell . children [ 0 ] . color . close ( true ) ;
} else {
cell . children [ 0 ] . onblur = null ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Restore value
cell . innerHTML = obj . edition && obj . edition [ 1 ] ? obj . edition [ 1 ] : "" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On edition end
obj . dispatch ( "oneditionend" , el , cell , x , y , value , save ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Remove editor class
cell . classList . remove ( "editor" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Finish edition
obj . edition = null ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the cell object
*
* @ param object cell
* @ return string value
* /
obj . getCell = function ( cell ) {
// Convert in case name is excel liked ex. A10, BB92
cell = jexcel . getIdFromColumnName ( cell , true ) ;
var x = cell [ 0 ] ;
var y = cell [ 1 ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return obj . records [ y ] [ x ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the column options
* @ param x
* @ param y
* @ returns { { type : string } }
* /
obj . getColumnOptions = function ( x , y ) {
// Type
var options = obj . options . columns [ x ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Cell type
if ( ! options ) {
options = { type : "text" } ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return options ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the cell object from coords
*
* @ param object cell
* @ return string value
* /
obj . getCellFromCoords = function ( x , y ) {
return obj . records [ y ] [ x ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get label
*
* @ param object cell
* @ return string value
* /
obj . getLabel = function ( cell ) {
// Convert in case name is excel liked ex. A10, BB92
cell = jexcel . getIdFromColumnName ( cell , true ) ;
var x = cell [ 0 ] ;
var y = cell [ 1 ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return obj . records [ y ] [ x ] . innerHTML ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get labelfrom coords
*
* @ param object cell
* @ return string value
* /
obj . getLabelFromCoords = function ( x , y ) {
return obj . records [ y ] [ x ] . innerHTML ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the value from a cell
*
* @ param object cell
* @ return string value
* /
obj . getValue = function ( cell , processedValue ) {
if ( typeof cell == "object" ) {
var x = cell . getAttribute ( "data-x" ) ;
var y = cell . getAttribute ( "data-y" ) ;
} else {
cell = jexcel . getIdFromColumnName ( cell , true ) ;
var x = cell [ 0 ] ;
var y = cell [ 1 ] ;
}
var value = null ;
if ( x != null && y != null ) {
if (
obj . records [ y ] &&
obj . records [ y ] [ x ] &&
( processedValue || obj . options . copyCompatibility == true )
) {
value = obj . records [ y ] [ x ] . innerHTML ;
} else {
if ( obj . options . data [ y ] && obj . options . data [ y ] [ x ] != "undefined" ) {
value = obj . options . data [ y ] [ x ] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return value ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the value from a coords
*
* @ param int x
* @ param int y
* @ return string value
* /
obj . getValueFromCoords = function ( x , y , processedValue ) {
var value = null ;
if ( x != null && y != null ) {
if (
( obj . records [ y ] && obj . records [ y ] [ x ] && processedValue ) ||
obj . options . copyCompatibility == true
) {
value = obj . records [ y ] [ x ] . innerHTML ;
} else {
if ( obj . options . data [ y ] && obj . options . data [ y ] [ x ] != "undefined" ) {
value = obj . options . data [ y ] [ x ] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return value ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set a cell value
*
* @ param mixed cell destination cell
* @ param string value value
* @ return void
* /
obj . setValue = function ( cell , value , force ) {
var records = [ ] ;
if ( typeof cell == "string" ) {
var columnId = jexcel . getIdFromColumnName ( cell , true ) ;
var x = columnId [ 0 ] ;
var y = columnId [ 1 ] ;
// Update cell
records . push ( obj . updateCell ( x , y , value , force ) ) ;
// Update all formulas in the chain
obj . updateFormulaChain ( x , y , records ) ;
} else {
var x = null ;
var y = null ;
if ( cell && cell . getAttribute ) {
var x = cell . getAttribute ( "data-x" ) ;
var y = cell . getAttribute ( "data-y" ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update cell
if ( x != null && y != null ) {
records . push ( obj . updateCell ( x , y , value , force ) ) ;
// Update all formulas in the chain
obj . updateFormulaChain ( x , y , records ) ;
} else {
var keys = Object . keys ( cell ) ;
if ( keys . length > 0 ) {
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( typeof cell [ i ] == "string" ) {
var columnId = jexcel . getIdFromColumnName ( cell [ i ] , true ) ;
var x = columnId [ 0 ] ;
var y = columnId [ 1 ] ;
} else {
if ( cell [ i ] . x != null && cell [ i ] . y != null ) {
var x = cell [ i ] . x ;
var y = cell [ i ] . y ;
// Flexible setup
if ( cell [ i ] . newValue != null ) {
value = cell [ i ] . newValue ;
} else if ( cell [ i ] . value != null ) {
value = cell [ i ] . value ;
}
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
var x = cell [ i ] . getAttribute ( "data-x" ) ;
var y = cell [ i ] . getAttribute ( "data-y" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update cell
if ( x != null && y != null ) {
records . push ( obj . updateCell ( x , y , value , force ) ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update all formulas in the chain
obj . updateFormulaChain ( x , y , records ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update history
obj . setHistory ( {
action : "setValue" ,
records : records ,
selection : obj . selectedCell ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table with custom configurations if applicable
obj . updateTable ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On after changes
obj . onafterchanges ( el , records ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set a cell value based on coordinates
*
* @ param int x destination cell
* @ param int y destination cell
* @ param string value
* @ return void
* /
obj . setValueFromCoords = function ( x , y , value , force ) {
var records = [ ] ;
records . push ( obj . updateCell ( x , y , value , force ) ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update all formulas in the chain
obj . updateFormulaChain ( x , y , records ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update history
obj . setHistory ( {
action : "setValue" ,
records : records ,
selection : obj . selectedCell ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table with custom configurations if applicable
obj . updateTable ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On after changes
obj . onafterchanges ( el , records ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Toogle
* /
obj . setCheckRadioValue = function ( ) {
var records = [ ] ;
var keys = Object . keys ( obj . highlighted ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var x = obj . highlighted [ i ] . getAttribute ( "data-x" ) ;
var y = obj . highlighted [ i ] . getAttribute ( "data-y" ) ;
if (
obj . options . columns [ x ] . type == "checkbox" ||
obj . options . columns [ x ] . type == "radio"
) {
// Update cell
records . push ( obj . updateCell ( x , y , ! obj . options . data [ y ] [ x ] ) ) ;
}
}
if ( records . length ) {
// Update history
obj . setHistory ( {
action : "setValue" ,
records : records ,
selection : obj . selectedCell ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On after changes
obj . onafterchanges ( el , records ) ;
}
} ;
/ * *
* Strip tags
* /
var stripScript = function ( a ) {
var b = new Option ( ) ;
b . innerHTML = a ;
var c = null ;
for ( a = b . getElementsByTagName ( "script" ) ; ( c = a [ 0 ] ) ; )
c . parentNode . removeChild ( c ) ;
return b . innerHTML ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update cell content
*
* @ param object cell
* @ return void
* /
obj . updateCell = function ( x , y , value , force ) {
// Changing value depending on the column type
if ( obj . records [ y ] [ x ] . classList . contains ( "readonly" ) == true && ! force ) {
// Do nothing
var record = {
x : x ,
y : y ,
col : x ,
row : y ,
} ;
} else {
// Security
if (
( "" + value ) . substr ( 0 , 1 ) == "=" &&
obj . options . secureFormulas == true
) {
var val = secureFormula ( value ) ;
if ( val != value ) {
// Update the data container
value = val ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On change
var val = obj . dispatch (
"onbeforechange" ,
el ,
obj . records [ y ] [ x ] ,
x ,
y ,
value
) ;
// If you return something this will overwrite the value
if ( val != undefined ) {
value = val ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if (
obj . options . columns [ x ] . editor &&
typeof obj . options . columns [ x ] . editor . updateCell == "function"
) {
value = obj . options . columns [ x ] . editor . updateCell (
obj . records [ y ] [ x ] ,
value ,
force
) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// History format
var record = {
x : x ,
y : y ,
col : x ,
row : y ,
newValue : value ,
oldValue : obj . options . data [ y ] [ x ] ,
2022-07-28 07:33:25 -07:00
} ;
2023-02-16 21:17:00 -05:00
if ( obj . options . columns [ x ] . editor ) {
// Update data and cell
obj . options . data [ y ] [ x ] = value ;
} else {
// Native functions
if (
obj . options . columns [ x ] . type == "checkbox" ||
obj . options . columns [ x ] . type == "radio"
) {
// Unchecked all options
if ( obj . options . columns [ x ] . type == "radio" ) {
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
obj . options . data [ j ] [ x ] = false ;
}
}
// Update data and cell
obj . records [ y ] [ x ] . children [ 0 ] . checked =
value == 1 || value == true || value == "true" || value == "TRUE"
? true
: false ;
obj . options . data [ y ] [ x ] = obj . records [ y ] [ x ] . children [ 0 ] . checked ;
} else if (
obj . options . columns [ x ] . type == "dropdown" ||
obj . options . columns [ x ] . type == "autocomplete"
) {
// Update data and cell
obj . options . data [ y ] [ x ] = value ;
obj . records [ y ] [ x ] . textContent = obj . getDropDownValue ( x , value ) ;
} else if ( obj . options . columns [ x ] . type == "calendar" ) {
// Try formatted date
var formatted = null ;
if ( ! validDate ( value ) ) {
var tmp = jSuites . calendar . extractDateFromString (
value ,
obj . options . columns [ x ] . options . format
) ;
if ( tmp ) {
formatted = tmp ;
}
}
// Update data and cell
obj . options . data [ y ] [ x ] = value ;
obj . records [ y ] [ x ] . textContent = jSuites . calendar . getDateString (
formatted ? formatted : value ,
obj . options . columns [ x ] . options . format
) ;
} else if ( obj . options . columns [ x ] . type == "color" ) {
// Update color
obj . options . data [ y ] [ x ] = value ;
// Render
if ( obj . options . columns [ x ] . render == "square" ) {
var color = document . createElement ( "div" ) ;
color . className = "color" ;
color . style . backgroundColor = value ;
obj . records [ y ] [ x ] . textContent = "" ;
obj . records [ y ] [ x ] . appendChild ( color ) ;
} else {
obj . records [ y ] [ x ] . style . color = value ;
obj . records [ y ] [ x ] . textContent = value ;
}
} else if ( obj . options . columns [ x ] . type == "image" ) {
value = "" + value ;
obj . options . data [ y ] [ x ] = value ;
obj . records [ y ] [ x ] . innerHTML = "" ;
if ( value && value . substr ( 0 , 10 ) == "data:image" ) {
var img = document . createElement ( "img" ) ;
img . src = value ;
obj . records [ y ] [ x ] . appendChild ( img ) ;
}
} else {
// Update data and cell
obj . options . data [ y ] [ x ] = value ;
// Label
if ( obj . options . columns [ x ] . type == "html" ) {
obj . records [ y ] [ x ] . innerHTML = stripScript (
obj . parseValue ( x , y , value )
) ;
} else {
if (
obj . options . stripHTML === false ||
obj . options . columns [ x ] . stripHTML === false
) {
obj . records [ y ] [ x ] . innerHTML = stripScript (
obj . parseValue ( x , y , value , obj . records [ y ] [ x ] )
) ;
} else {
obj . records [ y ] [ x ] . textContent = obj . parseValue (
x ,
y ,
value ,
obj . records [ y ] [ x ]
) ;
}
}
// Handle big text inside a cell
if (
obj . options . columns [ x ] . wordWrap != false &&
( obj . options . wordWrap == true ||
obj . options . columns [ x ] . wordWrap == true ||
obj . records [ y ] [ x ] . innerHTML . length > 200 )
) {
obj . records [ y ] [ x ] . style . whiteSpace = "pre-wrap" ;
} else {
obj . records [ y ] [ x ] . style . whiteSpace = "" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Overflow
if ( x > 0 ) {
if ( value ) {
obj . records [ y ] [ x - 1 ] . style . overflow = "hidden" ;
} else {
obj . records [ y ] [ x - 1 ] . style . overflow = "" ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// On change
obj . dispatch (
"onchange" ,
el ,
obj . records [ y ] && obj . records [ y ] [ x ] ? obj . records [ y ] [ x ] : null ,
x ,
y ,
value ,
record . oldValue
) ;
}
return record ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Helper function to copy data using the corner icon
* /
obj . copyData = function ( o , d ) {
// Get data from all selected cells
var data = obj . getData ( true , true ) ;
// Selected cells
var h = obj . selectedContainer ;
// Cells
var x1 = parseInt ( o . getAttribute ( "data-x" ) ) ;
var y1 = parseInt ( o . getAttribute ( "data-y" ) ) ;
var x2 = parseInt ( d . getAttribute ( "data-x" ) ) ;
var y2 = parseInt ( d . getAttribute ( "data-y" ) ) ;
// Records
var records = [ ] ;
var breakControl = false ;
if ( h [ 0 ] == x1 ) {
// Vertical copy
if ( y1 < h [ 1 ] ) {
var rowNumber = y1 - h [ 1 ] ;
} else {
var rowNumber = 1 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var colNumber = 0 ;
} else {
if ( x1 < h [ 0 ] ) {
var colNumber = x1 - h [ 0 ] ;
} else {
var colNumber = 1 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var rowNumber = 0 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Copy data procedure
var posx = 0 ;
var posy = 0 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var j = y1 ; j <= y2 ; j ++ ) {
// Skip hidden rows
if ( obj . rows [ j ] && obj . rows [ j ] . style . display == "none" ) {
continue ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Controls
if ( data [ posy ] == undefined ) {
posy = 0 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
posx = 0 ;
// Data columns
if ( h [ 0 ] != x1 ) {
if ( x1 < h [ 0 ] ) {
var colNumber = x1 - h [ 0 ] ;
} else {
var colNumber = 1 ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Data columns
for ( var i = x1 ; i <= x2 ; i ++ ) {
// Update non-readonly
if (
obj . records [ j ] [ i ] &&
! obj . records [ j ] [ i ] . classList . contains ( "readonly" ) &&
obj . records [ j ] [ i ] . style . display != "none" &&
breakControl == false
) {
// Stop if contains value
if ( ! obj . selection . length ) {
if ( obj . options . data [ j ] [ i ] != "" ) {
breakControl = true ;
continue ;
}
}
// Column
if ( data [ posy ] == undefined ) {
posx = 0 ;
} else if ( data [ posy ] [ posx ] == undefined ) {
posx = 0 ;
}
// Value
var value = data [ posy ] [ posx ] ;
if ( value && ! data [ 1 ] && obj . options . autoIncrement == true ) {
if (
obj . options . columns [ i ] . type == "text" ||
obj . options . columns [ i ] . type == "number"
) {
if ( ( "" + value ) . substr ( 0 , 1 ) == "=" ) {
var tokens = value . match ( /([A-Z]+[0-9]+)/g ) ;
if ( tokens ) {
var affectedTokens = [ ] ;
for ( var index = 0 ; index < tokens . length ; index ++ ) {
var position = jexcel . getIdFromColumnName (
tokens [ index ] ,
1
) ;
position [ 0 ] += colNumber ;
position [ 1 ] += rowNumber ;
if ( position [ 1 ] < 0 ) {
position [ 1 ] = 0 ;
}
var token = jexcel . getColumnNameFromId ( [
position [ 0 ] ,
position [ 1 ] ,
] ) ;
if ( token != tokens [ index ] ) {
affectedTokens [ tokens [ index ] ] = token ;
}
}
// Update formula
if ( affectedTokens ) {
value = obj . updateFormula ( value , affectedTokens ) ;
}
}
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
if ( value == Number ( value ) ) {
value = Number ( value ) + rowNumber ;
}
}
} else if ( obj . options . columns [ i ] . type == "calendar" ) {
var date = new Date ( value ) ;
date . setDate ( date . getDate ( ) + rowNumber ) ;
value =
date . getFullYear ( ) +
"-" +
jexcel . doubleDigitFormat ( parseInt ( date . getMonth ( ) + 1 ) ) +
"-" +
jexcel . doubleDigitFormat ( date . getDate ( ) ) +
" " +
"00:00:00" ;
}
}
records . push ( obj . updateCell ( i , j , value ) ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update all formulas in the chain
obj . updateFormulaChain ( i , j , records ) ;
}
posx ++ ;
if ( h [ 0 ] != x1 ) {
colNumber ++ ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
posy ++ ;
rowNumber ++ ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update history
obj . setHistory ( {
action : "setValue" ,
records : records ,
selection : obj . selectedCell ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table with custom configuration if applicable
obj . updateTable ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On after changes
obj . onafterchanges ( el , records ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Refresh current selection
* /
obj . refreshSelection = function ( ) {
if ( obj . selectedCell ) {
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Move coords to A1 in case overlaps with an excluded cell
* /
obj . conditionalSelectionUpdate = function ( type , o , d ) {
if ( type == 1 ) {
if (
obj . selectedCell &&
( ( o >= obj . selectedCell [ 1 ] && o <= obj . selectedCell [ 3 ] ) ||
( d >= obj . selectedCell [ 1 ] && d <= obj . selectedCell [ 3 ] ) )
) {
obj . resetSelection ( ) ;
return ;
}
} else {
if (
obj . selectedCell &&
( ( o >= obj . selectedCell [ 0 ] && o <= obj . selectedCell [ 2 ] ) ||
( d >= obj . selectedCell [ 0 ] && d <= obj . selectedCell [ 2 ] ) )
) {
obj . resetSelection ( ) ;
return ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Clear table selection
* /
obj . resetSelection = function ( blur ) {
// Remove style
if ( ! obj . highlighted . length ) {
var previousStatus = 0 ;
} else {
var previousStatus = 1 ;
for ( var i = 0 ; i < obj . highlighted . length ; i ++ ) {
obj . highlighted [ i ] . classList . remove ( "highlight" ) ;
obj . highlighted [ i ] . classList . remove ( "highlight-left" ) ;
obj . highlighted [ i ] . classList . remove ( "highlight-right" ) ;
obj . highlighted [ i ] . classList . remove ( "highlight-top" ) ;
obj . highlighted [ i ] . classList . remove ( "highlight-bottom" ) ;
obj . highlighted [ i ] . classList . remove ( "highlight-selected" ) ;
var px = parseInt ( obj . highlighted [ i ] . getAttribute ( "data-x" ) ) ;
var py = parseInt ( obj . highlighted [ i ] . getAttribute ( "data-y" ) ) ;
// Check for merged cells
if ( obj . highlighted [ i ] . getAttribute ( "data-merged" ) ) {
var colspan = parseInt ( obj . highlighted [ i ] . getAttribute ( "colspan" ) ) ;
var rowspan = parseInt ( obj . highlighted [ i ] . getAttribute ( "rowspan" ) ) ;
var ux = colspan > 0 ? px + ( colspan - 1 ) : px ;
var uy = rowspan > 0 ? py + ( rowspan - 1 ) : py ;
} else {
var ux = px ;
var uy = py ;
}
// Remove selected from headers
for ( var j = px ; j <= ux ; j ++ ) {
if ( obj . headers [ j ] ) {
obj . headers [ j ] . classList . remove ( "selected" ) ;
}
}
// Remove selected from rows
for ( var j = py ; j <= uy ; j ++ ) {
if ( obj . rows [ j ] ) {
obj . rows [ j ] . classList . remove ( "selected" ) ;
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Reset highlighted cells
obj . highlighted = [ ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Reset
obj . selectedCell = null ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Hide corner
obj . corner . style . top = "-2000px" ;
obj . corner . style . left = "-2000px" ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( blur == true && previousStatus == 1 ) {
obj . dispatch ( "onblur" , el ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return previousStatus ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update selection based on two cells
* /
obj . updateSelection = function ( el1 , el2 , origin ) {
var x1 = el1 . getAttribute ( "data-x" ) ;
var y1 = el1 . getAttribute ( "data-y" ) ;
if ( el2 ) {
var x2 = el2 . getAttribute ( "data-x" ) ;
var y2 = el2 . getAttribute ( "data-y" ) ;
} else {
var x2 = x1 ;
var y2 = y1 ;
}
obj . updateSelectionFromCoords ( x1 , y1 , x2 , y2 , origin ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update selection from coords
* /
obj . updateSelectionFromCoords = function ( x1 , y1 , x2 , y2 , origin ) {
// Reset Selection
var updated = null ;
var previousState = obj . resetSelection ( ) ;
// select column
if ( y1 == null ) {
y1 = 0 ;
y2 = obj . rows . length - 1 ;
}
// Same element
if ( x2 == null ) {
x2 = x1 ;
}
if ( y2 == null ) {
y2 = y1 ;
}
// Selection must be within the existing data
if ( x1 >= obj . headers . length ) {
x1 = obj . headers . length - 1 ;
}
if ( y1 >= obj . rows . length ) {
y1 = obj . rows . length - 1 ;
}
if ( x2 >= obj . headers . length ) {
x2 = obj . headers . length - 1 ;
}
if ( y2 >= obj . rows . length ) {
y2 = obj . rows . length - 1 ;
}
// Keep selected cell
obj . selectedCell = [ x1 , y1 , x2 , y2 ] ;
// Select cells
if ( x1 != null ) {
// Add selected cell
if ( obj . records [ y1 ] [ x1 ] ) {
obj . records [ y1 ] [ x1 ] . classList . add ( "highlight-selected" ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Origin & Destination
if ( parseInt ( x1 ) < parseInt ( x2 ) ) {
var px = parseInt ( x1 ) ;
var ux = parseInt ( x2 ) ;
} else {
var px = parseInt ( x2 ) ;
var ux = parseInt ( x1 ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( parseInt ( y1 ) < parseInt ( y2 ) ) {
var py = parseInt ( y1 ) ;
var uy = parseInt ( y2 ) ;
} else {
var py = parseInt ( y2 ) ;
var uy = parseInt ( y1 ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Verify merged columns
for ( var i = px ; i <= ux ; i ++ ) {
for ( var j = py ; j <= uy ; j ++ ) {
if (
obj . records [ j ] [ i ] &&
obj . records [ j ] [ i ] . getAttribute ( "data-merged" )
) {
var x = parseInt ( obj . records [ j ] [ i ] . getAttribute ( "data-x" ) ) ;
var y = parseInt ( obj . records [ j ] [ i ] . getAttribute ( "data-y" ) ) ;
var colspan = parseInt ( obj . records [ j ] [ i ] . getAttribute ( "colspan" ) ) ;
var rowspan = parseInt ( obj . records [ j ] [ i ] . getAttribute ( "rowspan" ) ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( colspan > 1 ) {
if ( x < px ) {
px = x ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( x + colspan > ux ) {
ux = x + colspan - 1 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( rowspan ) {
if ( y < py ) {
py = y ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( y + rowspan > uy ) {
uy = y + rowspan - 1 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Limits
var borderLeft = null ;
var borderRight = null ;
var borderTop = null ;
var borderBottom = null ;
// Vertical limits
for ( var j = py ; j <= uy ; j ++ ) {
if ( obj . rows [ j ] . style . display != "none" ) {
if ( borderTop == null ) {
borderTop = j ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
borderBottom = j ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Redefining styles
for ( var i = px ; i <= ux ; i ++ ) {
for ( var j = py ; j <= uy ; j ++ ) {
if (
obj . rows [ j ] . style . display != "none" &&
obj . records [ j ] [ i ] . style . display != "none"
) {
obj . records [ j ] [ i ] . classList . add ( "highlight" ) ;
obj . highlighted . push ( obj . records [ j ] [ i ] ) ;
}
}
// Horizontal limits
if ( obj . options . columns [ i ] . type != "hidden" ) {
if ( borderLeft == null ) {
borderLeft = i ;
}
borderRight = i ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Create borders
if ( ! borderLeft ) {
borderLeft = 0 ;
}
if ( ! borderRight ) {
borderRight = 0 ;
}
for ( var i = borderLeft ; i <= borderRight ; i ++ ) {
if ( obj . options . columns [ i ] . type != "hidden" ) {
// Top border
if ( obj . records [ borderTop ] && obj . records [ borderTop ] [ i ] ) {
obj . records [ borderTop ] [ i ] . classList . add ( "highlight-top" ) ;
}
// Bottom border
if ( obj . records [ borderBottom ] && obj . records [ borderBottom ] [ i ] ) {
obj . records [ borderBottom ] [ i ] . classList . add ( "highlight-bottom" ) ;
}
// Add selected from headers
obj . headers [ i ] . classList . add ( "selected" ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var j = borderTop ; j <= borderBottom ; j ++ ) {
if ( obj . rows [ j ] && obj . rows [ j ] . style . display != "none" ) {
// Left border
obj . records [ j ] [ borderLeft ] . classList . add ( "highlight-left" ) ;
// Right border
obj . records [ j ] [ borderRight ] . classList . add ( "highlight-right" ) ;
// Add selected from rows
obj . rows [ j ] . classList . add ( "selected" ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . selectedContainer = [
borderLeft ,
borderTop ,
borderRight ,
borderBottom ,
] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Handle events
if ( previousState == 0 ) {
obj . dispatch ( "onfocus" , el ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . removeCopyingSelection ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . dispatch (
"onselection" ,
el ,
borderLeft ,
borderTop ,
borderRight ,
borderBottom ,
origin
) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Find corner cell
obj . updateCornerPosition ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Remove copy selection
*
* @ return void
* /
obj . removeCopySelection = function ( ) {
// Remove current selection
for ( var i = 0 ; i < obj . selection . length ; i ++ ) {
obj . selection [ i ] . classList . remove ( "selection" ) ;
obj . selection [ i ] . classList . remove ( "selection-left" ) ;
obj . selection [ i ] . classList . remove ( "selection-right" ) ;
obj . selection [ i ] . classList . remove ( "selection-top" ) ;
obj . selection [ i ] . classList . remove ( "selection-bottom" ) ;
}
obj . selection = [ ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update copy selection
*
* @ param int x , y
* @ return void
* /
obj . updateCopySelection = function ( x3 , y3 ) {
// Remove selection
obj . removeCopySelection ( ) ;
// Get elements first and last
var x1 = obj . selectedContainer [ 0 ] ;
var y1 = obj . selectedContainer [ 1 ] ;
var x2 = obj . selectedContainer [ 2 ] ;
var y2 = obj . selectedContainer [ 3 ] ;
if ( x3 != null && y3 != null ) {
if ( x3 - x2 > 0 ) {
var px = parseInt ( x2 ) + 1 ;
var ux = parseInt ( x3 ) ;
} else {
var px = parseInt ( x3 ) ;
var ux = parseInt ( x1 ) - 1 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( y3 - y2 > 0 ) {
var py = parseInt ( y2 ) + 1 ;
var uy = parseInt ( y3 ) ;
} else {
var py = parseInt ( y3 ) ;
var uy = parseInt ( y1 ) - 1 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ux - px <= uy - py ) {
var px = parseInt ( x1 ) ;
var ux = parseInt ( x2 ) ;
} else {
var py = parseInt ( y1 ) ;
var uy = parseInt ( y2 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
for ( var j = py ; j <= uy ; j ++ ) {
for ( var i = px ; i <= ux ; i ++ ) {
if (
obj . records [ j ] [ i ] &&
obj . rows [ j ] . style . display != "none" &&
obj . records [ j ] [ i ] . style . display != "none"
) {
obj . records [ j ] [ i ] . classList . add ( "selection" ) ;
obj . records [ py ] [ i ] . classList . add ( "selection-top" ) ;
obj . records [ uy ] [ i ] . classList . add ( "selection-bottom" ) ;
obj . records [ j ] [ px ] . classList . add ( "selection-left" ) ;
obj . records [ j ] [ ux ] . classList . add ( "selection-right" ) ;
// Persist selected elements
obj . selection . push ( obj . records [ j ] [ i ] ) ;
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update corner position
*
* @ return void
* /
obj . updateCornerPosition = function ( ) {
// If any selected cells
if ( ! obj . highlighted . length ) {
obj . corner . style . top = "-2000px" ;
obj . corner . style . left = "-2000px" ;
} else {
// Get last cell
var last = obj . highlighted [ obj . highlighted . length - 1 ] ;
var lastX = last . getAttribute ( "data-x" ) ;
var contentRect = obj . content . getBoundingClientRect ( ) ;
var x1 = contentRect . left ;
var y1 = contentRect . top ;
var lastRect = last . getBoundingClientRect ( ) ;
var x2 = lastRect . left ;
var y2 = lastRect . top ;
var w2 = lastRect . width ;
var h2 = lastRect . height ;
var x = x2 - x1 + obj . content . scrollLeft + w2 - 4 ;
var y = y2 - y1 + obj . content . scrollTop + h2 - 4 ;
// Place the corner in the correct place
obj . corner . style . top = y + "px" ;
obj . corner . style . left = x + "px" ;
if ( obj . options . freezeColumns ) {
var width = obj . getFreezeWidth ( ) ;
// Only check if the last column is not part of the merged cells
if ( lastX > obj . options . freezeColumns - 1 && x2 - x1 + w2 < width ) {
obj . corner . style . display = "none" ;
} else {
if ( obj . options . selectionCopy == true ) {
obj . corner . style . display = "" ;
}
}
} else {
if ( obj . options . selectionCopy == true ) {
obj . corner . style . display = "" ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update scroll position based on the selection
* /
obj . updateScroll = function ( direction ) {
// Jspreadsheet Container information
var contentRect = obj . content . getBoundingClientRect ( ) ;
var x1 = contentRect . left ;
var y1 = contentRect . top ;
var w1 = contentRect . width ;
var h1 = contentRect . height ;
// Direction Left or Up
var reference = obj . records [ obj . selectedCell [ 3 ] ] [ obj . selectedCell [ 2 ] ] ;
// Reference
var referenceRect = reference . getBoundingClientRect ( ) ;
var x2 = referenceRect . left ;
var y2 = referenceRect . top ;
var w2 = referenceRect . width ;
var h2 = referenceRect . height ;
// Direction
if ( direction == 0 || direction == 1 ) {
var x = x2 - x1 + obj . content . scrollLeft ;
var y = y2 - y1 + obj . content . scrollTop - 2 ;
} else {
var x = x2 - x1 + obj . content . scrollLeft + w2 ;
var y = y2 - y1 + obj . content . scrollTop + h2 ;
}
// Top position check
if ( y > obj . content . scrollTop + 30 && y < obj . content . scrollTop + h1 ) {
// In the viewport
} else {
// Out of viewport
if ( y < obj . content . scrollTop + 30 ) {
obj . content . scrollTop = y - h2 ;
} else {
obj . content . scrollTop = y - ( h1 - 2 ) ;
}
}
// Freeze columns?
var freezed = obj . getFreezeWidth ( ) ;
// Left position check - TODO: change that to the bottom border of the element
if (
x > obj . content . scrollLeft + freezed &&
x < obj . content . scrollLeft + w1
) {
// In the viewport
} else {
// Out of viewport
if ( x < obj . content . scrollLeft + 30 ) {
obj . content . scrollLeft = x ;
if ( obj . content . scrollLeft < 50 ) {
obj . content . scrollLeft = 0 ;
}
} else if ( x < obj . content . scrollLeft + freezed ) {
obj . content . scrollLeft = x - freezed - 1 ;
} else {
obj . content . scrollLeft = x - ( w1 - 20 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the column width
*
* @ param int column column number ( first column is : 0 )
* @ return int current width
* /
obj . getWidth = function ( column ) {
if ( typeof column === "undefined" ) {
// Get all headers
var data = [ ] ;
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
data . push ( obj . options . columns [ i ] . width ) ;
}
} else {
// In case the column is an object
if ( typeof column == "object" ) {
column = $ ( column ) . getAttribute ( "data-x" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
data = obj . colgroup [ column ] . getAttribute ( "width" ) ;
}
return data ;
} ;
/ * *
* Set the column width
*
* @ param int column number ( first column is : 0 )
* @ param int new column width
* @ param int old column width
* /
obj . setWidth = function ( column , width , oldWidth ) {
if ( width ) {
if ( Array . isArray ( column ) ) {
// Oldwidth
if ( ! oldWidth ) {
var oldWidth = [ ] ;
}
// Set width
for ( var i = 0 ; i < column . length ; i ++ ) {
if ( ! oldWidth [ i ] ) {
oldWidth [ i ] = obj . colgroup [ column [ i ] ] . getAttribute ( "width" ) ;
}
var w = Array . isArray ( width ) && width [ i ] ? width [ i ] : width ;
obj . colgroup [ column [ i ] ] . setAttribute ( "width" , w ) ;
obj . options . columns [ column [ i ] ] . width = w ;
}
} else {
// Oldwidth
if ( ! oldWidth ) {
oldWidth = obj . colgroup [ column ] . getAttribute ( "width" ) ;
}
// Set width
obj . colgroup [ column ] . setAttribute ( "width" , width ) ;
obj . options . columns [ column ] . width = width ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Keeping history of changes
obj . setHistory ( {
action : "setWidth" ,
column : column ,
oldValue : oldWidth ,
newValue : width ,
} ) ;
// On resize column
obj . dispatch ( "onresizecolumn" , el , column , width , oldWidth ) ;
// Update corner position
obj . updateCornerPosition ( ) ;
}
} ;
/ * *
* Set the row height
*
* @ param row - row number ( first row is : 0 )
* @ param height - new row height
* @ param oldHeight - old row height
* /
obj . setHeight = function ( row , height , oldHeight ) {
if ( height > 0 ) {
// In case the column is an object
if ( typeof row == "object" ) {
row = row . getAttribute ( "data-y" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Oldwidth
if ( ! oldHeight ) {
oldHeight = obj . rows [ row ] . getAttribute ( "height" ) ;
if ( ! oldHeight ) {
var rect = obj . rows [ row ] . getBoundingClientRect ( ) ;
oldHeight = rect . height ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Integer
height = parseInt ( height ) ;
// Set width
obj . rows [ row ] . style . height = height + "px" ;
// Keep options updated
if ( ! obj . options . rows [ row ] ) {
obj . options . rows [ row ] = { } ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . options . rows [ row ] . height = height ;
// Keeping history of changes
obj . setHistory ( {
action : "setHeight" ,
row : row ,
oldValue : oldHeight ,
newValue : height ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On resize column
obj . dispatch ( "onresizerow" , el , row , height , oldHeight ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update corner position
obj . updateCornerPosition ( ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the row height
*
* @ param row - row number ( first row is : 0 )
* @ return height - current row height
* /
obj . getHeight = function ( row ) {
if ( typeof row === "undefined" ) {
// Get height of all rows
var data = [ ] ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
var h = obj . rows [ j ] . style . height ;
if ( h ) {
data [ j ] = h ;
}
}
} else {
// In case the row is an object
if ( typeof row == "object" ) {
row = $ ( row ) . getAttribute ( "data-y" ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var data = obj . rows [ row ] . style . height ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return data ;
} ;
obj . setFooter = function ( data ) {
if ( data ) {
obj . options . footers = data ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . footers ) {
if ( ! obj . tfoot ) {
obj . tfoot = document . createElement ( "tfoot" ) ;
obj . table . appendChild ( obj . tfoot ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
for ( var j = 0 ; j < obj . options . footers . length ; j ++ ) {
if ( obj . tfoot . children [ j ] ) {
var tr = obj . tfoot . children [ j ] ;
} else {
var tr = document . createElement ( "tr" ) ;
var td = document . createElement ( "td" ) ;
tr . appendChild ( td ) ;
obj . tfoot . appendChild ( tr ) ;
}
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
if ( ! obj . options . footers [ j ] [ i ] ) {
obj . options . footers [ j ] [ i ] = "" ;
}
if ( obj . tfoot . children [ j ] . children [ i + 1 ] ) {
var td = obj . tfoot . children [ j ] . children [ i + 1 ] ;
} else {
var td = document . createElement ( "td" ) ;
tr . appendChild ( td ) ;
// Text align
var colAlign = obj . options . columns [ i ] . align
? obj . options . columns [ i ] . align
: "center" ;
td . style . textAlign = colAlign ;
}
td . textContent = obj . parseValue (
+ obj . records . length + i ,
j ,
obj . options . footers [ j ] [ i ]
) ;
// Hide/Show with hideColumn()/showColumn()
td . style . display = obj . colgroup [ i ] . style . display ;
}
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the column title
*
* @ param column - column number ( first column is : 0 )
* @ param title - new column title
* /
obj . getHeader = function ( column ) {
return obj . headers [ column ] . textContent ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set the column title
*
* @ param column - column number ( first column is : 0 )
* @ param title - new column title
* /
obj . setHeader = function ( column , newValue ) {
if ( obj . headers [ column ] ) {
var oldValue = obj . headers [ column ] . textContent ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! newValue ) {
newValue = prompt ( obj . options . text . columnName , oldValue ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( newValue ) {
obj . headers [ column ] . textContent = newValue ;
// Keep the title property
obj . headers [ column ] . setAttribute ( "title" , newValue ) ;
// Update title
obj . options . columns [ column ] . title = newValue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . setHistory ( {
action : "setHeader" ,
column : column ,
oldValue : oldValue ,
newValue : newValue ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On onchange header
obj . dispatch ( "onchangeheader" , el , column , oldValue , newValue ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get the headers
*
* @ param asArray
* @ return mixed
* /
obj . getHeaders = function ( asArray ) {
var title = [ ] ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
title . push ( obj . getHeader ( i ) ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return asArray ? title : title . join ( obj . options . csvDelimiter ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get meta information from cell ( s )
*
* @ return integer
* /
obj . getMeta = function ( cell , key ) {
if ( ! cell ) {
return obj . options . meta ;
} else {
if ( key ) {
return obj . options . meta [ cell ] && obj . options . meta [ cell ] [ key ]
? obj . options . meta [ cell ] [ key ]
: null ;
} else {
return obj . options . meta [ cell ] ? obj . options . meta [ cell ] : null ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set meta information to cell ( s )
*
* @ return integer
* /
obj . setMeta = function ( o , k , v ) {
if ( ! obj . options . meta ) {
obj . options . meta = { } ;
}
if ( k && v ) {
// Set data value
if ( ! obj . options . meta [ o ] ) {
obj . options . meta [ o ] = { } ;
}
obj . options . meta [ o ] [ k ] = v ;
} else {
// Apply that for all cells
var keys = Object . keys ( o ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( ! obj . options . meta [ keys [ i ] ] ) {
obj . options . meta [ keys [ i ] ] = { } ;
}
var prop = Object . keys ( o [ keys [ i ] ] ) ;
for ( var j = 0 ; j < prop . length ; j ++ ) {
obj . options . meta [ keys [ i ] ] [ prop [ j ] ] = o [ keys [ i ] ] [ prop [ j ] ] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . dispatch ( "onchangemeta" , el , o , k , v ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update meta information
*
* @ return integer
* /
obj . updateMeta = function ( affectedCells ) {
if ( obj . options . meta ) {
var newMeta = { } ;
var keys = Object . keys ( obj . options . meta ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( affectedCells [ keys [ i ] ] ) {
newMeta [ affectedCells [ keys [ i ] ] ] = obj . options . meta [ keys [ i ] ] ;
} else {
newMeta [ keys [ i ] ] = obj . options . meta [ keys [ i ] ] ;
}
}
// Update meta information
obj . options . meta = newMeta ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get style information from cell ( s )
*
* @ return integer
* /
( obj . getStyle = function ( cell , key ) {
// Cell
if ( ! cell ) {
// Control vars
var data = { } ;
// Column and row length
var x = obj . options . data [ 0 ] . length ;
var y = obj . options . data . length ;
// Go through the columns to get the data
for ( var j = 0 ; j < y ; j ++ ) {
for ( var i = 0 ; i < x ; i ++ ) {
// Value
var v = key
? obj . records [ j ] [ i ] . style [ key ]
: obj . records [ j ] [ i ] . getAttribute ( "style" ) ;
// Any meta data for this column?
if ( v ) {
// Column name
var k = jexcel . getColumnNameFromId ( [ i , j ] ) ;
// Value
data [ k ] = v ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return data ;
} else {
cell = jexcel . getIdFromColumnName ( cell , true ) ;
return key
? obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . style [ key ]
: obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "style" ) ;
}
} ) ,
( obj . resetStyle = function ( o , ignoreHistoryAndEvents ) {
var keys = Object . keys ( o ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
// Position
var cell = jexcel . getIdFromColumnName ( keys [ i ] , true ) ;
if ( obj . records [ cell [ 1 ] ] && obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] ) {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute ( "style" , "" ) ;
}
}
obj . setStyle ( o , null , null , null , ignoreHistoryAndEvents ) ;
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Set meta information to cell ( s )
*
* @ return integer
* /
obj . setStyle = function ( o , k , v , force , ignoreHistoryAndEvents ) {
var newValue = { } ;
var oldValue = { } ;
// Apply style
var applyStyle = function ( cellId , key , value ) {
// Position
var cell = jexcel . getIdFromColumnName ( cellId , true ) ;
if (
obj . records [ cell [ 1 ] ] &&
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] &&
( obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . classList . contains ( "readonly" ) ==
false ||
force )
) {
// Current value
var currentValue = obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . style [ key ] ;
// Change layout
if ( currentValue == value && ! force ) {
value = "" ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . style [ key ] = "" ;
} else {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . style [ key ] = value ;
}
// History
if ( ! oldValue [ cellId ] ) {
oldValue [ cellId ] = [ ] ;
}
if ( ! newValue [ cellId ] ) {
newValue [ cellId ] = [ ] ;
}
oldValue [ cellId ] . push ( [ key + ":" + currentValue ] ) ;
newValue [ cellId ] . push ( [ key + ":" + value ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( k && v ) {
// Get object from string
if ( typeof o == "string" ) {
applyStyle ( o , k , v ) ;
} else {
// Avoid duplications
var oneApplication = [ ] ;
// Apply that for all cells
for ( var i = 0 ; i < o . length ; i ++ ) {
var x = o [ i ] . getAttribute ( "data-x" ) ;
var y = o [ i ] . getAttribute ( "data-y" ) ;
var cellName = jexcel . getColumnNameFromId ( [ x , y ] ) ;
// This happens when is a merged cell
if ( ! oneApplication [ cellName ] ) {
applyStyle ( cellName , k , v ) ;
oneApplication [ cellName ] = true ;
}
}
}
} else {
var keys = Object . keys ( o ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
var style = o [ keys [ i ] ] ;
if ( typeof style == "string" ) {
style = style . split ( ";" ) ;
}
for ( var j = 0 ; j < style . length ; j ++ ) {
if ( typeof style [ j ] == "string" ) {
style [ j ] = style [ j ] . split ( ":" ) ;
}
// Apply value
if ( style [ j ] [ 0 ] . trim ( ) ) {
applyStyle ( keys [ i ] , style [ j ] [ 0 ] . trim ( ) , style [ j ] [ 1 ] ) ;
}
}
}
}
var keys = Object . keys ( oldValue ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
oldValue [ keys [ i ] ] = oldValue [ keys [ i ] ] . join ( ";" ) ;
}
var keys = Object . keys ( newValue ) ;
for ( var i = 0 ; i < keys . length ; i ++ ) {
newValue [ keys [ i ] ] = newValue [ keys [ i ] ] . join ( ";" ) ;
}
if ( ! ignoreHistoryAndEvents ) {
// Keeping history of changes
obj . setHistory ( {
action : "setStyle" ,
oldValue : oldValue ,
newValue : newValue ,
} ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . dispatch ( "onchangestyle" , el , o , k , v ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get cell comments , null cell for all
* /
obj . getComments = function ( cell , withAuthor ) {
if ( cell ) {
if ( typeof cell == "string" ) {
var cell = jexcel . getIdFromColumnName ( cell , true ) ;
}
if ( withAuthor ) {
return [
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "title" ) ,
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "author" ) ,
] ;
} else {
return obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "title" ) || "" ;
}
} else {
var data = { } ;
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
for ( var i = 0 ; i < obj . options . columns . length ; i ++ ) {
var comments = obj . records [ j ] [ i ] . getAttribute ( "title" ) ;
if ( comments ) {
var cell = jexcel . getColumnNameFromId ( [ i , j ] ) ;
data [ cell ] = comments ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
return data ;
}
} ;
/ * *
* Set cell comments
* /
obj . setComments = function ( cellId , comments , author ) {
if ( typeof cellId == "string" ) {
var cell = jexcel . getIdFromColumnName ( cellId , true ) ;
} else {
var cell = cellId ;
}
// Keep old value
var title = obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "title" ) ;
var author = obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . getAttribute ( "data-author" ) ;
var oldValue = [ title , author ] ;
// Set new values
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute (
"title" ,
comments ? comments : ""
) ;
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . setAttribute (
"data-author" ,
author ? author : ""
) ;
// Remove class if there is no comment
if ( comments ) {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . classList . add ( "jexcel_comments" ) ;
} else {
obj . records [ cell [ 1 ] ] [ cell [ 0 ] ] . classList . remove ( "jexcel_comments" ) ;
}
// Save history
obj . setHistory ( {
action : "setComments" ,
column : cellId ,
newValue : [ comments , author ] ,
oldValue : oldValue ,
} ) ;
// Set comments
obj . dispatch ( "oncomments" , el , comments , title , cell , cell [ 0 ] , cell [ 1 ] ) ;
} ;
/ * *
* Get table config information
* /
obj . getConfig = function ( ) {
var options = obj . options ;
options . style = obj . getStyle ( ) ;
options . mergeCells = obj . getMerge ( ) ;
options . comments = obj . getComments ( ) ;
return options ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Sort data and reload table
* /
obj . orderBy = function ( column , order ) {
if ( column >= 0 ) {
// Merged cells
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
} else {
// Remove merged cells
obj . destroyMerged ( ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Direction
if ( order == null ) {
order = obj . headers [ column ] . classList . contains ( "arrow-down" ) ? 1 : 0 ;
} else {
order = order ? 1 : 0 ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Test order
var temp = [ ] ;
if (
obj . options . columns [ column ] . type == "number" ||
obj . options . columns [ column ] . type == "numeric" ||
obj . options . columns [ column ] . type == "percentage" ||
obj . options . columns [ column ] . type == "autonumber" ||
obj . options . columns [ column ] . type == "color"
) {
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
temp [ j ] = [ j , Number ( obj . options . data [ j ] [ column ] ) ] ;
}
} else if (
obj . options . columns [ column ] . type == "calendar" ||
obj . options . columns [ column ] . type == "checkbox" ||
obj . options . columns [ column ] . type == "radio"
) {
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
temp [ j ] = [ j , obj . options . data [ j ] [ column ] ] ;
}
} else {
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
temp [ j ] = [ j , obj . records [ j ] [ column ] . textContent . toLowerCase ( ) ] ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Default sorting method
if ( typeof obj . options . sorting !== "function" ) {
obj . options . sorting = function ( direction ) {
return function ( a , b ) {
var valueA = a [ 1 ] ;
var valueB = b [ 1 ] ;
if ( ! direction ) {
return valueA === "" && valueB !== ""
? 1
: valueA !== "" && valueB === ""
? - 1
: valueA > valueB
? 1
: valueA < valueB
? - 1
: 0 ;
} else {
return valueA === "" && valueB !== ""
? 1
: valueA !== "" && valueB === ""
? - 1
: valueA > valueB
? - 1
: valueA < valueB
? 1
: 0 ;
}
} ;
} ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
temp = temp . sort ( obj . options . sorting ( order ) ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Save history
var newValue = [ ] ;
for ( var j = 0 ; j < temp . length ; j ++ ) {
newValue [ j ] = temp [ j ] [ 0 ] ;
}
// Save history
obj . setHistory ( {
action : "orderBy" ,
rows : newValue ,
column : column ,
order : order ,
} ) ;
// Update order
obj . updateOrderArrow ( column , order ) ;
obj . updateOrder ( newValue ) ;
// On sort event
obj . dispatch ( "onsort" , el , column , order ) ;
return true ;
}
} ;
/ * *
* Update order arrow
* /
obj . updateOrderArrow = function ( column , order ) {
// Remove order
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
obj . headers [ i ] . classList . remove ( "arrow-up" ) ;
obj . headers [ i ] . classList . remove ( "arrow-down" ) ;
}
// No order specified then toggle order
if ( order ) {
obj . headers [ column ] . classList . add ( "arrow-up" ) ;
} else {
obj . headers [ column ] . classList . add ( "arrow-down" ) ;
}
} ;
/ * *
* Update rows position
* /
obj . updateOrder = function ( rows ) {
// History
var data = [ ] ;
for ( var j = 0 ; j < rows . length ; j ++ ) {
data [ j ] = obj . options . data [ rows [ j ] ] ;
}
obj . options . data = data ;
var data = [ ] ;
for ( var j = 0 ; j < rows . length ; j ++ ) {
data [ j ] = obj . records [ rows [ j ] ] ;
}
obj . records = data ;
var data = [ ] ;
for ( var j = 0 ; j < rows . length ; j ++ ) {
data [ j ] = obj . rows [ rows [ j ] ] ;
}
obj . rows = data ;
// Update references
obj . updateTableReferences ( ) ;
// Redo search
if ( obj . results && obj . results . length ) {
if ( obj . searchInput . value ) {
obj . search ( obj . searchInput . value ) ;
} else {
obj . closeFilter ( ) ;
}
} else {
// Create page
obj . results = null ;
obj . pageNumber = 0 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . pagination > 0 ) {
obj . page ( 0 ) ;
} else if ( obj . options . lazyLoading == true ) {
obj . loadPage ( 0 ) ;
} else {
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
obj . tbody . appendChild ( obj . rows [ j ] ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Move row
*
* @ return void
* /
obj . moveRow = function ( o , d , ignoreDom ) {
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
if ( o > d ) {
var insertBefore = 1 ;
} else {
var insertBefore = 0 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if (
obj . isRowMerged ( o ) . length ||
obj . isRowMerged ( d , insertBefore ) . length
) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
} else {
obj . destroyMerged ( ) ;
}
}
}
if ( obj . options . search == true ) {
if ( obj . results && obj . results . length != obj . rows . length ) {
if (
confirm (
obj . options . text . thisActionWillClearYourSearchResultsAreYouSure
)
) {
obj . resetSearch ( ) ;
} else {
return false ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . results = null ;
}
if ( ! ignoreDom ) {
if (
Array . prototype . indexOf . call ( obj . tbody . children , obj . rows [ d ] ) >= 0
) {
if ( o > d ) {
obj . tbody . insertBefore ( obj . rows [ o ] , obj . rows [ d ] ) ;
} else {
obj . tbody . insertBefore ( obj . rows [ o ] , obj . rows [ d ] . nextSibling ) ;
}
} else {
obj . tbody . removeChild ( obj . rows [ o ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
// Place references in the correct position
obj . rows . splice ( d , 0 , obj . rows . splice ( o , 1 ) [ 0 ] ) ;
obj . records . splice ( d , 0 , obj . records . splice ( o , 1 ) [ 0 ] ) ;
obj . options . data . splice ( d , 0 , obj . options . data . splice ( o , 1 ) [ 0 ] ) ;
// Respect pagination
if (
obj . options . pagination > 0 &&
obj . tbody . children . length != obj . options . pagination
) {
obj . page ( obj . pageNumber ) ;
}
// Keeping history of changes
obj . setHistory ( {
action : "moveRow" ,
oldValue : o ,
newValue : d ,
} ) ;
// Update table references
obj . updateTableReferences ( ) ;
// Events
obj . dispatch ( "onmoverow" , el , o , d ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Insert a new row
*
* @ param mixed - number of blank lines to be insert or a single array with the data of the new row
* @ param rowNumber
* @ param insertBefore
* @ return void
* /
obj . insertRow = function ( mixed , rowNumber , insertBefore ) {
// Configuration
if ( obj . options . allowInsertRow == true ) {
// Records
var records = [ ] ;
// Data to be insert
var data = [ ] ;
// The insert could be lead by number of rows or the array of data
if ( mixed > 0 ) {
var numOfRows = mixed ;
} else {
var numOfRows = 1 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( mixed ) {
data = mixed ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Direction
var insertBefore = insertBefore ? true : false ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Current column number
var lastRow = obj . options . data . length - 1 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if (
rowNumber == undefined ||
rowNumber >= parseInt ( lastRow ) ||
rowNumber < 0
) {
rowNumber = lastRow ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Onbeforeinsertrow
if (
obj . dispatch (
"onbeforeinsertrow" ,
el ,
rowNumber ,
numOfRows ,
insertBefore
) === false
) {
return false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Merged cells
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
if ( obj . isRowMerged ( rowNumber , insertBefore ) . length ) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
obj . destroyMerged ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Clear any search
if ( obj . options . search == true ) {
if ( obj . results && obj . results . length != obj . rows . length ) {
if (
confirm (
obj . options . text . thisActionWillClearYourSearchResultsAreYouSure
)
) {
obj . resetSearch ( ) ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
return false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . results = null ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Insertbefore
var rowIndex = ! insertBefore ? rowNumber + 1 : rowNumber ;
// Keep the current data
var currentRecords = obj . records . splice ( rowIndex ) ;
var currentData = obj . options . data . splice ( rowIndex ) ;
var currentRows = obj . rows . splice ( rowIndex ) ;
// Adding lines
var rowRecords = [ ] ;
var rowData = [ ] ;
var rowNode = [ ] ;
for ( var row = rowIndex ; row < numOfRows + rowIndex ; row ++ ) {
// Push data to the data container
obj . options . data [ row ] = [ ] ;
for ( var col = 0 ; col < obj . options . columns . length ; col ++ ) {
obj . options . data [ row ] [ col ] = data [ col ] ? data [ col ] : "" ;
}
// Create row
var tr = obj . createRow ( row , obj . options . data [ row ] ) ;
// Append node
if ( currentRows [ 0 ] ) {
if (
Array . prototype . indexOf . call (
obj . tbody . children ,
currentRows [ 0 ]
) >= 0
) {
obj . tbody . insertBefore ( tr , currentRows [ 0 ] ) ;
}
} else {
if (
Array . prototype . indexOf . call (
obj . tbody . children ,
obj . rows [ rowNumber ]
) >= 0
) {
obj . tbody . appendChild ( tr ) ;
}
}
// Record History
rowRecords . push ( obj . records [ row ] ) ;
rowData . push ( obj . options . data [ row ] ) ;
rowNode . push ( tr ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Copy the data back to the main data
Array . prototype . push . apply ( obj . records , currentRecords ) ;
Array . prototype . push . apply ( obj . options . data , currentData ) ;
Array . prototype . push . apply ( obj . rows , currentRows ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Respect pagination
if ( obj . options . pagination > 0 ) {
obj . page ( obj . pageNumber ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Keep history
obj . setHistory ( {
action : "insertRow" ,
rowNumber : rowNumber ,
numOfRows : numOfRows ,
insertBefore : insertBefore ,
rowRecords : rowRecords ,
rowData : rowData ,
rowNode : rowNode ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Remove table references
obj . updateTableReferences ( ) ;
// Events
obj . dispatch (
"oninsertrow" ,
el ,
rowNumber ,
numOfRows ,
rowRecords ,
insertBefore
) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Delete a row by number
*
* @ param integer rowNumber - row number to be excluded
* @ param integer numOfRows - number of lines
* @ return void
* /
obj . deleteRow = function ( rowNumber , numOfRows ) {
// Global Configuration
if ( obj . options . allowDeleteRow == true ) {
if (
obj . options . allowDeletingAllRows == true ||
obj . options . data . length > 1
) {
// Delete row definitions
if ( rowNumber == undefined ) {
var number = obj . getSelectedRows ( ) ;
if ( ! number [ 0 ] ) {
rowNumber = obj . options . data . length - 1 ;
numOfRows = 1 ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
rowNumber = parseInt ( number [ 0 ] . getAttribute ( "data-y" ) ) ;
numOfRows = number . length ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Last column
var lastRow = obj . options . data . length - 1 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( rowNumber == undefined || rowNumber > lastRow || rowNumber < 0 ) {
rowNumber = lastRow ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! numOfRows ) {
numOfRows = 1 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Do not delete more than the number of records
if ( rowNumber + numOfRows >= obj . options . data . length ) {
numOfRows = obj . options . data . length - rowNumber ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Onbeforedeleterow
if (
obj . dispatch ( "onbeforedeleterow" , el , rowNumber , numOfRows ) ===
false
) {
return false ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( parseInt ( rowNumber ) > - 1 ) {
// Merged cells
var mergeExists = false ;
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
for ( var row = rowNumber ; row < rowNumber + numOfRows ; row ++ ) {
if ( obj . isRowMerged ( row , false ) . length ) {
mergeExists = true ;
}
}
}
if ( mergeExists ) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
} else {
obj . destroyMerged ( ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Clear any search
if ( obj . options . search == true ) {
if ( obj . results && obj . results . length != obj . rows . length ) {
if (
confirm (
obj . options . text
. thisActionWillClearYourSearchResultsAreYouSure
)
) {
obj . resetSearch ( ) ;
} else {
return false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
obj . results = null ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// If delete all rows, and set allowDeletingAllRows false, will stay one row
if (
obj . options . allowDeletingAllRows == false &&
lastRow + 1 === numOfRows
) {
numOfRows -- ;
console . error (
"Jspreadsheet: It is not possible to delete the last row"
) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Remove node
for ( var row = rowNumber ; row < rowNumber + numOfRows ; row ++ ) {
if (
Array . prototype . indexOf . call (
obj . tbody . children ,
obj . rows [ row ]
) >= 0
) {
obj . rows [ row ] . className = "" ;
obj . rows [ row ] . parentNode . removeChild ( obj . rows [ row ] ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Remove data
var rowRecords = obj . records . splice ( rowNumber , numOfRows ) ;
var rowData = obj . options . data . splice ( rowNumber , numOfRows ) ;
var rowNode = obj . rows . splice ( rowNumber , numOfRows ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Respect pagination
if (
obj . options . pagination > 0 &&
obj . tbody . children . length != obj . options . pagination
) {
obj . page ( obj . pageNumber ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Remove selection
obj . conditionalSelectionUpdate (
1 ,
rowNumber ,
rowNumber + numOfRows - 1
) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Keep history
obj . setHistory ( {
action : "deleteRow" ,
rowNumber : rowNumber ,
numOfRows : numOfRows ,
insertBefore : 1 ,
rowRecords : rowRecords ,
rowData : rowData ,
rowNode : rowNode ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Remove table references
obj . updateTableReferences ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Events
obj . dispatch ( "ondeleterow" , el , rowNumber , numOfRows , rowRecords ) ;
}
} else {
console . error (
"Jspreadsheet: It is not possible to delete the last row"
) ;
}
}
} ;
/ * *
* Move column
*
* @ return void
* /
obj . moveColumn = function ( o , d ) {
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
if ( o > d ) {
var insertBefore = 1 ;
} else {
var insertBefore = 0 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if (
obj . isColMerged ( o ) . length ||
obj . isColMerged ( d , insertBefore ) . length
) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
} else {
obj . destroyMerged ( ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var o = parseInt ( o ) ;
var d = parseInt ( d ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( o > d ) {
obj . headerContainer . insertBefore ( obj . headers [ o ] , obj . headers [ d ] ) ;
obj . colgroupContainer . insertBefore ( obj . colgroup [ o ] , obj . colgroup [ d ] ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
obj . rows [ j ] . insertBefore ( obj . records [ j ] [ o ] , obj . records [ j ] [ d ] ) ;
}
} else {
obj . headerContainer . insertBefore (
obj . headers [ o ] ,
obj . headers [ d ] . nextSibling
) ;
obj . colgroupContainer . insertBefore (
obj . colgroup [ o ] ,
obj . colgroup [ d ] . nextSibling
) ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
obj . rows [ j ] . insertBefore (
obj . records [ j ] [ o ] ,
obj . records [ j ] [ d ] . nextSibling
) ;
}
}
obj . options . columns . splice ( d , 0 , obj . options . columns . splice ( o , 1 ) [ 0 ] ) ;
obj . headers . splice ( d , 0 , obj . headers . splice ( o , 1 ) [ 0 ] ) ;
obj . colgroup . splice ( d , 0 , obj . colgroup . splice ( o , 1 ) [ 0 ] ) ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
obj . options . data [ j ] . splice ( d , 0 , obj . options . data [ j ] . splice ( o , 1 ) [ 0 ] ) ;
obj . records [ j ] . splice ( d , 0 , obj . records [ j ] . splice ( o , 1 ) [ 0 ] ) ;
}
// Update footers position
if ( obj . options . footers ) {
for ( var j = 0 ; j < obj . options . footers . length ; j ++ ) {
obj . options . footers [ j ] . splice (
d ,
0 ,
obj . options . footers [ j ] . splice ( o , 1 ) [ 0 ]
) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Keeping history of changes
obj . setHistory ( {
action : "moveColumn" ,
oldValue : o ,
newValue : d ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table references
obj . updateTableReferences ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Events
obj . dispatch ( "onmovecolumn" , el , o , d ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Insert a new column
*
* @ param mixed - num of columns to be added or data to be added in one single column
* @ param int columnNumber - number of columns to be created
* @ param bool insertBefore
* @ param object properties - column properties
* @ return void
* /
obj . insertColumn = function (
mixed ,
columnNumber ,
insertBefore ,
properties
) {
// Configuration
if ( obj . options . allowInsertColumn == true ) {
// Records
var records = [ ] ;
// Data to be insert
var data = [ ] ;
// The insert could be lead by number of rows or the array of data
if ( mixed > 0 ) {
var numOfColumns = mixed ;
} else {
var numOfColumns = 1 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( mixed ) {
data = mixed ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Direction
var insertBefore = insertBefore ? true : false ;
// Current column number
var lastColumn = obj . options . columns . length - 1 ;
// Confirm position
if (
columnNumber == undefined ||
columnNumber >= parseInt ( lastColumn ) ||
columnNumber < 0
) {
columnNumber = lastColumn ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Onbeforeinsertcolumn
if (
obj . dispatch (
"onbeforeinsertcolumn" ,
el ,
columnNumber ,
numOfColumns ,
insertBefore
) === false
) {
return false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Merged cells
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
if ( obj . isColMerged ( columnNumber , insertBefore ) . length ) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
obj . destroyMerged ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
// Create default properties
if ( ! properties ) {
properties = [ ] ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < numOfColumns ; i ++ ) {
if ( ! properties [ i ] ) {
properties [ i ] = {
type : "text" ,
source : [ ] ,
options : [ ] ,
width : obj . options . defaultColWidth ,
align : obj . options . defaultColAlign ,
} ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Insert before
var columnIndex = ! insertBefore ? columnNumber + 1 : columnNumber ;
obj . options . columns = jexcel . injectArray (
obj . options . columns ,
columnIndex ,
properties
) ;
// Open space in the containers
var currentHeaders = obj . headers . splice ( columnIndex ) ;
var currentColgroup = obj . colgroup . splice ( columnIndex ) ;
// History
var historyHeaders = [ ] ;
var historyColgroup = [ ] ;
var historyRecords = [ ] ;
var historyData = [ ] ;
var historyFooters = [ ] ;
// Add new headers
for ( var col = columnIndex ; col < numOfColumns + columnIndex ; col ++ ) {
obj . createCellHeader ( col ) ;
obj . headerContainer . insertBefore (
obj . headers [ col ] ,
obj . headerContainer . children [ col + 1 ]
) ;
obj . colgroupContainer . insertBefore (
obj . colgroup [ col ] ,
obj . colgroupContainer . children [ col + 1 ]
) ;
historyHeaders . push ( obj . headers [ col ] ) ;
historyColgroup . push ( obj . colgroup [ col ] ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Add new footer cells
if ( obj . options . footers ) {
for ( var j = 0 ; j < obj . options . footers . length ; j ++ ) {
historyFooters [ j ] = [ ] ;
for ( var i = 0 ; i < numOfColumns ; i ++ ) {
historyFooters [ j ] . push ( "" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . options . footers [ j ] . splice ( columnIndex , 0 , historyFooters [ j ] ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Adding visual columns
for ( var row = 0 ; row < obj . options . data . length ; row ++ ) {
// Keep the current data
var currentData = obj . options . data [ row ] . splice ( columnIndex ) ;
var currentRecord = obj . records [ row ] . splice ( columnIndex ) ;
// History
historyData [ row ] = [ ] ;
historyRecords [ row ] = [ ] ;
for ( var col = columnIndex ; col < numOfColumns + columnIndex ; col ++ ) {
// New value
var value = data [ row ] ? data [ row ] : "" ;
obj . options . data [ row ] [ col ] = value ;
// New cell
var td = obj . createCell ( col , row , obj . options . data [ row ] [ col ] ) ;
obj . records [ row ] [ col ] = td ;
// Add cell to the row
if ( obj . rows [ row ] ) {
obj . rows [ row ] . insertBefore ( td , obj . rows [ row ] . children [ col + 1 ] ) ;
}
// Record History
historyData [ row ] . push ( value ) ;
historyRecords [ row ] . push ( td ) ;
}
// Copy the data back to the main data
Array . prototype . push . apply ( obj . options . data [ row ] , currentData ) ;
Array . prototype . push . apply ( obj . records [ row ] , currentRecord ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
Array . prototype . push . apply ( obj . headers , currentHeaders ) ;
Array . prototype . push . apply ( obj . colgroup , currentColgroup ) ;
// Adjust nested headers
if ( obj . options . nestedHeaders && obj . options . nestedHeaders . length > 0 ) {
// Flexible way to handle nestedheaders
if ( obj . options . nestedHeaders [ 0 ] && obj . options . nestedHeaders [ 0 ] [ 0 ] ) {
for ( var j = 0 ; j < obj . options . nestedHeaders . length ; j ++ ) {
var colspan =
parseInt (
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan
) + numOfColumns ;
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan = colspan ;
obj . thead . children [ j ] . children [
obj . thead . children [ j ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
var o =
obj . thead . children [ j ] . children [
obj . thead . children [ j ] . children . length - 1
] . getAttribute ( "data-column" ) ;
o = o . split ( "," ) ;
for (
var col = columnIndex ;
col < numOfColumns + columnIndex ;
col ++
) {
o . push ( col ) ;
}
obj . thead . children [ j ] . children [
obj . thead . children [ j ] . children . length - 1
] . setAttribute ( "data-column" , o ) ;
}
} else {
var colspan =
parseInt ( obj . options . nestedHeaders [ 0 ] . colspan ) + numOfColumns ;
obj . options . nestedHeaders [ 0 ] . colspan = colspan ;
obj . thead . children [ 0 ] . children [
obj . thead . children [ 0 ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Keep history
obj . setHistory ( {
action : "insertColumn" ,
columnNumber : columnNumber ,
numOfColumns : numOfColumns ,
insertBefore : insertBefore ,
columns : properties ,
headers : historyHeaders ,
colgroup : historyColgroup ,
records : historyRecords ,
footers : historyFooters ,
data : historyData ,
} ) ;
// Remove table references
obj . updateTableReferences ( ) ;
// Events
obj . dispatch (
"oninsertcolumn" ,
el ,
columnNumber ,
numOfColumns ,
historyRecords ,
insertBefore
) ;
}
} ;
/ * *
* Delete a column by number
*
* @ param integer columnNumber - reference column to be excluded
* @ param integer numOfColumns - number of columns to be excluded from the reference column
* @ return void
* /
obj . deleteColumn = function ( columnNumber , numOfColumns ) {
// Global Configuration
if ( obj . options . allowDeleteColumn == true ) {
if ( obj . headers . length > 1 ) {
// Delete column definitions
if ( columnNumber == undefined ) {
var number = obj . getSelectedColumns ( true ) ;
if ( ! number . length ) {
// Remove last column
columnNumber = obj . headers . length - 1 ;
numOfColumns = 1 ;
} else {
// Remove selected
columnNumber = parseInt ( number [ 0 ] ) ;
numOfColumns = parseInt ( number . length ) ;
}
}
// Lasat column
var lastColumn = obj . options . data [ 0 ] . length - 1 ;
if (
columnNumber == undefined ||
columnNumber > lastColumn ||
columnNumber < 0
) {
columnNumber = lastColumn ;
}
// Minimum of columns to be delete is 1
if ( ! numOfColumns ) {
numOfColumns = 1 ;
}
// Can't delete more than the limit of the table
if ( numOfColumns > obj . options . data [ 0 ] . length - columnNumber ) {
numOfColumns = obj . options . data [ 0 ] . length - columnNumber ;
}
// onbeforedeletecolumn
if (
obj . dispatch (
"onbeforedeletecolumn" ,
el ,
columnNumber ,
numOfColumns
) === false
) {
return false ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Can't remove the last column
if ( parseInt ( columnNumber ) > - 1 ) {
// Merged cells
var mergeExists = false ;
if ( Object . keys ( obj . options . mergeCells ) . length > 0 ) {
for (
var col = columnNumber ;
col < columnNumber + numOfColumns ;
col ++
) {
if ( obj . isColMerged ( col , false ) . length ) {
mergeExists = true ;
}
}
}
if ( mergeExists ) {
if (
! confirm (
obj . options . text
. thisActionWillDestroyAnyExistingMergedCellsAreYouSure
)
) {
return false ;
} else {
obj . destroyMerged ( ) ;
}
}
// Delete the column properties
var columns = obj . options . columns . splice (
columnNumber ,
numOfColumns
) ;
for (
var col = columnNumber ;
col < columnNumber + numOfColumns ;
col ++
) {
obj . colgroup [ col ] . className = "" ;
obj . headers [ col ] . className = "" ;
obj . colgroup [ col ] . parentNode . removeChild ( obj . colgroup [ col ] ) ;
obj . headers [ col ] . parentNode . removeChild ( obj . headers [ col ] ) ;
}
var historyHeaders = obj . headers . splice ( columnNumber , numOfColumns ) ;
var historyColgroup = obj . colgroup . splice (
columnNumber ,
numOfColumns
) ;
var historyRecords = [ ] ;
var historyData = [ ] ;
var historyFooters = [ ] ;
for ( var row = 0 ; row < obj . options . data . length ; row ++ ) {
for (
var col = columnNumber ;
col < columnNumber + numOfColumns ;
col ++
) {
obj . records [ row ] [ col ] . className = "" ;
obj . records [ row ] [ col ] . parentNode . removeChild (
obj . records [ row ] [ col ]
) ;
}
}
// Delete headers
for ( var row = 0 ; row < obj . options . data . length ; row ++ ) {
// History
historyData [ row ] = obj . options . data [ row ] . splice (
columnNumber ,
numOfColumns
) ;
historyRecords [ row ] = obj . records [ row ] . splice (
columnNumber ,
numOfColumns
) ;
}
// Delete footers
if ( obj . options . footers ) {
for ( var row = 0 ; row < obj . options . footers . length ; row ++ ) {
historyFooters [ row ] = obj . options . footers [ row ] . splice (
columnNumber ,
numOfColumns
) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Remove selection
obj . conditionalSelectionUpdate (
0 ,
columnNumber ,
columnNumber + numOfColumns - 1
) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Adjust nested headers
if (
obj . options . nestedHeaders &&
obj . options . nestedHeaders . length > 0
) {
// Flexible way to handle nestedheaders
if (
obj . options . nestedHeaders [ 0 ] &&
obj . options . nestedHeaders [ 0 ] [ 0 ]
) {
for ( var j = 0 ; j < obj . options . nestedHeaders . length ; j ++ ) {
var colspan =
parseInt (
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan
) - numOfColumns ;
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan = colspan ;
obj . thead . children [ j ] . children [
obj . thead . children [ j ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
}
} else {
var colspan =
parseInt ( obj . options . nestedHeaders [ 0 ] . colspan ) - numOfColumns ;
obj . options . nestedHeaders [ 0 ] . colspan = colspan ;
obj . thead . children [ 0 ] . children [
obj . thead . children [ 0 ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Keeping history of changes
obj . setHistory ( {
action : "deleteColumn" ,
columnNumber : columnNumber ,
numOfColumns : numOfColumns ,
insertBefore : 1 ,
columns : columns ,
headers : historyHeaders ,
colgroup : historyColgroup ,
records : historyRecords ,
footers : historyFooters ,
data : historyData ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table references
obj . updateTableReferences ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Delete
obj . dispatch (
"ondeletecolumn" ,
el ,
columnNumber ,
numOfColumns ,
historyRecords
) ;
}
} else {
console . error (
"Jspreadsheet: It is not possible to delete the last column"
) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get selected rows numbers
*
* @ return array
* /
( obj . getSelectedRows = function ( asIds ) {
var rows = [ ] ;
// Get all selected rows
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( obj . rows [ j ] . classList . contains ( "selected" ) ) {
if ( asIds ) {
rows . push ( j ) ;
} else {
rows . push ( obj . rows [ j ] ) ;
}
}
}
return rows ;
} ) ,
/ * *
* Get selected column numbers
*
* @ return array
* /
( obj . getSelectedColumns = function ( ) {
var cols = [ ] ;
// Get all selected cols
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
if ( obj . headers [ i ] . classList . contains ( "selected" ) ) {
cols . push ( i ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
return cols ;
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get highlighted
*
* @ return array
* /
obj . getHighlighted = function ( ) {
return obj . highlighted ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update cell references
*
* @ return void
* /
obj . updateTableReferences = function ( ) {
// Update headers
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
var x = obj . headers [ i ] . getAttribute ( "data-x" ) ;
if ( x != i ) {
// Update coords
obj . headers [ i ] . setAttribute ( "data-x" , i ) ;
// Title
if ( ! obj . headers [ i ] . getAttribute ( "title" ) ) {
obj . headers [ i ] . innerHTML = jexcel . getColumnName ( i ) ;
}
}
}
// Update all rows
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( obj . rows [ j ] ) {
var y = obj . rows [ j ] . getAttribute ( "data-y" ) ;
if ( y != j ) {
// Update coords
obj . rows [ j ] . setAttribute ( "data-y" , j ) ;
obj . rows [ j ] . children [ 0 ] . setAttribute ( "data-y" , j ) ;
// Row number
obj . rows [ j ] . children [ 0 ] . innerHTML = j + 1 ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Regular cells affected by this change
var affectedTokens = [ ] ;
var mergeCellUpdates = [ ] ;
// Update cell
var updatePosition = function ( x , y , i , j ) {
if ( x != i ) {
obj . records [ j ] [ i ] . setAttribute ( "data-x" , i ) ;
}
if ( y != j ) {
obj . records [ j ] [ i ] . setAttribute ( "data-y" , j ) ;
}
// Other updates
if ( x != i || y != j ) {
var columnIdFrom = jexcel . getColumnNameFromId ( [ x , y ] ) ;
var columnIdTo = jexcel . getColumnNameFromId ( [ i , j ] ) ;
affectedTokens [ columnIdFrom ] = columnIdTo ;
}
} ;
for ( var j = 0 ; j < obj . records . length ; j ++ ) {
for ( var i = 0 ; i < obj . records [ 0 ] . length ; i ++ ) {
if ( obj . records [ j ] [ i ] ) {
// Current values
var x = obj . records [ j ] [ i ] . getAttribute ( "data-x" ) ;
var y = obj . records [ j ] [ i ] . getAttribute ( "data-y" ) ;
// Update column
if ( obj . records [ j ] [ i ] . getAttribute ( "data-merged" ) ) {
var columnIdFrom = jexcel . getColumnNameFromId ( [ x , y ] ) ;
var columnIdTo = jexcel . getColumnNameFromId ( [ i , j ] ) ;
if ( mergeCellUpdates [ columnIdFrom ] == null ) {
if ( columnIdFrom == columnIdTo ) {
mergeCellUpdates [ columnIdFrom ] = false ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
var totalX = parseInt ( i - x ) ;
var totalY = parseInt ( j - y ) ;
mergeCellUpdates [ columnIdFrom ] = [ columnIdTo , totalX , totalY ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} else {
updatePosition ( x , y , i , j ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
}
// Update merged if applicable
var keys = Object . keys ( mergeCellUpdates ) ;
if ( keys . length ) {
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( mergeCellUpdates [ keys [ i ] ] ) {
var info = jexcel . getIdFromColumnName ( keys [ i ] , true ) ;
var x = info [ 0 ] ;
var y = info [ 1 ] ;
updatePosition (
x ,
y ,
x + mergeCellUpdates [ keys [ i ] ] [ 1 ] ,
y + mergeCellUpdates [ keys [ i ] ] [ 2 ]
) ;
var columnIdFrom = keys [ i ] ;
var columnIdTo = mergeCellUpdates [ keys [ i ] ] [ 0 ] ;
for (
var j = 0 ;
j < obj . options . mergeCells [ columnIdFrom ] [ 2 ] . length ;
j ++
) {
var x = parseInt (
obj . options . mergeCells [ columnIdFrom ] [ 2 ] [ j ] . getAttribute (
"data-x"
)
) ;
var y = parseInt (
obj . options . mergeCells [ columnIdFrom ] [ 2 ] [ j ] . getAttribute (
"data-y"
)
) ;
obj . options . mergeCells [ columnIdFrom ] [ 2 ] [ j ] . setAttribute (
"data-x" ,
x + mergeCellUpdates [ keys [ i ] ] [ 1 ]
) ;
obj . options . mergeCells [ columnIdFrom ] [ 2 ] [ j ] . setAttribute (
"data-y" ,
y + mergeCellUpdates [ keys [ i ] ] [ 2 ]
) ;
}
obj . options . mergeCells [ columnIdTo ] =
obj . options . mergeCells [ columnIdFrom ] ;
delete obj . options . mergeCells [ columnIdFrom ] ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update formulas
obj . updateFormulas ( affectedTokens ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update meta data
obj . updateMeta ( affectedTokens ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Refresh selection
obj . refreshSelection ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table with custom configuration if applicable
obj . updateTable ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Custom settings for the cells
* /
obj . updateTable = function ( ) {
// Check for spare
if ( obj . options . minSpareRows > 0 ) {
var numBlankRows = 0 ;
for ( var j = obj . rows . length - 1 ; j >= 0 ; j -- ) {
var test = false ;
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
if ( obj . options . data [ j ] [ i ] ) {
test = true ;
}
}
if ( test ) {
break ;
} else {
numBlankRows ++ ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( obj . options . minSpareRows - numBlankRows > 0 ) {
obj . insertRow ( obj . options . minSpareRows - numBlankRows ) ;
}
}
if ( obj . options . minSpareCols > 0 ) {
var numBlankCols = 0 ;
for ( var i = obj . headers . length - 1 ; i >= 0 ; i -- ) {
var test = false ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( obj . options . data [ j ] [ i ] ) {
test = true ;
}
}
if ( test ) {
break ;
} else {
numBlankCols ++ ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . minSpareCols - numBlankCols > 0 ) {
obj . insertColumn ( obj . options . minSpareCols - numBlankCols ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Customizations by the developer
if ( typeof obj . options . updateTable == "function" ) {
if ( obj . options . detachForUpdates ) {
el . removeChild ( obj . content ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
for ( var i = 0 ; i < obj . headers . length ; i ++ ) {
obj . options . updateTable (
el ,
obj . records [ j ] [ i ] ,
i ,
j ,
obj . options . data [ j ] [ i ] ,
obj . records [ j ] [ i ] . textContent ,
jexcel . getColumnNameFromId ( [ i , j ] )
) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . detachForUpdates ) {
el . insertBefore ( obj . content , obj . pagination ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update footers
if ( obj . options . footers ) {
obj . setFooter ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update corner position
setTimeout ( function ( ) {
obj . updateCornerPosition ( ) ;
} , 0 ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Readonly
* /
obj . isReadOnly = function ( cell ) {
if ( ( cell = obj . getCell ( cell ) ) ) {
return cell . classList . contains ( "readonly" ) ? true : false ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Readonly
* /
obj . setReadOnly = function ( cell , state ) {
if ( ( cell = obj . getCell ( cell ) ) ) {
if ( state ) {
cell . classList . add ( "readonly" ) ;
} else {
cell . classList . remove ( "readonly" ) ;
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Show row
* /
obj . showRow = function ( rowNumber ) {
obj . rows [ rowNumber ] . style . display = "" ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Hide row
* /
obj . hideRow = function ( rowNumber ) {
obj . rows [ rowNumber ] . style . display = "none" ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Show column
* /
obj . showColumn = function ( colNumber ) {
obj . headers [ colNumber ] . style . display = "" ;
obj . colgroup [ colNumber ] . style . display = "" ;
if ( obj . filter && obj . filter . children . length > colNumber + 1 ) {
obj . filter . children [ colNumber + 1 ] . style . display = "" ;
}
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
obj . records [ j ] [ colNumber ] . style . display = "" ;
}
// Update footers
if ( obj . options . footers ) {
obj . setFooter ( ) ;
}
obj . resetSelection ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Hide column
* /
obj . hideColumn = function ( colNumber ) {
obj . headers [ colNumber ] . style . display = "none" ;
obj . colgroup [ colNumber ] . style . display = "none" ;
if ( obj . filter && obj . filter . children . length > colNumber + 1 ) {
obj . filter . children [ colNumber + 1 ] . style . display = "none" ;
}
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
obj . records [ j ] [ colNumber ] . style . display = "none" ;
}
// Update footers
if ( obj . options . footers ) {
obj . setFooter ( ) ;
}
obj . resetSelection ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Show index column
* /
obj . showIndex = function ( ) {
obj . table . classList . remove ( "jexcel_hidden_index" ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Hide index column
* /
obj . hideIndex = function ( ) {
obj . table . classList . add ( "jexcel_hidden_index" ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update all related cells in the chain
* /
var chainLoopProtection = [ ] ;
obj . updateFormulaChain = function ( x , y , records ) {
var cellId = jexcel . getColumnNameFromId ( [ x , y ] ) ;
if ( obj . formula [ cellId ] && obj . formula [ cellId ] . length > 0 ) {
if ( chainLoopProtection [ cellId ] ) {
obj . records [ y ] [ x ] . innerHTML = "#ERROR" ;
obj . formula [ cellId ] = "" ;
} else {
// Protection
chainLoopProtection [ cellId ] = true ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < obj . formula [ cellId ] . length ; i ++ ) {
var cell = jexcel . getIdFromColumnName ( obj . formula [ cellId ] [ i ] , true ) ;
// Update cell
var value = "" + obj . options . data [ cell [ 1 ] ] [ cell [ 0 ] ] ;
if ( value . substr ( 0 , 1 ) == "=" ) {
records . push ( obj . updateCell ( cell [ 0 ] , cell [ 1 ] , value , true ) ) ;
} else {
// No longer a formula, remove from the chain
Object . keys ( obj . formula ) [ i ] = null ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . updateFormulaChain ( cell [ 0 ] , cell [ 1 ] , records ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
chainLoopProtection = [ ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update formulas
* /
obj . updateFormulas = function ( referencesToUpdate ) {
// Update formulas
for ( var j = 0 ; j < obj . options . data . length ; j ++ ) {
for ( var i = 0 ; i < obj . options . data [ 0 ] . length ; i ++ ) {
var value = "" + obj . options . data [ j ] [ i ] ;
// Is formula
if ( value . substr ( 0 , 1 ) == "=" ) {
// Replace tokens
var newFormula = obj . updateFormula ( value , referencesToUpdate ) ;
if ( newFormula != value ) {
obj . options . data [ j ] [ i ] = newFormula ;
}
}
}
}
// Update formula chain
var formula = [ ] ;
var keys = Object . keys ( obj . formula ) ;
for ( var j = 0 ; j < keys . length ; j ++ ) {
// Current key and values
var key = keys [ j ] ;
var value = obj . formula [ key ] ;
// Update key
if ( referencesToUpdate [ key ] ) {
key = referencesToUpdate [ key ] ;
}
// Update values
formula [ key ] = [ ] ;
for ( var i = 0 ; i < value . length ; i ++ ) {
var letter = value [ i ] ;
if ( referencesToUpdate [ letter ] ) {
letter = referencesToUpdate [ letter ] ;
}
formula [ key ] . push ( letter ) ;
}
}
obj . formula = formula ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Update formula
* /
obj . updateFormula = function ( formula , referencesToUpdate ) {
var testLetter = /[A-Z]/ ;
var testNumber = /[0-9]/ ;
var newFormula = "" ;
var letter = null ;
var number = null ;
var token = "" ;
for ( var index = 0 ; index < formula . length ; index ++ ) {
if ( testLetter . exec ( formula [ index ] ) ) {
letter = 1 ;
number = 0 ;
token += formula [ index ] ;
} else if ( testNumber . exec ( formula [ index ] ) ) {
number = letter ? 1 : 0 ;
token += formula [ index ] ;
} else {
if ( letter && number ) {
token = referencesToUpdate [ token ]
? referencesToUpdate [ token ]
: token ;
}
newFormula += token ;
newFormula += formula [ index ] ;
letter = 0 ;
number = 0 ;
token = "" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( token ) {
if ( letter && number ) {
token = referencesToUpdate [ token ] ? referencesToUpdate [ token ] : token ;
}
newFormula += token ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return newFormula ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Secure formula
* /
var secureFormula = function ( oldValue ) {
var newValue = "" ;
var inside = 0 ;
for ( var i = 0 ; i < oldValue . length ; i ++ ) {
if ( oldValue [ i ] == '"' ) {
if ( inside == 0 ) {
inside = 1 ;
} else {
inside = 0 ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( inside == 1 ) {
newValue += oldValue [ i ] ;
} else {
newValue += oldValue [ i ] . toUpperCase ( ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return newValue ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Parse formulas
* /
obj . executeFormula = function ( expression , x , y ) {
var formulaResults = [ ] ;
var formulaLoopProtection = [ ] ;
// Execute formula with loop protection
var execute = function ( expression , x , y ) {
// Parent column identification
var parentId = jexcel . getColumnNameFromId ( [ x , y ] ) ;
// Code protection
if ( formulaLoopProtection [ parentId ] ) {
console . error ( "Reference loop detected" ) ;
return "#ERROR" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
formulaLoopProtection [ parentId ] = true ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Convert range tokens
var tokensUpdate = function ( tokens ) {
for ( var index = 0 ; index < tokens . length ; index ++ ) {
var f = [ ] ;
var token = tokens [ index ] . split ( ":" ) ;
var e1 = jexcel . getIdFromColumnName ( token [ 0 ] , true ) ;
var e2 = jexcel . getIdFromColumnName ( token [ 1 ] , true ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( e1 [ 0 ] <= e2 [ 0 ] ) {
var x1 = e1 [ 0 ] ;
var x2 = e2 [ 0 ] ;
} else {
var x1 = e2 [ 0 ] ;
var x2 = e1 [ 0 ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( e1 [ 1 ] <= e2 [ 1 ] ) {
var y1 = e1 [ 1 ] ;
var y2 = e2 [ 1 ] ;
} else {
var y1 = e2 [ 1 ] ;
var y2 = e1 [ 1 ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
for ( var j = y1 ; j <= y2 ; j ++ ) {
for ( var i = x1 ; i <= x2 ; i ++ ) {
f . push ( jexcel . getColumnNameFromId ( [ i , j ] ) ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
expression = expression . replace ( tokens [ index ] , f . join ( "," ) ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Range with $ remove $
expression = expression . replace ( /\$?([A-Z]+)\$?([0-9]+)/g , "$1$2" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
var tokens = expression . match ( /([A-Z]+[0-9]+)\:([A-Z]+[0-9]+)/g ) ;
if ( tokens && tokens . length ) {
tokensUpdate ( tokens ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Get tokens
var tokens = expression . match ( /([A-Z]+[0-9]+)/g ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Direct self-reference protection
if ( tokens && tokens . indexOf ( parentId ) > - 1 ) {
console . error ( "Self Reference detected" ) ;
return "#ERROR" ;
} else {
// Expressions to be used in the parsing
var formulaExpressions = { } ;
if ( tokens ) {
for ( var i = 0 ; i < tokens . length ; i ++ ) {
// Keep chain
if ( ! obj . formula [ tokens [ i ] ] ) {
obj . formula [ tokens [ i ] ] = [ ] ;
}
// Is already in the register
if ( obj . formula [ tokens [ i ] ] . indexOf ( parentId ) < 0 ) {
obj . formula [ tokens [ i ] ] . push ( parentId ) ;
}
// Do not calculate again
if ( eval ( "typeof(" + tokens [ i ] + ') == "undefined"' ) ) {
// Coords
var position = jexcel . getIdFromColumnName ( tokens [ i ] , 1 ) ;
// Get value
if (
typeof obj . options . data [ position [ 1 ] ] != "undefined" &&
typeof obj . options . data [ position [ 1 ] ] [ position [ 0 ] ] !=
"undefined"
) {
var value = obj . options . data [ position [ 1 ] ] [ position [ 0 ] ] ;
} else {
var value = "" ;
}
// Get column data
if ( ( "" + value ) . substr ( 0 , 1 ) == "=" ) {
if ( formulaResults [ tokens [ i ] ] ) {
value = formulaResults [ tokens [ i ] ] ;
} else {
value = execute ( value , position [ 0 ] , position [ 1 ] ) ;
formulaResults [ tokens [ i ] ] = value ;
}
}
// Type!
if ( ( "" + value ) . trim ( ) == "" ) {
// Null
formulaExpressions [ tokens [ i ] ] = null ;
} else {
if (
value == Number ( value ) &&
obj . options . autoCasting == true
) {
// Number
formulaExpressions [ tokens [ i ] ] = Number ( value ) ;
} else {
// Trying any formatted number
var number = obj . parseNumber ( value , position [ 0 ] ) ;
if ( obj . options . autoCasting == true && number ) {
formulaExpressions [ tokens [ i ] ] = number ;
} else {
formulaExpressions [ tokens [ i ] ] = '"' + value + '"' ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Convert formula to javascript
try {
var res = jexcel . formula (
expression . substr ( 1 ) ,
formulaExpressions ,
x ,
y ,
obj
) ;
} catch ( e ) {
var res = "#ERROR" ;
console . log ( e ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return res ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return execute ( expression , x , y ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Trying to extract a number from a string
* /
obj . parseNumber = function ( value , columnNumber ) {
// Decimal point
var decimal =
columnNumber && obj . options . columns [ columnNumber ] . decimal
? obj . options . columns [ columnNumber ] . decimal
: "." ;
// Parse both parts of the number
var number = "" + value ;
number = number . split ( decimal ) ;
number [ 0 ] = number [ 0 ] . match ( /[+-]?[0-9]/g ) ;
if ( number [ 0 ] ) {
number [ 0 ] = number [ 0 ] . join ( "" ) ;
}
if ( number [ 1 ] ) {
number [ 1 ] = number [ 1 ] . match ( /[0-9]*/g ) . join ( "" ) ;
}
// Is a valid number
if ( number [ 0 ] && Number . isInteger ( Number ( number [ 0 ] ) ) ) {
if ( ! number [ 1 ] ) {
var value = Number ( number [ 0 ] + ".00" ) ;
} else {
var value = Number ( number [ 0 ] + "." + number [ 1 ] ) ;
}
} else {
var value = null ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return value ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get row number
* /
obj . row = function ( cell ) { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get col number
* /
obj . col = function ( cell ) { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . up = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( obj . selectedCell [ 3 ] > 0 ) {
obj . up . visible ( 1 , ctrlKey ? 0 : 1 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else {
if ( obj . selectedCell [ 1 ] > 0 ) {
obj . up . visible ( 0 , ctrlKey ? 0 : 1 ) ;
}
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
// Update selection
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
// Change page
if ( obj . options . lazyLoading == true ) {
if ( obj . selectedCell [ 1 ] == 0 || obj . selectedCell [ 3 ] == 0 ) {
obj . loadPage ( 0 ) ;
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
} else {
if ( obj . loadValidation ( ) ) {
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
} else {
var item = parseInt ( obj . tbody . firstChild . getAttribute ( "data-y" ) ) ;
if ( obj . selectedCell [ 1 ] - item < 30 ) {
obj . loadUp ( ) ;
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
}
}
}
} else if ( obj . options . pagination > 0 ) {
var pageNumber = obj . whichPage ( obj . selectedCell [ 3 ] ) ;
if ( pageNumber != obj . pageNumber ) {
obj . page ( pageNumber ) ;
}
}
obj . updateScroll ( 1 ) ;
} ;
obj . up . visible = function ( group , direction ) {
if ( group == 0 ) {
var x = parseInt ( obj . selectedCell [ 0 ] ) ;
var y = parseInt ( obj . selectedCell [ 1 ] ) ;
} else {
var x = parseInt ( obj . selectedCell [ 2 ] ) ;
var y = parseInt ( obj . selectedCell [ 3 ] ) ;
}
if ( direction == 0 ) {
for ( var j = 0 ; j < y ; j ++ ) {
if (
obj . records [ j ] [ x ] . style . display != "none" &&
obj . rows [ j ] . style . display != "none"
) {
y = j ;
break ;
}
}
} else {
y = obj . up . get ( x , y ) ;
}
if ( group == 0 ) {
obj . selectedCell [ 0 ] = x ;
obj . selectedCell [ 1 ] = y ;
} else {
obj . selectedCell [ 2 ] = x ;
obj . selectedCell [ 3 ] = y ;
}
} ;
obj . up . get = function ( x , y ) {
var x = parseInt ( x ) ;
var y = parseInt ( y ) ;
for ( var j = y - 1 ; j >= 0 ; j -- ) {
if (
obj . records [ j ] [ x ] . style . display != "none" &&
obj . rows [ j ] . style . display != "none"
) {
if ( obj . records [ j ] [ x ] . getAttribute ( "data-merged" ) ) {
if ( obj . records [ j ] [ x ] == obj . records [ y ] [ x ] ) {
continue ;
}
}
y = j ;
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return y ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . down = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( obj . selectedCell [ 3 ] < obj . records . length - 1 ) {
obj . down . visible ( 1 , ctrlKey ? 0 : 1 ) ;
}
} else {
if ( obj . selectedCell [ 1 ] < obj . records . length - 1 ) {
obj . down . visible ( 0 , ctrlKey ? 0 : 1 ) ;
}
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
// Change page
if ( obj . options . lazyLoading == true ) {
if (
obj . selectedCell [ 1 ] == obj . records . length - 1 ||
obj . selectedCell [ 3 ] == obj . records . length - 1
) {
obj . loadPage ( - 1 ) ;
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
} else {
if ( obj . loadValidation ( ) ) {
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
} else {
var item = parseInt ( obj . tbody . lastChild . getAttribute ( "data-y" ) ) ;
if ( item - obj . selectedCell [ 3 ] < 30 ) {
obj . loadDown ( ) ;
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
}
}
}
} else if ( obj . options . pagination > 0 ) {
var pageNumber = obj . whichPage ( obj . selectedCell [ 3 ] ) ;
if ( pageNumber != obj . pageNumber ) {
obj . page ( pageNumber ) ;
}
}
obj . updateScroll ( 3 ) ;
} ;
obj . down . visible = function ( group , direction ) {
if ( group == 0 ) {
var x = parseInt ( obj . selectedCell [ 0 ] ) ;
var y = parseInt ( obj . selectedCell [ 1 ] ) ;
} else {
var x = parseInt ( obj . selectedCell [ 2 ] ) ;
var y = parseInt ( obj . selectedCell [ 3 ] ) ;
}
if ( direction == 0 ) {
for ( var j = obj . rows . length - 1 ; j > y ; j -- ) {
if (
obj . records [ j ] [ x ] . style . display != "none" &&
obj . rows [ j ] . style . display != "none"
) {
y = j ;
break ;
}
}
} else {
y = obj . down . get ( x , y ) ;
}
if ( group == 0 ) {
obj . selectedCell [ 0 ] = x ;
obj . selectedCell [ 1 ] = y ;
} else {
obj . selectedCell [ 2 ] = x ;
obj . selectedCell [ 3 ] = y ;
}
} ;
obj . down . get = function ( x , y ) {
var x = parseInt ( x ) ;
var y = parseInt ( y ) ;
for ( var j = y + 1 ; j < obj . rows . length ; j ++ ) {
if (
obj . records [ j ] [ x ] . style . display != "none" &&
obj . rows [ j ] . style . display != "none"
) {
if ( obj . records [ j ] [ x ] . getAttribute ( "data-merged" ) ) {
if ( obj . records [ j ] [ x ] == obj . records [ y ] [ x ] ) {
continue ;
}
}
y = j ;
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return y ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . right = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( obj . selectedCell [ 2 ] < obj . headers . length - 1 ) {
obj . right . visible ( 1 , ctrlKey ? 0 : 1 ) ;
}
} else {
if ( obj . selectedCell [ 0 ] < obj . headers . length - 1 ) {
obj . right . visible ( 0 , ctrlKey ? 0 : 1 ) ;
}
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
obj . updateScroll ( 2 ) ;
} ;
obj . right . visible = function ( group , direction ) {
if ( group == 0 ) {
var x = parseInt ( obj . selectedCell [ 0 ] ) ;
var y = parseInt ( obj . selectedCell [ 1 ] ) ;
} else {
var x = parseInt ( obj . selectedCell [ 2 ] ) ;
var y = parseInt ( obj . selectedCell [ 3 ] ) ;
}
if ( direction == 0 ) {
for ( var i = obj . headers . length - 1 ; i > x ; i -- ) {
if ( obj . records [ y ] [ i ] . style . display != "none" ) {
x = i ;
break ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else {
x = obj . right . get ( x , y ) ;
}
if ( group == 0 ) {
obj . selectedCell [ 0 ] = x ;
obj . selectedCell [ 1 ] = y ;
} else {
obj . selectedCell [ 2 ] = x ;
obj . selectedCell [ 3 ] = y ;
}
} ;
obj . right . get = function ( x , y ) {
var x = parseInt ( x ) ;
var y = parseInt ( y ) ;
for ( var i = x + 1 ; i < obj . headers . length ; i ++ ) {
if ( obj . records [ y ] [ i ] . style . display != "none" ) {
if ( obj . records [ y ] [ i ] . getAttribute ( "data-merged" ) ) {
if ( obj . records [ y ] [ i ] == obj . records [ y ] [ x ] ) {
continue ;
}
}
x = i ;
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return x ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . left = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( obj . selectedCell [ 2 ] > 0 ) {
obj . left . visible ( 1 , ctrlKey ? 0 : 1 ) ;
}
} else {
if ( obj . selectedCell [ 0 ] > 0 ) {
obj . left . visible ( 0 , ctrlKey ? 0 : 1 ) ;
}
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
obj . updateScroll ( 0 ) ;
} ;
obj . left . visible = function ( group , direction ) {
if ( group == 0 ) {
var x = parseInt ( obj . selectedCell [ 0 ] ) ;
var y = parseInt ( obj . selectedCell [ 1 ] ) ;
} else {
var x = parseInt ( obj . selectedCell [ 2 ] ) ;
var y = parseInt ( obj . selectedCell [ 3 ] ) ;
}
if ( direction == 0 ) {
for ( var i = 0 ; i < x ; i ++ ) {
if ( obj . records [ y ] [ i ] . style . display != "none" ) {
x = i ;
break ;
}
}
} else {
x = obj . left . get ( x , y ) ;
}
if ( group == 0 ) {
obj . selectedCell [ 0 ] = x ;
obj . selectedCell [ 1 ] = y ;
} else {
obj . selectedCell [ 2 ] = x ;
obj . selectedCell [ 3 ] = y ;
}
} ;
obj . left . get = function ( x , y ) {
var x = parseInt ( x ) ;
var y = parseInt ( y ) ;
for ( var i = x - 1 ; i >= 0 ; i -- ) {
if ( obj . records [ y ] [ i ] . style . display != "none" ) {
if ( obj . records [ y ] [ i ] . getAttribute ( "data-merged" ) ) {
if ( obj . records [ y ] [ i ] == obj . records [ y ] [ x ] ) {
continue ;
}
}
x = i ;
break ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return x ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . first = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( ctrlKey ) {
obj . selectedCell [ 3 ] = 0 ;
} else {
obj . left . visible ( 1 , 0 ) ;
}
} else {
if ( ctrlKey ) {
obj . selectedCell [ 1 ] = 0 ;
} else {
obj . left . visible ( 0 , 0 ) ;
}
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
// Change page
if (
obj . options . lazyLoading == true &&
( obj . selectedCell [ 1 ] == 0 || obj . selectedCell [ 3 ] == 0 )
) {
obj . loadPage ( 0 ) ;
} else if ( obj . options . pagination > 0 ) {
var pageNumber = obj . whichPage ( obj . selectedCell [ 3 ] ) ;
if ( pageNumber != obj . pageNumber ) {
obj . page ( pageNumber ) ;
}
}
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
obj . updateScroll ( 1 ) ;
} ;
obj . last = function ( shiftKey , ctrlKey ) {
if ( shiftKey ) {
if ( ctrlKey ) {
obj . selectedCell [ 3 ] = obj . records . length - 1 ;
} else {
obj . right . visible ( 1 , 0 ) ;
}
} else {
if ( ctrlKey ) {
obj . selectedCell [ 1 ] = obj . records . length - 1 ;
} else {
obj . right . visible ( 0 , 0 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . selectedCell [ 2 ] = obj . selectedCell [ 0 ] ;
obj . selectedCell [ 3 ] = obj . selectedCell [ 1 ] ;
}
// Change page
if (
obj . options . lazyLoading == true &&
( obj . selectedCell [ 1 ] == obj . records . length - 1 ||
obj . selectedCell [ 3 ] == obj . records . length - 1 )
) {
obj . loadPage ( - 1 ) ;
} else if ( obj . options . pagination > 0 ) {
var pageNumber = obj . whichPage ( obj . selectedCell [ 3 ] ) ;
if ( pageNumber != obj . pageNumber ) {
obj . page ( pageNumber ) ;
}
}
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
obj . updateScroll ( 3 ) ;
} ;
obj . selectAll = function ( ) {
if ( ! obj . selectedCell ) {
obj . selectedCell = [ ] ;
}
obj . selectedCell [ 0 ] = 0 ;
obj . selectedCell [ 1 ] = 0 ;
obj . selectedCell [ 2 ] = obj . headers . length - 1 ;
obj . selectedCell [ 3 ] = obj . records . length - 1 ;
obj . updateSelectionFromCoords (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
obj . selectedCell [ 2 ] ,
obj . selectedCell [ 3 ]
) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Go to a page in a lazyLoading
* /
obj . loadPage = function ( pageNumber ) {
// Search
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
var results = obj . results ;
} else {
var results = obj . rows ;
}
// Per page
var quantityPerPage = 100 ;
// pageNumber
if ( pageNumber == null || pageNumber == - 1 ) {
// Last page
pageNumber = Math . ceil ( results . length / quantityPerPage ) - 1 ;
}
var startRow = pageNumber * quantityPerPage ;
var finalRow = pageNumber * quantityPerPage + quantityPerPage ;
if ( finalRow > results . length ) {
finalRow = results . length ;
}
startRow = finalRow - 100 ;
if ( startRow < 0 ) {
startRow = 0 ;
}
// Appeding items
for ( var j = startRow ; j < finalRow ; j ++ ) {
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
obj . tbody . appendChild ( obj . rows [ results [ j ] ] ) ;
} else {
obj . tbody . appendChild ( obj . rows [ j ] ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . tbody . children . length > quantityPerPage ) {
obj . tbody . removeChild ( obj . tbody . firstChild ) ;
}
}
} ;
obj . loadUp = function ( ) {
// Search
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
var results = obj . results ;
} else {
var results = obj . rows ;
}
var test = 0 ;
if ( results . length > 100 ) {
// Get the first element in the page
var item = parseInt ( obj . tbody . firstChild . getAttribute ( "data-y" ) ) ;
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
item = results . indexOf ( item ) ;
}
if ( item > 0 ) {
for ( var j = 0 ; j < 30 ; j ++ ) {
item = item - 1 ;
if ( item > - 1 ) {
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
obj . tbody . insertBefore (
obj . rows [ results [ item ] ] ,
obj . tbody . firstChild
) ;
} else {
obj . tbody . insertBefore ( obj . rows [ item ] , obj . tbody . firstChild ) ;
}
if ( obj . tbody . children . length > 100 ) {
obj . tbody . removeChild ( obj . tbody . lastChild ) ;
test = 1 ;
}
}
}
}
}
return test ;
} ;
obj . loadDown = function ( ) {
// Search
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
var results = obj . results ;
} else {
var results = obj . rows ;
}
var test = 0 ;
if ( results . length > 100 ) {
// Get the last element in the page
var item = parseInt ( obj . tbody . lastChild . getAttribute ( "data-y" ) ) ;
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
item = results . indexOf ( item ) ;
}
if ( item < obj . rows . length - 1 ) {
for ( var j = 0 ; j <= 30 ; j ++ ) {
if ( item < results . length ) {
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
obj . tbody . appendChild ( obj . rows [ results [ item ] ] ) ;
} else {
obj . tbody . appendChild ( obj . rows [ item ] ) ;
}
if ( obj . tbody . children . length > 100 ) {
obj . tbody . removeChild ( obj . tbody . firstChild ) ;
test = 1 ;
}
}
item = item + 1 ;
}
}
}
return test ;
} ;
obj . loadValidation = function ( ) {
if ( obj . selectedCell ) {
var currentPage =
parseInt ( obj . tbody . firstChild . getAttribute ( "data-y" ) ) / 100 ;
var selectedPage = parseInt ( obj . selectedCell [ 3 ] / 100 ) ;
var totalPages = parseInt ( obj . rows . length / 100 ) ;
if ( currentPage != selectedPage && selectedPage <= totalPages ) {
if (
! Array . prototype . indexOf . call (
obj . tbody . children ,
obj . rows [ obj . selectedCell [ 3 ] ]
)
) {
obj . loadPage ( selectedPage ) ;
return true ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return false ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Reset search
* /
obj . resetSearch = function ( ) {
obj . searchInput . value = "" ;
obj . search ( "" ) ;
obj . results = null ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Search
* /
obj . search = function ( query ) {
// Query
if ( query ) {
var query = query . toLowerCase ( ) ;
}
// Reset any filter
if ( obj . options . filters ) {
obj . resetFilters ( ) ;
}
// Reset selection
obj . resetSelection ( ) ;
// Total of results
obj . pageNumber = 0 ;
obj . results = [ ] ;
if ( query ) {
// Search filter
var search = function ( item , query , index ) {
for ( var i = 0 ; i < item . length ; i ++ ) {
if (
( "" + item [ i ] ) . toLowerCase ( ) . search ( query ) >= 0 ||
( "" + obj . records [ index ] [ i ] . innerHTML )
. toLowerCase ( )
. search ( query ) >= 0
) {
return true ;
}
}
return false ;
} ;
// Result
var addToResult = function ( k ) {
if ( obj . results . indexOf ( k ) == - 1 ) {
obj . results . push ( k ) ;
}
} ;
// Filter
var data = obj . options . data . filter ( function ( v , k ) {
if ( search ( v , query , k ) ) {
// Merged rows found
var rows = obj . isRowMerged ( k ) ;
if ( rows . length ) {
for ( var i = 0 ; i < rows . length ; i ++ ) {
var row = jexcel . getIdFromColumnName ( rows [ i ] , true ) ;
for ( var j = 0 ; j < obj . options . mergeCells [ rows [ i ] ] [ 1 ] ; j ++ ) {
addToResult ( row [ 1 ] + j ) ;
}
}
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
// Normal row found
addToResult ( k ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
return true ;
} else {
return false ;
}
} ) ;
} else {
obj . results = null ;
}
return obj . updateResult ( ) ;
} ;
obj . updateResult = function ( ) {
var total = 0 ;
var index = 0 ;
// Page 1
if ( obj . options . lazyLoading == true ) {
total = 100 ;
} else if ( obj . options . pagination > 0 ) {
total = obj . options . pagination ;
} else {
if ( obj . results ) {
total = obj . results . length ;
} else {
total = obj . rows . length ;
}
}
// Reset current nodes
while ( obj . tbody . firstChild ) {
obj . tbody . removeChild ( obj . tbody . firstChild ) ;
}
// Hide all records from the table
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( ! obj . results || obj . results . indexOf ( j ) > - 1 ) {
if ( index < total ) {
obj . tbody . appendChild ( obj . rows [ j ] ) ;
index ++ ;
}
obj . rows [ j ] . style . display = "" ;
} else {
obj . rows [ j ] . style . display = "none" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update pagination
if ( obj . options . pagination > 0 ) {
obj . updatePagination ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . updateCornerPosition ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return total ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Which page the cell is
* /
obj . whichPage = function ( cell ) {
// Search
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
cell = obj . results . indexOf ( cell ) ;
}
return (
Math . ceil ( ( parseInt ( cell ) + 1 ) / parseInt ( obj . options . pagination ) ) - 1
) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Go to page
* /
obj . page = function ( pageNumber ) {
var oldPage = obj . pageNumber ;
// Search
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
var results = obj . results ;
} else {
var results = obj . rows ;
}
// Per page
var quantityPerPage = parseInt ( obj . options . pagination ) ;
// pageNumber
if ( pageNumber == null || pageNumber == - 1 ) {
// Last page
pageNumber = Math . ceil ( results . length / quantityPerPage ) - 1 ;
}
// Page number
obj . pageNumber = pageNumber ;
var startRow = pageNumber * quantityPerPage ;
var finalRow = pageNumber * quantityPerPage + quantityPerPage ;
if ( finalRow > results . length ) {
finalRow = results . length ;
}
if ( startRow < 0 ) {
startRow = 0 ;
}
// Reset container
while ( obj . tbody . firstChild ) {
obj . tbody . removeChild ( obj . tbody . firstChild ) ;
}
// Appeding items
for ( var j = startRow ; j < finalRow ; j ++ ) {
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
obj . tbody . appendChild ( obj . rows [ results [ j ] ] ) ;
} else {
obj . tbody . appendChild ( obj . rows [ j ] ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( obj . options . pagination > 0 ) {
obj . updatePagination ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update corner position
obj . updateCornerPosition ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Events
obj . dispatch ( "onchangepage" , el , pageNumber , oldPage ) ;
} ;
/ * *
* Update the pagination
* /
obj . updatePagination = function ( ) {
// Reset container
obj . pagination . children [ 0 ] . innerHTML = "" ;
obj . pagination . children [ 1 ] . innerHTML = "" ;
// Start pagination
if ( obj . options . pagination ) {
// Searchable
if (
( obj . options . search == true || obj . options . filters == true ) &&
obj . results
) {
var results = obj . results . length ;
} else {
var results = obj . rows . length ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( ! results ) {
// No records found
obj . pagination . children [ 0 ] . innerHTML =
obj . options . text . noRecordsFound ;
} else {
// Pagination container
var quantyOfPages = Math . ceil ( results / obj . options . pagination ) ;
if ( obj . pageNumber < 6 ) {
var startNumber = 1 ;
var finalNumber = quantyOfPages < 10 ? quantyOfPages : 10 ;
} else if ( quantyOfPages - obj . pageNumber < 5 ) {
var startNumber = quantyOfPages - 9 ;
var finalNumber = quantyOfPages ;
if ( startNumber < 1 ) {
startNumber = 1 ;
}
} else {
var startNumber = obj . pageNumber - 4 ;
var finalNumber = obj . pageNumber + 5 ;
}
// First
if ( startNumber > 1 ) {
var paginationItem = document . createElement ( "div" ) ;
paginationItem . className = "jexcel_page" ;
paginationItem . innerHTML = "<" ;
paginationItem . title = 1 ;
obj . pagination . children [ 1 ] . appendChild ( paginationItem ) ;
}
// Get page links
for ( var i = startNumber ; i <= finalNumber ; i ++ ) {
var paginationItem = document . createElement ( "div" ) ;
paginationItem . className = "jexcel_page" ;
paginationItem . innerHTML = i ;
obj . pagination . children [ 1 ] . appendChild ( paginationItem ) ;
if ( obj . pageNumber == i - 1 ) {
paginationItem . classList . add ( "jexcel_page_selected" ) ;
}
}
// Last
if ( finalNumber < quantyOfPages ) {
var paginationItem = document . createElement ( "div" ) ;
paginationItem . className = "jexcel_page" ;
paginationItem . innerHTML = ">" ;
paginationItem . title = quantyOfPages ;
obj . pagination . children [ 1 ] . appendChild ( paginationItem ) ;
}
// Text
var format = function ( format ) {
var args = Array . prototype . slice . call ( arguments , 1 ) ;
return format . replace ( /{(\d+)}/g , function ( match , number ) {
return typeof args [ number ] != "undefined" ? args [ number ] : match ;
} ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . pagination . children [ 0 ] . innerHTML = format (
obj . options . text . showingPage ,
obj . pageNumber + 1 ,
quantyOfPages
) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Download CSV table
*
* @ return null
* /
obj . download = function ( includeHeaders ) {
if ( obj . options . allowExport == false ) {
console . error ( "Export not allowed" ) ;
} else {
// Data
var data = "" ;
// Get data
data += obj . copy (
false ,
obj . options . csvDelimiter ,
true ,
includeHeaders ,
true
) ;
// Download element
var blob = new Blob ( [ "\uFEFF" + data ] , {
type : "text/csv;charset=utf-8;" ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// IE Compatibility
if ( window . navigator && window . navigator . msSaveOrOpenBlob ) {
window . navigator . msSaveOrOpenBlob (
blob ,
obj . options . csvFileName + ".csv"
) ;
} else {
// Download element
var pom = document . createElement ( "a" ) ;
var url = URL . createObjectURL ( blob ) ;
pom . href = url ;
pom . setAttribute ( "download" , obj . options . csvFileName + ".csv" ) ;
document . body . appendChild ( pom ) ;
pom . click ( ) ;
pom . parentNode . removeChild ( pom ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Initializes a new history record for undo / redo
*
* @ return null
* /
obj . setHistory = function ( changes ) {
if ( obj . ignoreHistory != true ) {
// Increment and get the current history index
var index = ++ obj . historyIndex ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Slice the array to discard undone changes
obj . history = obj . history = obj . history . slice ( 0 , index + 1 ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Keep history
obj . history [ index ] = changes ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Copy method
*
* @ param bool highlighted - Get only highlighted cells
* @ param delimiter - \ t default to keep compatibility with excel
* @ return string value
* /
obj . copy = function (
highlighted ,
delimiter ,
returnData ,
includeHeaders ,
download
) {
if ( ! delimiter ) {
delimiter = "\t" ;
}
var div = new RegExp ( delimiter , "ig" ) ;
// Controls
var header = [ ] ;
var col = [ ] ;
var colLabel = [ ] ;
var row = [ ] ;
var rowLabel = [ ] ;
var x = obj . options . data [ 0 ] . length ;
var y = obj . options . data . length ;
var tmp = "" ;
var copyHeader = false ;
var headers = "" ;
var nestedHeaders = "" ;
var numOfCols = 0 ;
var numOfRows = 0 ;
// Partial copy
var copyX = 0 ;
var copyY = 0 ;
var isPartialCopy = true ;
// Go through the columns to get the data
for ( var j = 0 ; j < y ; j ++ ) {
for ( var i = 0 ; i < x ; i ++ ) {
// If cell is highlighted
if (
! highlighted ||
obj . records [ j ] [ i ] . classList . contains ( "highlight" )
) {
if ( copyX <= i ) {
copyX = i ;
}
if ( copyY <= j ) {
copyY = j ;
}
}
}
}
if ( x === copyX + 1 && y === copyY + 1 ) {
isPartialCopy = false ;
}
if (
( download && obj . options . includeHeadersOnDownload == true ) ||
( ! download &&
obj . options . includeHeadersOnCopy == true &&
! isPartialCopy ) ||
includeHeaders
) {
// Nested headers
if ( obj . options . nestedHeaders && obj . options . nestedHeaders . length > 0 ) {
// Flexible way to handle nestedheaders
if (
! ( obj . options . nestedHeaders [ 0 ] && obj . options . nestedHeaders [ 0 ] [ 0 ] )
) {
tmp = [ obj . options . nestedHeaders ] ;
} else {
tmp = obj . options . nestedHeaders ;
}
for ( var j = 0 ; j < tmp . length ; j ++ ) {
var nested = [ ] ;
for ( var i = 0 ; i < tmp [ j ] . length ; i ++ ) {
var colspan = parseInt ( tmp [ j ] [ i ] . colspan ) ;
nested . push ( tmp [ j ] [ i ] . title ) ;
for ( var c = 0 ; c < colspan - 1 ; c ++ ) {
nested . push ( "" ) ;
}
}
nestedHeaders += nested . join ( delimiter ) + "\r\n" ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
copyHeader = true ;
}
// Reset container
obj . style = [ ] ;
// Go through the columns to get the data
for ( var j = 0 ; j < y ; j ++ ) {
col = [ ] ;
colLabel = [ ] ;
for ( var i = 0 ; i < x ; i ++ ) {
// If cell is highlighted
if (
! highlighted ||
obj . records [ j ] [ i ] . classList . contains ( "highlight" )
) {
if ( copyHeader == true ) {
header . push ( obj . headers [ i ] . textContent ) ;
}
// Values
var value = obj . options . data [ j ] [ i ] ;
if (
value . match &&
( value . match ( div ) ||
value . match ( /,/g ) ||
value . match ( /\n/ ) ||
value . match ( /\"/ ) )
) {
value = value . replace ( new RegExp ( '"' , "g" ) , '""' ) ;
value = '"' + value + '"' ;
}
col . push ( value ) ;
// Labels
if (
obj . options . columns [ i ] . type == "checkbox" ||
obj . options . columns [ i ] . type == "radio"
) {
var label = value ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
if ( obj . options . stripHTMLOnCopy == true ) {
var label = obj . records [ j ] [ i ] . textContent ;
} else {
var label = obj . records [ j ] [ i ] . innerHTML ;
}
if (
label . match &&
( label . match ( div ) ||
label . match ( /,/g ) ||
label . match ( /\n/ ) ||
label . match ( /\"/ ) )
) {
// Scape double quotes
label = label . replace ( new RegExp ( '"' , "g" ) , '""' ) ;
label = '"' + label + '"' ;
}
}
colLabel . push ( label ) ;
// Get style
tmp = obj . records [ j ] [ i ] . getAttribute ( "style" ) ;
tmp = tmp . replace ( "display: none;" , "" ) ;
obj . style . push ( tmp ? tmp : "" ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( col . length ) {
if ( copyHeader ) {
numOfCols = col . length ;
row . push ( header . join ( delimiter ) ) ;
}
row . push ( col . join ( delimiter ) ) ;
}
if ( colLabel . length ) {
numOfRows ++ ;
if ( copyHeader ) {
rowLabel . push ( header . join ( delimiter ) ) ;
copyHeader = false ;
}
rowLabel . push ( colLabel . join ( delimiter ) ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( x == numOfCols && y == numOfRows ) {
headers = nestedHeaders ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Final string
var str = headers + row . join ( "\r\n" ) ;
var strLabel = headers + rowLabel . join ( "\r\n" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Create a hidden textarea to copy the values
if ( ! returnData ) {
if ( obj . options . copyCompatibility == true ) {
obj . textarea . value = strLabel ;
} else {
obj . textarea . value = str ;
}
obj . textarea . select ( ) ;
document . execCommand ( "copy" ) ;
}
// Keep data
if ( obj . options . copyCompatibility == true ) {
obj . data = strLabel ;
} else {
obj . data = str ;
}
// Keep non visible information
obj . hashString = obj . hash ( obj . data ) ;
// Any exiting border should go
if ( ! returnData ) {
obj . removeCopyingSelection ( ) ;
// Border
if ( obj . highlighted ) {
for ( var i = 0 ; i < obj . highlighted . length ; i ++ ) {
obj . highlighted [ i ] . classList . add ( "copying" ) ;
if ( obj . highlighted [ i ] . classList . contains ( "highlight-left" ) ) {
obj . highlighted [ i ] . classList . add ( "copying-left" ) ;
}
if ( obj . highlighted [ i ] . classList . contains ( "highlight-right" ) ) {
obj . highlighted [ i ] . classList . add ( "copying-right" ) ;
}
if ( obj . highlighted [ i ] . classList . contains ( "highlight-top" ) ) {
obj . highlighted [ i ] . classList . add ( "copying-top" ) ;
}
if ( obj . highlighted [ i ] . classList . contains ( "highlight-bottom" ) ) {
obj . highlighted [ i ] . classList . add ( "copying-bottom" ) ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Paste event
obj . dispatch (
"oncopy" ,
el ,
obj . options . copyCompatibility == true ? rowLabel : row ,
obj . hashString
) ;
}
return obj . data ;
} ;
/ * *
* Jspreadsheet paste method
*
* @ param integer row number
* @ return string value
* /
obj . paste = function ( x , y , data ) {
// Paste filter
var ret = obj . dispatch ( "onbeforepaste" , el , data , x , y ) ;
if ( ret === false ) {
return false ;
} else if ( ret ) {
var data = ret ;
}
// Controls
var hash = obj . hash ( data ) ;
var style = hash == obj . hashString ? obj . style : null ;
// Depending on the behavior
if ( obj . options . copyCompatibility == true && hash == obj . hashString ) {
var data = obj . data ;
}
// Split new line
var data = obj . parseCSV ( data , "\t" ) ;
if ( x != null && y != null && data ) {
// Records
var i = 0 ;
var j = 0 ;
var records = [ ] ;
var newStyle = { } ;
var oldStyle = { } ;
var styleIndex = 0 ;
// Index
var colIndex = parseInt ( x ) ;
var rowIndex = parseInt ( y ) ;
var row = null ;
// Go through the columns to get the data
while ( ( row = data [ j ] ) ) {
i = 0 ;
colIndex = parseInt ( x ) ;
while ( row [ i ] != null ) {
// Update and keep history
var record = obj . updateCell ( colIndex , rowIndex , row [ i ] ) ;
// Keep history
records . push ( record ) ;
// Update all formulas in the chain
obj . updateFormulaChain ( colIndex , rowIndex , records ) ;
// Style
if ( style && style [ styleIndex ] ) {
var columnName = jexcel . getColumnNameFromId ( [ colIndex , rowIndex ] ) ;
newStyle [ columnName ] = style [ styleIndex ] ;
oldStyle [ columnName ] = obj . getStyle ( columnName ) ;
obj . records [ rowIndex ] [ colIndex ] . setAttribute (
"style" ,
style [ styleIndex ]
) ;
styleIndex ++ ;
}
i ++ ;
if ( row [ i ] != null ) {
if ( colIndex >= obj . headers . length - 1 ) {
// If the pasted column is out of range, create it if possible
if ( obj . options . allowInsertColumn == true ) {
obj . insertColumn ( ) ;
// Otherwise skip the pasted data that overflows
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
break ;
}
}
colIndex = obj . right . get ( colIndex , rowIndex ) ;
}
}
j ++ ;
if ( data [ j ] ) {
if ( rowIndex >= obj . rows . length - 1 ) {
// If the pasted row is out of range, create it if possible
if ( obj . options . allowInsertRow == true ) {
obj . insertRow ( ) ;
// Otherwise skip the pasted data that overflows
} else {
break ;
}
}
rowIndex = obj . down . get ( x , rowIndex ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Select the new cells
obj . updateSelectionFromCoords ( x , y , colIndex , rowIndex ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update history
obj . setHistory ( {
action : "setValue" ,
records : records ,
selection : obj . selectedCell ,
newStyle : newStyle ,
oldStyle : oldStyle ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Update table
obj . updateTable ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Paste event
obj . dispatch ( "onpaste" , el , data ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// On after changes
obj . onafterchanges ( el , records ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . removeCopyingSelection ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Remove copying border
* /
obj . removeCopyingSelection = function ( ) {
var copying = document . querySelectorAll ( ".jexcel .copying" ) ;
for ( var i = 0 ; i < copying . length ; i ++ ) {
copying [ i ] . classList . remove ( "copying" ) ;
copying [ i ] . classList . remove ( "copying-left" ) ;
copying [ i ] . classList . remove ( "copying-right" ) ;
copying [ i ] . classList . remove ( "copying-top" ) ;
copying [ i ] . classList . remove ( "copying-bottom" ) ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Process row
* /
obj . historyProcessRow = function ( type , historyRecord ) {
var rowIndex = ! historyRecord . insertBefore
? historyRecord . rowNumber + 1
: + historyRecord . rowNumber ;
if ( obj . options . search == true ) {
if ( obj . results && obj . results . length != obj . rows . length ) {
obj . resetSearch ( ) ;
}
}
// Remove row
if ( type == 1 ) {
var numOfRows = historyRecord . numOfRows ;
// Remove nodes
for ( var j = rowIndex ; j < numOfRows + rowIndex ; j ++ ) {
obj . rows [ j ] . parentNode . removeChild ( obj . rows [ j ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Remove references
obj . records . splice ( rowIndex , numOfRows ) ;
obj . options . data . splice ( rowIndex , numOfRows ) ;
obj . rows . splice ( rowIndex , numOfRows ) ;
obj . conditionalSelectionUpdate ( 1 , rowIndex , numOfRows + rowIndex - 1 ) ;
} else {
// Insert data
obj . records = jexcel . injectArray (
obj . records ,
rowIndex ,
historyRecord . rowRecords
) ;
obj . options . data = jexcel . injectArray (
obj . options . data ,
rowIndex ,
historyRecord . rowData
) ;
obj . rows = jexcel . injectArray (
obj . rows ,
rowIndex ,
historyRecord . rowNode
) ;
// Insert nodes
var index = 0 ;
for ( var j = rowIndex ; j < historyRecord . numOfRows + rowIndex ; j ++ ) {
obj . tbody . insertBefore (
historyRecord . rowNode [ index ] ,
obj . tbody . children [ j ]
) ;
index ++ ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Respect pagination
if ( obj . options . pagination > 0 ) {
obj . page ( obj . pageNumber ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . updateTableReferences ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Process column
* /
obj . historyProcessColumn = function ( type , historyRecord ) {
var columnIndex = ! historyRecord . insertBefore
? historyRecord . columnNumber + 1
: historyRecord . columnNumber ;
// Remove column
if ( type == 1 ) {
var numOfColumns = historyRecord . numOfColumns ;
obj . options . columns . splice ( columnIndex , numOfColumns ) ;
for ( var i = columnIndex ; i < numOfColumns + columnIndex ; i ++ ) {
obj . headers [ i ] . parentNode . removeChild ( obj . headers [ i ] ) ;
obj . colgroup [ i ] . parentNode . removeChild ( obj . colgroup [ i ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . headers . splice ( columnIndex , numOfColumns ) ;
obj . colgroup . splice ( columnIndex , numOfColumns ) ;
for ( var j = 0 ; j < historyRecord . data . length ; j ++ ) {
for ( var i = columnIndex ; i < numOfColumns + columnIndex ; i ++ ) {
obj . records [ j ] [ i ] . parentNode . removeChild ( obj . records [ j ] [ i ] ) ;
}
obj . records [ j ] . splice ( columnIndex , numOfColumns ) ;
obj . options . data [ j ] . splice ( columnIndex , numOfColumns ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Process footers
if ( obj . options . footers ) {
for ( var j = 0 ; j < obj . options . footers . length ; j ++ ) {
obj . options . footers [ j ] . splice ( columnIndex , numOfColumns ) ;
}
}
} else {
// Insert data
obj . options . columns = jexcel . injectArray (
obj . options . columns ,
columnIndex ,
historyRecord . columns
) ;
obj . headers = jexcel . injectArray (
obj . headers ,
columnIndex ,
historyRecord . headers
) ;
obj . colgroup = jexcel . injectArray (
obj . colgroup ,
columnIndex ,
historyRecord . colgroup
) ;
var index = 0 ;
for (
var i = columnIndex ;
i < historyRecord . numOfColumns + columnIndex ;
i ++
) {
obj . headerContainer . insertBefore (
historyRecord . headers [ index ] ,
obj . headerContainer . children [ i + 1 ]
) ;
obj . colgroupContainer . insertBefore (
historyRecord . colgroup [ index ] ,
obj . colgroupContainer . children [ i + 1 ]
) ;
index ++ ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
for ( var j = 0 ; j < historyRecord . data . length ; j ++ ) {
obj . options . data [ j ] = jexcel . injectArray (
obj . options . data [ j ] ,
columnIndex ,
historyRecord . data [ j ]
) ;
obj . records [ j ] = jexcel . injectArray (
obj . records [ j ] ,
columnIndex ,
historyRecord . records [ j ]
) ;
var index = 0 ;
for (
var i = columnIndex ;
i < historyRecord . numOfColumns + columnIndex ;
i ++
) {
obj . rows [ j ] . insertBefore (
historyRecord . records [ j ] [ index ] ,
obj . rows [ j ] . children [ i + 1 ]
) ;
index ++ ;
}
}
// Process footers
if ( obj . options . footers ) {
for ( var j = 0 ; j < obj . options . footers . length ; j ++ ) {
obj . options . footers [ j ] = jexcel . injectArray (
obj . options . footers [ j ] ,
columnIndex ,
historyRecord . footers [ j ]
) ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Adjust nested headers
if ( obj . options . nestedHeaders && obj . options . nestedHeaders . length > 0 ) {
// Flexible way to handle nestedheaders
if ( obj . options . nestedHeaders [ 0 ] && obj . options . nestedHeaders [ 0 ] [ 0 ] ) {
for ( var j = 0 ; j < obj . options . nestedHeaders . length ; j ++ ) {
if ( type == 1 ) {
var colspan =
parseInt (
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan
) - historyRecord . numOfColumns ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
var colspan =
parseInt (
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan
) + historyRecord . numOfColumns ;
}
obj . options . nestedHeaders [ j ] [
obj . options . nestedHeaders [ j ] . length - 1
] . colspan = colspan ;
obj . thead . children [ j ] . children [
obj . thead . children [ j ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
}
} else {
if ( type == 1 ) {
var colspan =
parseInt ( obj . options . nestedHeaders [ 0 ] . colspan ) -
historyRecord . numOfColumns ;
} else {
var colspan =
parseInt ( obj . options . nestedHeaders [ 0 ] . colspan ) +
historyRecord . numOfColumns ;
}
obj . options . nestedHeaders [ 0 ] . colspan = colspan ;
obj . thead . children [ 0 ] . children [
obj . thead . children [ 0 ] . children . length - 1
] . setAttribute ( "colspan" , colspan ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . updateTableReferences ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Undo last action
* /
obj . undo = function ( ) {
// Ignore events and history
var ignoreEvents = obj . ignoreEvents ? true : false ;
var ignoreHistory = obj . ignoreHistory ? true : false ;
obj . ignoreEvents = true ;
obj . ignoreHistory = true ;
// Records
var records = [ ] ;
// Update cells
if ( obj . historyIndex >= 0 ) {
// History
var historyRecord = obj . history [ obj . historyIndex -- ] ;
if ( historyRecord . action == "insertRow" ) {
obj . historyProcessRow ( 1 , historyRecord ) ;
} else if ( historyRecord . action == "deleteRow" ) {
obj . historyProcessRow ( 0 , historyRecord ) ;
} else if ( historyRecord . action == "insertColumn" ) {
obj . historyProcessColumn ( 1 , historyRecord ) ;
} else if ( historyRecord . action == "deleteColumn" ) {
obj . historyProcessColumn ( 0 , historyRecord ) ;
} else if ( historyRecord . action == "moveRow" ) {
obj . moveRow ( historyRecord . newValue , historyRecord . oldValue ) ;
} else if ( historyRecord . action == "moveColumn" ) {
obj . moveColumn ( historyRecord . newValue , historyRecord . oldValue ) ;
} else if ( historyRecord . action == "setMerge" ) {
obj . removeMerge ( historyRecord . column , historyRecord . data ) ;
} else if ( historyRecord . action == "setStyle" ) {
obj . setStyle ( historyRecord . oldValue , null , null , 1 ) ;
} else if ( historyRecord . action == "setWidth" ) {
obj . setWidth ( historyRecord . column , historyRecord . oldValue ) ;
} else if ( historyRecord . action == "setHeight" ) {
obj . setHeight ( historyRecord . row , historyRecord . oldValue ) ;
} else if ( historyRecord . action == "setHeader" ) {
obj . setHeader ( historyRecord . column , historyRecord . oldValue ) ;
} else if ( historyRecord . action == "setComments" ) {
obj . setComments (
historyRecord . column ,
historyRecord . oldValue [ 0 ] ,
historyRecord . oldValue [ 1 ]
) ;
} else if ( historyRecord . action == "orderBy" ) {
var rows = [ ] ;
for ( var j = 0 ; j < historyRecord . rows . length ; j ++ ) {
rows [ historyRecord . rows [ j ] ] = j ;
}
obj . updateOrderArrow (
historyRecord . column ,
historyRecord . order ? 0 : 1
) ;
obj . updateOrder ( rows ) ;
} else if ( historyRecord . action == "setValue" ) {
// Redo for changes in cells
for ( var i = 0 ; i < historyRecord . records . length ; i ++ ) {
records . push ( {
x : historyRecord . records [ i ] . x ,
y : historyRecord . records [ i ] . y ,
newValue : historyRecord . records [ i ] . oldValue ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( historyRecord . oldStyle ) {
obj . resetStyle ( historyRecord . oldStyle ) ;
}
}
// Update records
obj . setValue ( records ) ;
// Update selection
if ( historyRecord . selection ) {
obj . updateSelectionFromCoords (
historyRecord . selection [ 0 ] ,
historyRecord . selection [ 1 ] ,
historyRecord . selection [ 2 ] ,
historyRecord . selection [ 3 ]
) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
obj . ignoreEvents = ignoreEvents ;
obj . ignoreHistory = ignoreHistory ;
// Events
obj . dispatch ( "onundo" , el , historyRecord ) ;
} ;
2022-07-28 07:33:25 -07:00
/ * *
2023-02-16 21:17:00 -05:00
* Redo previously undone action
2022-07-28 07:33:25 -07:00
* /
2023-02-16 21:17:00 -05:00
obj . redo = function ( ) {
// Ignore events and history
var ignoreEvents = obj . ignoreEvents ? true : false ;
var ignoreHistory = obj . ignoreHistory ? true : false ;
obj . ignoreEvents = true ;
obj . ignoreHistory = true ;
// Records
var records = [ ] ;
// Update cells
if ( obj . historyIndex < obj . history . length - 1 ) {
// History
var historyRecord = obj . history [ ++ obj . historyIndex ] ;
if ( historyRecord . action == "insertRow" ) {
obj . historyProcessRow ( 0 , historyRecord ) ;
} else if ( historyRecord . action == "deleteRow" ) {
obj . historyProcessRow ( 1 , historyRecord ) ;
} else if ( historyRecord . action == "insertColumn" ) {
obj . historyProcessColumn ( 0 , historyRecord ) ;
} else if ( historyRecord . action == "deleteColumn" ) {
obj . historyProcessColumn ( 1 , historyRecord ) ;
} else if ( historyRecord . action == "moveRow" ) {
obj . moveRow ( historyRecord . oldValue , historyRecord . newValue ) ;
} else if ( historyRecord . action == "moveColumn" ) {
obj . moveColumn ( historyRecord . oldValue , historyRecord . newValue ) ;
} else if ( historyRecord . action == "setMerge" ) {
obj . setMerge (
historyRecord . column ,
historyRecord . colspan ,
historyRecord . rowspan ,
1
) ;
} else if ( historyRecord . action == "setStyle" ) {
obj . setStyle ( historyRecord . newValue , null , null , 1 ) ;
} else if ( historyRecord . action == "setWidth" ) {
obj . setWidth ( historyRecord . column , historyRecord . newValue ) ;
} else if ( historyRecord . action == "setHeight" ) {
obj . setHeight ( historyRecord . row , historyRecord . newValue ) ;
} else if ( historyRecord . action == "setHeader" ) {
obj . setHeader ( historyRecord . column , historyRecord . newValue ) ;
} else if ( historyRecord . action == "setComments" ) {
obj . setComments (
historyRecord . column ,
historyRecord . newValue [ 0 ] ,
historyRecord . newValue [ 1 ]
) ;
} else if ( historyRecord . action == "orderBy" ) {
obj . updateOrderArrow ( historyRecord . column , historyRecord . order ) ;
obj . updateOrder ( historyRecord . rows ) ;
} else if ( historyRecord . action == "setValue" ) {
obj . setValue ( historyRecord . records ) ;
// Redo for changes in cells
for ( var i = 0 ; i < historyRecord . records . length ; i ++ ) {
if ( historyRecord . oldStyle ) {
obj . resetStyle ( historyRecord . newStyle ) ;
}
}
// Update selection
if ( historyRecord . selection ) {
obj . updateSelectionFromCoords (
historyRecord . selection [ 0 ] ,
historyRecord . selection [ 1 ] ,
historyRecord . selection [ 2 ] ,
historyRecord . selection [ 3 ]
) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
obj . ignoreEvents = ignoreEvents ;
obj . ignoreHistory = ignoreHistory ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Events
obj . dispatch ( "onredo" , el , historyRecord ) ;
} ;
2022-07-28 07:33:25 -07:00
/ * *
2023-02-16 21:17:00 -05:00
* Get dropdown value from key
2022-07-28 07:33:25 -07:00
* /
2023-02-16 21:17:00 -05:00
obj . getDropDownValue = function ( column , key ) {
var value = [ ] ;
if ( obj . options . columns [ column ] && obj . options . columns [ column ] . source ) {
// Create array from source
var combo = [ ] ;
var source = obj . options . columns [ column ] . source ;
for ( var i = 0 ; i < source . length ; i ++ ) {
if ( typeof source [ i ] == "object" ) {
combo [ source [ i ] . id ] = source [ i ] . name ;
} else {
combo [ source [ i ] ] = source [ i ] ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Guarantee single multiple compatibility
var keys = Array . isArray ( key ) ? key : ( "" + key ) . split ( ";" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
for ( var i = 0 ; i < keys . length ; i ++ ) {
if ( typeof keys [ i ] === "object" ) {
value . push ( combo [ keys [ i ] . id ] ) ;
} else {
if ( combo [ keys [ i ] ] ) {
value . push ( combo [ keys [ i ] ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else {
console . error ( "Invalid column" ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return value . length > 0 ? value . join ( "; " ) : "" ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* From stack overflow contributions
* /
obj . parseCSV = function ( str , delimiter ) {
// Remove last line break
str = str . replace ( /\r?\n$|\r$|\n$/g , "" ) ;
// Last caracter is the delimiter
if ( str . charCodeAt ( str . length - 1 ) == 9 ) {
str += "\0" ;
}
// user-supplied delimeter or default comma
delimiter = delimiter || "," ;
var arr = [ ] ;
var quote = false ; // true means we're inside a quoted field
// iterate over each character, keep track of current row and column (of the returned array)
for ( var row = 0 , col = 0 , c = 0 ; c < str . length ; c ++ ) {
var cc = str [ c ] ,
nc = str [ c + 1 ] ;
arr [ row ] = arr [ row ] || [ ] ;
arr [ row ] [ col ] = arr [ row ] [ col ] || "" ;
// If the current character is a quotation mark, and we're inside a quoted field, and the next character is also a quotation mark, add a quotation mark to the current column and skip the next character
if ( cc == '"' && quote && nc == '"' ) {
arr [ row ] [ col ] += cc ;
++ c ;
continue ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// If it's just one quotation mark, begin/end quoted field
if ( cc == '"' ) {
quote = ! quote ;
continue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// If it's a comma and we're not in a quoted field, move on to the next column
if ( cc == delimiter && ! quote ) {
++ col ;
continue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// If it's a newline (CRLF) and we're not in a quoted field, skip the next character and move on to the next row and move to column 0 of that new row
if ( cc == "\r" && nc == "\n" && ! quote ) {
++ row ;
col = 0 ;
++ c ;
continue ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// If it's a newline (LF or CR) and we're not in a quoted field, move on to the next row and move to column 0 of that new row
if ( cc == "\n" && ! quote ) {
++ row ;
col = 0 ;
continue ;
}
if ( cc == "\r" && ! quote ) {
++ row ;
col = 0 ;
continue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Otherwise, append the current character to the current column
arr [ row ] [ col ] += cc ;
}
return arr ;
} ;
obj . hash = function ( str ) {
var hash = 0 ,
i ,
chr ;
if ( str . length === 0 ) {
return hash ;
} else {
for ( i = 0 ; i < str . length ; i ++ ) {
chr = str . charCodeAt ( i ) ;
hash = ( hash << 5 ) - hash + chr ;
hash |= 0 ;
}
}
return hash ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . onafterchanges = function ( el , records ) {
// Events
obj . dispatch ( "onafterchanges" , el , records ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . destroy = function ( ) {
jexcel . destroy ( el ) ;
} ;
/ * *
* Initialization method
* /
obj . init = function ( ) {
jexcel . current = obj ;
// Build handlers
if ( typeof jexcel . build == "function" ) {
if ( obj . options . root ) {
jexcel . build ( obj . options . root ) ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
jexcel . build ( document ) ;
jexcel . build = null ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
// Event
el . setAttribute ( "tabindex" , 1 ) ;
el . addEventListener ( "focus" , function ( e ) {
if ( jexcel . current && ! obj . selectedCell ) {
obj . updateSelectionFromCoords ( 0 , 0 , 0 , 0 ) ;
obj . left ( ) ;
}
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Load the table data based on an CSV file
if ( obj . options . csv ) {
// Loading
if ( obj . options . loadingSpin == true ) {
jSuites . loading . show ( ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Load CSV file
jSuites . ajax ( {
url : obj . options . csv ,
method : obj . options . method ,
data : obj . options . requestVariables ,
dataType : "text" ,
success : function ( result ) {
// Convert data
var newData = obj . parseCSV ( result , obj . options . csvDelimiter ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Headers
if ( obj . options . csvHeaders == true && newData . length > 0 ) {
var headers = newData . shift ( ) ;
for ( var i = 0 ; i < headers . length ; i ++ ) {
if ( ! obj . options . columns [ i ] ) {
obj . options . columns [ i ] = {
type : "text" ,
align : obj . options . defaultColAlign ,
width : obj . options . defaultColWidth ,
} ;
}
// Precedence over pre-configurated titles
if ( typeof obj . options . columns [ i ] . title === "undefined" ) {
obj . options . columns [ i ] . title = headers [ i ] ;
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Data
obj . options . data = newData ;
// Prepare table
obj . prepareTable ( ) ;
// Hide spin
if ( obj . options . loadingSpin == true ) {
jSuites . loading . hide ( ) ;
}
} ,
} ) ;
} else if ( obj . options . url ) {
// Loading
if ( obj . options . loadingSpin == true ) {
jSuites . loading . show ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
jSuites . ajax ( {
url : obj . options . url ,
method : obj . options . method ,
data : obj . options . requestVariables ,
dataType : "json" ,
success : function ( result ) {
// Data
obj . options . data = result . data ? result . data : result ;
// Prepare table
obj . prepareTable ( ) ;
// Hide spin
if ( obj . options . loadingSpin == true ) {
jSuites . loading . hide ( ) ;
}
} ,
} ) ;
} else {
// Prepare table
obj . prepareTable ( ) ;
}
} ;
// Context menu
if ( options && options . contextMenu != null ) {
obj . options . contextMenu = options . contextMenu ;
} else {
obj . options . contextMenu = function ( el , x , y , e ) {
var items = [ ] ;
if ( y == null ) {
// Insert a new column
if ( obj . options . allowInsertColumn == true ) {
items . push ( {
title : obj . options . text . insertANewColumnBefore ,
onclick : function ( ) {
obj . insertColumn ( 1 , parseInt ( x ) , 1 ) ;
} ,
} ) ;
}
if ( obj . options . allowInsertColumn == true ) {
items . push ( {
title : obj . options . text . insertANewColumnAfter ,
onclick : function ( ) {
obj . insertColumn ( 1 , parseInt ( x ) , 0 ) ;
} ,
} ) ;
}
// Delete a column
if ( obj . options . allowDeleteColumn == true ) {
items . push ( {
title : obj . options . text . deleteSelectedColumns ,
onclick : function ( ) {
obj . deleteColumn (
obj . getSelectedColumns ( ) . length ? undefined : parseInt ( x )
) ;
} ,
} ) ;
}
// Rename column
if ( obj . options . allowRenameColumn == true ) {
items . push ( {
title : obj . options . text . renameThisColumn ,
onclick : function ( ) {
obj . setHeader ( x ) ;
} ,
} ) ;
}
// Sorting
if ( obj . options . columnSorting == true ) {
// Line
items . push ( { type : "line" } ) ;
items . push ( {
title : obj . options . text . orderAscending ,
onclick : function ( ) {
obj . orderBy ( x , 0 ) ;
} ,
} ) ;
items . push ( {
title : obj . options . text . orderDescending ,
onclick : function ( ) {
obj . orderBy ( x , 1 ) ;
} ,
} ) ;
}
} else {
// Insert new row
if ( obj . options . allowInsertRow == true ) {
items . push ( {
title : obj . options . text . insertANewRowBefore ,
onclick : function ( ) {
obj . insertRow ( 1 , parseInt ( y ) , 1 ) ;
} ,
} ) ;
items . push ( {
title : obj . options . text . insertANewRowAfter ,
onclick : function ( ) {
obj . insertRow ( 1 , parseInt ( y ) ) ;
} ,
} ) ;
}
if ( obj . options . allowDeleteRow == true ) {
items . push ( {
title : obj . options . text . deleteSelectedRows ,
onclick : function ( ) {
obj . deleteRow (
obj . getSelectedRows ( ) . length ? undefined : parseInt ( y )
) ;
} ,
} ) ;
}
if ( x ) {
if ( obj . options . allowComments == true ) {
items . push ( { type : "line" } ) ;
var title = obj . records [ y ] [ x ] . getAttribute ( "title" ) || "" ;
items . push ( {
title : title
? obj . options . text . editComments
: obj . options . text . addComments ,
onclick : function ( ) {
var comment = prompt ( obj . options . text . comments , title ) ;
if ( comment ) {
obj . setComments ( [ x , y ] , comment ) ;
}
} ,
} ) ;
if ( title ) {
items . push ( {
title : obj . options . text . clearComments ,
onclick : function ( ) {
obj . setComments ( [ x , y ] , "" ) ;
} ,
} ) ;
}
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Line
items . push ( { type : "line" } ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Copy
items . push ( {
title : obj . options . text . copy ,
shortcut : "Ctrl + C" ,
onclick : function ( ) {
obj . copy ( true ) ;
} ,
} ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Paste
if ( navigator && navigator . clipboard ) {
items . push ( {
title : obj . options . text . paste ,
shortcut : "Ctrl + V" ,
onclick : function ( ) {
if ( obj . selectedCell ) {
navigator . clipboard . readText ( ) . then ( function ( text ) {
if ( text ) {
jexcel . current . paste (
obj . selectedCell [ 0 ] ,
obj . selectedCell [ 1 ] ,
text
) ;
}
} ) ;
}
} ,
} ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Save
if ( obj . options . allowExport ) {
items . push ( {
title : obj . options . text . saveAs ,
shortcut : "Ctrl + S" ,
onclick : function ( ) {
obj . download ( ) ;
} ,
} ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// About
if ( obj . options . about ) {
items . push ( {
title : obj . options . text . about ,
onclick : function ( ) {
if ( obj . options . about === true ) {
alert ( Version ( ) . print ( ) ) ;
} else {
alert ( obj . options . about ) ;
}
} ,
} ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return items ;
} ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . scrollControls = function ( e ) {
obj . wheelControls ( ) ;
if (
obj . options . freezeColumns > 0 &&
obj . content . scrollLeft != scrollLeft
) {
obj . updateFreezePosition ( ) ;
}
// Close editor
if (
obj . options . lazyLoading == true ||
obj . options . tableOverflow == true
) {
if ( obj . edition && e . target . className . substr ( 0 , 9 ) != "jdropdown" ) {
obj . closeEditor ( obj . edition [ 0 ] , true ) ;
}
}
} ;
obj . wheelControls = function ( e ) {
if ( obj . options . lazyLoading == true ) {
if ( jexcel . timeControlLoading == null ) {
jexcel . timeControlLoading = setTimeout ( function ( ) {
if (
obj . content . scrollTop + obj . content . clientHeight >=
obj . content . scrollHeight - 10
) {
if ( obj . loadDown ( ) ) {
if (
obj . content . scrollTop + obj . content . clientHeight >
obj . content . scrollHeight - 10
) {
obj . content . scrollTop =
obj . content . scrollTop - obj . content . clientHeight ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . updateCornerPosition ( ) ;
}
} else if ( obj . content . scrollTop <= obj . content . clientHeight ) {
if ( obj . loadUp ( ) ) {
if ( obj . content . scrollTop < 10 ) {
obj . content . scrollTop =
obj . content . scrollTop + obj . content . clientHeight ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
obj . updateCornerPosition ( ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
jexcel . timeControlLoading = null ;
} , 100 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} ;
// Get width of all freezed cells together
obj . getFreezeWidth = function ( ) {
var width = 0 ;
if ( obj . options . freezeColumns > 0 ) {
for ( var i = 0 ; i < obj . options . freezeColumns ; i ++ ) {
width += parseInt ( obj . options . columns [ i ] . width ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
return width ;
} ;
var scrollLeft = 0 ;
obj . updateFreezePosition = function ( ) {
scrollLeft = obj . content . scrollLeft ;
var width = 0 ;
if ( scrollLeft > 50 ) {
for ( var i = 0 ; i < obj . options . freezeColumns ; i ++ ) {
if ( i > 0 ) {
// Must check if the previous column is hidden or not to determin whether the width shoule be added or not!
if ( obj . options . columns [ i - 1 ] . type !== "hidden" ) {
width += parseInt ( obj . options . columns [ i - 1 ] . width ) ;
}
}
obj . headers [ i ] . classList . add ( "jexcel_freezed" ) ;
obj . headers [ i ] . style . left = width + "px" ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( obj . rows [ j ] && obj . records [ j ] [ i ] ) {
var shifted =
scrollLeft +
( i > 0 ? obj . records [ j ] [ i - 1 ] . style . width : 0 ) -
51 +
"px" ;
obj . records [ j ] [ i ] . classList . add ( "jexcel_freezed" ) ;
obj . records [ j ] [ i ] . style . left = shifted ;
}
}
}
} else {
for ( var i = 0 ; i < obj . options . freezeColumns ; i ++ ) {
obj . headers [ i ] . classList . remove ( "jexcel_freezed" ) ;
obj . headers [ i ] . style . left = "" ;
for ( var j = 0 ; j < obj . rows . length ; j ++ ) {
if ( obj . records [ j ] [ i ] ) {
obj . records [ j ] [ i ] . classList . remove ( "jexcel_freezed" ) ;
obj . records [ j ] [ i ] . style . left = "" ;
}
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Place the corner in the correct place
obj . updateCornerPosition ( ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
el . addEventListener ( "DOMMouseScroll" , obj . wheelControls ) ;
el . addEventListener ( "mousewheel" , obj . wheelControls ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
el . jexcel = obj ;
el . jspreadsheet = obj ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
obj . init ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return obj ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Define dictionary
jexcel . setDictionary = function ( o ) {
jSuites . setDictionary ( o ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Define extensions
jexcel . setExtensions = function ( o ) {
var k = Object . keys ( o ) ;
for ( var i = 0 ; i < k . length ; i ++ ) {
if ( typeof o [ k [ i ] ] === "function" ) {
jexcel [ k [ i ] ] = o [ k [ i ] ] ;
if ( jexcel . license && typeof o [ k [ i ] ] . license == "function" ) {
o [ k [ i ] ] . license ( jexcel . license ) ;
}
}
}
} ;
/ * *
* Formulas
* /
if ( typeof formula !== "undefined" ) {
jexcel . formula = formula ;
}
jexcel . version = Version ;
jexcel . current = null ;
jexcel . timeControl = null ;
jexcel . timeControlLoading = null ;
const destroyEvents = function ( root ) {
root . removeEventListener ( "mouseup" , jexcel . mouseUpControls ) ;
root . removeEventListener ( "mousedown" , jexcel . mouseDownControls ) ;
root . removeEventListener ( "mousemove" , jexcel . mouseMoveControls ) ;
root . removeEventListener ( "mouseover" , jexcel . mouseOverControls ) ;
root . removeEventListener ( "dblclick" , jexcel . doubleClickControls ) ;
root . removeEventListener ( "paste" , jexcel . pasteControls ) ;
root . removeEventListener ( "contextmenu" , jexcel . contextMenuControls ) ;
root . removeEventListener ( "touchstart" , jexcel . touchStartControls ) ;
root . removeEventListener ( "touchend" , jexcel . touchEndControls ) ;
root . removeEventListener ( "touchcancel" , jexcel . touchEndControls ) ;
document . removeEventListener ( "keydown" , jexcel . keyDownControls ) ;
} ;
jexcel . destroy = function ( element , destroyEventHandlers ) {
if ( element . jexcel ) {
var root = element . jexcel . options . root
? element . jexcel . options . root
: document ;
element . removeEventListener (
"DOMMouseScroll" ,
element . jexcel . scrollControls
) ;
element . removeEventListener ( "mousewheel" , element . jexcel . scrollControls ) ;
element . jexcel = null ;
element . innerHTML = "" ;
if ( destroyEventHandlers ) {
destroyEvents ( root ) ;
jexcel = null ;
}
}
} ;
jexcel . build = function ( root ) {
destroyEvents ( root ) ;
root . addEventListener ( "mouseup" , jexcel . mouseUpControls ) ;
root . addEventListener ( "mousedown" , jexcel . mouseDownControls ) ;
root . addEventListener ( "mousemove" , jexcel . mouseMoveControls ) ;
root . addEventListener ( "mouseover" , jexcel . mouseOverControls ) ;
root . addEventListener ( "dblclick" , jexcel . doubleClickControls ) ;
root . addEventListener ( "paste" , jexcel . pasteControls ) ;
root . addEventListener ( "contextmenu" , jexcel . contextMenuControls ) ;
root . addEventListener ( "touchstart" , jexcel . touchStartControls ) ;
root . addEventListener ( "touchend" , jexcel . touchEndControls ) ;
root . addEventListener ( "touchcancel" , jexcel . touchEndControls ) ;
root . addEventListener ( "touchmove" , jexcel . touchEndControls ) ;
document . addEventListener ( "keydown" , jexcel . keyDownControls ) ;
} ;
/ * *
* Events
* /
jexcel . keyDownControls = function ( e ) {
if ( jexcel . current ) {
if ( jexcel . current . edition ) {
if ( e . which == 27 ) {
// Escape
if ( jexcel . current . edition ) {
// Exit without saving
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , false ) ;
}
e . preventDefault ( ) ;
} else if ( e . which == 13 ) {
// Enter
if (
jexcel . current . options . columns [ jexcel . current . edition [ 2 ] ] . type ==
"calendar"
) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
} else if (
jexcel . current . options . columns [ jexcel . current . edition [ 2 ] ] . type ==
"dropdown" ||
jexcel . current . options . columns [ jexcel . current . edition [ 2 ] ] . type ==
"autocomplete"
) {
// Do nothing
} else {
// Alt enter -> do not close editor
if (
( jexcel . current . options . wordWrap == true ||
jexcel . current . options . columns [ jexcel . current . edition [ 2 ] ]
. wordWrap == true ||
jexcel . current . options . data [ jexcel . current . edition [ 3 ] ] [
jexcel . current . edition [ 2 ]
] . length > 200 ) &&
e . altKey
) {
// Add new line to the editor
var editorTextarea = jexcel . current . edition [ 0 ] . children [ 0 ] ;
var editorValue = jexcel . current . edition [ 0 ] . children [ 0 ] . value ;
var editorIndexOf = editorTextarea . selectionStart ;
editorValue =
editorValue . slice ( 0 , editorIndexOf ) +
"\n" +
editorValue . slice ( editorIndexOf ) ;
editorTextarea . value = editorValue ;
editorTextarea . focus ( ) ;
editorTextarea . selectionStart = editorIndexOf + 1 ;
editorTextarea . selectionEnd = editorIndexOf + 1 ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
jexcel . current . edition [ 0 ] . children [ 0 ] . blur ( ) ;
}
}
} else if ( e . which == 9 ) {
// Tab
if (
[ "calendar" , "html" ] . includes (
jexcel . current . options . columns [ jexcel . current . edition [ 2 ] ] . type
)
) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
} else {
jexcel . current . edition [ 0 ] . children [ 0 ] . blur ( ) ;
}
}
}
if ( ! jexcel . current . edition && jexcel . current . selectedCell ) {
// Which key
if ( e . which == 37 ) {
jexcel . current . left ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 39 ) {
jexcel . current . right ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 38 ) {
jexcel . current . up ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 40 ) {
jexcel . current . down ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 36 ) {
jexcel . current . first ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 35 ) {
jexcel . current . last ( e . shiftKey , e . ctrlKey ) ;
e . preventDefault ( ) ;
} else if ( e . which == 46 ) {
// Delete
if ( jexcel . current . options . editable == true ) {
if ( jexcel . current . selectedRow ) {
if ( jexcel . current . options . allowDeleteRow == true ) {
if (
confirm (
jexcel . current . options . text
. areYouSureToDeleteTheSelectedRows
)
) {
jexcel . current . deleteRow ( ) ;
}
}
} else if ( jexcel . current . selectedHeader ) {
if ( jexcel . current . options . allowDeleteColumn == true ) {
if (
confirm (
jexcel . current . options . text
. areYouSureToDeleteTheSelectedColumns
)
) {
jexcel . current . deleteColumn ( ) ;
}
}
} else {
// Change value
jexcel . current . setValue ( jexcel . current . highlighted , "" ) ;
}
}
} else if ( e . which == 13 ) {
// Move cursor
if ( e . shiftKey ) {
jexcel . current . up ( ) ;
} else {
if ( jexcel . current . options . allowInsertRow == true ) {
if ( jexcel . current . options . allowManualInsertRow == true ) {
if (
jexcel . current . selectedCell [ 1 ] ==
jexcel . current . options . data . length - 1
) {
// New record in case selectedCell in the last row
jexcel . current . insertRow ( ) ;
}
}
}
jexcel . current . down ( ) ;
}
e . preventDefault ( ) ;
} else if ( e . which == 9 ) {
// Tab
if ( e . shiftKey ) {
jexcel . current . left ( ) ;
} else {
if ( jexcel . current . options . allowInsertColumn == true ) {
if ( jexcel . current . options . allowManualInsertColumn == true ) {
if (
jexcel . current . selectedCell [ 0 ] ==
jexcel . current . options . data [ 0 ] . length - 1
) {
// New record in case selectedCell in the last column
jexcel . current . insertColumn ( ) ;
}
}
}
jexcel . current . right ( ) ;
}
e . preventDefault ( ) ;
} else {
if ( ( e . ctrlKey || e . metaKey ) && ! e . shiftKey ) {
if ( e . which == 65 ) {
// Ctrl + A
jexcel . current . selectAll ( ) ;
e . preventDefault ( ) ;
} else if ( e . which == 83 ) {
// Ctrl + S
jexcel . current . download ( ) ;
e . preventDefault ( ) ;
} else if ( e . which == 89 ) {
// Ctrl + Y
jexcel . current . redo ( ) ;
e . preventDefault ( ) ;
} else if ( e . which == 90 ) {
// Ctrl + Z
jexcel . current . undo ( ) ;
e . preventDefault ( ) ;
} else if ( e . which == 67 ) {
// Ctrl + C
jexcel . current . copy ( true ) ;
e . preventDefault ( ) ;
} else if ( e . which == 88 ) {
// Ctrl + X
if ( jexcel . current . options . editable == true ) {
jexcel . cutControls ( ) ;
} else {
jexcel . copyControls ( ) ;
}
e . preventDefault ( ) ;
} else if ( e . which == 86 ) {
// Ctrl + V
jexcel . pasteControls ( ) ;
}
} else {
if ( jexcel . current . selectedCell ) {
if ( jexcel . current . options . editable == true ) {
var rowId = jexcel . current . selectedCell [ 1 ] ;
var columnId = jexcel . current . selectedCell [ 0 ] ;
// If is not readonly
if (
jexcel . current . options . columns [ columnId ] . type != "readonly"
) {
// Characters able to start a edition
if ( e . keyCode == 32 ) {
// Space
e . preventDefault ( ) ;
if (
jspreadsheet . current . options . columns [ columnId ] . type ==
"checkbox" ||
jspreadsheet . current . options . columns [ columnId ] . type ==
"radio"
) {
jspreadsheet . current . setCheckRadioValue ( ) ;
} else {
// Start edition
jspreadsheet . current . openEditor (
jspreadsheet . current . records [ rowId ] [ columnId ] ,
true
) ;
}
} else if ( e . keyCode == 113 ) {
// Start edition with current content F2
jexcel . current . openEditor (
jexcel . current . records [ rowId ] [ columnId ] ,
false
) ;
} else if (
e . keyCode == 8 ||
( e . keyCode >= 48 && e . keyCode <= 57 ) ||
( e . keyCode >= 96 && e . keyCode <= 111 ) ||
( e . keyCode >= 187 && e . keyCode <= 190 ) ||
( ( String . fromCharCode ( e . keyCode ) == e . key ||
String . fromCharCode ( e . keyCode ) . toLowerCase ( ) ==
e . key . toLowerCase ( ) ) &&
jexcel . validLetter ( String . fromCharCode ( e . keyCode ) ) )
) {
// Start edition
jexcel . current . openEditor (
jexcel . current . records [ rowId ] [ columnId ] ,
true
) ;
// Prevent entries in the calendar
if (
jexcel . current . options . columns [ columnId ] . type ==
"calendar"
) {
e . preventDefault ( ) ;
}
}
}
}
}
}
}
} else {
if ( e . target . classList . contains ( "jexcel_search" ) ) {
if ( jexcel . timeControl ) {
clearTimeout ( jexcel . timeControl ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jexcel . timeControl = setTimeout ( function ( ) {
jexcel . current . search ( e . target . value ) ;
} , 200 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
} ;
jexcel . isMouseAction = false ;
jexcel . mouseDownControls = function ( e ) {
e = e || window . event ;
if ( e . buttons ) {
var mouseButton = e . buttons ;
} else if ( e . button ) {
var mouseButton = e . button ;
} else {
var mouseButton = e . which ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Get elements
var jexcelTable = jexcel . getElement ( e . target ) ;
if ( jexcelTable [ 0 ] ) {
if ( jexcel . current != jexcelTable [ 0 ] . jexcel ) {
if ( jexcel . current ) {
if ( jexcel . current . edition ) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
}
jexcel . current . resetSelection ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
jexcel . current = jexcelTable [ 0 ] . jexcel ;
}
} else {
if ( jexcel . current ) {
if ( jexcel . current . edition ) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
}
jexcel . current . resetSelection ( true ) ;
jexcel . current = null ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( jexcel . current && mouseButton == 1 ) {
if ( e . target . classList . contains ( "jexcel_selectall" ) ) {
2022-07-28 07:33:25 -07:00
if ( jexcel . current ) {
2023-02-16 21:17:00 -05:00
jexcel . current . selectAll ( ) ;
}
} else if ( e . target . classList . contains ( "jexcel_corner" ) ) {
if ( jexcel . current . options . editable == true ) {
jexcel . current . selectedCorner = true ;
}
} else {
// Header found
if ( jexcelTable [ 1 ] == 1 ) {
var columnId = e . target . getAttribute ( "data-x" ) ;
if ( columnId ) {
// Update cursor
var info = e . target . getBoundingClientRect ( ) ;
if (
jexcel . current . options . columnResize == true &&
info . width - e . offsetX < 6
) {
// Resize helper
jexcel . current . resizing = {
mousePosition : e . pageX ,
column : columnId ,
width : info . width ,
} ;
// Border indication
jexcel . current . headers [ columnId ] . classList . add ( "resizing" ) ;
for ( var j = 0 ; j < jexcel . current . records . length ; j ++ ) {
if ( jexcel . current . records [ j ] [ columnId ] ) {
jexcel . current . records [ j ] [ columnId ] . classList . add ( "resizing" ) ;
}
}
} else if (
jexcel . current . options . columnDrag == true &&
info . height - e . offsetY < 6
) {
if ( jexcel . current . isColMerged ( columnId ) . length ) {
console . error (
"Jspreadsheet: This column is part of a merged cell."
) ;
} else {
// Reset selection
jexcel . current . resetSelection ( ) ;
// Drag helper
jexcel . current . dragging = {
element : e . target ,
column : columnId ,
destination : columnId ,
} ;
// Border indication
jexcel . current . headers [ columnId ] . classList . add ( "dragging" ) ;
for ( var j = 0 ; j < jexcel . current . records . length ; j ++ ) {
if ( jexcel . current . records [ j ] [ columnId ] ) {
jexcel . current . records [ j ] [ columnId ] . classList . add (
"dragging"
) ;
}
}
}
} else {
if ( jexcel . current . selectedHeader && ( e . shiftKey || e . ctrlKey ) ) {
var o = jexcel . current . selectedHeader ;
var d = columnId ;
} else {
// Press to rename
if (
jexcel . current . selectedHeader == columnId &&
jexcel . current . options . allowRenameColumn == true
) {
jexcel . timeControl = setTimeout ( function ( ) {
jexcel . current . setHeader ( columnId ) ;
} , 800 ) ;
}
// Keep track of which header was selected first
jexcel . current . selectedHeader = columnId ;
// Update selection single column
var o = columnId ;
var d = columnId ;
}
// Update selection
jexcel . current . updateSelectionFromCoords (
o ,
0 ,
d ,
jexcel . current . options . data . length - 1
) ;
}
} else {
if ( e . target . parentNode . classList . contains ( "jexcel_nested" ) ) {
if ( e . target . getAttribute ( "data-column" ) ) {
var column = e . target . getAttribute ( "data-column" ) . split ( "," ) ;
var c1 = parseInt ( column [ 0 ] ) ;
var c2 = parseInt ( column [ column . length - 1 ] ) ;
} else {
var c1 = 0 ;
var c2 = jexcel . current . options . columns . length - 1 ;
}
jexcel . current . updateSelectionFromCoords (
c1 ,
0 ,
c2 ,
jexcel . current . options . data . length - 1
) ;
}
}
} else {
jexcel . current . selectedHeader = false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Body found
if ( jexcelTable [ 1 ] == 2 ) {
var rowId = e . target . getAttribute ( "data-y" ) ;
if ( e . target . classList . contains ( "jexcel_row" ) ) {
var info = e . target . getBoundingClientRect ( ) ;
if (
jexcel . current . options . rowResize == true &&
info . height - e . offsetY < 6
) {
// Resize helper
jexcel . current . resizing = {
element : e . target . parentNode ,
mousePosition : e . pageY ,
row : rowId ,
height : info . height ,
} ;
// Border indication
e . target . parentNode . classList . add ( "resizing" ) ;
} else if (
jexcel . current . options . rowDrag == true &&
info . width - e . offsetX < 6
) {
if ( jexcel . current . isRowMerged ( rowId ) . length ) {
console . error (
"Jspreadsheet: This row is part of a merged cell"
) ;
} else if (
jexcel . current . options . search == true &&
jexcel . current . results
) {
console . error (
"Jspreadsheet: Please clear your search before perform this action"
) ;
} else {
// Reset selection
jexcel . current . resetSelection ( ) ;
// Drag helper
jexcel . current . dragging = {
element : e . target . parentNode ,
row : rowId ,
destination : rowId ,
} ;
// Border indication
e . target . parentNode . classList . add ( "dragging" ) ;
}
} else {
if ( jexcel . current . selectedRow && ( e . shiftKey || e . ctrlKey ) ) {
var o = jexcel . current . selectedRow ;
var d = rowId ;
} else {
// Keep track of which header was selected first
jexcel . current . selectedRow = rowId ;
// Update selection single column
var o = rowId ;
var d = rowId ;
}
// Update selection
jexcel . current . updateSelectionFromCoords (
0 ,
o ,
jexcel . current . options . data [ 0 ] . length - 1 ,
d
) ;
}
} else {
// Jclose
if (
e . target . classList . contains ( "jclose" ) &&
e . target . clientWidth - e . offsetX < 50 &&
e . offsetY < 50
) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
} else {
var getCellCoords = function ( element ) {
var x = element . getAttribute ( "data-x" ) ;
var y = element . getAttribute ( "data-y" ) ;
if ( x && y ) {
return [ x , y ] ;
} else {
if ( element . parentNode ) {
return getCellCoords ( element . parentNode ) ;
}
}
} ;
var position = getCellCoords ( e . target ) ;
if ( position ) {
var columnId = position [ 0 ] ;
var rowId = position [ 1 ] ;
// Close edition
if ( jexcel . current . edition ) {
if (
jexcel . current . edition [ 2 ] != columnId ||
jexcel . current . edition [ 3 ] != rowId
) {
jexcel . current . closeEditor ( jexcel . current . edition [ 0 ] , true ) ;
}
}
if ( ! jexcel . current . edition ) {
// Update cell selection
if ( e . shiftKey ) {
jexcel . current . updateSelectionFromCoords (
jexcel . current . selectedCell [ 0 ] ,
jexcel . current . selectedCell [ 1 ] ,
columnId ,
rowId
) ;
} else {
jexcel . current . updateSelectionFromCoords ( columnId , rowId ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// No full row selected
jexcel . current . selectedHeader = null ;
jexcel . current . selectedRow = null ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
} else {
jexcel . current . selectedRow = false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Pagination
if ( e . target . classList . contains ( "jexcel_page" ) ) {
if ( e . target . textContent == "<" ) {
jexcel . current . page ( 0 ) ;
} else if ( e . target . textContent == ">" ) {
jexcel . current . page ( e . target . getAttribute ( "title" ) - 1 ) ;
} else {
jexcel . current . page ( e . target . textContent - 1 ) ;
}
}
}
if ( jexcel . current . edition ) {
jexcel . isMouseAction = false ;
} else {
jexcel . isMouseAction = true ;
}
} else {
jexcel . isMouseAction = false ;
}
} ;
jexcel . mouseUpControls = function ( e ) {
if ( jexcel . current ) {
// Update cell size
if ( jexcel . current . resizing ) {
// Columns to be updated
if ( jexcel . current . resizing . column ) {
// New width
var newWidth =
jexcel . current . colgroup [
jexcel . current . resizing . column
] . getAttribute ( "width" ) ;
// Columns
var columns = jexcel . current . getSelectedColumns ( ) ;
if ( columns . length > 1 ) {
var currentWidth = [ ] ;
for ( var i = 0 ; i < columns . length ; i ++ ) {
currentWidth . push (
parseInt (
jexcel . current . colgroup [ columns [ i ] ] . getAttribute ( "width" )
)
) ;
}
// Previous width
var index = columns . indexOf (
parseInt ( jexcel . current . resizing . column )
) ;
currentWidth [ index ] = jexcel . current . resizing . width ;
jexcel . current . setWidth ( columns , newWidth , currentWidth ) ;
} else {
jexcel . current . setWidth (
jexcel . current . resizing . column ,
newWidth ,
jexcel . current . resizing . width
) ;
}
// Remove border
jexcel . current . headers [
jexcel . current . resizing . column
] . classList . remove ( "resizing" ) ;
for ( var j = 0 ; j < jexcel . current . records . length ; j ++ ) {
if ( jexcel . current . records [ j ] [ jexcel . current . resizing . column ] ) {
jexcel . current . records [ j ] [
jexcel . current . resizing . column
] . classList . remove ( "resizing" ) ;
}
}
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
// Remove Class
jexcel . current . rows [
jexcel . current . resizing . row
] . children [ 0 ] . classList . remove ( "resizing" ) ;
var newHeight =
jexcel . current . rows [ jexcel . current . resizing . row ] . getAttribute (
"height"
) ;
jexcel . current . setHeight (
jexcel . current . resizing . row ,
newHeight ,
jexcel . current . resizing . height
) ;
// Remove border
jexcel . current . resizing . element . classList . remove ( "resizing" ) ;
}
// Reset resizing helper
jexcel . current . resizing = null ;
} else if ( jexcel . current . dragging ) {
// Reset dragging helper
if ( jexcel . current . dragging ) {
if ( jexcel . current . dragging . column ) {
// Target
var columnId = e . target . getAttribute ( "data-x" ) ;
// Remove move style
jexcel . current . headers [
jexcel . current . dragging . column
] . classList . remove ( "dragging" ) ;
for ( var j = 0 ; j < jexcel . current . rows . length ; j ++ ) {
if ( jexcel . current . records [ j ] [ jexcel . current . dragging . column ] ) {
jexcel . current . records [ j ] [
jexcel . current . dragging . column
] . classList . remove ( "dragging" ) ;
}
}
for ( var i = 0 ; i < jexcel . current . headers . length ; i ++ ) {
jexcel . current . headers [ i ] . classList . remove ( "dragging-left" ) ;
jexcel . current . headers [ i ] . classList . remove ( "dragging-right" ) ;
}
// Update position
if ( columnId ) {
if (
jexcel . current . dragging . column !=
jexcel . current . dragging . destination
) {
jexcel . current . moveColumn (
jexcel . current . dragging . column ,
jexcel . current . dragging . destination
) ;
}
}
} else {
if ( jexcel . current . dragging . element . nextSibling ) {
var position = parseInt (
jexcel . current . dragging . element . nextSibling . getAttribute (
"data-y"
)
) ;
if ( jexcel . current . dragging . row < position ) {
position -= 1 ;
}
} else {
var position = parseInt (
jexcel . current . dragging . element . previousSibling . getAttribute (
"data-y"
)
) ;
}
if (
jexcel . current . dragging . row != jexcel . current . dragging . destination
) {
jexcel . current . moveRow (
jexcel . current . dragging . row ,
position ,
true
) ;
}
jexcel . current . dragging . element . classList . remove ( "dragging" ) ;
}
jexcel . current . dragging = null ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else {
// Close any corner selection
if ( jexcel . current . selectedCorner ) {
jexcel . current . selectedCorner = false ;
// Data to be copied
if ( jexcel . current . selection . length > 0 ) {
// Copy data
jexcel . current . copyData (
jexcel . current . selection [ 0 ] ,
jexcel . current . selection [ jexcel . current . selection . length - 1 ]
) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Remove selection
jexcel . current . removeCopySelection ( ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Clear any time control
if ( jexcel . timeControl ) {
clearTimeout ( jexcel . timeControl ) ;
jexcel . timeControl = null ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Mouse up
jexcel . isMouseAction = false ;
} ;
// Mouse move controls
jexcel . mouseMoveControls = function ( e ) {
e = e || window . event ;
if ( e . buttons ) {
var mouseButton = e . buttons ;
} else if ( e . button ) {
var mouseButton = e . button ;
} else {
var mouseButton = e . which ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ! mouseButton ) {
jexcel . isMouseAction = false ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( jexcel . current ) {
if ( jexcel . isMouseAction == true ) {
// Resizing is ongoing
if ( jexcel . current . resizing ) {
if ( jexcel . current . resizing . column ) {
var width = e . pageX - jexcel . current . resizing . mousePosition ;
if ( jexcel . current . resizing . width + width > 0 ) {
var tempWidth = jexcel . current . resizing . width + width ;
jexcel . current . colgroup [
jexcel . current . resizing . column
] . setAttribute ( "width" , tempWidth ) ;
jexcel . current . updateCornerPosition ( ) ;
}
} else {
var height = e . pageY - jexcel . current . resizing . mousePosition ;
if ( jexcel . current . resizing . height + height > 0 ) {
var tempHeight = jexcel . current . resizing . height + height ;
jexcel . current . rows [ jexcel . current . resizing . row ] . setAttribute (
"height" ,
tempHeight
) ;
jexcel . current . updateCornerPosition ( ) ;
}
}
} else if ( jexcel . current . dragging ) {
if ( jexcel . current . dragging . column ) {
var columnId = e . target . getAttribute ( "data-x" ) ;
if ( columnId ) {
if ( jexcel . current . isColMerged ( columnId ) . length ) {
console . error (
"Jspreadsheet: This column is part of a merged cell."
) ;
} else {
for ( var i = 0 ; i < jexcel . current . headers . length ; i ++ ) {
jexcel . current . headers [ i ] . classList . remove ( "dragging-left" ) ;
jexcel . current . headers [ i ] . classList . remove ( "dragging-right" ) ;
}
if ( jexcel . current . dragging . column == columnId ) {
jexcel . current . dragging . destination = parseInt ( columnId ) ;
} else {
if ( e . target . clientWidth / 2 > e . offsetX ) {
if ( jexcel . current . dragging . column < columnId ) {
jexcel . current . dragging . destination =
parseInt ( columnId ) - 1 ;
} else {
jexcel . current . dragging . destination = parseInt ( columnId ) ;
}
jexcel . current . headers [ columnId ] . classList . add (
"dragging-left"
) ;
} else {
if ( jexcel . current . dragging . column < columnId ) {
jexcel . current . dragging . destination = parseInt ( columnId ) ;
} else {
jexcel . current . dragging . destination =
parseInt ( columnId ) + 1 ;
}
jexcel . current . headers [ columnId ] . classList . add (
"dragging-right"
) ;
}
}
}
}
} else {
var rowId = e . target . getAttribute ( "data-y" ) ;
if ( rowId ) {
if ( jexcel . current . isRowMerged ( rowId ) . length ) {
console . error (
"Jspreadsheet: This row is part of a merged cell."
) ;
} else {
var target =
e . target . clientHeight / 2 > e . offsetY
? e . target . parentNode . nextSibling
: e . target . parentNode ;
if ( jexcel . current . dragging . element != target ) {
e . target . parentNode . parentNode . insertBefore (
jexcel . current . dragging . element ,
target
) ;
jexcel . current . dragging . destination =
Array . prototype . indexOf . call (
jexcel . current . dragging . element . parentNode . children ,
jexcel . current . dragging . element
) ;
}
}
}
}
}
} else {
var x = e . target . getAttribute ( "data-x" ) ;
var y = e . target . getAttribute ( "data-y" ) ;
var rect = e . target . getBoundingClientRect ( ) ;
if ( jexcel . current . cursor ) {
jexcel . current . cursor . style . cursor = "" ;
jexcel . current . cursor = null ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if (
e . target . parentNode . parentNode &&
e . target . parentNode . parentNode . className
) {
if ( e . target . parentNode . parentNode . classList . contains ( "resizable" ) ) {
if (
e . target &&
x &&
! y &&
rect . width - ( e . clientX - rect . left ) < 6
) {
jexcel . current . cursor = e . target ;
jexcel . current . cursor . style . cursor = "col-resize" ;
} else if (
e . target &&
! x &&
y &&
rect . height - ( e . clientY - rect . top ) < 6
) {
jexcel . current . cursor = e . target ;
jexcel . current . cursor . style . cursor = "row-resize" ;
}
}
if ( e . target . parentNode . parentNode . classList . contains ( "draggable" ) ) {
if (
e . target &&
! x &&
y &&
rect . width - ( e . clientX - rect . left ) < 6
) {
jexcel . current . cursor = e . target ;
jexcel . current . cursor . style . cursor = "move" ;
} else if (
e . target &&
x &&
! y &&
rect . height - ( e . clientY - rect . top ) < 6
) {
jexcel . current . cursor = e . target ;
jexcel . current . cursor . style . cursor = "move" ;
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
} ;
jexcel . mouseOverControls = function ( e ) {
e = e || window . event ;
if ( e . buttons ) {
var mouseButton = e . buttons ;
} else if ( e . button ) {
var mouseButton = e . button ;
} else {
var mouseButton = e . which ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( ! mouseButton ) {
jexcel . isMouseAction = false ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( jexcel . current && jexcel . isMouseAction == true ) {
// Get elements
var jexcelTable = jexcel . getElement ( e . target ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( jexcelTable [ 0 ] ) {
// Avoid cross reference
if ( jexcel . current != jexcelTable [ 0 ] . jexcel ) {
if ( jexcel . current ) {
return false ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var columnId = e . target . getAttribute ( "data-x" ) ;
var rowId = e . target . getAttribute ( "data-y" ) ;
if ( jexcel . current . resizing || jexcel . current . dragging ) {
} else {
// Header found
if ( jexcelTable [ 1 ] == 1 ) {
if ( jexcel . current . selectedHeader ) {
var columnId = e . target . getAttribute ( "data-x" ) ;
var o = jexcel . current . selectedHeader ;
var d = columnId ;
// Update selection
jexcel . current . updateSelectionFromCoords (
o ,
0 ,
d ,
jexcel . current . options . data . length - 1
) ;
}
}
// Body found
if ( jexcelTable [ 1 ] == 2 ) {
if ( e . target . classList . contains ( "jexcel_row" ) ) {
if ( jexcel . current . selectedRow ) {
var o = jexcel . current . selectedRow ;
var d = rowId ;
// Update selection
jexcel . current . updateSelectionFromCoords (
0 ,
o ,
jexcel . current . options . data [ 0 ] . length - 1 ,
d
) ;
}
} else {
// Do not select edtion is in progress
if ( ! jexcel . current . edition ) {
if ( columnId && rowId ) {
if ( jexcel . current . selectedCorner ) {
jexcel . current . updateCopySelection ( columnId , rowId ) ;
} else {
if ( jexcel . current . selectedCell ) {
jexcel . current . updateSelectionFromCoords (
jexcel . current . selectedCell [ 0 ] ,
jexcel . current . selectedCell [ 1 ] ,
columnId ,
rowId
) ;
}
}
}
}
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Clear any time control
if ( jexcel . timeControl ) {
clearTimeout ( jexcel . timeControl ) ;
jexcel . timeControl = null ;
}
} ;
/ * *
* Double click event handler : controls the double click in the corner , cell edition or column re - ordering .
* /
jexcel . doubleClickControls = function ( e ) {
// Jexcel is selected
if ( jexcel . current ) {
// Corner action
if ( e . target . classList . contains ( "jexcel_corner" ) ) {
// Any selected cells
if ( jexcel . current . highlighted . length > 0 ) {
// Copy from this
var x1 = jexcel . current . highlighted [ 0 ] . getAttribute ( "data-x" ) ;
var y1 =
parseInt (
jexcel . current . highlighted [
jexcel . current . highlighted . length - 1
] . getAttribute ( "data-y" )
) + 1 ;
// Until this
var x2 =
jexcel . current . highlighted [
jexcel . current . highlighted . length - 1
] . getAttribute ( "data-x" ) ;
var y2 = jexcel . current . records . length - 1 ;
// Execute copy
jexcel . current . copyData (
jexcel . current . records [ y1 ] [ x1 ] ,
jexcel . current . records [ y2 ] [ x2 ]
) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} else if ( e . target . classList . contains ( "jexcel_column_filter" ) ) {
// Column
var columnId = e . target . getAttribute ( "data-x" ) ;
// Open filter
jexcel . current . openFilter ( columnId ) ;
} else {
// Get table
var jexcelTable = jexcel . getElement ( e . target ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Double click over header
if (
jexcelTable [ 1 ] == 1 &&
jexcel . current . options . columnSorting == true
) {
// Check valid column header coords
var columnId = e . target . getAttribute ( "data-x" ) ;
if ( columnId ) {
jexcel . current . orderBy ( columnId ) ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Double click over body
if ( jexcelTable [ 1 ] == 2 && jexcel . current . options . editable == true ) {
if ( ! jexcel . current . edition ) {
var getCellCoords = function ( element ) {
if ( element . parentNode ) {
var x = element . getAttribute ( "data-x" ) ;
var y = element . getAttribute ( "data-y" ) ;
if ( x && y ) {
return element ;
} else {
return getCellCoords ( element . parentNode ) ;
}
}
2022-07-28 07:33:25 -07:00
} ;
2023-02-16 21:17:00 -05:00
var cell = getCellCoords ( e . target ) ;
if ( cell && cell . classList . contains ( "highlight" ) ) {
jexcel . current . openEditor ( cell ) ;
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jexcel . copyControls = function ( e ) {
if ( jexcel . current && jexcel . copyControls . enabled ) {
if ( ! jexcel . current . edition ) {
jexcel . current . copy ( true ) ;
}
}
} ;
jexcel . cutControls = function ( e ) {
if ( jexcel . current ) {
if ( ! jexcel . current . edition ) {
jexcel . current . copy ( true ) ;
if ( jexcel . current . options . editable == true ) {
jexcel . current . setValue ( jexcel . current . highlighted , "" ) ;
}
}
}
} ;
jexcel . pasteControls = function ( e ) {
if ( jexcel . current && jexcel . current . selectedCell ) {
if ( ! jexcel . current . edition ) {
if ( jexcel . current . options . editable == true ) {
if ( e && e . clipboardData ) {
jexcel . current . paste (
jexcel . current . selectedCell [ 0 ] ,
jexcel . current . selectedCell [ 1 ] ,
e . clipboardData . getData ( "text" )
) ;
e . preventDefault ( ) ;
} else if ( window . clipboardData ) {
jexcel . current . paste (
jexcel . current . selectedCell [ 0 ] ,
jexcel . current . selectedCell [ 1 ] ,
window . clipboardData . getData ( "text" )
) ;
}
}
}
}
} ;
jexcel . contextMenuControls = function ( e ) {
e = e || window . event ;
if ( "buttons" in e ) {
var mouseButton = e . buttons ;
} else {
var mouseButton = e . which || e . button ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( jexcel . current ) {
if ( jexcel . current . edition ) {
e . preventDefault ( ) ;
} else if ( jexcel . current . options . contextMenu ) {
jexcel . current . contextMenu . contextmenu . close ( ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( jexcel . current ) {
var x = e . target . getAttribute ( "data-x" ) ;
var y = e . target . getAttribute ( "data-y" ) ;
if ( x || y ) {
if (
x < parseInt ( jexcel . current . selectedCell [ 0 ] ) ||
x > parseInt ( jexcel . current . selectedCell [ 2 ] ) ||
y < parseInt ( jexcel . current . selectedCell [ 1 ] ) ||
y > parseInt ( jexcel . current . selectedCell [ 3 ] )
) {
jexcel . current . updateSelectionFromCoords ( x , y , x , y ) ;
}
// Table found
var items = jexcel . current . options . contextMenu (
jexcel . current ,
x ,
y ,
e
) ;
// The id is depending on header and body
jexcel . current . contextMenu . contextmenu . open ( e , items ) ;
// Avoid the real one
e . preventDefault ( ) ;
}
}
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jexcel . touchStartControls = function ( e ) {
var jexcelTable = jexcel . getElement ( e . target ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( jexcelTable [ 0 ] ) {
if ( jexcel . current != jexcelTable [ 0 ] . jexcel ) {
if ( jexcel . current ) {
jexcel . current . resetSelection ( ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
jexcel . current = jexcelTable [ 0 ] . jexcel ;
}
} else {
if ( jexcel . current ) {
jexcel . current . resetSelection ( ) ;
jexcel . current = null ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( jexcel . current ) {
if ( ! jexcel . current . edition ) {
var columnId = e . target . getAttribute ( "data-x" ) ;
var rowId = e . target . getAttribute ( "data-y" ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( columnId && rowId ) {
jexcel . current . updateSelectionFromCoords ( columnId , rowId ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jexcel . timeControl = setTimeout ( function ( ) {
// Keep temporary reference to the element
if ( jexcel . current . options . columns [ columnId ] . type == "color" ) {
jexcel . tmpElement = null ;
2022-07-28 07:33:25 -07:00
} else {
2023-02-16 21:17:00 -05:00
jexcel . tmpElement = e . target ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
jexcel . current . openEditor ( e . target , false , e ) ;
} , 500 ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
}
} ;
jexcel . touchEndControls = function ( e ) {
// Clear any time control
if ( jexcel . timeControl ) {
clearTimeout ( jexcel . timeControl ) ;
jexcel . timeControl = null ;
// Element
if (
jexcel . tmpElement &&
jexcel . tmpElement . children [ 0 ] . tagName == "INPUT"
) {
jexcel . tmpElement . children [ 0 ] . focus ( ) ;
}
jexcel . tmpElement = null ;
}
} ;
/ * *
* Jexcel extensions
* /
jexcel . tabs = function ( tabs , result ) {
var instances = [ ] ;
// Create tab container
if ( ! tabs . classList . contains ( "jexcel_tabs" ) ) {
tabs . innerHTML = "" ;
tabs . classList . add ( "jexcel_tabs" ) ;
tabs . jexcel = [ ] ;
var div = document . createElement ( "div" ) ;
var headers = tabs . appendChild ( div ) ;
var div = document . createElement ( "div" ) ;
var content = tabs . appendChild ( div ) ;
} else {
var headers = tabs . children [ 0 ] ;
var content = tabs . children [ 1 ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var spreadsheet = [ ] ;
var link = [ ] ;
for ( var i = 0 ; i < result . length ; i ++ ) {
// Spreadsheet container
spreadsheet [ i ] = document . createElement ( "div" ) ;
spreadsheet [ i ] . classList . add ( "jexcel_tab" ) ;
var worksheet = jexcel ( spreadsheet [ i ] , result [ i ] ) ;
content . appendChild ( spreadsheet [ i ] ) ;
instances [ i ] = tabs . jexcel . push ( worksheet ) ;
// Tab link
link [ i ] = document . createElement ( "div" ) ;
link [ i ] . classList . add ( "jexcel_tab_link" ) ;
link [ i ] . setAttribute ( "data-spreadsheet" , tabs . jexcel . length - 1 ) ;
link [ i ] . innerHTML = result [ i ] . sheetName ;
link [ i ] . onclick = function ( ) {
for ( var j = 0 ; j < headers . children . length ; j ++ ) {
headers . children [ j ] . classList . remove ( "selected" ) ;
content . children [ j ] . style . display = "none" ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var i = this . getAttribute ( "data-spreadsheet" ) ;
content . children [ i ] . style . display = "block" ;
headers . children [ i ] . classList . add ( "selected" ) ;
} ;
headers . appendChild ( link [ i ] ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// First tab
for ( var j = 0 ; j < headers . children . length ; j ++ ) {
headers . children [ j ] . classList . remove ( "selected" ) ;
content . children [ j ] . style . display = "none" ;
}
headers . children [ headers . children . length - 1 ] . classList . add ( "selected" ) ;
content . children [ headers . children . length - 1 ] . style . display = "block" ;
return instances ;
} ;
// Compability to older versions
jexcel . createTabs = jexcel . tabs ;
jexcel . fromSpreadsheet = function ( file , _ _callback ) {
var convert = function ( workbook ) {
var spreadsheets = [ ] ;
workbook . SheetNames . forEach ( function ( sheetName ) {
var spreadsheet = { } ;
spreadsheet . rows = [ ] ;
spreadsheet . columns = [ ] ;
spreadsheet . data = [ ] ;
spreadsheet . style = { } ;
spreadsheet . sheetName = sheetName ;
// Column widths
var temp = workbook . Sheets [ sheetName ] [ "!cols" ] ;
if ( temp && temp . length ) {
for ( var i = 0 ; i < temp . length ; i ++ ) {
spreadsheet . columns [ i ] = { } ;
if ( temp [ i ] && temp [ i ] . wpx ) {
spreadsheet . columns [ i ] . width = temp [ i ] . wpx + "px" ;
}
}
}
// Rows heights
var temp = workbook . Sheets [ sheetName ] [ "!rows" ] ;
if ( temp && temp . length ) {
for ( var i = 0 ; i < temp . length ; i ++ ) {
if ( temp [ i ] && temp [ i ] . hpx ) {
spreadsheet . rows [ i ] = { } ;
spreadsheet . rows [ i ] . height = temp [ i ] . hpx + "px" ;
}
}
}
// Merge cells
var temp = workbook . Sheets [ sheetName ] [ "!merges" ] ;
if ( temp && temp . length > 0 ) {
spreadsheet . mergeCells = [ ] ;
for ( var i = 0 ; i < temp . length ; i ++ ) {
var x1 = temp [ i ] . s . c ;
var y1 = temp [ i ] . s . r ;
var x2 = temp [ i ] . e . c ;
var y2 = temp [ i ] . e . r ;
var key = jexcel . getColumnNameFromId ( [ x1 , y1 ] ) ;
spreadsheet . mergeCells [ key ] = [ x2 - x1 + 1 , y2 - y1 + 1 ] ;
}
}
// Data container
var max _x = 0 ;
var max _y = 0 ;
var temp = Object . keys ( workbook . Sheets [ sheetName ] ) ;
for ( var i = 0 ; i < temp . length ; i ++ ) {
if ( temp [ i ] . substr ( 0 , 1 ) != "!" ) {
var cell = workbook . Sheets [ sheetName ] [ temp [ i ] ] ;
var info = jexcel . getIdFromColumnName ( temp [ i ] , true ) ;
if ( ! spreadsheet . data [ info [ 1 ] ] ) {
spreadsheet . data [ info [ 1 ] ] = [ ] ;
}
spreadsheet . data [ info [ 1 ] ] [ info [ 0 ] ] = cell . f ? "=" + cell . f : cell . w ;
if ( max _x < info [ 0 ] ) {
max _x = info [ 0 ] ;
}
if ( max _y < info [ 1 ] ) {
max _y = info [ 1 ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Style
if ( cell . style && Object . keys ( cell . style ) . length > 0 ) {
spreadsheet . style [ temp [ i ] ] = cell . style ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( cell . s && cell . s . fgColor ) {
if ( spreadsheet . style [ temp [ i ] ] ) {
spreadsheet . style [ temp [ i ] ] += ";" ;
}
spreadsheet . style [ temp [ i ] ] +=
"background-color:#" + cell . s . fgColor . rgb ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
var numColumns = spreadsheet . columns ;
for ( var j = 0 ; j <= max _y ; j ++ ) {
for ( var i = 0 ; i <= max _x ; i ++ ) {
if ( ! spreadsheet . data [ j ] ) {
spreadsheet . data [ j ] = [ ] ;
}
if ( ! spreadsheet . data [ j ] [ i ] ) {
if ( numColumns < i ) {
spreadsheet . data [ j ] [ i ] = "" ;
}
}
}
}
spreadsheets . push ( spreadsheet ) ;
} ) ;
return spreadsheets ;
} ;
var oReq ;
oReq = new XMLHttpRequest ( ) ;
oReq . open ( "GET" , file , true ) ;
if ( typeof Uint8Array !== "undefined" ) {
oReq . responseType = "arraybuffer" ;
oReq . onload = function ( e ) {
var arraybuffer = oReq . response ;
var data = new Uint8Array ( arraybuffer ) ;
var wb = XLSX . read ( data , {
type : "array" ,
cellFormula : true ,
cellStyles : true ,
} ) ;
_ _callback ( convert ( wb ) ) ;
} ;
} else {
oReq . setRequestHeader ( "Accept-Charset" , "x-user-defined" ) ;
oReq . onreadystatechange = function ( ) {
if ( oReq . readyState == 4 && oReq . status == 200 ) {
var ff = convertResponseBodyToText ( oReq . responseBody ) ;
var wb = XLSX . read ( ff , {
type : "binary" ,
cellFormula : true ,
cellStyles : true ,
} ) ;
_ _callback ( convert ( wb ) ) ;
}
} ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
oReq . send ( ) ;
} ;
/ * *
* Valid international letter
* /
jexcel . validLetter = function ( text ) {
var regex =
/ ( [ \ u 0 0 4 1 - \ u 0 0 5 A \ u 0 0 6 1 - \ u 0 0 7 A \ u 0 0 A A \ u 0 0 B 5 \ u 0 0 B A \ u 0 0 C 0 - \ u 0 0 D 6 \ u 0 0 D 8 - \ u 0 0 F 6 \ u 0 0 F 8 - \ u 0 2 C 1 \ u 0 2 C 6 - \ u 0 2 D 1 \ u 0 2 E 0 - \ u 0 2 E 4 \ u 0 2 E C \ u 0 2 E E \ u 0 3 7 0 - \ u 0 3 7 4 \ u 0 3 7 6 \ u 0 3 7 7 \ u 0 3 7 A - \ u 0 3 7 D \ u 0 3 8 6 \ u 0 3 8 8 - \ u 0 3 8 A \ u 0 3 8 C \ u 0 3 8 E - \ u 0 3 A 1 \ u 0 3 A 3 - \ u 0 3 F 5 \ u 0 3 F 7 - \ u 0 4 8 1 \ u 0 4 8 A - \ u 0 5 2 7 \ u 0 5 3 1 - \ u 0 5 5 6 \ u 0 5 5 9 \ u 0 5 6 1 - \ u 0 5 8 7 \ u 0 5 D 0 - \ u 0 5 E A \ u 0 5 F 0 - \ u 0 5 F 2 \ u 0 6 2 0 - \ u 0 6 4 A \ u 0 6 6 E \ u 0 6 6 F \ u 0 6 7 1 - \ u 0 6 D 3 \ u 0 6 D 5 \ u 0 6 E 5 \ u 0 6 E 6 \ u 0 6 E E \ u 0 6 E F \ u 0 6 F A - \ u 0 6 F C \ u 0 6 F F \ u 0 7 1 0 \ u 0 7 1 2 - \ u 0 7 2 F \ u 0 7 4 D - \ u 0 7 A 5 \ u 0 7 B 1 \ u 0 7 C A - \ u 0 7 E A \ u 0 7 F 4 \ u 0 7 F 5 \ u 0 7 F A \ u 0 8 0 0 - \ u 0 8 1 5 \ u 0 8 1 A \ u 0 8 2 4 \ u 0 8 2 8 \ u 0 8 4 0 - \ u 0 8 5 8 \ u 0 8 A 0 \ u 0 8 A 2 - \ u 0 8 A C \ u 0 9 0 4 - \ u 0 9 3 9 \ u 0 9 3 D \ u 0 9 5 0 \ u 0 9 5 8 - \ u 0 9 6 1 \ u 0 9 7 1 - \ u 0 9 7 7 \ u 0 9 7 9 - \ u 0 9 7 F \ u 0 9 8 5 - \ u 0 9 8 C \ u 0 9 8 F \ u 0 9 9 0 \ u 0 9 9 3 - \ u 0 9 A 8 \ u 0 9 A A - \ u 0 9 B 0 \ u 0 9 B 2 \ u 0 9 B 6 - \ u 0 9 B 9 \ u 0 9 B D \ u 0 9 C E \ u 0 9 D C \ u 0 9 D D \ u 0 9 D F - \ u 0 9 E 1 \ u 0 9 F 0 \ u 0 9 F 1 \ u 0 A 0 5 - \ u 0 A 0 A \ u 0 A 0 F \ u 0 A 1 0 \ u 0 A 1 3 - \ u 0 A 2 8 \ u 0 A 2 A - \ u 0 A 3 0 \ u 0 A 3 2 \ u 0 A 3 3 \ u 0 A 3 5 \ u 0 A 3 6 \ u 0 A 3 8 \ u 0 A 3 9 \ u 0 A 5 9 - \ u 0 A 5 C \ u 0 A 5 E \ u 0 A 7 2 - \ u 0 A 7 4 \ u 0 A 8 5 - \ u 0 A 8 D \ u 0 A 8 F - \ u 0 A 9 1 \ u 0 A 9 3 - \ u 0 A A 8 \ u 0 A A A - \ u 0 A B 0 \ u 0 A B 2 \ u 0 A B 3 \ u 0 A B 5 - \ u 0 A B 9 \ u 0 A B D \ u 0 A D 0 \ u 0 A E 0 \ u 0 A E 1 \ u 0 B 0 5 - \ u 0 B 0 C \ u 0 B 0 F \ u 0 B 1 0 \ u 0 B 1 3 - \ u 0 B 2 8 \ u 0 B 2 A - \ u 0 B 3 0 \ u 0 B 3 2 \ u 0 B 3 3 \ u 0 B 3 5 - \ u 0 B 3 9 \ u 0 B 3 D \ u 0 B 5 C \ u 0 B 5 D \ u 0 B 5 F - \ u 0 B 6 1 \ u 0 B 7 1 \ u 0 B 8 3 \ u 0 B 8 5 - \ u 0 B 8 A \ u 0 B 8 E - \ u 0 B 9 0 \ u 0 B 9 2 - \ u 0 B 9 5 \ u 0 B 9 9 \ u 0 B 9 A \ u 0 B 9 C \ u 0 B 9 E \ u 0 B 9 F \ u 0 B A 3 \ u 0 B A 4 \ u 0 B A 8 - \ u 0 B A A \ u 0 B A E - \ u 0 B B 9 \ u 0 B D 0 \ u 0 C 0 5 - \ u 0 C 0 C \ u 0 C 0 E - \ u 0 C 1 0 \ u 0 C 1 2 - \ u 0 C 2 8 \ u 0 C 2 A - \ u 0 C 3 3 \ u 0 C 3 5 - \ u 0 C 3 9 \ u 0 C 3 D \ u 0 C 5 8 \ u 0 C 5 9 \ u 0 C 6 0 \ u 0 C 6 1 \ u 0 C 8 5 - \ u 0 C 8 C \ u 0 C 8 E - \ u 0 C 9 0 \ u 0 C 9 2 - \ u 0 C A 8 \ u 0 C A A - \ u 0 C B 3 \ u 0 C B 5 - \ u 0 C B 9 \ u 0 C B D \ u 0 C D E \ u 0 C E 0 \ u 0 C E 1 \ u 0 C F 1 \ u 0 C F 2 \ u 0 D 0 5 - \ u 0 D 0 C \ u 0 D 0 E - \ u 0 D 1 0 \ u 0 D 1 2 - \ u 0 D 3 A \ u 0 D 3 D \ u 0 D 4 E \ u 0 D 6 0 \ u 0 D 6 1 \ u 0 D 7 A - \ u 0 D 7 F \ u 0 D 8 5 - \ u 0 D 9 6 \ u 0 D 9 A - \ u 0 D B 1 \ u 0 D B 3 - \ u 0 D B B \ u 0 D B D \ u 0 D C 0 - \ u 0 D C 6 \ u 0 E 0 1 - \ u 0 E 3 0 \ u 0 E 3 2 \ u 0 E 3 3 \ u 0 E 4 0 - \ u 0 E 4 6 \ u 0 E 8 1 \ u 0 E 8 2 \ u 0 E 8 4 \ u 0 E 8 7 \ u 0 E 8 8 \ u 0 E 8 A \ u 0 E 8 D \ u 0 E 9 4 - \ u 0 E 9 7 \ u 0 E 9 9 - \ u 0 E 9 F \ u 0 E A 1 - \ u 0 E A 3 \ u 0 E A 5 \ u 0 E A 7 \ u 0 E A A \ u 0 E A B \ u 0 E A D - \ u 0 E B 0 \ u 0 E B 2 \ u 0 E B 3 \ u 0 E B D \ u 0 E C 0 - \ u 0 E C 4 \ u 0 E C 6 \ u 0 E D C - \ u 0 E D F \ u 0 F 0 0 \ u 0 F 4 0 - \ u 0 F 4 7 \ u 0 F 4 9 - \ u 0 F 6 C \ u 0 F 8 8 - \ u 0 F 8 C \ u 1 0 0 0 - \ u 1 0 2 A \ u 1 0 3 F \ u 1 0 5 0 - \ u 1 0 5 5 \ u 1 0 5 A - \ u 1 0 5 D \ u 1 0 6 1 \ u 1 0 6 5 \ u 1 0 6 6 \ u 1 0 6 E - \ u 1 0 7 0 \ u 1 0 7 5 - \ u 1 0 8 1 \ u 1 0 8 E \ u 1 0 A 0 - \ u 1 0 C 5 \ u 1 0 C 7 \ u 1 0 C D \ u 1 0 D 0 - \ u 1 0 F A \ u 1 0 F C - \ u 1 2 4 8 \ u 1 2 4 A - \ u 1 2 4 D \ u 1 2 5 0 - \ u 1 2 5 6 \ u 1 2 5 8 \ u 1 2 5 A - \ u 1 2 5 D \ u 1 2 6 0 - \ u 1 2 8 8 \ u 1 2 8 A - \ u 1 2 8 D \ u 1 2 9 0 - \ u 1 2 B 0 \ u 1 2 B 2 - \ u 1 2 B 5 \ u 1 2 B 8 - \ u 1 2 B E \ u 1 2 C 0 \ u 1 2 C 2 - \ u 1 2 C 5 \ u 1 2 C 8 - \ u 1 2 D 6 \ u 1 2 D 8 - \ u 1 3 1 0 \ u 1 3 1 2 - \ u 1 3 1 5 \ u 1 3 1 8 - \ u 1 3 5 A \ u 1 3 8 0 - \ u 1 3 8 F \ u 1 3 A 0 - \ u 1 3 F 4 \ u 1 4 0 1 - \ u 1 6 6 C \ u 1 6 6 F - \ u 1 6 7 F \ u 1 6 8 1 - \ u 1 6 9 A \ u 1 6 A 0 - \ u 1 6 E A \ u 1 7 0 0 - \ u 1 7 0 C \ u 1 7 0 E - \ u 1 7 1 1 \ u 1 7 2 0 - \ u 1 7 3 1 \ u 1 7 4 0 - \ u 1 7 5 1 \ u 1 7 6 0 - \ u 1 7 6 C \ u 1 7 6 E - \ u 1 7 7 0 \ u 1 7 8 0 - \ u 1 7 B 3 \ u 1 7 D 7 \ u 1 7 D C \ u 1 8 2 0 - \ u 1 8 7 7 \ u 1 8 8 0 - \ u 1 8 A 8 \ u 1 8 A A \ u 1 8 B 0 - \ u 1 8 F 5 \ u 1 9 0 0 - \ u 1 9 1 C \ u 1 9 5 0 - \ u 1 9 6 D \ u 1 9 7 0 - \ u 1 9 7 4 \ u 1 9 8 0 - \ u 1 9 A B \ u 1 9 C 1 - \ u 1 9 C 7 \ u 1 A 0 0 - \ u 1 A 1 6 \ u 1 A 2 0 - \ u 1 A 5 4 \ u 1 A A 7 \ u 1 B 0 5 - \ u 1 B 3 3 \ u 1 B 4 5 - \ u 1 B 4 B \ u 1 B 8 3 - \ u 1 B A 0 \ u 1 B A E \ u 1 B A F \ u 1 B B A - \ u 1 B E 5 \ u 1 C 0 0 - \ u 1 C 2 3 \ u 1 C 4 D - \ u 1 C 4 F \ u 1 C 5 A - \ u 1 C 7 D \ u 1 C E 9 - \ u 1 C E C \ u 1 C E E - \ u 1 C F 1 \ u 1 C F 5 \ u 1 C F 6 \ u 1 D 0 0 - \ u 1 D B F \ u 1 E 0 0 - \ u 1 F 1 5 \ u 1 F 1 8 - \ u 1 F 1 D \ u 1 F 2 0 - \ u 1 F 4 5 \ u 1 F 4 8 - \ u 1 F 4 D \ u 1 F 5 0 - \ u 1 F 5 7 \ u 1 F 5 9 \ u 1 F 5 B \ u 1 F 5 D \ u 1 F 5 F - \ u 1 F 7 D \ u 1 F 8 0 - \ u 1 F B 4 \ u 1 F B 6 - \ u 1 F B C \ u 1 F B E \ u 1 F C 2 - \ u 1 F C 4 \ u 1 F C 6 - \ u 1 F C C \ u 1 F D 0 - \ u 1 F D 3 \ u 1 F D 6 - \ u 1 F D B \ u 1 F E 0 - \ u 1 F E C \ u 1 F F 2 - \ u 1 F F 4 \ u 1 F F 6 - \ u 1 F F C \ u 2 0 7 1 \ u 2 0 7 F \ u 2 0 9 0 - \ u 2 0 9 C \ u 2 1 0 2 \ u 2 1 0 7 \ u 2 1 0 A - \ u 2 1 1 3 \ u 2 1 1 5 \ u 2 1 1 9 - \ u 2 1 1 D \ u 2 1 2 4 \ u 2 1 2 6 \ u 2 1 2 8 \ u 2 1 2 A - \ u 2 1 2 D \ u 2 1 2 F - \ u 2 1 3 9 \ u 2 1 3 C - \ u 2 1 3 F \ u 2 1 4 5 - \ u 2 1 4 9 \ u 2 1 4 E \ u 2 1 8 3 \ u 2 1 8 4 \ u 2 C 0 0 - \ u 2 C 2 E \ u 2 C 3 0 - \ u 2 C 5 E \ u 2 C 6 0 - \ u 2 C E 4 \ u 2 C E B - \ u 2 C E E \ u 2 C F 2 \ u 2 C F 3 \ u 2 D 0 0 - \ u 2 D 2 5 \ u 2 D 2 7 \ u 2 D 2 D \ u 2 D 3 0 - \ u 2 D 6 7 \ u 2 D 6 F \ u 2 D 8 0 - \ u 2 D 9 6 \ u 2 D A 0 - \ u 2 D A 6 \ u 2 D A 8 - \ u 2 D A E \ u 2 D B 0 - \ u 2 D B 6 \ u 2 D B 8 - \ u 2 D B E \ u 2 D C 0 - \ u 2 D C 6 \ u 2 D C 8 - \ u 2 D C E \ u 2 D D 0 - \ u 2 D D 6 \ u 2 D D 8 - \ u 2 D D E \ u 2 E 2 F \ u 3 0 0 5 \ u 3 0 0 6 \ u 3 0 3 1 - \ u 3 0 3 5 \ u 3 0 3 B \ u 3 0 3 C \ u 3 0 4 1 - \ u 3 0 9 6 \ u 3 0 9 D - \ u 3 0 9 F \ u 3 0 A 1 - \ u 3 0 F A \ u 3 0 F C - \ u 3 0 F F \ u 3 1 0 5 - \ u 3 1 2 D \ u 3 1 3 1 - \ u 3 1 8 E \ u 3 1 A 0 - \ u 3 1 B A \ u 3 1 F 0 - \ u 3 1 F F \ u 3 4 0 0 - \ u 4 D B 5 \ u 4 E 0 0 - \ u 9 F C C \ u A 0 0 0 - \ u A 4 8 C \ u A 4 D 0 - \ u A 4 F D \ u A 5 0 0 - \ u A 6 0 C \ u A 6 1 0 - \ u A 6 1 F \ u A 6 2 A \ u A 6 2 B \ u A 6 4 0 - \ u A 6 6 E \ u A 6 7 F - \ u A 6 9 7 \ u A 6 A 0 - \ u A 6 E 5 \ u A 7 1 7 - \ u A 7 1 F \ u A 7 2 2 - \ u A 7 8 8 \ u A 7 8 B - \ u A 7 8 E \ u A 7 9 0 - \ u A 7 9 3 \ u A 7 A 0 - \ u A 7 A A \ u A 7 F 8 - \ u A 8 0 1 \ u A 8 0 3 - \ u A 8 0 5 \ u A 8 0 7 - \ u A 8 0 A \ u A 8 0 C - \ u A 8 2 2 \ u A 8 4 0 - \ u A 8 7 3 \ u A 8 8 2 - \ u A 8 B 3 \ u A 8 F 2 - \ u A 8 F 7 \ u A 8 F B \ u A 9 0 A - \ u A 9 2 5 \ u A 9 3 0 - \ u A 9 4 6 \ u A 9 6 0 - \ u A 9 7 C \ u A 9 8 4 - \ u A 9 B 2 \ u A 9 C F \ u A A 0 0 - \ u A A 2 8 \ u A A 4 0 - \ u A A 4 2 \ u A A 4 4 - \ u A A 4 B \ u A A 6 0 - \ u A A 7 6 \ u A A 7 A \ u A A 8 0 - \ u A A A F \ u A A B 1 \ u A A B 5 \ u A A B 6 \ u A A B 9 - \ u A A B D \ u A A C 0 \ u A A C 2 \ u A A D B - \ u A A D D \ u A A E 0 - \ u A A E A \ u A A F 2 - \ u A A F 4 \ u A B 0 1 - \ u A B 0 6 \ u A B 0 9 - \ u A B 0 E \ u A B 1 1 - \ u A B 1 6 \ u A B 2 0 - \ u A B 2 6 \ u A B 2 8 - \ u A B 2 E \ u A B C 0 - \ u A B E 2 \ u A C 0 0 - \ u D 7 A 3 \ u D 7 B 0 - \ u D 7 C 6 \ u D 7 C B - \ u D 7 F B \ u F 9 0 0 - \ u F A 6 D \ u F A 7 0 - \ u F A D 9 \ u F B 0 0 - \ u F B 0 6 \ u F B 1 3 - \ u F B 1 7 \ u F B 1 D \ u F B 1 F - \ u F B 2 8 \ u F B 2 A - \ u F B 3 6 \ u F B 3 8 - \ u F B 3 C \ u F B 3 E \ u F B 4 0 \ u F B 4 1 \ u F B 4 3 \ u F B 4 4 \ u F B 4 6 - \ u F B B 1 \ u F B D 3 - \ u F D 3 D \ u F D 5 0 - \ u F D 8 F \ u F D 9 2 - \ u F D C 7 \ u F D F 0 -
return text . match ( regex ) ? 1 : 0 ;
} ;
/ * *
* Helper injectArray
* /
jexcel . injectArray = function ( o , idx , arr ) {
return o . slice ( 0 , idx ) . concat ( arr ) . concat ( o . slice ( idx ) ) ;
} ;
/ * *
* Get letter based on a number
*
* @ param integer i
* @ return string letter
* /
jexcel . getColumnName = function ( i ) {
var letter = "" ;
if ( i > 701 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 676 ) ) ;
letter += String . fromCharCode ( 64 + parseInt ( ( i % 676 ) / 26 ) ) ;
} else if ( i > 25 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 26 ) ) ;
}
letter += String . fromCharCode ( 65 + ( i % 26 ) ) ;
return letter ;
} ;
/ * *
* Convert excel like column to jexcel id
*
* @ param string id
* @ return string id
* /
jexcel . getIdFromColumnName = function ( id , arr ) {
// Get the letters
var t = /^[a-zA-Z]+/ . exec ( id ) ;
if ( t ) {
// Base 26 calculation
var code = 0 ;
for ( var i = 0 ; i < t [ 0 ] . length ; i ++ ) {
code +=
parseInt ( t [ 0 ] . charCodeAt ( i ) - 64 ) * Math . pow ( 26 , t [ 0 ] . length - 1 - i ) ;
}
code -- ;
// Make sure jexcel starts on zero
if ( code < 0 ) {
code = 0 ;
}
// Number
var number = parseInt ( /[0-9]+$/ . exec ( id ) ) ;
if ( number > 0 ) {
number -- ;
}
if ( arr == true ) {
id = [ code , number ] ;
} else {
id = code + "-" + number ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
return id ;
} ;
/ * *
* Convert jexcel id to excel like column name
*
* @ param string id
* @ return string id
* /
jexcel . getColumnNameFromId = function ( cellId ) {
if ( ! Array . isArray ( cellId ) ) {
cellId = cellId . split ( "-" ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
return (
jexcel . getColumnName ( parseInt ( cellId [ 0 ] ) ) + ( parseInt ( cellId [ 1 ] ) + 1 )
) ;
} ;
/ * *
* Verify element inside jexcel table
*
* @ param string id
* @ return string id
* /
jexcel . getElement = function ( element ) {
var jexcelSection = 0 ;
var jexcelElement = 0 ;
function path ( element ) {
if ( element . className ) {
if ( element . classList . contains ( "jexcel_container" ) ) {
jexcelElement = element ;
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( element . tagName == "THEAD" ) {
jexcelSection = 1 ;
} else if ( element . tagName == "TBODY" ) {
jexcelSection = 2 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( element . parentNode ) {
if ( ! jexcelElement ) {
path ( element . parentNode ) ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
path ( element ) ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return [ jexcelElement , jexcelSection ] ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
jexcel . doubleDigitFormat = function ( v ) {
v = "" + v ;
if ( v . length == 1 ) {
v = "0" + v ;
}
return v ;
} ;
jexcel . createFromTable = function ( el , options ) {
if ( el . tagName != "TABLE" ) {
console . log ( "Element is not a table" ) ;
} else {
// Configuration
if ( ! options ) {
options = { } ;
}
options . columns = [ ] ;
options . data = [ ] ;
// Colgroup
var colgroup = el . querySelectorAll ( "colgroup > col" ) ;
if ( colgroup . length ) {
// Get column width
for ( var i = 0 ; i < colgroup . length ; i ++ ) {
var width = colgroup [ i ] . style . width ;
if ( ! width ) {
var width = colgroup [ i ] . getAttribute ( "width" ) ;
}
// Set column width
if ( width ) {
if ( ! options . columns [ i ] ) {
options . columns [ i ] = { } ;
}
options . columns [ i ] . width = width ;
}
}
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Parse header
var parseHeader = function ( header ) {
// Get width information
var info = header . getBoundingClientRect ( ) ;
var width = info . width > 50 ? info . width : 50 ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Create column option
if ( ! options . columns [ i ] ) {
options . columns [ i ] = { } ;
}
if ( header . getAttribute ( "data-celltype" ) ) {
options . columns [ i ] . type = header . getAttribute ( "data-celltype" ) ;
} else {
options . columns [ i ] . type = "text" ;
}
options . columns [ i ] . width = width + "px" ;
options . columns [ i ] . title = header . innerHTML ;
options . columns [ i ] . align = header . style . textAlign || "center" ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
if ( ( info = header . getAttribute ( "name" ) ) ) {
options . columns [ i ] . name = info ;
}
if ( ( info = header . getAttribute ( "id" ) ) ) {
options . columns [ i ] . id = info ;
}
} ;
// Headers
var nested = [ ] ;
var headers = el . querySelectorAll ( ":scope > thead > tr" ) ;
if ( headers . length ) {
for ( var j = 0 ; j < headers . length - 1 ; j ++ ) {
var cells = [ ] ;
for ( var i = 0 ; i < headers [ j ] . children . length ; i ++ ) {
var row = {
title : headers [ j ] . children [ i ] . textContent ,
colspan : headers [ j ] . children [ i ] . getAttribute ( "colspan" ) || 1 ,
} ;
cells . push ( row ) ;
}
nested . push ( cells ) ;
}
// Get the last row in the thead
headers = headers [ headers . length - 1 ] . children ;
// Go though the headers
for ( var i = 0 ; i < headers . length ; i ++ ) {
parseHeader ( headers [ i ] ) ;
}
}
// Content
var rowNumber = 0 ;
var mergeCells = { } ;
var rows = { } ;
var style = { } ;
var classes = { } ;
var content = el . querySelectorAll ( ":scope > tr, :scope > tbody > tr" ) ;
for ( var j = 0 ; j < content . length ; j ++ ) {
options . data [ rowNumber ] = [ ] ;
if (
options . parseTableFirstRowAsHeader == true &&
! headers . length &&
j == 0
) {
for ( var i = 0 ; i < content [ j ] . children . length ; i ++ ) {
parseHeader ( content [ j ] . children [ i ] ) ;
}
} else {
for ( var i = 0 ; i < content [ j ] . children . length ; i ++ ) {
// WickedGrid formula compatibility
var value = content [ j ] . children [ i ] . getAttribute ( "data-formula" ) ;
if ( value ) {
if ( value . substr ( 0 , 1 ) != "=" ) {
value = "=" + value ;
}
} else {
var value = content [ j ] . children [ i ] . innerHTML ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
options . data [ rowNumber ] . push ( value ) ;
// Key
var cellName = jexcel . getColumnNameFromId ( [ i , j ] ) ;
2022-07-28 07:33:25 -07:00
// Classes
2023-02-16 21:17:00 -05:00
var tmp = content [ j ] . children [ i ] . getAttribute ( "class" ) ;
if ( tmp ) {
classes [ cellName ] = tmp ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Merged cells
var mergedColspan =
parseInt ( content [ j ] . children [ i ] . getAttribute ( "colspan" ) ) || 0 ;
var mergedRowspan =
parseInt ( content [ j ] . children [ i ] . getAttribute ( "rowspan" ) ) || 0 ;
if ( mergedColspan || mergedRowspan ) {
mergeCells [ cellName ] = [ mergedColspan || 1 , mergedRowspan || 1 ] ;
}
// Avoid problems with hidden cells
if (
( s =
content [ j ] . children [ i ] . style &&
content [ j ] . children [ i ] . style . display == "none" )
) {
content [ j ] . children [ i ] . style . display = "" ;
}
// Get style
var s = content [ j ] . children [ i ] . getAttribute ( "style" ) ;
if ( s ) {
style [ cellName ] = s ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
// Bold
if ( content [ j ] . children [ i ] . classList . contains ( "styleBold" ) ) {
if ( style [ cellName ] ) {
style [ cellName ] += "; font-weight:bold;" ;
} else {
style [ cellName ] = "font-weight:bold;" ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Row Height
if ( content [ j ] . style && content [ j ] . style . height ) {
rows [ j ] = { height : content [ j ] . style . height } ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Index
rowNumber ++ ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
// Nested
if ( Object . keys ( nested ) . length > 0 ) {
options . nestedHeaders = nested ;
}
// Style
if ( Object . keys ( style ) . length > 0 ) {
options . style = style ;
}
// Merged
if ( Object . keys ( mergeCells ) . length > 0 ) {
options . mergeCells = mergeCells ;
}
// Row height
if ( Object . keys ( rows ) . length > 0 ) {
options . rows = rows ;
}
// Classes
if ( Object . keys ( classes ) . length > 0 ) {
options . classes = classes ;
}
var content = el . querySelectorAll ( "tfoot tr" ) ;
if ( content . length ) {
var footers = [ ] ;
for ( var j = 0 ; j < content . length ; j ++ ) {
var footer = [ ] ;
for ( var i = 0 ; i < content [ j ] . children . length ; i ++ ) {
footer . push ( content [ j ] . children [ i ] . textContent ) ;
}
footers . push ( footer ) ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
if ( Object . keys ( footers ) . length > 0 ) {
options . footers = footers ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
// TODO: data-hiddencolumns="3,4"
// I guess in terms the better column type
if ( options . parseTableAutoCellType == true ) {
var pattern = [ ] ;
for ( var i = 0 ; i < options . columns . length ; i ++ ) {
var test = true ;
var testCalendar = true ;
pattern [ i ] = [ ] ;
for ( var j = 0 ; j < options . data . length ; j ++ ) {
var value = options . data [ j ] [ i ] ;
if ( ! pattern [ i ] [ value ] ) {
pattern [ i ] [ value ] = 0 ;
}
pattern [ i ] [ value ] ++ ;
if ( value . length > 25 ) {
test = false ;
}
if ( value . length == 10 ) {
if ( ! ( value . substr ( 4 , 1 ) == "-" && value . substr ( 7 , 1 ) == "-" ) ) {
testCalendar = false ;
}
} else {
testCalendar = false ;
}
}
var keys = Object . keys ( pattern [ i ] ) . length ;
if ( testCalendar ) {
options . columns [ i ] . type = "calendar" ;
} else if (
test == true &&
keys > 1 &&
keys <= parseInt ( options . data . length * 0.1 )
) {
options . columns [ i ] . type = "dropdown" ;
options . columns [ i ] . source = Object . keys ( pattern [ i ] ) ;
}
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return options ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Helpers
jexcel . helpers = ( function ( ) {
var component = { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get carret position for one element
* /
component . getCaretIndex = function ( e ) {
if ( this . config . root ) {
var d = this . config . root ;
} else {
var d = window ;
}
var pos = 0 ;
var s = d . getSelection ( ) ;
if ( s ) {
if ( s . rangeCount !== 0 ) {
var r = s . getRangeAt ( 0 ) ;
var p = r . cloneRange ( ) ;
p . selectNodeContents ( e ) ;
p . setEnd ( r . endContainer , r . endOffset ) ;
pos = p . toString ( ) . length ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
return pos ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Invert keys and values
* /
component . invert = function ( o ) {
var d = [ ] ;
var k = Object . keys ( o ) ;
for ( var i = 0 ; i < k . length ; i ++ ) {
d [ o [ k [ i ] ] ] = k [ i ] ;
}
return d ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get letter based on a number
*
* @ param integer i
* @ return string letter
* /
component . getColumnName = function ( i ) {
var letter = "" ;
if ( i > 701 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 676 ) ) ;
letter += String . fromCharCode ( 64 + parseInt ( ( i % 676 ) / 26 ) ) ;
} else if ( i > 25 ) {
letter += String . fromCharCode ( 64 + parseInt ( i / 26 ) ) ;
}
letter += String . fromCharCode ( 65 + ( i % 26 ) ) ;
return letter ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Get column name from coords
* /
component . getColumnNameFromCoords = function ( x , y ) {
return component . getColumnName ( parseInt ( x ) ) + ( parseInt ( y ) + 1 ) ;
} ;
component . getCoordsFromColumnName = function ( columnName ) {
// Get the letters
var t = /^[a-zA-Z]+/ . exec ( columnName ) ;
if ( t ) {
// Base 26 calculation
var code = 0 ;
for ( var i = 0 ; i < t [ 0 ] . length ; i ++ ) {
code +=
parseInt ( t [ 0 ] . charCodeAt ( i ) - 64 ) *
Math . pow ( 26 , t [ 0 ] . length - 1 - i ) ;
}
code -- ;
// Make sure jspreadsheet starts on zero
if ( code < 0 ) {
code = 0 ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Number
var number = parseInt ( /[0-9]+$/ . exec ( columnName ) ) || null ;
if ( number > 0 ) {
number -- ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return [ code , number ] ;
}
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Extract json configuration from a TABLE DOM tag
* /
component . createFromTable = function ( ) { } ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Helper injectArray
* /
component . injectArray = function ( o , idx , arr ) {
return o . slice ( 0 , idx ) . concat ( arr ) . concat ( o . slice ( idx ) ) ;
} ;
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
/ * *
* Parse CSV string to JS array
* /
component . parseCSV = function ( str , delimiter ) {
// user-supplied delimeter or default comma
delimiter = delimiter || "," ;
// Final data
var col = 0 ;
var row = 0 ;
var num = 0 ;
var data = [ [ ] ] ;
var limit = 0 ;
var flag = null ;
var inside = false ;
var closed = false ;
// Go over all chars
for ( var i = 0 ; i < str . length ; i ++ ) {
// Create new row
if ( ! data [ row ] ) {
data [ row ] = [ ] ;
}
// Create new column
if ( ! data [ row ] [ col ] ) {
data [ row ] [ col ] = "" ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// Ignore
if ( str [ i ] == "\r" ) {
continue ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
// New row
if (
( str [ i ] == "\n" || str [ i ] == delimiter ) &&
( inside == false || closed == true || ! flag )
) {
// Restart flags
flag = null ;
inside = false ;
closed = false ;
if ( data [ row ] [ col ] [ 0 ] == '"' ) {
var val = data [ row ] [ col ] . trim ( ) ;
if ( val [ val . length - 1 ] == '"' ) {
data [ row ] [ col ] = val . substr ( 1 , val . length - 2 ) ;
}
}
// Go to the next cell
if ( str [ i ] == "\n" ) {
// New line
col = 0 ;
row ++ ;
} else {
// New column
col ++ ;
if ( col > limit ) {
// Keep the reference of max column
limit = col ;
}
}
} else {
// Inside quotes
if ( str [ i ] == '"' ) {
inside = ! inside ;
}
if ( flag === null ) {
flag = inside ;
if ( flag == true ) {
continue ;
}
} else if ( flag === true && ! closed ) {
if ( str [ i ] == '"' ) {
if ( str [ i + 1 ] == '"' ) {
inside = true ;
data [ row ] [ col ] += str [ i ] ;
i ++ ;
} else {
closed = true ;
}
continue ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
data [ row ] [ col ] += str [ i ] ;
2022-07-28 07:33:25 -07:00
}
2023-02-16 21:17:00 -05:00
}
// Make sure a square matrix is generated
for ( var j = 0 ; j < data . length ; j ++ ) {
for ( var i = 0 ; i <= limit ; i ++ ) {
if ( data [ j ] [ i ] === undefined ) {
data [ j ] [ i ] = "" ;
}
}
}
return data ;
} ;
return component ;
} ) ( ) ;
/ * *
* Jquery Support
* /
if ( typeof jQuery != "undefined" ) {
( function ( $ ) {
$ . fn . jspreadsheet = $ . fn . jexcel = function ( mixed ) {
var spreadsheetContainer = $ ( this ) . get ( 0 ) ;
if ( ! spreadsheetContainer . jexcel ) {
return jexcel ( $ ( this ) . get ( 0 ) , arguments [ 0 ] ) ;
} else {
if ( Array . isArray ( spreadsheetContainer . jexcel ) ) {
return spreadsheetContainer . jexcel [ mixed ] [ arguments [ 1 ] ] . apply (
this ,
Array . prototype . slice . call ( arguments , 2 )
) ;
} else {
return spreadsheetContainer . jexcel [ mixed ] . apply (
this ,
Array . prototype . slice . call ( arguments , 1 )
) ;
}
}
} ;
} ) ( jQuery ) ;
}
2022-07-28 07:33:25 -07:00
2023-02-16 21:17:00 -05:00
return jexcel ;
} ) ;