1 16 17 package org.apache.cocoon.woody.flow.javascript.v2; 18 import org.apache.cocoon.woody.formmodel.Action; 19 import org.apache.cocoon.woody.formmodel.AggregateField; 20 import org.apache.cocoon.woody.formmodel.BooleanField; 21 import org.apache.cocoon.woody.formmodel.Field; 22 import org.apache.cocoon.woody.formmodel.Form; 23 import org.apache.cocoon.woody.formmodel.ContainerWidget; 24 import org.apache.cocoon.woody.formmodel.MultiValueField; 25 import org.apache.cocoon.woody.formmodel.Output; 26 import org.apache.cocoon.woody.formmodel.Repeater; 27 import org.apache.cocoon.woody.formmodel.Submit; 28 import org.apache.cocoon.woody.formmodel.Upload; 29 import org.apache.cocoon.woody.formmodel.Widget; 30 import org.apache.cocoon.woody.formmodel.DataWidget; 31 import org.apache.cocoon.woody.formmodel.SelectableWidget; 32 import org.apache.cocoon.woody.datatype.Datatype; 33 import org.apache.cocoon.woody.validation.ValidationError; 34 import org.apache.cocoon.woody.validation.ValidationErrorAware; 35 import org.apache.cocoon.woody.datatype.SelectionList; 36 import org.apache.cocoon.woody.event.FormHandler; 37 import org.apache.cocoon.woody.event.ActionEvent; 38 import org.apache.cocoon.woody.event.ValueChangedEvent; 39 import org.apache.cocoon.woody.event.WidgetEvent; 40 import org.mozilla.javascript.Context; 41 import org.mozilla.javascript.JavaScriptException; 42 import org.mozilla.javascript.NativeArray; 43 import org.mozilla.javascript.Function; 44 import org.mozilla.javascript.Scriptable; 45 import org.mozilla.javascript.ScriptableObject; 46 import org.mozilla.javascript.Undefined; 47 import org.mozilla.javascript.Wrapper; 48 import java.math.BigDecimal ; 49 import java.util.List ; 50 import java.util.LinkedList ; 51 import java.util.Iterator ; 52 import java.util.Map ; 53 import java.util.HashMap ; 54 55 59 public class ScriptableWidget extends ScriptableObject { 60 61 final static String WIDGETS_PROPERTY = "__widgets__"; 62 63 Widget delegate; 64 ScriptableWidget formWidget; 65 66 class ScriptableFormHandler implements FormHandler { 67 public void handleEvent(WidgetEvent widgetEvent) { 68 Widget src = widgetEvent.getSourceWidget(); 69 ScriptableWidget w = wrap(src); 70 w.handleEvent(widgetEvent); 71 } 72 } 73 74 public String getClassName() { 75 return "Widget"; 76 } 77 78 public ScriptableWidget() { 79 } 80 81 public ScriptableWidget(Object widget) { 82 this.delegate = (Widget)unwrap(widget); 83 if (delegate instanceof Form) { 84 Form form = (Form)delegate; 85 form.setFormHandler(new ScriptableFormHandler()); 86 formWidget = this; 87 Map widgetMap = new HashMap (); 88 widgetMap.put(delegate, this); 89 defineProperty(WIDGETS_PROPERTY, widgetMap, DONTENUM|PERMANENT); 90 } 91 } 92 93 static private Object unwrap(Object obj) { 94 if (obj == Undefined.instance) { 95 return null; 96 } 97 if (obj instanceof Wrapper) { 98 return ((Wrapper)obj).unwrap(); 99 } 100 return obj; 101 } 102 103 private void deleteWrapper(Widget w) { 104 if (delegate instanceof Form) { 105 Map widgetMap = (Map )super.get(WIDGETS_PROPERTY, this); 106 widgetMap.remove(w); 107 } 108 } 109 110 private ScriptableWidget wrap(Widget w) { 111 if (w == null) return null; 112 if (delegate instanceof Form) { 113 Map widgetMap = (Map )super.get(WIDGETS_PROPERTY, this); 114 ScriptableWidget result = null; 115 result = (ScriptableWidget)widgetMap.get(w); 116 if (result == null) { 117 result = new ScriptableWidget(w); 118 result.formWidget = this; 119 result.setPrototype(getClassPrototype(this, getClassName())); 120 result.setParentScope(getParentScope()); 121 widgetMap.put(w, result); 122 } 123 return result; 124 } else { 125 return formWidget.wrap(w); 126 } 127 } 128 129 public boolean has(String id, Scriptable start) { 130 if (delegate != null) { 131 if (!(delegate instanceof Repeater)) { 132 Widget sub = delegate.getWidget(id); 133 if (sub != null) { 134 return true; 135 } 136 } 137 } 138 return super.has(id, start); 139 } 140 141 public boolean has(int index, Scriptable start) { 142 if (super.has(index, start)) { 143 return true; 144 } 145 if (delegate instanceof Repeater) { 146 Repeater repeater = (Repeater)delegate; 147 return index >= 0 && index < repeater.getSize(); 148 } 149 if (delegate instanceof MultiValueField) { 150 Object [] values = (Object [])delegate.getValue(); 151 return index >= 0 && index < values.length; 152 } 153 return false; 154 } 155 156 public Object get(String id, Scriptable start) { 157 Object result = super.get(id, start); 158 if (result != NOT_FOUND) { 159 return result; 160 } 161 if (delegate != null && !(delegate instanceof Repeater)) { 162 Widget sub = delegate.getWidget(id); 163 if (sub != null) { 164 return wrap(sub); 165 } 166 } 167 return NOT_FOUND; 168 } 169 170 public Object get(int index, Scriptable start) { 171 Object result = super.get(index, start); 172 if (result != NOT_FOUND) { 173 return result; 174 } 175 if (delegate instanceof Repeater) { 176 Repeater repeater = (Repeater)delegate; 177 if (index >= 0) { 178 int count = index + 1 - repeater.getSize(); 179 if (count > 0) { 180 ScriptableWidget[] rows = new ScriptableWidget[count]; 181 for (int i = 0; i < count; i++) { 182 rows[i] = wrap(repeater.addRow()); 183 } 184 for (int i = 0; i < count; i++) { 185 rows[i].notifyAddRow(); 186 } 187 } 188 return wrap(repeater.getRow(index)); 189 } 190 } else if (delegate instanceof MultiValueField) { 191 Object [] values = (Object [])delegate.getValue(); 192 if (index >= 0 && index < values.length) { 193 return values[index]; 194 } 195 } 196 return NOT_FOUND; 197 } 198 199 public Object [] getAllIds() { 200 Object [] result = super.getAllIds(); 201 return addWidgetIds(result); 202 } 203 204 public Object [] getIds() { 205 Object [] result = super.getIds(); 206 return addWidgetIds(result); 207 } 208 209 private Object [] addWidgetIds(Object [] result) { 210 if (delegate instanceof ContainerWidget) { 211 Iterator iter = ((ContainerWidget)delegate).getChildren(); 212 List list = new LinkedList (); 213 for (int i = 0; i < result.length; i++) { 214 list.add(result[i]); 215 } 216 while (iter.hasNext()) { 217 Widget widget = (Widget)iter.next(); 218 list.add(widget.getId()); 219 } 220 result = list.toArray(); 221 } 222 return result; 223 } 224 225 private void deleteRow(Repeater repeater, int index) { 226 Widget row = repeater.getRow(index); 227 ScriptableWidget s = wrap(row); 228 s.notifyRemoveRow(); 229 formWidget.deleteWrapper(row); 230 repeater.removeRow(index); 231 } 232 233 private void notifyAddRow() { 234 ScriptableWidget repeater = wrap(delegate.getParent()); 235 Object prop = getProperty(repeater, "onAddRow"); 236 if (prop instanceof Function) { 237 try { 238 Function fun = (Function)prop; 239 Object [] args = new Object [1]; 240 Scriptable scope = getTopLevelScope(this); 241 Scriptable thisObj = scope; 242 Context cx = Context.getCurrentContext(); 243 args[0] = this; 244 fun.call(cx, scope, thisObj, args); 245 } catch (Exception exc) { 246 throw Context.reportRuntimeError(exc.getMessage()); 247 } 248 } 249 } 250 251 private void notifyRemoveRow() { 252 ScriptableWidget repeater = wrap(delegate.getParent()); 253 Object prop = getProperty(repeater, "onRemoveRow"); 254 if (prop instanceof Function) { 255 try { 256 Function fun = (Function)prop; 257 Object [] args = new Object [1]; 258 Scriptable scope = getTopLevelScope(this); 259 Scriptable thisObj = scope; 260 Context cx = Context.getCurrentContext(); 261 args[0] = this; 262 fun.call(cx, scope, thisObj, args); 263 } catch (Exception exc) { 264 throw Context.reportRuntimeError(exc.getMessage()); 265 } 266 } 267 } 268 269 public void delete(int index) { 270 if (delegate instanceof Repeater) { 271 Repeater repeater = (Repeater)delegate; 272 if (index >= 0 && index < repeater.getSize()) { 273 deleteRow(repeater, index); 274 return; 275 } 276 } else if (delegate instanceof MultiValueField) { 277 MultiValueField field = (MultiValueField)delegate; 278 Object [] values = (Object [])field.getValue(); 279 if (values != null && values.length > index) { 280 Object [] newValues = new Object [values.length-1]; 281 int i; 282 for (i = 0; i < index; i++) { 283 newValues[i] = values[i]; 284 } 285 i++; 286 for (;i < values.length; i++) { 287 newValues[i-1] = values[i]; 288 } 289 field.setValues(newValues); 290 } 291 return; 292 } 293 super.delete(index); 294 } 295 296 public Object jsGet_value() { 297 return delegate.getValue(); 298 } 299 300 public Object jsFunction_getValue() { 301 return jsGet_value(); 302 } 303 304 public void jsFunction_setValue(Object value) throws JavaScriptException { 305 jsSet_value(value); 306 } 307 308 public void jsSet_length(int len) { 309 if (delegate instanceof Repeater) { 310 Repeater repeater = (Repeater)delegate; 311 int size = repeater.getSize(); 312 if (size > len) { 313 while (repeater.getSize() > len) { 314 deleteRow(repeater, repeater.getSize() - 1); 315 } 316 } else { 317 for (int i = size; i < len; ++i) { 318 wrap(repeater.addRow()).notifyAddRow(); 319 } 320 } 321 } 322 } 323 324 public Object jsGet_length() { 325 if (delegate instanceof Repeater) { 326 Repeater repeater = (Repeater)delegate; 327 return new Integer (repeater.getSize()); 328 } 329 return Undefined.instance; 330 } 331 332 public void jsSet_value(Object value) throws JavaScriptException { 333 if (delegate instanceof DataWidget) { 334 value = unwrap(value); 335 if (value != null) { 336 Datatype datatype = ((DataWidget)delegate).getDatatype(); 337 Class typeClass = datatype.getTypeClass(); 338 if (typeClass == String .class) { 339 value = Context.toString(value); 340 } else if (typeClass == boolean.class || 341 typeClass == Boolean .class) { 342 value = Context.toBoolean(value) ? Boolean.TRUE : Boolean.FALSE; 343 } else { 344 if (value instanceof Double ) { 345 if (typeClass == long.class || typeClass == Long .class) { 347 value = new Long (((Number )value).longValue()); 348 } else if (typeClass == int.class || 349 typeClass == Integer .class) { 350 value = new Integer (((Number )value).intValue()); 351 } else if (typeClass == float.class || 352 typeClass == Float .class) { 353 value = new Float (((Number )value).floatValue()); 354 } else if (typeClass == short.class || 355 typeClass == Short .class) { 356 value = new Short (((Number )value).shortValue()); 357 } else if (typeClass == BigDecimal .class) { 358 value = new BigDecimal (((Number )value).doubleValue()); 359 } 360 } 361 } 362 } 363 delegate.setValue(value); 364 } else if (delegate instanceof BooleanField) { 365 BooleanField field = (BooleanField)delegate; 366 field.setValue(new Boolean (Context.toBoolean(value))); 367 } else if (delegate instanceof Repeater) { 368 Repeater repeater = (Repeater)delegate; 369 if (value instanceof NativeArray) { 370 NativeArray arr = (NativeArray)value; 371 Object length = getProperty(arr, "length"); 372 int len = ((Number )length).intValue(); 373 for (int i = repeater.getSize(); i >= len; --i) { 374 deleteRow(repeater, i); 375 } 376 for (int i = 0; i < len; i++) { 377 Object elemValue = getProperty(arr, i); 378 ScriptableWidget wid = wrap(repeater.getRow(i)); 379 wid.jsSet_value(elemValue); 380 } 381 } 382 } else if (delegate instanceof AggregateField) { 383 AggregateField aggregateField = (AggregateField)delegate; 384 if (value instanceof Scriptable) { 385 Scriptable obj = (Scriptable)value; 386 Object [] ids = obj.getIds(); 387 for (int i = 0; i < ids.length; i++) { 388 String id = String.valueOf(ids[i]); 389 Object val = getProperty(obj, id); 390 ScriptableWidget wid = wrap(aggregateField.getWidget(id)); 391 if (wid == null) { 392 throw new JavaScriptException("No field \"" + id + "\" in widget \"" + aggregateField.getId() + "\""); 393 } 394 if (wid.delegate instanceof Field || 395 wid.delegate instanceof BooleanField || 396 wid.delegate instanceof Output) { 397 if (val instanceof Scriptable) { 398 Scriptable s = (Scriptable)val; 399 if (s.has("value", s)) { 400 wid.jsSet_value(s.get("value", s)); 401 } 402 } 403 } else { 404 wid.jsSet_value(val); 405 } 406 } 407 } 408 } else if (delegate instanceof Repeater.RepeaterRow) { 409 Repeater.RepeaterRow row = (Repeater.RepeaterRow)delegate; 410 if (value instanceof Scriptable) { 411 Scriptable obj = (Scriptable)value; 412 Object [] ids = obj.getIds(); 413 for (int i = 0; i < ids.length; i++) { 414 String id = String.valueOf(ids[i]); 415 Object val = getProperty(obj, id); 416 ScriptableWidget wid = wrap(row.getWidget(id)); 417 if (wid == null) { 418 throw new JavaScriptException("No field \"" + id + "\" in row " + i + " of repeater \"" + row.getParent().getId() + "\""); 419 } 420 if (wid.delegate instanceof Field || 421 wid.delegate instanceof BooleanField || 422 wid.delegate instanceof Output) { 423 if (val instanceof Scriptable) { 424 Scriptable s = (Scriptable)val; 425 if (s.has("value", s)) { 426 wid.jsSet_value(s.get("value", s)); 427 } 428 } 429 } else { 430 wid.jsSet_value(val); 431 } 432 } 433 } else { 434 throw new JavaScriptException("Expected an object instead of: " + Context.toString(value)); 435 } 436 } else if (delegate instanceof MultiValueField) { 437 MultiValueField field = (MultiValueField)delegate; 438 Object [] values = null; 439 if (value instanceof NativeArray) { 440 NativeArray arr = (NativeArray)value; 441 Object length = getProperty(arr, "length"); 442 int len = ((Number )length).intValue(); 443 values = new Object [len]; 444 for (int i = 0; i < len; i++) { 445 Object elemValue = getProperty(arr, i); 446 values[i] = unwrap(elemValue); 447 } 448 } else if (value instanceof Object []) { 449 values = (Object [])value; 450 } 451 field.setValues(values); 452 } else { 453 delegate.setValue(value); 454 } 455 } 456 457 public String jsFunction_getId() { 458 return delegate.getId(); 459 } 460 461 public ScriptableWidget jsFunction_getSubmitWidget() { 462 return wrap(delegate.getForm().getSubmitWidget()); 463 } 464 465 public String jsFunction_getFullyQualifiedId() { 466 return delegate.getFullyQualifiedId(); 467 } 468 469 public String jsFunction_getNamespace() { 470 return delegate.getNamespace(); 471 } 472 473 public Scriptable jsFunction_getParent() { 474 if (delegate != null) { 475 return wrap(delegate.getParent()); 476 } 477 return Undefined.instance; 478 } 479 480 public boolean jsFunction_isRequired() { 481 return delegate.isRequired(); 482 } 483 484 public ScriptableWidget jsFunction_getForm() { 485 return formWidget; 486 } 487 488 public boolean jsFunction_equals(Object other) { 489 if (other instanceof ScriptableWidget) { 490 ScriptableWidget otherWidget = (ScriptableWidget)other; 491 return delegate.equals(otherWidget.delegate); 492 } 493 return false; 494 } 495 496 public ScriptableWidget jsFunction_getWidget(String id) { 497 Widget sub = delegate.getWidget(id); 498 return wrap(sub); 499 } 500 501 public void jsFunction_setValidationError(String message, 502 Object parameters) { 503 if (delegate instanceof ValidationErrorAware) { 504 String [] parms = null; 505 if (parameters != null && parameters != Undefined.instance) { 506 Scriptable obj = Context.toObject(parameters, this); 507 int len = (int) 508 Context.toNumber(getProperty(obj, "length")); 509 parms = new String [len]; 510 for (int i = 0; i < len; i++) { 511 parms[i] = Context.toString(getProperty(obj, i)); 512 } 513 } 514 ValidationError validationError = null; 515 if (message != null) { 516 if (parms != null && parms.length > 0) { 517 validationError = 518 new ValidationError(message, parms); 519 } else { 520 validationError = 521 new ValidationError(message, parms != null); 522 } 523 } 524 ((ValidationErrorAware)delegate).setValidationError(validationError); 525 formWidget.notifyValidationErrorListener(this, validationError); 526 } 527 } 528 529 private void notifyValidationErrorListener(ScriptableWidget widget, 530 ValidationError error) { 531 Object fun = getProperty(this, "validationErrorListener"); 532 if (fun instanceof Function) { 533 try { 534 Scriptable scope = getTopLevelScope(this); 535 Scriptable thisObj = scope; 536 Context cx = Context.getCurrentContext(); 537 Object [] args = new Object [2]; 538 args[0] = widget; 539 args[1] = error; 540 ((Function)fun).call(cx, scope, thisObj, args); 541 } catch (Exception exc) { 542 throw Context.reportRuntimeError(exc.getMessage()); 543 } 544 } 545 } 546 547 public Widget jsFunction_unwrap() { 548 return delegate; 549 } 550 551 public ScriptableWidget jsFunction_addRow() { 552 ScriptableWidget result = null; 553 if (delegate instanceof Repeater) { 554 result = wrap(((Repeater)delegate).addRow()); 555 result.notifyAddRow(); 556 } 557 return result; 558 } 559 560 public ScriptableObject jsFunction_getRow(int index) { 561 if (delegate instanceof Repeater) { 562 return wrap(((Repeater)delegate).getRow(index)); 563 } 564 return null; 565 } 566 567 public void jsFunction_removeRow(Object obj) throws JavaScriptException { 568 if (delegate instanceof Repeater) { 569 Repeater repeater = (Repeater)delegate; 570 if (obj instanceof Function) { 571 Function fun = (Function)obj; 572 int len = repeater.getSize(); 573 boolean[] index = new boolean[len]; 574 Object [] args = new Object [1]; 575 Scriptable scope = getTopLevelScope(this); 576 Scriptable thisObj = scope; 577 Context cx = Context.getCurrentContext(); 578 for (int i = 0; i < len; i++) { 579 ScriptableWidget row = wrap(repeater.getRow(i)); 580 args[0] = row; 581 Object result = fun.call(cx, scope, thisObj, args); 582 index[i] = Context.toBoolean(result); 583 } 584 for (int i = len-1; i >= 0; --i) { 585 if (index[i]) { 586 deleteRow(repeater, i); 587 } 588 } 589 } else if (obj instanceof Number ) { 590 int index = (int)Context.toNumber(obj); 591 if (index > 0 && index < repeater.getSize()) { 592 deleteRow(repeater, index); 593 } 594 } else { 595 } 597 } 598 } 599 600 private void handleEvent(WidgetEvent e) { 601 if (e instanceof ActionEvent) { 602 Object obj = super.get("onClick", this); 603 if (obj instanceof Function) { 604 try { 605 Function fun = (Function)obj; 606 Object [] args = new Object [1]; 607 Scriptable scope = getTopLevelScope(this); 608 Scriptable thisObj = scope; 609 Context cx = Context.getCurrentContext(); 610 args[0] = ((ActionEvent)e).getActionCommand(); 611 fun.call(cx, scope, thisObj, args); 612 } catch (Exception exc) { 613 throw Context.reportRuntimeError(exc.getMessage()); 614 } 615 } 616 } else if (e instanceof ValueChangedEvent) { 617 ValueChangedEvent vce = (ValueChangedEvent)e; 618 Object obj = super.get("onChange", this); 619 if (obj instanceof Function) { 620 try { 621 Function fun = (Function)obj; 622 Object [] args = new Object [2]; 623 Scriptable scope = getTopLevelScope(this); 624 Scriptable thisObj = scope; 625 Context cx = Context.getCurrentContext(); 626 args[0] = vce.getOldValue(); 627 args[1] = vce.getNewValue(); 628 fun.call(cx, scope, thisObj, args); 629 } catch (Exception exc) { 630 throw Context.reportRuntimeError(exc.getMessage()); 631 } 632 } 633 } 634 } 635 636 public void jsFunction_setSelectionList(Object arg, 637 Object valuePathArg, 638 Object labelPathArg) 639 throws Exception { 640 if (delegate instanceof SelectableWidget) { 641 arg = unwrap(arg); 642 if (valuePathArg != Undefined.instance && labelPathArg != Undefined.instance) { 643 String valuePath = Context.toString(valuePathArg); 644 String labelPath = Context.toString(labelPathArg); 645 ((SelectableWidget)delegate).setSelectionList(arg, valuePath, labelPath); 646 } else { 647 if (arg instanceof SelectionList) { 648 SelectionList selectionList = (SelectionList)arg; 649 ((SelectableWidget)delegate).setSelectionList(selectionList); 650 } else { 651 String str = Context.toString(arg); 652 ((SelectableWidget)delegate).setSelectionList(str); 653 } 654 } 655 } 656 } 657 658 static final Object [] WIDGET_CLASS_MAP = { 659 Form.class, "Form", 660 Field.class, "Field", 661 Action.class, "Action", 662 Repeater.class, "Repeater", 663 Repeater.RepeaterRow.class, "RepeaterRow", 664 AggregateField.class, "AggregateField", 665 BooleanField.class, "BooleanField", 666 MultiValueField.class, "MultiValueField", 667 Output.class, "Output", 668 Submit.class, "Submit", 669 Upload.class, "Upload" 670 }; 671 672 public String jsFunction_getWidgetClass() { 673 for (int i = 0; i < WIDGET_CLASS_MAP.length; i += 2) { 674 Class c = (Class )WIDGET_CLASS_MAP[i]; 675 if (c.isAssignableFrom(delegate.getClass())) { 676 return (String )WIDGET_CLASS_MAP[i + 1]; 677 } 678 } 679 return "<unknown>"; 680 } 681 682 public String jsFunction_toString() { 683 return "[object Widget (" + jsFunction_getWidgetClass() + ")]"; 684 } 685 686 } 687
| Popular Tags
|