File indexing completed on 2024-05-12 04:33:31
0001 /* 0002 SPDX-FileCopyrightText: 2018 Intevation GmbH <intevation@intevation.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 /* QJSEngine limits what we can do with the global object in C++, so map Doc into this here. */ 0008 { 0009 const props = Object.getOwnPropertyDescriptors(Doc); 0010 for (prop in props) { 0011 Object.defineProperty(this, prop, props[prop]); 0012 } 0013 for (const name of Object.getOwnPropertyNames(Doc)) { 0014 if (typeof Doc[name] === 'function') { 0015 this.__proto__[name] = Doc[name]; 0016 } 0017 } 0018 } 0019 0020 /* Builtin functions for Okular's PDF JavaScript interpretation. */ 0021 0022 /** AFSimple_Calculate 0023 * 0024 * cFunction is a string that identifies the operation. 0025 * It is one of AVG, SUM, PRD, MIN, MAX 0026 * cFields is an array of the names of the fields used to calculate. 0027 */ 0028 function AFSimple_Calculate( cFunction, cFields ) 0029 { 0030 var ret = 0; 0031 0032 if ( cFunction === "PRD" ) 0033 { 0034 ret = 1; 0035 } 0036 0037 for (i = 0; i < cFields.length; i++) 0038 { 0039 var field = Doc.getField( cFields[i] ); 0040 var val = util.stringToNumber( field.value ); 0041 0042 if ( cFunction === "SUM" || cFunction === "AVG" ) 0043 { 0044 ret += val; 0045 } 0046 else if ( cFunction === "PRD" ) 0047 { 0048 ret *= val; 0049 } 0050 else if ( cFunction === "MIN" ) 0051 { 0052 if ( i === 0 || val < ret ) 0053 { 0054 ret = val; 0055 } 0056 } 0057 else if ( cFunction === "MAX" ) 0058 { 0059 if ( i === 0 || val > ret ) 0060 { 0061 ret = val; 0062 } 0063 } 0064 } 0065 0066 if ( cFunction === "AVG" ) 0067 { 0068 ret /= cFields.length; 0069 } 0070 0071 event.value = util.numberToString( ret, "g", 32 ); 0072 } 0073 0074 0075 /** AFNumber_Format 0076 * 0077 * Formats event.value based on parameters. 0078 * 0079 * Parameter description based on Acrobat Help: 0080 * 0081 * nDec is the number of places after the decimal point. 0082 * 0083 * sepStyle is an integer denoting separator style 0084 * 0 => . as decimal separator , as thousand separators => 1,234.56 0085 * 1 => . as decimal separator no thousand separators => 1234.56 0086 * 2 => , as decimal separator . as thousand separators => 1.234,56 0087 * 3 => , as decimal separator no thousand separators => 1234,56 0088 * 0089 * negStyle is the formatting used for negative numbers: - not implemented. 0090 * 0 = MinusBlack 0091 * 1 = Red 0092 * 2 = ParensBlack 0093 * 3 = ParensRed 0094 * 0095 * currStyle is the currency style - not used. 0096 * 0097 * strCurrency is the currency symbol. 0098 * 0099 * bCurrencyPrepend is true to prepend the currency symbol; 0100 * false to display on the end of the number. 0101 */ 0102 function AFNumber_Format( nDec, sepStyle, negStyle, currStyle, strCurrency, bCurrencyPrepend ) 0103 { 0104 if ( !event.value ) 0105 { 0106 return; 0107 } 0108 0109 var ret; 0110 var localized = util.stringToNumber( event.value ); 0111 0112 if ( sepStyle === 2 || sepStyle === 3 ) 0113 { 0114 // Use de_DE as the locale for the dot separator format 0115 ret = util.numberToString( localized, "f", nDec, 'de_DE' ); 0116 0117 if ( sepStyle === 3 ) 0118 { 0119 // No thousands separators. Remove all dots from the DE format. 0120 ret = ret.replace( /\./g, '' ); 0121 } 0122 } 0123 else 0124 { 0125 // Otherwise US 0126 ret = util.numberToString( localized, "f", nDec, 'en_US' ); 0127 0128 if ( sepStyle === 1 ) 0129 { 0130 // No thousands separators. Remove all commas from the US format. 0131 ret = ret.replace( /,/g, '' ); 0132 } 0133 } 0134 0135 if ( strCurrency ) 0136 { 0137 if ( bCurrencyPrepend ) 0138 { 0139 ret = strCurrency + ret; 0140 } 0141 else 0142 { 0143 ret = ret + strCurrency; 0144 } 0145 } 0146 0147 event.value = ret; 0148 } 0149 0150 function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency, bCurrencyPrepend) 0151 { 0152 // TODO 0153 return; 0154 } 0155 0156 function AFMakeNumber(string) 0157 { 0158 var type = typeof string; 0159 if ( type == "number" ) 0160 return string; 0161 if ( type != "string" ) 0162 return 0; 0163 return util.stringToNumber( string ); 0164 } 0165 0166 /** AFTime_Format 0167 * 0168 * Formats event.value based on parameters. 0169 * 0170 * Parameter description based on Acrobat Help: 0171 * 0172 * ptf is the number which should be used to format the time, is one of: 0173 * 0 = 24HR_MM [ 14:30 ] 0174 * 1 = 12HR_MM [ 2:30 PM ] 0175 * 2 = 24HR_MM_SS [ 14:30:15 ] 0176 * 3 = 12HR_MM_SS [ 2:30:15 PM ] 0177 */ 0178 function AFTime_Format( ptf ) 0179 { 0180 if( !event.value ) 0181 { 0182 return; 0183 } 0184 var tokens = event.value.split( /\D/ ); 0185 var invalidDate = false; 0186 0187 // Remove empty elements of the array 0188 tokens = tokens.filter(Boolean); 0189 0190 if( tokens.length < 2 ) 0191 invalidDate = true; 0192 0193 // Check if every number is valid 0194 for( i = 0 ; i < tokens.length ; ++i ) 0195 { 0196 if( isNaN( tokens[i] ) ) 0197 { 0198 invalidDate = true; 0199 break; 0200 } 0201 switch( i ) 0202 { 0203 case 0: 0204 { 0205 if( tokens[i] > 23 || tokens[i] < 0 ) 0206 invalidDate = true; 0207 break; 0208 } 0209 case 1: 0210 case 2: 0211 { 0212 if( tokens[i] > 59 || tokens[i] < 0 ) 0213 invalidDate = true; 0214 break; 0215 } 0216 } 0217 } 0218 if( invalidDate ) 0219 { 0220 event.value = ""; 0221 return; 0222 } 0223 0224 // Make it of lenght 3, since we use hh, mm, ss 0225 while( tokens.length < 3 ) 0226 tokens.push( 0 ); 0227 0228 // We get pm string in the user locale to search. 0229 var dummyPm = util.printd( 'ap', new Date( 2018, 5, 11, 23, 11, 11) ).toLocaleLowerCase(); 0230 // Add 12 to time if it's PM and less than 12 0231 if( event.value.toLocaleLowerCase().search( dummyPm ) !== -1 && Number( tokens[0] ) < 12 ) 0232 tokens[0] = Number( tokens[0] ) + 12; 0233 0234 // We use a random date, because we only care about time. 0235 var date = new Date( 2019, 7, 12, tokens[0], tokens[1], tokens[2] ); 0236 var ret; 0237 switch( ptf ) 0238 { 0239 case 0: 0240 ret = util.printd( "hh:MM", date ); 0241 break; 0242 case 1: 0243 ret = util.printd( "h:MM ap", date ); 0244 break; 0245 case 2: 0246 ret = util.printd( "hh:MM:ss", date ); 0247 break; 0248 case 3: 0249 ret = util.printd( "h:MM:ss ap", date ); 0250 break; 0251 } 0252 event.value = ret; 0253 } 0254 0255 /** AFTime_Keystroke 0256 * 0257 * Checks if the string in event.value is valid. Not used. 0258 */ 0259 function AFTime_Keystroke( ptf ) 0260 { 0261 return; 0262 } 0263 0264 /** AFSpecial_Format 0265 * psf is the type of formatting to use: 0266 * 0 = zip code 0267 * 1 = zip + 4 0268 * 2 = phone 0269 * 3 = SSN 0270 * 0271 * These are all in the US format. 0272 */ 0273 function AFSpecial_Format( psf ) 0274 { 0275 if( !event.value || psf == 0 ) 0276 { 0277 return; 0278 } 0279 0280 var ret = event.value; 0281 0282 if( psf === 1 ) 0283 ret = ret.substr( 0, 5 ) + '-' + ret.substr( 5, 4 ); 0284 0285 else if( psf === 2 ) 0286 ret = '(' + ret.substr( 0, 3 ) + ') ' + ret.substr( 3, 3 ) + '-' + ret.substr( 6, 4 ); 0287 0288 else if( psf === 3 ) 0289 ret = ret.substr( 0, 3 ) + '-' + ret.substr( 3, 2 ) + '-' + ret.substr( 5, 4 ); 0290 0291 event.value = ret; 0292 } 0293 0294 /** AFSpecial_Keystroke 0295 * 0296 * Checks if the String in event.value is valid. 0297 * 0298 * Parameter description based on Acrobat Help: 0299 * 0300 * psf is the type of formatting to use: 0301 * 0 = zip code 0302 * 1 = zip + 4 0303 * 2 = phone 0304 * 3 = SSN 0305 * 0306 * These are all in the US format. We check to see if only numbers are inserted and the length of the string. 0307 */ 0308 function AFSpecial_Keystroke( psf ) 0309 { 0310 if ( !event.value ) 0311 { 0312 return; 0313 } 0314 0315 var str = event.value; 0316 if( psf === 0 ) 0317 { 0318 if( str.length > 5 ) 0319 { 0320 event.rc = false; 0321 return; 0322 } 0323 } 0324 0325 else if( psf === 1 || psf === 3 ) 0326 { 0327 if( str.length > 9 ) 0328 { 0329 event.rc = false; 0330 return; 0331 } 0332 } 0333 0334 else if( psf === 2 ) 0335 { 0336 if( str.length > 10 ) 0337 { 0338 event.rc = false; 0339 return; 0340 } 0341 } 0342 0343 for( i = 0 ; i < str.length ; ++i ) 0344 { 0345 if( !( str[i] <= '9' && str[i] >= '0' ) ) 0346 { 0347 event.rc = false; 0348 return; 0349 } 0350 } 0351 } 0352 0353 function AFPercent_Keystroke( nDec, sepStyle ) 0354 { 0355 if (event.willCommit) { 0356 event.rc = true 0357 } else { 0358 // Allow only numbers plus possible separators 0359 // TODO disallow too many separators 0360 // TODO Make separator locale-dependen/use sepStyle properly 0361 event.rc = !isNaN(event.change) || event.change == "." || event.change == "," 0362 } 0363 } 0364 0365 app.popUpMenuEx = function() { 0366 return app.okular_popUpMenuEx(arguments); 0367 } 0368 0369 app.popUpMenu = function() { 0370 // Convert arguments like this: 0371 // app.popUpMenu(["Fruits","Apples","Oranges"], "-","Beans","Corn"); 0372 // into this: 0373 // app.popUpMenuEx( 0374 // {cName:"Fruits", oSubMenu:[ 0375 // {cName:"Apples"}, 0376 // {cName:"Oranges"} 0377 // ]}, 0378 // {cName:"-"}, 0379 // {cName:"Beans"}, 0380 // {cName:"Corn"} 0381 // ); 0382 function convertArgument(arg) { 0383 var exArguments = []; 0384 0385 for (element of arg) { 0386 var newElement = null; 0387 0388 if (Array.isArray(element) && element.length > 0) { 0389 newElement = { 0390 cName: element[0], 0391 oSubMenu: convertArgument(element.slice(1)) 0392 }; 0393 } else if (!Array.isArray(element)) { 0394 newElement = { 0395 cName: element 0396 }; 0397 } 0398 0399 if (newElement !== null) 0400 exArguments.push(newElement); 0401 } 0402 0403 return exArguments; 0404 } 0405 0406 var exArguments = convertArgument(arguments); 0407 var result = app.okular_popUpMenuEx(exArguments); 0408 return result; 0409 }