Remove JavaScript.h
[pdfium.git] / fpdfsdk / src / javascript / PublicMethods.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "../../include/javascript/IJavaScript.h"
8 #include "../../include/javascript/JS_Define.h"
9 #include "../../include/javascript/JS_Object.h"
10 #include "../../include/javascript/JS_Value.h"
11 #include "../../include/javascript/PublicMethods.h"
12 #include "../../include/javascript/JS_EventHandler.h"
13 #include "../../include/javascript/resource.h"
14 #include "../../include/javascript/JS_Context.h"
15 #include "../../include/javascript/JS_Value.h"
16 #include "../../include/javascript/util.h"
17 #include "../../include/javascript/Field.h"
18 #include "../../include/javascript/color.h"
19 #include "../../include/javascript/JS_Runtime.h"
20
21 static v8::Isolate* GetIsolate(IFXJS_Context* cc) {
22   CJS_Context* pContext = (CJS_Context*)cc;
23   ASSERT(pContext != NULL);
24
25   CJS_Runtime* pRuntime = pContext->GetJSRuntime();
26   ASSERT(pRuntime != NULL);
27
28   return pRuntime->GetIsolate();
29 }
30
31 /* -------------------------------- CJS_PublicMethods
32  * -------------------------------- */
33
34 #define DOUBLE_CORRECT 0.000000000000001
35
36 BEGIN_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
37 JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Format)
38 JS_STATIC_GLOBAL_FUN_ENTRY(AFNumber_Keystroke)
39 JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Format)
40 JS_STATIC_GLOBAL_FUN_ENTRY(AFPercent_Keystroke)
41 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_FormatEx)
42 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_KeystrokeEx)
43 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Format)
44 JS_STATIC_GLOBAL_FUN_ENTRY(AFDate_Keystroke)
45 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_FormatEx)
46 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_KeystrokeEx)
47 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Format)
48 JS_STATIC_GLOBAL_FUN_ENTRY(AFTime_Keystroke)
49 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Format)
50 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_Keystroke)
51 JS_STATIC_GLOBAL_FUN_ENTRY(AFSpecial_KeystrokeEx)
52 JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple)
53 JS_STATIC_GLOBAL_FUN_ENTRY(AFMakeNumber)
54 JS_STATIC_GLOBAL_FUN_ENTRY(AFSimple_Calculate)
55 JS_STATIC_GLOBAL_FUN_ENTRY(AFRange_Validate)
56 JS_STATIC_GLOBAL_FUN_ENTRY(AFMergeChange)
57 JS_STATIC_GLOBAL_FUN_ENTRY(AFParseDateEx)
58 JS_STATIC_GLOBAL_FUN_ENTRY(AFExtractNums)
59 END_JS_STATIC_GLOBAL_FUN()
60
61 IMPLEMENT_JS_STATIC_GLOBAL_FUN(CJS_PublicMethods)
62
63 static const FX_WCHAR* months[] = {L"Jan", L"Feb", L"Mar", L"Apr",
64                                    L"May", L"Jun", L"Jul", L"Aug",
65                                    L"Sep", L"Oct", L"Nov", L"Dec"};
66
67 static const FX_WCHAR* fullmonths[] = {L"January", L"February", L"March",
68                                        L"April",   L"May",      L"June",
69                                        L"July",    L"August",   L"September",
70                                        L"October", L"November", L"December"};
71
72 FX_BOOL CJS_PublicMethods::IsNumber(const FX_WCHAR* string) {
73   CFX_WideString sTrim = StrTrim(string);
74   const FX_WCHAR* pTrim = sTrim.c_str();
75   const FX_WCHAR* p = pTrim;
76
77   FX_BOOL bDot = FALSE;
78   FX_BOOL bKXJS = FALSE;
79
80   wchar_t c;
81   while ((c = *p)) {
82     if (c == '.' || c == ',') {
83       if (bDot)
84         return FALSE;
85       bDot = TRUE;
86     } else if (c == '-' || c == '+') {
87       if (p != pTrim)
88         return FALSE;
89     } else if (c == 'e' || c == 'E') {
90       if (bKXJS)
91         return FALSE;
92
93       p++;
94       c = *p;
95       if (c == '+' || c == '-') {
96         bKXJS = TRUE;
97       } else {
98         return FALSE;
99       }
100     } else if (!IsDigit(c)) {
101       return FALSE;
102     }
103     p++;
104   }
105
106   return TRUE;
107 }
108
109 FX_BOOL CJS_PublicMethods::IsDigit(wchar_t ch) {
110   return (ch >= L'0' && ch <= L'9');
111 }
112
113 FX_BOOL CJS_PublicMethods::IsDigit(char ch) {
114   return (ch >= '0' && ch <= '9');
115 }
116
117 FX_BOOL CJS_PublicMethods::IsAlphabetic(wchar_t ch) {
118   return ((ch >= L'a' && ch <= L'z') || (ch >= L'A' && ch <= L'Z'));
119 }
120
121 FX_BOOL CJS_PublicMethods::IsAlphaNumeric(wchar_t ch) {
122   return (IsDigit(ch) || IsAlphabetic(ch));
123 }
124
125 FX_BOOL CJS_PublicMethods::maskSatisfied(wchar_t c_Change, wchar_t c_Mask) {
126   switch (c_Mask) {
127     case L'9':
128       return IsDigit(c_Change);
129     case L'A':
130       return IsAlphabetic(c_Change);
131     case L'O':
132       return IsAlphaNumeric(c_Change);
133     case L'X':
134       return TRUE;
135     default:
136       return (c_Change == c_Mask);
137   }
138 }
139
140 FX_BOOL CJS_PublicMethods::isReservedMaskChar(wchar_t ch) {
141   return ch == L'9' || ch == L'A' || ch == L'O' || ch == L'X';
142 }
143
144 double CJS_PublicMethods::AF_Simple(const FX_WCHAR* sFuction,
145                                     double dValue1,
146                                     double dValue2) {
147   if (FXSYS_wcsicmp(sFuction, L"AVG") == 0 ||
148       FXSYS_wcsicmp(sFuction, L"SUM") == 0) {
149     return dValue1 + dValue2;
150   }
151   if (FXSYS_wcsicmp(sFuction, L"PRD") == 0) {
152     return dValue1 * dValue2;
153   }
154   if (FXSYS_wcsicmp(sFuction, L"MIN") == 0) {
155     return FX_MIN(dValue1, dValue2);
156   }
157   if (FXSYS_wcsicmp(sFuction, L"MAX") == 0) {
158     return FX_MAX(dValue1, dValue2);
159   }
160   return dValue1;
161 }
162
163 CFX_WideString CJS_PublicMethods::StrLTrim(const FX_WCHAR* pStr) {
164   while (*pStr && *pStr == L' ')
165     pStr++;
166
167   return pStr;
168 }
169
170 CFX_WideString CJS_PublicMethods::StrRTrim(const FX_WCHAR* pStr) {
171   const FX_WCHAR* p = pStr;
172   while (*p)
173     p++;
174   while (p > pStr && *(p - 1) == L' ')
175     p--;
176
177   return CFX_WideString(pStr, p - pStr);
178 }
179
180 CFX_WideString CJS_PublicMethods::StrTrim(const FX_WCHAR* pStr) {
181   return StrRTrim(StrLTrim(pStr).c_str());
182 }
183
184 CFX_ByteString CJS_PublicMethods::StrLTrim(const FX_CHAR* pStr) {
185   while (*pStr && *pStr == ' ')
186     pStr++;
187
188   return pStr;
189 }
190
191 CFX_ByteString CJS_PublicMethods::StrRTrim(const FX_CHAR* pStr) {
192   const FX_CHAR* p = pStr;
193   while (*p)
194     p++;
195   while (p > pStr && *(p - 1) == L' ')
196     p--;
197
198   return CFX_ByteString(pStr, p - pStr);
199 }
200
201 CFX_ByteString CJS_PublicMethods::StrTrim(const FX_CHAR* pStr) {
202   return StrRTrim(StrLTrim(pStr));
203 }
204
205 double CJS_PublicMethods::ParseNumber(const FX_WCHAR* swSource,
206                                       FX_BOOL& bAllDigits,
207                                       FX_BOOL& bDot,
208                                       FX_BOOL& bSign,
209                                       FX_BOOL& bKXJS) {
210   bDot = FALSE;
211   bSign = FALSE;
212   bKXJS = FALSE;
213
214   FX_BOOL bDigitExist = FALSE;
215
216   const FX_WCHAR* p = swSource;
217   wchar_t c;
218
219   const FX_WCHAR* pStart = NULL;
220   const FX_WCHAR* pEnd = NULL;
221
222   while ((c = *p)) {
223     if (!pStart && c != L' ') {
224       pStart = p;
225     }
226
227     pEnd = p;
228     p++;
229   }
230
231   if (!pStart) {
232     bAllDigits = FALSE;
233     return 0;
234   }
235
236   while (pEnd != pStart) {
237     if (*pEnd == L' ')
238       pEnd--;
239     else
240       break;
241   }
242
243   double dRet = 0;
244   p = pStart;
245   bAllDigits = TRUE;
246   CFX_WideString swDigits;
247
248   while (p <= pEnd) {
249     c = *p;
250
251     if (IsDigit(c)) {
252       swDigits += c;
253       bDigitExist = TRUE;
254     } else {
255       switch (c) {
256         case L' ':
257           bAllDigits = FALSE;
258           break;
259         case L'.':
260         case L',':
261           if (!bDot) {
262             if (bDigitExist) {
263               swDigits += L'.';
264             } else {
265               swDigits += L'0';
266               swDigits += L'.';
267               bDigitExist = TRUE;
268             }
269
270             bDot = TRUE;
271             break;
272           }
273         case 'e':
274         case 'E':
275           if (!bKXJS) {
276             p++;
277             c = *p;
278             if (c == '+' || c == '-') {
279               bKXJS = TRUE;
280               swDigits += 'e';
281               swDigits += c;
282             }
283             break;
284           }
285         case L'-':
286           if (!bDigitExist && !bSign) {
287             swDigits += c;
288             bSign = TRUE;
289             break;
290           }
291         default:
292           bAllDigits = FALSE;
293
294           if (p != pStart && !bDot && bDigitExist) {
295             swDigits += L'.';
296             bDot = TRUE;
297           } else {
298             bDot = FALSE;
299             bDigitExist = FALSE;
300             swDigits = L"";
301           }
302           break;
303       }
304     }
305
306     p++;
307   }
308
309   if (swDigits.GetLength() > 0 && swDigits.GetLength() < 17) {
310     CFX_ByteString sDigits = swDigits.UTF8Encode();
311
312     if (bKXJS) {
313       dRet = atof(sDigits);
314     } else {
315       if (bDot) {
316         char* pStopString;
317         dRet = ::strtod(sDigits, &pStopString);
318       } else {
319         dRet = atol(sDigits);
320       }
321     }
322   }
323
324   return dRet;
325 }
326
327 double CJS_PublicMethods::ParseStringToNumber(const FX_WCHAR* swSource) {
328   FX_BOOL bAllDigits = FALSE;
329   FX_BOOL bDot = FALSE;
330   FX_BOOL bSign = FALSE;
331   FX_BOOL bKXJS = FALSE;
332
333   return ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS);
334 }
335
336 FX_BOOL CJS_PublicMethods::ConvertStringToNumber(const FX_WCHAR* swSource,
337                                                  double& dRet,
338                                                  FX_BOOL& bDot) {
339   FX_BOOL bAllDigits = FALSE;
340   FX_BOOL bSign = FALSE;
341   FX_BOOL bKXJS = FALSE;
342
343   dRet = ParseNumber(swSource, bAllDigits, bDot, bSign, bKXJS);
344
345   return bAllDigits;
346 }
347
348 CJS_Array CJS_PublicMethods::AF_MakeArrayFromList(v8::Isolate* isolate,
349                                                   CJS_Value val) {
350   CJS_Array StrArray(isolate);
351   if (val.IsArrayObject()) {
352     val.ConvertToArray(StrArray);
353     return StrArray;
354   }
355   CFX_WideString wsStr = val.ToCFXWideString();
356   CFX_ByteString t = CFX_ByteString::FromUnicode(wsStr);
357   const char* p = (const char*)t;
358
359   int ch = ',';
360   int nIndex = 0;
361
362   while (*p) {
363     const char* pTemp = strchr(p, ch);
364     if (pTemp == NULL) {
365       StrArray.SetElement(nIndex, CJS_Value(isolate, StrTrim(p).c_str()));
366       break;
367     } else {
368       char* pSub = new char[pTemp - p + 1];
369       strncpy(pSub, p, pTemp - p);
370       *(pSub + (pTemp - p)) = '\0';
371
372       StrArray.SetElement(nIndex, CJS_Value(isolate, StrTrim(pSub).c_str()));
373       delete[] pSub;
374
375       nIndex++;
376       p = ++pTemp;
377     }
378   }
379   return StrArray;
380 }
381
382 int CJS_PublicMethods::ParseStringInteger(const CFX_WideString& string,
383                                           int nStart,
384                                           int& nSkip,
385                                           int nMaxStep) {
386   int nRet = 0;
387   nSkip = 0;
388   for (int i = nStart, sz = string.GetLength(); i < sz; i++) {
389     if (i - nStart > 10)
390       break;
391
392     FX_WCHAR c = string.GetAt(i);
393     if (IsDigit((wchar_t)c)) {
394       nRet = nRet * 10 + (c - '0');
395       nSkip = i - nStart + 1;
396       if (nSkip >= nMaxStep)
397         break;
398     } else
399       break;
400   }
401
402   return nRet;
403 }
404
405 CFX_WideString CJS_PublicMethods::ParseStringString(
406     const CFX_WideString& string,
407     int nStart,
408     int& nSkip) {
409   CFX_WideString swRet;
410   nSkip = 0;
411   for (int i = nStart, sz = string.GetLength(); i < sz; i++) {
412     FX_WCHAR c = string.GetAt(i);
413     if ((c >= L'a' && c <= L'z') || (c >= L'A' && c <= L'Z')) {
414       swRet += c;
415       nSkip = i - nStart + 1;
416     } else
417       break;
418   }
419
420   return swRet;
421 }
422
423 double CJS_PublicMethods::ParseNormalDate(const CFX_WideString& value,
424                                           FX_BOOL& bWrongFormat) {
425   double dt = JS_GetDateTime();
426
427   int nYear = JS_GetYearFromTime(dt);
428   int nMonth = JS_GetMonthFromTime(dt) + 1;
429   int nDay = JS_GetDayFromTime(dt);
430   int nHour = JS_GetHourFromTime(dt);
431   int nMin = JS_GetMinFromTime(dt);
432   int nSec = JS_GetSecFromTime(dt);
433
434   int number[3];
435
436   int nSkip = 0;
437   int nLen = value.GetLength();
438   int nIndex = 0;
439   int i = 0;
440   while (i < nLen) {
441     if (nIndex > 2)
442       break;
443
444     FX_WCHAR c = value.GetAt(i);
445     if (IsDigit((wchar_t)c)) {
446       number[nIndex++] = ParseStringInteger(value, i, nSkip, 4);
447       i += nSkip;
448     } else {
449       i++;
450     }
451   }
452
453   if (nIndex == 2) {
454     // case2: month/day
455     // case3: day/month
456     if ((number[0] >= 1 && number[0] <= 12) &&
457         (number[1] >= 1 && number[1] <= 31)) {
458       nMonth = number[0];
459       nDay = number[1];
460     } else if ((number[0] >= 1 && number[0] <= 31) &&
461                (number[1] >= 1 && number[1] <= 12)) {
462       nDay = number[0];
463       nMonth = number[1];
464     }
465
466     bWrongFormat = FALSE;
467   } else if (nIndex == 3) {
468     // case1: year/month/day
469     // case2: month/day/year
470     // case3: day/month/year
471
472     if (number[0] > 12 && (number[1] >= 1 && number[1] <= 12) &&
473         (number[2] >= 1 && number[2] <= 31)) {
474       nYear = number[0];
475       nMonth = number[1];
476       nDay = number[2];
477     } else if ((number[0] >= 1 && number[0] <= 12) &&
478                (number[1] >= 1 && number[1] <= 31) && number[2] > 31) {
479       nMonth = number[0];
480       nDay = number[1];
481       nYear = number[2];
482     } else if ((number[0] >= 1 && number[0] <= 31) &&
483                (number[1] >= 1 && number[1] <= 12) && number[2] > 31) {
484       nDay = number[0];
485       nMonth = number[1];
486       nYear = number[2];
487     }
488
489     bWrongFormat = FALSE;
490   } else {
491     bWrongFormat = TRUE;
492     return dt;
493   }
494
495   CFX_WideString swTemp;
496   swTemp.Format(L"%d/%d/%d %d:%d:%d", nMonth, nDay, nYear, nHour, nMin, nSec);
497   return JS_DateParse(swTemp.c_str());
498 }
499
500 double CJS_PublicMethods::MakeRegularDate(const CFX_WideString& value,
501                                           const CFX_WideString& format,
502                                           FX_BOOL& bWrongFormat) {
503   double dt = JS_GetDateTime();
504
505   if (format.IsEmpty() || value.IsEmpty())
506     return dt;
507
508   int nYear = JS_GetYearFromTime(dt);
509   int nMonth = JS_GetMonthFromTime(dt) + 1;
510   int nDay = JS_GetDayFromTime(dt);
511   int nHour = JS_GetHourFromTime(dt);
512   int nMin = JS_GetMinFromTime(dt);
513   int nSec = JS_GetSecFromTime(dt);
514
515   int nYearSub = 99;  // nYear - 2000;
516
517   FX_BOOL bPm = FALSE;
518   FX_BOOL bExit = FALSE;
519   bWrongFormat = FALSE;
520
521   int i = 0;
522   int j = 0;
523
524   while (i < format.GetLength()) {
525     if (bExit)
526       break;
527
528     FX_WCHAR c = format.GetAt(i);
529     switch (c) {
530       case ':':
531       case '.':
532       case '-':
533       case '\\':
534       case '/':
535         i++;
536         j++;
537         break;
538
539       case 'y':
540       case 'm':
541       case 'd':
542       case 'H':
543       case 'h':
544       case 'M':
545       case 's':
546       case 't': {
547         int oldj = j;
548         int nSkip = 0;
549         int remaining = format.GetLength() - i - 1;
550
551         if (remaining == 0 || format.GetAt(i + 1) != c) {
552           switch (c) {
553             case 'y':
554               i++;
555               j++;
556               break;
557             case 'm':
558               nMonth = ParseStringInteger(value, j, nSkip, 2);
559               i++;
560               j += nSkip;
561               break;
562             case 'd':
563               nDay = ParseStringInteger(value, j, nSkip, 2);
564               i++;
565               j += nSkip;
566               break;
567             case 'H':
568               nHour = ParseStringInteger(value, j, nSkip, 2);
569               i++;
570               j += nSkip;
571               break;
572             case 'h':
573               nHour = ParseStringInteger(value, j, nSkip, 2);
574               i++;
575               j += nSkip;
576               break;
577             case 'M':
578               nMin = ParseStringInteger(value, j, nSkip, 2);
579               i++;
580               j += nSkip;
581               break;
582             case 's':
583               nSec = ParseStringInteger(value, j, nSkip, 2);
584               i++;
585               j += nSkip;
586               break;
587             case 't':
588               bPm = (j < value.GetLength() && value.GetAt(j) == 'p');
589               i++;
590               j++;
591               break;
592           }
593         } else if (remaining == 1 || format.GetAt(i + 2) != c) {
594           switch (c) {
595             case 'y':
596               nYear = ParseStringInteger(value, j, nSkip, 4);
597               i += 2;
598               j += nSkip;
599               break;
600             case 'm':
601               nMonth = ParseStringInteger(value, j, nSkip, 2);
602               i += 2;
603               j += nSkip;
604               break;
605             case 'd':
606               nDay = ParseStringInteger(value, j, nSkip, 2);
607               i += 2;
608               j += nSkip;
609               break;
610             case 'H':
611               nHour = ParseStringInteger(value, j, nSkip, 2);
612               i += 2;
613               j += nSkip;
614               break;
615             case 'h':
616               nHour = ParseStringInteger(value, j, nSkip, 2);
617               i += 2;
618               j += nSkip;
619               break;
620             case 'M':
621               nMin = ParseStringInteger(value, j, nSkip, 2);
622               i += 2;
623               j += nSkip;
624               break;
625             case 's':
626               nSec = ParseStringInteger(value, j, nSkip, 2);
627               i += 2;
628               j += nSkip;
629               break;
630             case 't':
631               bPm = (j + 1 < value.GetLength() && value.GetAt(j) == 'p' &&
632                      value.GetAt(j + 1) == 'm');
633               i += 2;
634               j += 2;
635               break;
636           }
637         } else if (remaining == 2 || format.GetAt(i + 3) != c) {
638           switch (c) {
639             case 'm': {
640               CFX_WideString sMonth = ParseStringString(value, j, nSkip);
641               FX_BOOL bFind = FALSE;
642               for (int m = 0; m < 12; m++) {
643                 if (sMonth.CompareNoCase(months[m]) == 0) {
644                   nMonth = m + 1;
645                   i += 3;
646                   j += nSkip;
647                   bFind = TRUE;
648                   break;
649                 }
650               }
651
652               if (!bFind) {
653                 nMonth = ParseStringInteger(value, j, nSkip, 3);
654                 i += 3;
655                 j += nSkip;
656               }
657             } break;
658             case 'y':
659               break;
660             default:
661               i += 3;
662               j += 3;
663               break;
664           }
665         } else if (remaining == 3 || format.GetAt(i + 4) != c) {
666           switch (c) {
667             case 'y':
668               nYear = ParseStringInteger(value, j, nSkip, 4);
669               j += nSkip;
670               i += 4;
671               break;
672             case 'm': {
673               FX_BOOL bFind = FALSE;
674
675               CFX_WideString sMonth = ParseStringString(value, j, nSkip);
676               sMonth.MakeLower();
677
678               for (int m = 0; m < 12; m++) {
679                 CFX_WideString sFullMonths = fullmonths[m];
680                 sFullMonths.MakeLower();
681
682                 if (sFullMonths.Find(sMonth.c_str(), 0) != -1) {
683                   nMonth = m + 1;
684                   i += 4;
685                   j += nSkip;
686                   bFind = TRUE;
687                   break;
688                 }
689               }
690
691               if (!bFind) {
692                 nMonth = ParseStringInteger(value, j, nSkip, 4);
693                 i += 4;
694                 j += nSkip;
695               }
696             } break;
697             default:
698               i += 4;
699               j += 4;
700               break;
701           }
702         } else {
703           if (j >= value.GetLength() || format.GetAt(i) != value.GetAt(j)) {
704             bWrongFormat = TRUE;
705             bExit = TRUE;
706           }
707           i++;
708           j++;
709         }
710
711         if (oldj == j) {
712           bWrongFormat = TRUE;
713           bExit = TRUE;
714         }
715       }
716
717       break;
718       default:
719         if (value.GetLength() <= j) {
720           bExit = TRUE;
721         } else if (format.GetAt(i) != value.GetAt(j)) {
722           bWrongFormat = TRUE;
723           bExit = TRUE;
724         }
725
726         i++;
727         j++;
728         break;
729     }
730   }
731
732   if (bPm)
733     nHour += 12;
734
735   if (nYear >= 0 && nYear <= nYearSub)
736     nYear += 2000;
737
738   if (nMonth < 1 || nMonth > 12)
739     bWrongFormat = TRUE;
740
741   if (nDay < 1 || nDay > 31)
742     bWrongFormat = TRUE;
743
744   if (nHour < 0 || nHour > 24)
745     bWrongFormat = TRUE;
746
747   if (nMin < 0 || nMin > 60)
748     bWrongFormat = TRUE;
749
750   if (nSec < 0 || nSec > 60)
751     bWrongFormat = TRUE;
752
753   double dRet = 0;
754
755   if (bWrongFormat) {
756     dRet = ParseNormalDate(value, bWrongFormat);
757   } else {
758     dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
759                        JS_MakeTime(nHour, nMin, nSec, 0));
760
761     if (JS_PortIsNan(dRet)) {
762       dRet = JS_DateParse(value.c_str());
763     }
764   }
765
766   if (JS_PortIsNan(dRet)) {
767     dRet = ParseNormalDate(value, bWrongFormat);
768   }
769
770   return dRet;
771 }
772
773 CFX_WideString CJS_PublicMethods::MakeFormatDate(double dDate,
774                                                  const CFX_WideString& format) {
775   CFX_WideString sRet = L"", sPart = L"";
776
777   int nYear = JS_GetYearFromTime(dDate);
778   int nMonth = JS_GetMonthFromTime(dDate) + 1;
779   int nDay = JS_GetDayFromTime(dDate);
780   int nHour = JS_GetHourFromTime(dDate);
781   int nMin = JS_GetMinFromTime(dDate);
782   int nSec = JS_GetSecFromTime(dDate);
783
784   int i = 0;
785   while (i < format.GetLength()) {
786     FX_WCHAR c = format.GetAt(i);
787     int remaining = format.GetLength() - i - 1;
788     sPart = L"";
789     switch (c) {
790       case 'y':
791       case 'm':
792       case 'd':
793       case 'H':
794       case 'h':
795       case 'M':
796       case 's':
797       case 't':
798         if (remaining == 0 || format.GetAt(i + 1) != c) {
799           switch (c) {
800             case 'y':
801               sPart += c;
802               break;
803             case 'm':
804               sPart.Format(L"%d", nMonth);
805               break;
806             case 'd':
807               sPart.Format(L"%d", nDay);
808               break;
809             case 'H':
810               sPart.Format(L"%d", nHour);
811               break;
812             case 'h':
813               sPart.Format(L"%d", nHour > 12 ? nHour - 12 : nHour);
814               break;
815             case 'M':
816               sPart.Format(L"%d", nMin);
817               break;
818             case 's':
819               sPart.Format(L"%d", nSec);
820               break;
821             case 't':
822               sPart += nHour > 12 ? 'p' : 'a';
823               break;
824           }
825           i++;
826         } else if (remaining == 1 || format.GetAt(i + 2) != c) {
827           switch (c) {
828             case 'y':
829               sPart.Format(L"%02d", nYear - (nYear / 100) * 100);
830               break;
831             case 'm':
832               sPart.Format(L"%02d", nMonth);
833               break;
834             case 'd':
835               sPart.Format(L"%02d", nDay);
836               break;
837             case 'H':
838               sPart.Format(L"%02d", nHour);
839               break;
840             case 'h':
841               sPart.Format(L"%02d", nHour > 12 ? nHour - 12 : nHour);
842               break;
843             case 'M':
844               sPart.Format(L"%02d", nMin);
845               break;
846             case 's':
847               sPart.Format(L"%02d", nSec);
848               break;
849             case 't':
850               sPart = nHour > 12 ? L"pm" : L"am";
851               break;
852           }
853           i += 2;
854         } else if (remaining == 2 || format.GetAt(i + 3) != c) {
855           switch (c) {
856             case 'm':
857               i += 3;
858               if (nMonth > 0 && nMonth <= 12)
859                 sPart += months[nMonth - 1];
860               break;
861             default:
862               i += 3;
863               sPart += c;
864               sPart += c;
865               sPart += c;
866               break;
867           }
868         } else if (remaining == 3 || format.GetAt(i + 4) != c) {
869           switch (c) {
870             case 'y':
871               sPart.Format(L"%04d", nYear);
872               i += 4;
873               break;
874             case 'm':
875               i += 4;
876               if (nMonth > 0 && nMonth <= 12)
877                 sPart += fullmonths[nMonth - 1];
878               break;
879             default:
880               i += 4;
881               sPart += c;
882               sPart += c;
883               sPart += c;
884               sPart += c;
885               break;
886           }
887         } else {
888           i++;
889           sPart += c;
890         }
891         break;
892       default:
893         i++;
894         sPart += c;
895         break;
896     }
897
898     sRet += sPart;
899   }
900
901   return sRet;
902 }
903
904 /* -------------------------------------------------------------------------- */
905
906 // function AFNumber_Format(nDec, sepStyle, negStyle, currStyle, strCurrency,
907 // bCurrencyPrepend)
908 FX_BOOL CJS_PublicMethods::AFNumber_Format(IFXJS_Context* cc,
909                                            const CJS_Parameters& params,
910                                            CJS_Value& vRet,
911                                            CFX_WideString& sError) {
912 #if _FX_OS_ != _FX_ANDROID_
913   v8::Isolate* isolate = ::GetIsolate(cc);
914   CJS_Context* pContext = (CJS_Context*)cc;
915   ASSERT(pContext != NULL);
916   CJS_EventHandler* pEvent = pContext->GetEventHandler();
917   ASSERT(pEvent != NULL);
918
919   if (params.size() != 6) {
920     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
921     return FALSE;
922   }
923   if (!pEvent->m_pValue)
924     return FALSE;
925   CFX_WideString& Value = pEvent->Value();
926   CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
927
928   if (strValue.IsEmpty())
929     return TRUE;
930
931   int iDec = params[0].ToInt();
932   int iSepStyle = params[1].ToInt();
933   int iNegStyle = params[2].ToInt();
934   // params[3] is iCurrStyle, it's not used.
935   std::wstring wstrCurrency(params[4].ToCFXWideString().c_str());
936   FX_BOOL bCurrencyPrepend = params[5].ToBool();
937
938   if (iDec < 0)
939     iDec = -iDec;
940
941   if (iSepStyle < 0 || iSepStyle > 3)
942     iSepStyle = 0;
943
944   if (iNegStyle < 0 || iNegStyle > 3)
945     iNegStyle = 0;
946
947   //////////////////////////////////////////////////////
948   // for processing decimal places
949   strValue.Replace(",", ".");
950   double dValue = atof(strValue);
951   if (iDec > 0)
952     dValue += DOUBLE_CORRECT;
953
954   int iDec2;
955   int iNegative = 0;
956
957   strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
958   if (strValue.IsEmpty()) {
959     dValue = 0;
960     strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
961     if (strValue.IsEmpty()) {
962       strValue = "0";
963       iDec2 = 1;
964     }
965   }
966
967   if (iDec2 < 0) {
968     for (int iNum = 0; iNum < abs(iDec2); iNum++) {
969       strValue = "0" + strValue;
970     }
971     iDec2 = 0;
972   }
973   int iMax = strValue.GetLength();
974   if (iDec2 > iMax) {
975     for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) {
976       strValue += "0";
977     }
978     iMax = iDec2 + 1;
979   }
980   ///////////////////////////////////////////////////////
981   // for processing seperator style
982   if (iDec2 < iMax) {
983     if (iSepStyle == 0 || iSepStyle == 1) {
984       strValue.Insert(iDec2, '.');
985       iMax++;
986     } else if (iSepStyle == 2 || iSepStyle == 3) {
987       strValue.Insert(iDec2, ',');
988       iMax++;
989     }
990
991     if (iDec2 == 0)
992       strValue.Insert(iDec2, '0');
993   }
994   if (iSepStyle == 0 || iSepStyle == 2) {
995     char cSeperator;
996     if (iSepStyle == 0)
997       cSeperator = ',';
998     else
999       cSeperator = '.';
1000
1001     int iDecPositive;
1002     iDecPositive = iDec2;
1003
1004     for (iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) {
1005       strValue.Insert(iDecPositive, cSeperator);
1006       iMax++;
1007     }
1008   }
1009
1010   //////////////////////////////////////////////////////////////////////
1011   // for processing currency string
1012
1013   Value = CFX_WideString::FromLocal(strValue);
1014   std::wstring strValue2 = Value.c_str();
1015
1016   if (bCurrencyPrepend)
1017     strValue2 = wstrCurrency + strValue2;
1018   else
1019     strValue2 = strValue2 + wstrCurrency;
1020
1021   /////////////////////////////////////////////////////////////////////////
1022   // for processing negative style
1023   if (iNegative) {
1024     if (iNegStyle == 0) {
1025       strValue2.insert(0, L"-");
1026     }
1027     if (iNegStyle == 2 || iNegStyle == 3) {
1028       strValue2.insert(0, L"(");
1029       strValue2.insert(strValue2.length(), L")");
1030     }
1031     if (iNegStyle == 1 || iNegStyle == 3) {
1032       if (Field* fTarget = pEvent->Target_Field()) {
1033         CJS_Array arColor(isolate);
1034         CJS_Value vColElm(isolate);
1035         vColElm = L"RGB";
1036         arColor.SetElement(0, vColElm);
1037         vColElm = 1;
1038         arColor.SetElement(1, vColElm);
1039         vColElm = 0;
1040         arColor.SetElement(2, vColElm);
1041
1042         arColor.SetElement(3, vColElm);
1043
1044         CJS_PropValue vProp(isolate);
1045         vProp.StartGetting();
1046         vProp << arColor;
1047         vProp.StartSetting();
1048         fTarget->textColor(cc, vProp, sError);  // red
1049       }
1050     }
1051   } else {
1052     if (iNegStyle == 1 || iNegStyle == 3) {
1053       if (Field* fTarget = pEvent->Target_Field()) {
1054         CJS_Array arColor(isolate);
1055         CJS_Value vColElm(isolate);
1056         vColElm = L"RGB";
1057         arColor.SetElement(0, vColElm);
1058         vColElm = 0;
1059         arColor.SetElement(1, vColElm);
1060         arColor.SetElement(2, vColElm);
1061         arColor.SetElement(3, vColElm);
1062
1063         CJS_PropValue vProp(isolate);
1064         vProp.StartGetting();
1065         fTarget->textColor(cc, vProp, sError);
1066
1067         CJS_Array aProp(isolate);
1068         vProp.ConvertToArray(aProp);
1069
1070         CPWL_Color crProp;
1071         CPWL_Color crColor;
1072         color::ConvertArrayToPWLColor(aProp, crProp);
1073         color::ConvertArrayToPWLColor(arColor, crColor);
1074
1075         if (crColor != crProp) {
1076           CJS_PropValue vProp2(isolate);
1077           vProp2.StartGetting();
1078           vProp2 << arColor;
1079           vProp2.StartSetting();
1080           fTarget->textColor(cc, vProp2, sError);
1081         }
1082       }
1083     }
1084   }
1085   Value = strValue2.c_str();
1086 #endif
1087   return TRUE;
1088 }
1089
1090 // function AFNumber_Keystroke(nDec, sepStyle, negStyle, currStyle, strCurrency,
1091 // bCurrencyPrepend)
1092 FX_BOOL CJS_PublicMethods::AFNumber_Keystroke(IFXJS_Context* cc,
1093                                               const CJS_Parameters& params,
1094                                               CJS_Value& vRet,
1095                                               CFX_WideString& sError) {
1096   CJS_Context* pContext = (CJS_Context*)cc;
1097   ASSERT(pContext != NULL);
1098   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1099   ASSERT(pEvent != NULL);
1100
1101   if (params.size() < 2)
1102     return FALSE;
1103   int iSepStyle = params[1].ToInt();
1104
1105   if (iSepStyle < 0 || iSepStyle > 3)
1106     iSepStyle = 0;
1107   if (!pEvent->m_pValue)
1108     return FALSE;
1109   CFX_WideString& val = pEvent->Value();
1110   CFX_WideString& w_strChange = pEvent->Change();
1111   CFX_WideString w_strValue = val;
1112
1113   if (pEvent->WillCommit()) {
1114     CFX_WideString wstrChange = w_strChange;
1115     CFX_WideString wstrValue = StrLTrim(w_strValue.c_str());
1116     if (wstrValue.IsEmpty())
1117       return TRUE;
1118
1119     CFX_WideString swTemp = wstrValue;
1120     swTemp.Replace(L",", L".");
1121     if (!IsNumber(swTemp.c_str())) {
1122       pEvent->Rc() = FALSE;
1123       sError = JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE);
1124       Alert(pContext, sError.c_str());
1125       return TRUE;
1126     }
1127     return TRUE;  // it happens after the last keystroke and before validating,
1128   }
1129
1130   std::wstring w_strValue2 = w_strValue.c_str();
1131   std::wstring w_strChange2 = w_strChange.c_str();
1132   std::wstring w_strSelected;
1133   if (-1 != pEvent->SelStart())
1134     w_strSelected = w_strValue2.substr(pEvent->SelStart(),
1135                                        (pEvent->SelEnd() - pEvent->SelStart()));
1136   bool bHasSign = (w_strValue2.find('-') != std::wstring::npos) &&
1137                   (w_strSelected.find('-') == std::wstring::npos);
1138   if (bHasSign) {
1139     // can't insert "change" in front to sign postion.
1140     if (pEvent->SelStart() == 0) {
1141       FX_BOOL& bRc = pEvent->Rc();
1142       bRc = FALSE;
1143       return TRUE;
1144     }
1145   }
1146
1147   char cSep = L'.';
1148
1149   switch (iSepStyle) {
1150     case 0:
1151     case 1:
1152       cSep = L'.';
1153       break;
1154     case 2:
1155     case 3:
1156       cSep = L',';
1157       break;
1158   }
1159
1160   bool bHasSep = (w_strValue2.find(cSep) != std::wstring::npos);
1161   for (std::wstring::iterator it = w_strChange2.begin();
1162        it != w_strChange2.end(); it++) {
1163     if (*it == cSep) {
1164       if (bHasSep) {
1165         FX_BOOL& bRc = pEvent->Rc();
1166         bRc = FALSE;
1167         return TRUE;
1168       }
1169       bHasSep = TRUE;
1170       continue;
1171     }
1172     if (*it == L'-') {
1173       if (bHasSign) {
1174         FX_BOOL& bRc = pEvent->Rc();
1175         bRc = FALSE;
1176         return TRUE;
1177       }
1178       if (it != w_strChange2.begin())  // sign's position is not correct
1179       {
1180         FX_BOOL& bRc = pEvent->Rc();
1181         bRc = FALSE;
1182         return TRUE;
1183       }
1184       if (pEvent->SelStart() != 0) {
1185         FX_BOOL& bRc = pEvent->Rc();
1186         bRc = FALSE;
1187         return TRUE;
1188       }
1189       bHasSign = TRUE;
1190       continue;
1191     }
1192
1193     if (!IsDigit(*it)) {
1194       FX_BOOL& bRc = pEvent->Rc();
1195       bRc = FALSE;
1196       return TRUE;
1197     }
1198   }
1199
1200   std::wstring w_prefix = w_strValue2.substr(0, pEvent->SelStart());
1201   std::wstring w_postfix;
1202   if (pEvent->SelEnd() < (int)w_strValue2.length())
1203     w_postfix = w_strValue2.substr(pEvent->SelEnd());
1204   w_strValue2 = w_prefix + w_strChange2 + w_postfix;
1205   w_strValue = w_strValue2.c_str();
1206   val = w_strValue;
1207   return TRUE;
1208 }
1209
1210 // function AFPercent_Format(nDec, sepStyle)
1211 FX_BOOL CJS_PublicMethods::AFPercent_Format(IFXJS_Context* cc,
1212                                             const CJS_Parameters& params,
1213                                             CJS_Value& vRet,
1214                                             CFX_WideString& sError) {
1215 #if _FX_OS_ != _FX_ANDROID_
1216   CJS_Context* pContext = (CJS_Context*)cc;
1217   ASSERT(pContext != NULL);
1218   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1219   ASSERT(pEvent != NULL);
1220
1221   if (params.size() != 2) {
1222     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1223     return FALSE;
1224   }
1225   if (!pEvent->m_pValue)
1226     return FALSE;
1227
1228   CFX_WideString& Value = pEvent->Value();
1229   CFX_ByteString strValue = StrTrim(CFX_ByteString::FromUnicode(Value));
1230   if (strValue.IsEmpty())
1231     return TRUE;
1232
1233   int iDec = params[0].ToInt();
1234   if (iDec < 0)
1235     iDec = -iDec;
1236
1237   int iSepStyle = params[1].ToInt();
1238   if (iSepStyle < 0 || iSepStyle > 3)
1239     iSepStyle = 0;
1240
1241   //////////////////////////////////////////////////////
1242   // for processing decimal places
1243   double dValue = atof(strValue);
1244   dValue *= 100;
1245   if (iDec > 0)
1246     dValue += DOUBLE_CORRECT;  //УÕý
1247
1248   int iDec2;
1249   int iNegative = 0;
1250   strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
1251   if (strValue.IsEmpty()) {
1252     dValue = 0;
1253     strValue = fcvt(dValue, iDec, &iDec2, &iNegative);
1254   }
1255
1256   if (iDec2 < 0) {
1257     for (int iNum = 0; iNum < abs(iDec2); iNum++) {
1258       strValue = "0" + strValue;
1259     }
1260     iDec2 = 0;
1261   }
1262   int iMax = strValue.GetLength();
1263   if (iDec2 > iMax) {
1264     for (int iNum = 0; iNum <= iDec2 - iMax; iNum++) {
1265       strValue += "0";
1266     }
1267     iMax = iDec2 + 1;
1268   }
1269   ///////////////////////////////////////////////////////
1270   // for processing seperator style
1271   if (iDec2 < iMax) {
1272     if (iSepStyle == 0 || iSepStyle == 1) {
1273       strValue.Insert(iDec2, '.');
1274       iMax++;
1275     } else if (iSepStyle == 2 || iSepStyle == 3) {
1276       strValue.Insert(iDec2, ',');
1277       iMax++;
1278     }
1279
1280     if (iDec2 == 0)
1281       strValue.Insert(iDec2, '0');
1282   }
1283   if (iSepStyle == 0 || iSepStyle == 2) {
1284     char cSeperator;
1285     if (iSepStyle == 0)
1286       cSeperator = ',';
1287     else
1288       cSeperator = '.';
1289
1290     int iDecPositive;
1291     iDecPositive = iDec2;
1292
1293     for (iDecPositive = iDec2 - 3; iDecPositive > 0; iDecPositive -= 3) {
1294       strValue.Insert(iDecPositive, cSeperator);
1295       iMax++;
1296     }
1297   }
1298   ////////////////////////////////////////////////////////////////////
1299   // negative mark
1300   if (iNegative)
1301     strValue = "-" + strValue;
1302   strValue += "%";
1303   Value = CFX_WideString::FromLocal(strValue);
1304 #endif
1305   return TRUE;
1306 }
1307 // AFPercent_Keystroke(nDec, sepStyle)
1308 FX_BOOL CJS_PublicMethods::AFPercent_Keystroke(IFXJS_Context* cc,
1309                                                const CJS_Parameters& params,
1310                                                CJS_Value& vRet,
1311                                                CFX_WideString& sError) {
1312   return AFNumber_Keystroke(cc, params, vRet, sError);
1313 }
1314
1315 // function AFDate_FormatEx(cFormat)
1316 FX_BOOL CJS_PublicMethods::AFDate_FormatEx(IFXJS_Context* cc,
1317                                            const CJS_Parameters& params,
1318                                            CJS_Value& vRet,
1319                                            CFX_WideString& sError) {
1320   CJS_Context* pContext = (CJS_Context*)cc;
1321   ASSERT(pContext != NULL);
1322   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1323   ASSERT(pEvent != NULL);
1324
1325   if (params.size() != 1) {
1326     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1327     return FALSE;
1328   }
1329   if (!pEvent->m_pValue)
1330     return FALSE;
1331
1332   CFX_WideString& val = pEvent->Value();
1333   CFX_WideString strValue = val;
1334   if (strValue.IsEmpty())
1335     return TRUE;
1336
1337   CFX_WideString sFormat = params[0].ToCFXWideString();
1338   FX_BOOL bWrongFormat = FALSE;
1339   double dDate = 0.0f;
1340
1341   if (strValue.Find(L"GMT") != -1) {
1342     // for GMT format time
1343     // such as "Tue Aug 11 14:24:16 GMT+08002009"
1344     dDate = MakeInterDate(strValue);
1345   } else {
1346     dDate = MakeRegularDate(strValue, sFormat, bWrongFormat);
1347   }
1348
1349   if (JS_PortIsNan(dDate)) {
1350     CFX_WideString swMsg;
1351     swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(),
1352                  sFormat.c_str());
1353     Alert(pContext, swMsg.c_str());
1354     return FALSE;
1355   }
1356
1357   val = MakeFormatDate(dDate, sFormat);
1358   return TRUE;
1359 }
1360
1361 double CJS_PublicMethods::MakeInterDate(CFX_WideString strValue) {
1362   int nHour;
1363   int nMin;
1364   int nSec;
1365   int nYear;
1366   int nMonth;
1367   int nDay;
1368
1369   CFX_WideStringArray wsArray;
1370   CFX_WideString sMonth = L"";
1371   CFX_WideString sTemp = L"";
1372   int nSize = strValue.GetLength();
1373
1374   for (int i = 0; i < nSize; i++) {
1375     FX_WCHAR c = strValue.GetAt(i);
1376     if (c == L' ' || c == L':') {
1377       wsArray.Add(sTemp);
1378       sTemp = L"";
1379       continue;
1380     }
1381
1382     sTemp += c;
1383   }
1384
1385   wsArray.Add(sTemp);
1386   if (wsArray.GetSize() != 8)
1387     return 0;
1388
1389   sTemp = wsArray[1];
1390   if (sTemp.Compare(L"Jan") == 0)
1391     nMonth = 1;
1392   if (sTemp.Compare(L"Feb") == 0)
1393     nMonth = 2;
1394   if (sTemp.Compare(L"Mar") == 0)
1395     nMonth = 3;
1396   if (sTemp.Compare(L"Apr") == 0)
1397     nMonth = 4;
1398   if (sTemp.Compare(L"May") == 0)
1399     nMonth = 5;
1400   if (sTemp.Compare(L"Jun") == 0)
1401     nMonth = 6;
1402   if (sTemp.Compare(L"Jul") == 0)
1403     nMonth = 7;
1404   if (sTemp.Compare(L"Aug") == 0)
1405     nMonth = 8;
1406   if (sTemp.Compare(L"Sep") == 0)
1407     nMonth = 9;
1408   if (sTemp.Compare(L"Oct") == 0)
1409     nMonth = 10;
1410   if (sTemp.Compare(L"Nov") == 0)
1411     nMonth = 11;
1412   if (sTemp.Compare(L"Dec") == 0)
1413     nMonth = 12;
1414
1415   nDay = (int)ParseStringToNumber(wsArray[2].c_str());
1416   nHour = (int)ParseStringToNumber(wsArray[3].c_str());
1417   nMin = (int)ParseStringToNumber(wsArray[4].c_str());
1418   nSec = (int)ParseStringToNumber(wsArray[5].c_str());
1419   nYear = (int)ParseStringToNumber(wsArray[7].c_str());
1420
1421   double dRet = JS_MakeDate(JS_MakeDay(nYear, nMonth - 1, nDay),
1422                             JS_MakeTime(nHour, nMin, nSec, 0));
1423
1424   if (JS_PortIsNan(dRet)) {
1425     dRet = JS_DateParse(strValue.c_str());
1426   }
1427
1428   return dRet;
1429 }
1430
1431 // AFDate_KeystrokeEx(cFormat)
1432 FX_BOOL CJS_PublicMethods::AFDate_KeystrokeEx(IFXJS_Context* cc,
1433                                               const CJS_Parameters& params,
1434                                               CJS_Value& vRet,
1435                                               CFX_WideString& sError) {
1436   CJS_Context* pContext = (CJS_Context*)cc;
1437   ASSERT(pContext != NULL);
1438   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1439   ASSERT(pEvent != NULL);
1440
1441   if (params.size() != 1) {
1442     sError = L"AFDate_KeystrokeEx's parameters' size r not correct";
1443     return FALSE;
1444   }
1445
1446   if (pEvent->WillCommit()) {
1447     if (!pEvent->m_pValue)
1448       return FALSE;
1449     CFX_WideString strValue = pEvent->Value();
1450     if (strValue.IsEmpty())
1451       return TRUE;
1452
1453     CFX_WideString sFormat = params[0].ToCFXWideString();
1454     FX_BOOL bWrongFormat = FALSE;
1455     double dRet = MakeRegularDate(strValue, sFormat, bWrongFormat);
1456     if (bWrongFormat || JS_PortIsNan(dRet)) {
1457       CFX_WideString swMsg;
1458       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(),
1459                    sFormat.c_str());
1460       Alert(pContext, swMsg.c_str());
1461       pEvent->Rc() = FALSE;
1462       return TRUE;
1463     }
1464   }
1465   return TRUE;
1466 }
1467
1468 FX_BOOL CJS_PublicMethods::AFDate_Format(IFXJS_Context* cc,
1469                                          const CJS_Parameters& params,
1470                                          CJS_Value& vRet,
1471                                          CFX_WideString& sError) {
1472   v8::Isolate* isolate = ::GetIsolate(cc);
1473
1474   if (params.size() != 1) {
1475     CJS_Context* pContext = (CJS_Context*)cc;
1476     ASSERT(pContext != NULL);
1477
1478     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1479     return FALSE;
1480   }
1481
1482   int iIndex = params[0].ToInt();
1483   const FX_WCHAR* cFormats[] = {L"m/d",
1484                                 L"m/d/yy",
1485                                 L"mm/dd/yy",
1486                                 L"mm/yy",
1487                                 L"d-mmm",
1488                                 L"d-mmm-yy",
1489                                 L"dd-mmm-yy",
1490                                 L"yy-mm-dd",
1491                                 L"mmm-yy",
1492                                 L"mmmm-yy",
1493                                 L"mmm d, yyyy",
1494                                 L"mmmm d, yyyy",
1495                                 L"m/d/yy h:MM tt",
1496                                 L"m/d/yy HH:MM"};
1497
1498   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1499     iIndex = 0;
1500
1501   CJS_Parameters newParams;
1502   CJS_Value val(isolate, cFormats[iIndex]);
1503   newParams.push_back(val);
1504   return AFDate_FormatEx(cc, newParams, vRet, sError);
1505 }
1506
1507 // AFDate_KeystrokeEx(cFormat)
1508 FX_BOOL CJS_PublicMethods::AFDate_Keystroke(IFXJS_Context* cc,
1509                                             const CJS_Parameters& params,
1510                                             CJS_Value& vRet,
1511                                             CFX_WideString& sError) {
1512   v8::Isolate* isolate = ::GetIsolate(cc);
1513
1514   if (params.size() != 1) {
1515     CJS_Context* pContext = (CJS_Context*)cc;
1516     ASSERT(pContext != NULL);
1517
1518     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1519     return FALSE;
1520   }
1521
1522   int iIndex = params[0].ToInt();
1523   const FX_WCHAR* cFormats[] = {L"m/d",
1524                                 L"m/d/yy",
1525                                 L"mm/dd/yy",
1526                                 L"mm/yy",
1527                                 L"d-mmm",
1528                                 L"d-mmm-yy",
1529                                 L"dd-mmm-yy",
1530                                 L"yy-mm-dd",
1531                                 L"mmm-yy",
1532                                 L"mmmm-yy",
1533                                 L"mmm d, yyyy",
1534                                 L"mmmm d, yyyy",
1535                                 L"m/d/yy h:MM tt",
1536                                 L"m/d/yy HH:MM"};
1537
1538   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1539     iIndex = 0;
1540
1541   CJS_Parameters newParams;
1542   CJS_Value val(isolate, cFormats[iIndex]);
1543   newParams.push_back(val);
1544   return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
1545 }
1546
1547 // function AFTime_Format(ptf)
1548 FX_BOOL CJS_PublicMethods::AFTime_Format(IFXJS_Context* cc,
1549                                          const CJS_Parameters& params,
1550                                          CJS_Value& vRet,
1551                                          CFX_WideString& sError) {
1552   v8::Isolate* isolate = ::GetIsolate(cc);
1553
1554   if (params.size() != 1) {
1555     CJS_Context* pContext = (CJS_Context*)cc;
1556     ASSERT(pContext != NULL);
1557     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1558     return FALSE;
1559   }
1560
1561   int iIndex = params[0].ToInt();
1562   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1563                                 L"h:MM:ss tt"};
1564
1565   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1566     iIndex = 0;
1567
1568   CJS_Parameters newParams;
1569   CJS_Value val(isolate, cFormats[iIndex]);
1570   newParams.push_back(val);
1571   return AFDate_FormatEx(cc, newParams, vRet, sError);
1572 }
1573
1574 FX_BOOL CJS_PublicMethods::AFTime_Keystroke(IFXJS_Context* cc,
1575                                             const CJS_Parameters& params,
1576                                             CJS_Value& vRet,
1577                                             CFX_WideString& sError) {
1578   v8::Isolate* isolate = ::GetIsolate(cc);
1579   if (params.size() != 1) {
1580     CJS_Context* pContext = (CJS_Context*)cc;
1581     ASSERT(pContext != NULL);
1582     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1583     return FALSE;
1584   }
1585
1586   int iIndex = params[0].ToInt();
1587   const FX_WCHAR* cFormats[] = {L"HH:MM", L"h:MM tt", L"HH:MM:ss",
1588                                 L"h:MM:ss tt"};
1589
1590   if (iIndex < 0 || (static_cast<size_t>(iIndex) >= FX_ArraySize(cFormats)))
1591     iIndex = 0;
1592
1593   CJS_Parameters newParams;
1594   CJS_Value val(isolate, cFormats[iIndex]);
1595   newParams.push_back(val);
1596   return AFDate_KeystrokeEx(cc, newParams, vRet, sError);
1597 }
1598
1599 FX_BOOL CJS_PublicMethods::AFTime_FormatEx(IFXJS_Context* cc,
1600                                            const CJS_Parameters& params,
1601                                            CJS_Value& vRet,
1602                                            CFX_WideString& sError) {
1603   return AFDate_FormatEx(cc, params, vRet, sError);
1604 }
1605
1606 FX_BOOL CJS_PublicMethods::AFTime_KeystrokeEx(IFXJS_Context* cc,
1607                                               const CJS_Parameters& params,
1608                                               CJS_Value& vRet,
1609                                               CFX_WideString& sError) {
1610   return AFDate_KeystrokeEx(cc, params, vRet, sError);
1611 }
1612
1613 // function AFSpecial_Format(psf)
1614 FX_BOOL CJS_PublicMethods::AFSpecial_Format(IFXJS_Context* cc,
1615                                             const CJS_Parameters& params,
1616                                             CJS_Value& vRet,
1617                                             CFX_WideString& sError) {
1618   CJS_Context* pContext = (CJS_Context*)cc;
1619   ASSERT(pContext != NULL);
1620
1621   if (params.size() != 1) {
1622     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1623     return FALSE;
1624   }
1625
1626   std::string cFormat;
1627   int iIndex = params[0].ToInt();
1628
1629   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1630   ASSERT(pEvent != NULL);
1631
1632   if (!pEvent->m_pValue)
1633     return FALSE;
1634   CFX_WideString& Value = pEvent->Value();
1635   std::string strSrc = CFX_ByteString::FromUnicode(Value).c_str();
1636
1637   switch (iIndex) {
1638     case 0:
1639       cFormat = "99999";
1640       break;
1641     case 1:
1642       cFormat = "99999-9999";
1643       break;
1644     case 2: {
1645       std::string NumberStr;
1646       util::printx("9999999999", strSrc, NumberStr);
1647       if (NumberStr.length() >= 10)
1648         cFormat = "(999) 999-9999";
1649       else
1650         cFormat = "999-9999";
1651       break;
1652     }
1653     case 3:
1654       cFormat = "999-99-9999";
1655       break;
1656   }
1657
1658   std::string strDes;
1659   util::printx(cFormat, strSrc, strDes);
1660   Value = CFX_WideString::FromLocal(strDes.c_str());
1661   return TRUE;
1662 }
1663
1664 // function AFSpecial_KeystrokeEx(mask)
1665 FX_BOOL CJS_PublicMethods::AFSpecial_KeystrokeEx(IFXJS_Context* cc,
1666                                                  const CJS_Parameters& params,
1667                                                  CJS_Value& vRet,
1668                                                  CFX_WideString& sError) {
1669   CJS_Context* pContext = (CJS_Context*)cc;
1670   ASSERT(pContext != NULL);
1671   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1672
1673   ASSERT(pEvent != NULL);
1674
1675   if (params.size() < 1) {
1676     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1677     return FALSE;
1678   }
1679
1680   if (!pEvent->m_pValue)
1681     return FALSE;
1682   CFX_WideString& valEvent = pEvent->Value();
1683
1684   CFX_WideString wstrMask = params[0].ToCFXWideString();
1685   if (wstrMask.IsEmpty())
1686     return TRUE;
1687
1688   const size_t wstrMaskLen = wstrMask.GetLength();
1689   const std::wstring wstrValue = valEvent.c_str();
1690
1691   if (pEvent->WillCommit()) {
1692     if (wstrValue.empty())
1693       return TRUE;
1694     size_t iIndexMask = 0;
1695     for (const auto& w_Value : wstrValue) {
1696       if (!maskSatisfied(w_Value, wstrMask[iIndexMask]))
1697         break;
1698       iIndexMask++;
1699     }
1700
1701     if (iIndexMask != wstrMaskLen ||
1702         (iIndexMask != wstrValue.size() && wstrMaskLen != 0)) {
1703       Alert(
1704           pContext,
1705           JSGetStringFromID(pContext, IDS_STRING_JSAFNUMBER_KEYSTROKE).c_str());
1706       pEvent->Rc() = FALSE;
1707     }
1708     return TRUE;
1709   }
1710
1711   CFX_WideString& wideChange = pEvent->Change();
1712   std::wstring wChange = wideChange.c_str();
1713   if (wChange.empty())
1714     return TRUE;
1715
1716   int iIndexMask = pEvent->SelStart();
1717
1718   size_t combined_len = wstrValue.length() + wChange.length() -
1719                         (pEvent->SelEnd() - pEvent->SelStart());
1720   if (combined_len > wstrMaskLen) {
1721     Alert(pContext,
1722           JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1723     pEvent->Rc() = FALSE;
1724     return TRUE;
1725   }
1726
1727   if (iIndexMask >= wstrMaskLen && (!wChange.empty())) {
1728     Alert(pContext,
1729           JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1730     pEvent->Rc() = FALSE;
1731     return TRUE;
1732   }
1733
1734   for (std::wstring::iterator it = wChange.begin(); it != wChange.end(); it++) {
1735     if (iIndexMask >= wstrMaskLen) {
1736       Alert(pContext,
1737             JSGetStringFromID(pContext, IDS_STRING_JSPARAM_TOOLONG).c_str());
1738       pEvent->Rc() = FALSE;
1739       return TRUE;
1740     }
1741     wchar_t w_Mask = wstrMask[iIndexMask];
1742     if (!isReservedMaskChar(w_Mask)) {
1743       *it = w_Mask;
1744     }
1745     wchar_t w_Change = *it;
1746     if (!maskSatisfied(w_Change, w_Mask)) {
1747       pEvent->Rc() = FALSE;
1748       return TRUE;
1749     }
1750     iIndexMask++;
1751   }
1752
1753   wideChange = wChange.c_str();
1754   return TRUE;
1755 }
1756
1757 // function AFSpecial_Keystroke(psf)
1758 FX_BOOL CJS_PublicMethods::AFSpecial_Keystroke(IFXJS_Context* cc,
1759                                                const CJS_Parameters& params,
1760                                                CJS_Value& vRet,
1761                                                CFX_WideString& sError) {
1762   v8::Isolate* isolate = ::GetIsolate(cc);
1763
1764   CJS_Context* pContext = (CJS_Context*)cc;
1765   ASSERT(pContext != NULL);
1766   CJS_EventHandler* pEvent = pContext->GetEventHandler();
1767   ASSERT(pEvent != NULL);
1768
1769   if (params.size() != 1) {
1770     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1771     return FALSE;
1772   }
1773
1774   std::string cFormat;
1775   int iIndex = params[0].ToInt();
1776
1777   if (!pEvent->m_pValue)
1778     return FALSE;
1779   // CJS_Value val = pEvent->Value();
1780   CFX_WideString& val = pEvent->Value();
1781   std::string strSrc = CFX_ByteString::FromUnicode(val).c_str();
1782   std::wstring wstrChange = pEvent->Change().c_str();
1783
1784   switch (iIndex) {
1785     case 0:
1786       cFormat = "99999";
1787       break;
1788     case 1:
1789       // cFormat = "99999-9999";
1790       cFormat = "999999999";
1791       break;
1792     case 2: {
1793       std::string NumberStr;
1794       util::printx("9999999999", strSrc, NumberStr);
1795       if (strSrc.length() + wstrChange.length() > 7)
1796         // cFormat = "(999) 999-9999";
1797         cFormat = "9999999999";
1798       else
1799         // cFormat = "999-9999";
1800         cFormat = "9999999";
1801       break;
1802     }
1803     case 3:
1804       // cFormat = "999-99-9999";
1805       cFormat = "999999999";
1806       break;
1807   }
1808
1809   CJS_Parameters params2;
1810   CJS_Value vMask(isolate, cFormat.c_str());
1811   params2.push_back(vMask);
1812
1813   return AFSpecial_KeystrokeEx(cc, params2, vRet, sError);
1814 }
1815
1816 FX_BOOL CJS_PublicMethods::AFMergeChange(IFXJS_Context* cc,
1817                                          const CJS_Parameters& params,
1818                                          CJS_Value& vRet,
1819                                          CFX_WideString& sError) {
1820   CJS_Context* pContext = (CJS_Context*)cc;
1821   ASSERT(pContext != NULL);
1822   CJS_EventHandler* pEventHandler = pContext->GetEventHandler();
1823   ASSERT(pEventHandler != NULL);
1824
1825   if (params.size() != 1) {
1826     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1827     return FALSE;
1828   }
1829
1830   CFX_WideString swValue;
1831   if (pEventHandler->m_pValue != NULL)
1832     swValue = pEventHandler->Value();
1833
1834   if (pEventHandler->WillCommit()) {
1835     vRet = swValue.c_str();
1836     return TRUE;
1837   }
1838
1839   CFX_WideString prefix, postfix;
1840
1841   if (pEventHandler->SelStart() >= 0)
1842     prefix = swValue.Mid(0, pEventHandler->SelStart());
1843   else
1844     prefix = L"";
1845
1846   if (pEventHandler->SelEnd() >= 0 &&
1847       pEventHandler->SelEnd() <= swValue.GetLength())
1848     postfix = swValue.Mid(pEventHandler->SelEnd(),
1849                           swValue.GetLength() - pEventHandler->SelEnd());
1850   else
1851     postfix = L"";
1852
1853   vRet = (prefix + pEventHandler->Change() + postfix).c_str();
1854
1855   return TRUE;
1856 }
1857
1858 FX_BOOL CJS_PublicMethods::AFParseDateEx(IFXJS_Context* cc,
1859                                          const CJS_Parameters& params,
1860                                          CJS_Value& vRet,
1861                                          CFX_WideString& sError) {
1862   CJS_Context* pContext = (CJS_Context*)cc;
1863   ASSERT(pContext != NULL);
1864
1865   if (params.size() != 2) {
1866     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1867     return FALSE;
1868   }
1869
1870   CFX_WideString sValue = params[0].ToCFXWideString();
1871   CFX_WideString sFormat = params[1].ToCFXWideString();
1872
1873   FX_BOOL bWrongFormat = FALSE;
1874   double dDate = MakeRegularDate(sValue, sFormat, bWrongFormat);
1875
1876   if (JS_PortIsNan(dDate)) {
1877     CFX_WideString swMsg;
1878     swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSPARSEDATE).c_str(),
1879                  sFormat.c_str());
1880     Alert((CJS_Context*)cc, swMsg.c_str());
1881     return FALSE;
1882   }
1883
1884   vRet = dDate;
1885   return TRUE;
1886 }
1887
1888 FX_BOOL CJS_PublicMethods::AFSimple(IFXJS_Context* cc,
1889                                     const CJS_Parameters& params,
1890                                     CJS_Value& vRet,
1891                                     CFX_WideString& sError) {
1892   if (params.size() != 3) {
1893     CJS_Context* pContext = (CJS_Context*)cc;
1894     ASSERT(pContext != NULL);
1895
1896     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1897     return FALSE;
1898   }
1899
1900   vRet = (double)AF_Simple(params[0].ToCFXWideString().c_str(),
1901                            params[1].ToDouble(), params[2].ToDouble());
1902   return TRUE;
1903 }
1904
1905 FX_BOOL CJS_PublicMethods::AFMakeNumber(IFXJS_Context* cc,
1906                                         const CJS_Parameters& params,
1907                                         CJS_Value& vRet,
1908                                         CFX_WideString& sError) {
1909   if (params.size() != 1) {
1910     CJS_Context* pContext = (CJS_Context*)cc;
1911     ASSERT(pContext != NULL);
1912
1913     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1914     return FALSE;
1915   }
1916   vRet = ParseStringToNumber(params[0].ToCFXWideString().c_str());
1917   return TRUE;
1918 }
1919
1920 FX_BOOL CJS_PublicMethods::AFSimple_Calculate(IFXJS_Context* cc,
1921                                               const CJS_Parameters& params,
1922                                               CJS_Value& vRet,
1923                                               CFX_WideString& sError) {
1924   v8::Isolate* isolate = ::GetIsolate(cc);
1925
1926   CJS_Context* pContext = (CJS_Context*)cc;
1927   ASSERT(pContext != NULL);
1928
1929   if (params.size() != 2) {
1930     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1931     return FALSE;
1932   }
1933
1934   CJS_Value params1 = params[1];
1935
1936   if (!params1.IsArrayObject() && params1.GetType() != CJS_Value::VT_string) {
1937     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
1938     return FALSE;
1939   }
1940
1941   CPDFSDK_Document* pReaderDoc = pContext->GetReaderDocument();
1942   ASSERT(pReaderDoc != NULL);
1943
1944   CPDFSDK_InterForm* pReaderInterForm = pReaderDoc->GetInterForm();
1945   ASSERT(pReaderInterForm != NULL);
1946
1947   CPDF_InterForm* pInterForm = pReaderInterForm->GetInterForm();
1948   ASSERT(pInterForm != NULL);
1949
1950   double dValue;
1951   CFX_WideString sFunction = params[0].ToCFXWideString();
1952   if (wcscmp(sFunction.c_str(), L"PRD") == 0)
1953     dValue = 1.0;
1954   else
1955     dValue = 0.0;
1956
1957   CJS_Array FieldNameArray = AF_MakeArrayFromList(isolate, params1);
1958
1959   int nFieldsCount = 0;
1960
1961   for (int i = 0, isz = FieldNameArray.GetLength(); i < isz; i++) {
1962     CJS_Value jsValue(isolate);
1963     FieldNameArray.GetElement(i, jsValue);
1964     CFX_WideString wsFieldName = jsValue.ToCFXWideString();
1965
1966     for (int j = 0, jsz = pInterForm->CountFields(wsFieldName); j < jsz; j++) {
1967       if (CPDF_FormField* pFormField = pInterForm->GetField(j, wsFieldName)) {
1968         double dTemp = 0.0;
1969
1970         switch (pFormField->GetFieldType()) {
1971           case FIELDTYPE_TEXTFIELD:
1972           case FIELDTYPE_COMBOBOX: {
1973             dTemp = ParseStringToNumber(pFormField->GetValue().c_str());
1974             break;
1975           }
1976           case FIELDTYPE_PUSHBUTTON: {
1977             dTemp = 0.0;
1978             break;
1979           }
1980           case FIELDTYPE_CHECKBOX:
1981           case FIELDTYPE_RADIOBUTTON: {
1982             dTemp = 0.0;
1983             for (int c = 0, csz = pFormField->CountControls(); c < csz; c++) {
1984               if (CPDF_FormControl* pFormCtrl = pFormField->GetControl(c)) {
1985                 if (pFormCtrl->IsChecked()) {
1986                   dTemp +=
1987                       ParseStringToNumber(pFormCtrl->GetExportValue().c_str());
1988                   break;
1989                 } else
1990                   continue;
1991               }
1992             }
1993             break;
1994           }
1995           case FIELDTYPE_LISTBOX: {
1996             dTemp = 0.0;
1997             if (pFormField->CountSelectedItems() > 1)
1998               break;
1999             else {
2000               dTemp = ParseStringToNumber(pFormField->GetValue().c_str());
2001               break;
2002             }
2003           }
2004           default:
2005             break;
2006         }
2007
2008         if (i == 0 && j == 0 && (wcscmp(sFunction.c_str(), L"MIN") == 0 ||
2009                                  wcscmp(sFunction.c_str(), L"MAX") == 0))
2010           dValue = dTemp;
2011
2012         dValue = AF_Simple(sFunction.c_str(), dValue, dTemp);
2013
2014         nFieldsCount++;
2015       }
2016     }
2017   }
2018
2019   if (wcscmp(sFunction.c_str(), L"AVG") == 0 && nFieldsCount > 0)
2020     dValue /= nFieldsCount;
2021
2022   dValue = (double)floor(dValue * FXSYS_pow((double)10, (double)6) + 0.49) /
2023            FXSYS_pow((double)10, (double)6);
2024   CJS_Value jsValue(isolate, dValue);
2025   if (pContext->GetEventHandler()->m_pValue)
2026     pContext->GetEventHandler()->Value() = jsValue.ToCFXWideString();
2027
2028   return TRUE;
2029 }
2030
2031 /* This function validates the current event to ensure that its value is
2032 ** within the specified range. */
2033
2034 FX_BOOL CJS_PublicMethods::AFRange_Validate(IFXJS_Context* cc,
2035                                             const CJS_Parameters& params,
2036                                             CJS_Value& vRet,
2037                                             CFX_WideString& sError) {
2038   CJS_Context* pContext = (CJS_Context*)cc;
2039   ASSERT(pContext != NULL);
2040   CJS_EventHandler* pEvent = pContext->GetEventHandler();
2041   ASSERT(pEvent != NULL);
2042
2043   if (params.size() != 4) {
2044     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
2045     return FALSE;
2046   }
2047
2048   if (!pEvent->m_pValue)
2049     return FALSE;
2050   if (pEvent->Value().IsEmpty())
2051     return TRUE;
2052   double dEentValue = atof(CFX_ByteString::FromUnicode(pEvent->Value()));
2053   FX_BOOL bGreaterThan = params[0].ToBool();
2054   double dGreaterThan = params[1].ToDouble();
2055   FX_BOOL bLessThan = params[2].ToBool();
2056   double dLessThan = params[3].ToDouble();
2057   CFX_WideString swMsg;
2058
2059   if (bGreaterThan && bLessThan) {
2060     if (dEentValue < dGreaterThan || dEentValue > dLessThan)
2061       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE1).c_str(),
2062                    params[1].ToCFXWideString().c_str(),
2063                    params[3].ToCFXWideString().c_str());
2064   } else if (bGreaterThan) {
2065     if (dEentValue < dGreaterThan)
2066       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE2).c_str(),
2067                    params[1].ToCFXWideString().c_str());
2068   } else if (bLessThan) {
2069     if (dEentValue > dLessThan)
2070       swMsg.Format(JSGetStringFromID(pContext, IDS_STRING_JSRANGE3).c_str(),
2071                    params[3].ToCFXWideString().c_str());
2072   }
2073
2074   if (!swMsg.IsEmpty()) {
2075     Alert(pContext, swMsg.c_str());
2076     pEvent->Rc() = FALSE;
2077   }
2078   return TRUE;
2079 }
2080
2081 FX_BOOL CJS_PublicMethods::AFExtractNums(IFXJS_Context* cc,
2082                                          const CJS_Parameters& params,
2083                                          CJS_Value& vRet,
2084                                          CFX_WideString& sError) {
2085   v8::Isolate* isolate = ::GetIsolate(cc);
2086   CJS_Context* pContext = (CJS_Context*)cc;
2087   ASSERT(pContext != NULL);
2088
2089   if (params.size() != 1) {
2090     sError = JSGetStringFromID(pContext, IDS_STRING_JSPARAMERROR);
2091     return FALSE;
2092   }
2093
2094   CJS_Array nums(isolate);
2095
2096   CFX_WideString str = params[0].ToCFXWideString();
2097   CFX_WideString sPart;
2098
2099   if (str.GetAt(0) == L'.' || str.GetAt(0) == L',')
2100     str = L"0" + str;
2101
2102   int nIndex = 0;
2103   for (int i = 0, sz = str.GetLength(); i < sz; i++) {
2104     FX_WCHAR wc = str.GetAt(i);
2105     if (IsDigit((wchar_t)wc)) {
2106       sPart += wc;
2107     } else {
2108       if (sPart.GetLength() > 0) {
2109         nums.SetElement(nIndex, CJS_Value(isolate, sPart.c_str()));
2110         sPart = L"";
2111         nIndex++;
2112       }
2113     }
2114   }
2115
2116   if (sPart.GetLength() > 0) {
2117     nums.SetElement(nIndex, CJS_Value(isolate, sPart.c_str()));
2118   }
2119
2120   if (nums.GetLength() > 0)
2121     vRet = nums;
2122   else
2123     vRet.SetNull();
2124
2125   return TRUE;
2126 }