1 // Copyright 2017 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 "fxjs/xfa/cjx_field.h"
8
9 #include <vector>
10
11 #include "fxjs/cfx_v8.h"
12 #include "fxjs/js_resources.h"
13 #include "fxjs/xfa/cfxjse_value.h"
14 #include "xfa/fgas/crt/cfgas_decimal.h"
15 #include "xfa/fxfa/cxfa_eventparam.h"
16 #include "xfa/fxfa/cxfa_ffnotify.h"
17 #include "xfa/fxfa/fxfa.h"
18 #include "xfa/fxfa/parser/cxfa_document.h"
19 #include "xfa/fxfa/parser/cxfa_field.h"
20 #include "xfa/fxfa/parser/cxfa_value.h"
21
22 const CJX_MethodSpec CJX_Field::MethodSpecs[] = {
23 {"addItem", addItem_static},
24 {"boundItem", boundItem_static},
25 {"clearItems", clearItems_static},
26 {"deleteItem", deleteItem_static},
27 {"execCalculate", execCalculate_static},
28 {"execEvent", execEvent_static},
29 {"execInitialize", execInitialize_static},
30 {"execValidate", execValidate_static},
31 {"getDisplayItem", getDisplayItem_static},
32 {"getItemState", getItemState_static},
33 {"getSaveItem", getSaveItem_static},
34 {"setItemState", setItemState_static}};
35
CJX_Field(CXFA_Field * field)36 CJX_Field::CJX_Field(CXFA_Field* field) : CJX_Container(field) {
37 DefineMethods(MethodSpecs);
38 }
39
~CJX_Field()40 CJX_Field::~CJX_Field() {}
41
DynamicTypeIs(TypeTag eType) const42 bool CJX_Field::DynamicTypeIs(TypeTag eType) const {
43 return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
44 }
45
clearItems(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)46 CJS_Result CJX_Field::clearItems(
47 CFX_V8* runtime,
48 const std::vector<v8::Local<v8::Value>>& params) {
49 CXFA_Node* node = GetXFANode();
50 if (node->IsWidgetReady())
51 node->DeleteItem(-1, true, false);
52 return CJS_Result::Success();
53 }
54
execEvent(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)55 CJS_Result CJX_Field::execEvent(
56 CFX_V8* runtime,
57 const std::vector<v8::Local<v8::Value>>& params) {
58 if (params.size() != 1)
59 return CJS_Result::Failure(JSMessage::kParamError);
60
61 WideString eventString = runtime->ToWideString(params[0]);
62 XFA_EventError iRet =
63 execSingleEventByName(eventString.AsStringView(), XFA_Element::Field);
64 if (!eventString.EqualsASCII("validate"))
65 return CJS_Result::Success();
66
67 return CJS_Result::Success(
68 runtime->NewBoolean(iRet != XFA_EventError::kError));
69 }
70
execInitialize(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)71 CJS_Result CJX_Field::execInitialize(
72 CFX_V8* runtime,
73 const std::vector<v8::Local<v8::Value>>& params) {
74 if (!params.empty())
75 return CJS_Result::Failure(JSMessage::kParamError);
76
77 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
78 if (pNotify) {
79 pNotify->ExecEventByDeepFirst(GetXFANode(), XFA_EVENT_Initialize, false,
80 false);
81 }
82 return CJS_Result::Success();
83 }
84
deleteItem(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)85 CJS_Result CJX_Field::deleteItem(
86 CFX_V8* runtime,
87 const std::vector<v8::Local<v8::Value>>& params) {
88 if (params.size() != 1)
89 return CJS_Result::Failure(JSMessage::kParamError);
90
91 CXFA_Node* node = GetXFANode();
92 if (!node->IsWidgetReady())
93 return CJS_Result::Success();
94
95 bool bValue = node->DeleteItem(runtime->ToInt32(params[0]), true, true);
96 return CJS_Result::Success(runtime->NewBoolean(bValue));
97 }
98
getSaveItem(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)99 CJS_Result CJX_Field::getSaveItem(
100 CFX_V8* runtime,
101 const std::vector<v8::Local<v8::Value>>& params) {
102 if (params.size() != 1)
103 return CJS_Result::Failure(JSMessage::kParamError);
104
105 int32_t iIndex = runtime->ToInt32(params[0]);
106 if (iIndex < 0)
107 return CJS_Result::Success(runtime->NewNull());
108
109 CXFA_Node* node = GetXFANode();
110 if (!node->IsWidgetReady())
111 return CJS_Result::Success(runtime->NewNull());
112
113 Optional<WideString> value = node->GetChoiceListItem(iIndex, true);
114 if (!value)
115 return CJS_Result::Success(runtime->NewNull());
116
117 return CJS_Result::Success(
118 runtime->NewString(value->ToUTF8().AsStringView()));
119 }
120
boundItem(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)121 CJS_Result CJX_Field::boundItem(
122 CFX_V8* runtime,
123 const std::vector<v8::Local<v8::Value>>& params) {
124 if (params.size() != 1)
125 return CJS_Result::Failure(JSMessage::kParamError);
126
127 CXFA_Node* node = GetXFANode();
128 if (!node->IsWidgetReady())
129 return CJS_Result::Success();
130
131 WideString value = runtime->ToWideString(params[0]);
132 WideString boundValue = node->GetItemValue(value.AsStringView());
133 return CJS_Result::Success(
134 runtime->NewString(boundValue.ToUTF8().AsStringView()));
135 }
136
getItemState(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)137 CJS_Result CJX_Field::getItemState(
138 CFX_V8* runtime,
139 const std::vector<v8::Local<v8::Value>>& params) {
140 if (params.size() != 1)
141 return CJS_Result::Failure(JSMessage::kParamError);
142
143 CXFA_Node* node = GetXFANode();
144 if (!node->IsWidgetReady())
145 return CJS_Result::Success();
146
147 int32_t state = node->GetItemState(runtime->ToInt32(params[0]));
148 return CJS_Result::Success(runtime->NewBoolean(state != 0));
149 }
150
execCalculate(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)151 CJS_Result CJX_Field::execCalculate(
152 CFX_V8* runtime,
153 const std::vector<v8::Local<v8::Value>>& params) {
154 if (!params.empty())
155 return CJS_Result::Failure(JSMessage::kParamError);
156
157 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
158 if (pNotify) {
159 pNotify->ExecEventByDeepFirst(GetXFANode(), XFA_EVENT_Calculate, false,
160 false);
161 }
162 return CJS_Result::Success();
163 }
164
getDisplayItem(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)165 CJS_Result CJX_Field::getDisplayItem(
166 CFX_V8* runtime,
167 const std::vector<v8::Local<v8::Value>>& params) {
168 if (params.size() != 1)
169 return CJS_Result::Failure(JSMessage::kParamError);
170
171 int32_t iIndex = runtime->ToInt32(params[0]);
172 if (iIndex < 0)
173 return CJS_Result::Success(runtime->NewNull());
174
175 CXFA_Node* node = GetXFANode();
176 if (!node->IsWidgetReady())
177 return CJS_Result::Success(runtime->NewNull());
178
179 Optional<WideString> value = node->GetChoiceListItem(iIndex, false);
180 if (!value)
181 return CJS_Result::Success(runtime->NewNull());
182
183 return CJS_Result::Success(
184 runtime->NewString(value->ToUTF8().AsStringView()));
185 }
186
setItemState(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)187 CJS_Result CJX_Field::setItemState(
188 CFX_V8* runtime,
189 const std::vector<v8::Local<v8::Value>>& params) {
190 if (params.size() != 2)
191 return CJS_Result::Failure(JSMessage::kParamError);
192
193 CXFA_Node* node = GetXFANode();
194 if (!node->IsWidgetReady())
195 return CJS_Result::Success();
196
197 int32_t iIndex = runtime->ToInt32(params[0]);
198 if (runtime->ToInt32(params[1]) != 0) {
199 node->SetItemState(iIndex, true, true, true, true);
200 return CJS_Result::Success();
201 }
202 if (node->GetItemState(iIndex))
203 node->SetItemState(iIndex, false, true, true, true);
204
205 return CJS_Result::Success();
206 }
207
addItem(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)208 CJS_Result CJX_Field::addItem(CFX_V8* runtime,
209 const std::vector<v8::Local<v8::Value>>& params) {
210 if (params.size() != 1 && params.size() != 2)
211 return CJS_Result::Failure(JSMessage::kParamError);
212
213 CXFA_Node* node = GetXFANode();
214 if (!node->IsWidgetReady())
215 return CJS_Result::Success();
216
217 WideString label;
218 if (params.size() >= 1)
219 label = runtime->ToWideString(params[0]);
220
221 WideString value;
222 if (params.size() >= 2)
223 value = runtime->ToWideString(params[1]);
224
225 node->InsertItem(label, value, true);
226 return CJS_Result::Success();
227 }
228
execValidate(CFX_V8 * runtime,const std::vector<v8::Local<v8::Value>> & params)229 CJS_Result CJX_Field::execValidate(
230 CFX_V8* runtime,
231 const std::vector<v8::Local<v8::Value>>& params) {
232 if (!params.empty())
233 return CJS_Result::Failure(JSMessage::kParamError);
234
235 CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
236 if (!pNotify)
237 return CJS_Result::Success(runtime->NewBoolean(false));
238
239 XFA_EventError iRet = pNotify->ExecEventByDeepFirst(
240 GetXFANode(), XFA_EVENT_Validate, false, false);
241 return CJS_Result::Success(
242 runtime->NewBoolean(iRet != XFA_EventError::kError));
243 }
244
defaultValue(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)245 void CJX_Field::defaultValue(CFXJSE_Value* pValue,
246 bool bSetting,
247 XFA_Attribute eAttribute) {
248 CXFA_Node* xfaNode = GetXFANode();
249 if (!xfaNode->IsWidgetReady())
250 return;
251
252 if (bSetting) {
253 if (pValue) {
254 xfaNode->SetPreNull(xfaNode->IsNull());
255 xfaNode->SetIsNull(pValue->IsNull());
256 }
257
258 WideString wsNewText;
259 if (pValue && !(pValue->IsNull() || pValue->IsUndefined()))
260 wsNewText = pValue->ToWideString();
261 if (xfaNode->GetUIChildNode()->GetElementType() == XFA_Element::NumericEdit)
262 wsNewText = xfaNode->NumericLimit(wsNewText);
263
264 CXFA_Node* pContainerNode = xfaNode->GetContainerNode();
265 WideString wsFormatText(wsNewText);
266 if (pContainerNode)
267 wsFormatText = pContainerNode->GetFormatDataValue(wsNewText);
268
269 SetContent(wsNewText, wsFormatText, true, true, true);
270 return;
271 }
272
273 WideString content = GetContent(true);
274 if (content.IsEmpty()) {
275 pValue->SetNull();
276 return;
277 }
278
279 CXFA_Node* formValue = xfaNode->GetFormValueIfExists();
280 CXFA_Node* pNode = formValue ? formValue->GetFirstChild() : nullptr;
281 if (pNode && pNode->GetElementType() == XFA_Element::Decimal) {
282 if (xfaNode->GetUIChildNode()->GetElementType() ==
283 XFA_Element::NumericEdit &&
284 (pNode->JSObject()->GetInteger(XFA_Attribute::FracDigits) == -1)) {
285 pValue->SetString(content.ToUTF8().AsStringView());
286 } else {
287 CFGAS_Decimal decimal(content.AsStringView());
288 pValue->SetFloat(decimal.ToFloat());
289 }
290 } else if (pNode && pNode->GetElementType() == XFA_Element::Integer) {
291 pValue->SetInteger(FXSYS_wtoi(content.c_str()));
292 } else if (pNode && pNode->GetElementType() == XFA_Element::Boolean) {
293 pValue->SetBoolean(FXSYS_wtoi(content.c_str()) != 0);
294 } else if (pNode && pNode->GetElementType() == XFA_Element::Float) {
295 CFGAS_Decimal decimal(content.AsStringView());
296 pValue->SetFloat(decimal.ToFloat());
297 } else {
298 pValue->SetString(content.ToUTF8().AsStringView());
299 }
300 }
301
editValue(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)302 void CJX_Field::editValue(CFXJSE_Value* pValue,
303 bool bSetting,
304 XFA_Attribute eAttribute) {
305 CXFA_Node* node = GetXFANode();
306 if (!node->IsWidgetReady())
307 return;
308
309 if (bSetting) {
310 node->SetValue(XFA_VALUEPICTURE_Edit, pValue->ToWideString());
311 return;
312 }
313 pValue->SetString(
314 node->GetValue(XFA_VALUEPICTURE_Edit).ToUTF8().AsStringView());
315 }
316
formatMessage(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)317 void CJX_Field::formatMessage(CFXJSE_Value* pValue,
318 bool bSetting,
319 XFA_Attribute eAttribute) {
320 ScriptSomMessage(pValue, bSetting, XFA_SOM_FormatMessage);
321 }
322
formattedValue(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)323 void CJX_Field::formattedValue(CFXJSE_Value* pValue,
324 bool bSetting,
325 XFA_Attribute eAttribute) {
326 CXFA_Node* node = GetXFANode();
327 if (!node->IsWidgetReady())
328 return;
329
330 if (bSetting) {
331 node->SetValue(XFA_VALUEPICTURE_Display, pValue->ToWideString());
332 return;
333 }
334 pValue->SetString(
335 node->GetValue(XFA_VALUEPICTURE_Display).ToUTF8().AsStringView());
336 }
337
length(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)338 void CJX_Field::length(CFXJSE_Value* pValue,
339 bool bSetting,
340 XFA_Attribute eAttribute) {
341 if (bSetting) {
342 ThrowInvalidPropertyException();
343 return;
344 }
345
346 CXFA_Node* node = GetXFANode();
347 if (!node->IsWidgetReady()) {
348 pValue->SetInteger(0);
349 return;
350 }
351 pValue->SetInteger(node->CountChoiceListItems(true));
352 }
353
parentSubform(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)354 void CJX_Field::parentSubform(CFXJSE_Value* pValue,
355 bool bSetting,
356 XFA_Attribute eAttribute) {
357 if (bSetting) {
358 ThrowInvalidPropertyException();
359 return;
360 }
361 pValue->SetNull();
362 }
363
selectedIndex(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)364 void CJX_Field::selectedIndex(CFXJSE_Value* pValue,
365 bool bSetting,
366 XFA_Attribute eAttribute) {
367 CXFA_Node* node = GetXFANode();
368 if (!node->IsWidgetReady())
369 return;
370
371 if (!bSetting) {
372 pValue->SetInteger(node->GetSelectedItem(0));
373 return;
374 }
375
376 int32_t iIndex = pValue->ToInteger();
377 if (iIndex == -1) {
378 node->ClearAllSelections();
379 return;
380 }
381
382 node->SetItemState(iIndex, true, true, true, true);
383 }
384
rawValue(CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)385 void CJX_Field::rawValue(CFXJSE_Value* pValue,
386 bool bSetting,
387 XFA_Attribute eAttribute) {
388 defaultValue(pValue, bSetting, eAttribute);
389 }
390