Permalink
Browse files

first svn add of trunk

git-svn-id: https://pyjamas.svn.sourceforge.net/svnroot/pyjamas/trunk@2 7a2bd370-bda8-463c-979e-2900ccfb811e
  • Loading branch information...
1 parent 48b248d commit 04ee4803644082f1fffbfacf53c0dc70c8f5f210 lkcl committed Sep 15, 2008
Showing with 85,432 additions and 0 deletions.
  1. +176 −0 COPYING
  2. +20 −0 CREDITS
  3. +8 −0 README
  4. +127 −0 addons/AutoComplete.py
  5. +16 −0 addons/BoundMethod.py
  6. +141 −0 addons/Canvas.py
  7. +77 −0 addons/Controls.py
  8. +257 −0 addons/CountryListBox.py
  9. +23 −0 addons/EventDelegate.py
  10. +131 −0 addons/RichTextEditor.py
  11. +330 −0 addons/TemplatePanel.py
  12. +107 −0 addons/Tooltip.py
  13. +99 −0 addons/datetime.py
  14. +39 −0 builder/boilerplate/all.cache.html
  15. +23 −0 builder/boilerplate/app.html
  16. +20 −0 builder/boilerplate/history.html
  17. +79 −0 builder/boilerplate/home.nocache.html
  18. +51 −0 builder/boilerplate/index.html
  19. +156 −0 builder/boilerplate/pygwt.js
  20. BIN builder/boilerplate/tree_closed.gif
  21. BIN builder/boilerplate/tree_open.gif
  22. BIN builder/boilerplate/tree_white.gif
  23. +216 −0 builder/build.py
  24. +59 −0 doc/gendocs.py
  25. +5 −0 examples/README
  26. +82 −0 examples/addonsgallery/AddonsGallery.py
  27. +28 −0 examples/addonsgallery/AutoCompleteTab.py
  28. +244 −0 examples/addonsgallery/CanvasTab.py
  29. +15 −0 examples/addonsgallery/IntroTab.py
  30. +38 −0 examples/addonsgallery/Sink.py
  31. +38 −0 examples/addonsgallery/SinkList.py
  32. +35 −0 examples/addonsgallery/TooltipTab.py
  33. +1 −0 examples/addonsgallery/build.sh
  34. +261 −0 examples/addonsgallery/public/AddonsGallery.css
  35. +13 −0 examples/addonsgallery/public/AddonsGallery.html
  36. +704 −0 examples/addonsgallery/public/excanvas.js
  37. BIN examples/addonsgallery/public/images/earth.png
  38. BIN examples/addonsgallery/public/images/moon.png
  39. BIN examples/addonsgallery/public/images/num1.png
  40. BIN examples/addonsgallery/public/images/num2.png
  41. BIN examples/addonsgallery/public/images/sun.png
  42. BIN examples/addonsgallery/public/images/wallpaper.png
  43. +10 −0 examples/browserdetect/BrowserDetect.html
  44. +11 −0 examples/browserdetect/BrowserDetect.py
  45. +1 −0 examples/browserdetect/build.sh
  46. +5 −0 examples/browserdetect/platform/BrowserDetectIE6.py
  47. +6 −0 examples/browserdetect/platform/BrowserDetectMozilla.py
  48. +5 −0 examples/browserdetect/platform/BrowserDetectOldMoz.py
  49. +5 −0 examples/browserdetect/platform/BrowserDetectOpera.py
  50. +5 −0 examples/browserdetect/platform/BrowserDetectSafari.py
  51. +10 −0 examples/buildall.sh
  52. +10 −0 examples/controls/ControlDemo.html
  53. +20 −0 examples/controls/ControlDemo.py
  54. +1 −0 examples/controls/build.sh
  55. +10 −0 examples/controls/output/ControlDemo.html
  56. +79 −0 examples/controls/output/ControlDemo.nocache.html
  57. +13,209 −0 examples/controls/output/IE6.cache.html
  58. +13,273 −0 examples/controls/output/Mozilla.cache.html
  59. +13,300 −0 examples/controls/output/OldMoz.cache.html
  60. +13,254 −0 examples/controls/output/Opera.cache.html
  61. +13,275 −0 examples/controls/output/Safari.cache.html
  62. +20 −0 examples/controls/output/history.html
  63. +157 −0 examples/controls/output/pygwt.js
  64. BIN examples/controls/output/tree_closed.gif
  65. BIN examples/controls/output/tree_open.gif
  66. BIN examples/controls/output/tree_white.gif
  67. +65 −0 examples/dynamictable/DayFilterWidget.py
  68. +20 −0 examples/dynamictable/DynaTable.py
  69. +139 −0 examples/dynamictable/DynaTableWidget.py
  70. +15 −0 examples/dynamictable/Person.py
  71. +13 −0 examples/dynamictable/Professor.py
  72. +22 −0 examples/dynamictable/Schedule.py
  73. +5 −0 examples/dynamictable/SchoolCalendarService.py
  74. +84 −0 examples/dynamictable/SchoolCalendarWidget.py
  75. +13 −0 examples/dynamictable/Student.py
  76. +38 −0 examples/dynamictable/TimeSlot.py
  77. +1 −0 examples/dynamictable/build.sh
  78. +71 −0 examples/dynamictable/public/DynaTable.css
  79. +23 −0 examples/dynamictable/public/DynaTable.html
  80. +155 −0 examples/dynamictable/public/SchoolCalendarService.php
  81. +791 −0 examples/dynamictable/public/phpolait/JSON.php
  82. +504 −0 examples/dynamictable/public/phpolait/copying.txt
  83. +112 −0 examples/dynamictable/public/phpolait/httpwrap.php
  84. +473 −0 examples/dynamictable/public/phpolait/jsolait/init.js
  85. +103 −0 examples/dynamictable/public/phpolait/jsolait/lib/codecs.js
  86. +81 −0 examples/dynamictable/public/phpolait/jsolait/lib/crypto.js
  87. +166 −0 examples/dynamictable/public/phpolait/jsolait/lib/iter.js
  88. +232 −0 examples/dynamictable/public/phpolait/jsolait/lib/jsonrpc.js
  89. +377 −0 examples/dynamictable/public/phpolait/jsolait/lib/lang.js
  90. +177 −0 examples/dynamictable/public/phpolait/jsolait/lib/urllib.js
  91. +180 −0 examples/dynamictable/public/phpolait/jsolait/lib/xml.js
  92. +567 −0 examples/dynamictable/public/phpolait/jsolait/lib/xmlrpc.js
  93. +115 −0 examples/dynamictable/public/phpolait/jsolait/missingmixin.js
  94. +486 −0 examples/dynamictable/public/phpolait/phpolait.php
  95. +63 −0 examples/dynamictable/public/phpolait/rpcproxy.php4
  96. +61 −0 examples/dynamictable/public/phpolait/rpcproxy.php5
  97. +33 −0 examples/dynamictable/public/phpolait/rpcproxy_call_method.php
  98. +30 −0 examples/dynamictable/public/phpolait/rpcproxy_constructor.php
  99. +12 −0 examples/f
  100. +10 −0 examples/formpanel/FormPanelExample.html
  101. +63 −0 examples/formpanel/FormPanelExample.py
  102. +1 −0 examples/formpanel/build.sh
  103. +10 −0 examples/gridtest/GridTest.html
  104. +59 −0 examples/gridtest/GridTest.py
  105. +1 −0 examples/gridtest/build.sh
  106. +10 −0 examples/helloworld/Hello.html
  107. +10 −0 examples/helloworld/Hello.py
  108. +7 −0 examples/helloworld/README
  109. +1 −0 examples/helloworld/build.sh
  110. +77 −0 examples/index.html
  111. +96 −0 examples/jsonrpc/JSONRPCExample.py
  112. +1 −0 examples/jsonrpc/build.sh
  113. +10 −0 examples/jsonrpc/public/JSONRPCExample.html
  114. +5 −0 examples/jsonrpc/public/services/.htaccess
  115. +15 −0 examples/jsonrpc/public/services/EchoService.php
  116. +20 −0 examples/jsonrpc/public/services/EchoService.py
  117. +241 −0 examples/jsonrpc/public/services/jsonrpc/__init__.py
  118. +62 −0 examples/jsonrpc/public/services/jsonrpc/apacheServiceHandler.py
  119. +62 −0 examples/jsonrpc/public/services/jsonrpc/cgihandler.py
  120. +45 −0 examples/jsonrpc/public/services/jsonrpc/errors.py
  121. +34 −0 examples/jsonrpc/public/services/jsonrpc/http.py
  122. +76 −0 examples/jsonrpc/public/services/jsonrpc/proxy.py
  123. +91 −0 examples/jsonrpc/public/services/jsonrpc/socketserver.py
  124. +791 −0 examples/jsonrpc/public/services/phpolait/JSON.php
  125. +504 −0 examples/jsonrpc/public/services/phpolait/copying.txt
  126. +112 −0 examples/jsonrpc/public/services/phpolait/httpwrap.php
  127. +473 −0 examples/jsonrpc/public/services/phpolait/jsolait/init.js
  128. +103 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/codecs.js
  129. +81 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/crypto.js
  130. +166 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/iter.js
  131. +232 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/jsonrpc.js
  132. +377 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/lang.js
  133. +177 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/urllib.js
  134. +180 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/xml.js
  135. +567 −0 examples/jsonrpc/public/services/phpolait/jsolait/lib/xmlrpc.js
  136. +115 −0 examples/jsonrpc/public/services/phpolait/jsolait/missingmixin.js
  137. +486 −0 examples/jsonrpc/public/services/phpolait/phpolait.php
  138. +63 −0 examples/jsonrpc/public/services/phpolait/rpcproxy.php4
  139. +61 −0 examples/jsonrpc/public/services/phpolait/rpcproxy.php5
  140. +33 −0 examples/jsonrpc/public/services/phpolait/rpcproxy_call_method.php
  141. +30 −0 examples/jsonrpc/public/services/phpolait/rpcproxy_constructor.php
  142. +229 −0 examples/jsonrpc/public/services/simplejson/__init__.py
  143. +273 −0 examples/jsonrpc/public/services/simplejson/decoder.py
  144. +307 −0 examples/jsonrpc/public/services/simplejson/encoder.py
  145. +40 −0 examples/jsonrpc/public/services/simplejson/jsonfilter.py
  146. +63 −0 examples/jsonrpc/public/services/simplejson/scanner.py
  147. +49 −0 examples/kitchensink/Buttons.py
  148. +15 −0 examples/kitchensink/Frames.py
  149. +64 −0 examples/kitchensink/Images.py
  150. +22 −0 examples/kitchensink/Info.py
  151. +103 −0 examples/kitchensink/KitchenSink.py
  152. +112 −0 examples/kitchensink/Layouts.py
  153. +70 −0 examples/kitchensink/Lists.py
  154. +62 −0 examples/kitchensink/Logger.py
  155. +45 −0 examples/kitchensink/Menus.py
  156. +91 −0 examples/kitchensink/Popups.py
  157. +38 −0 examples/kitchensink/Sink.py
  158. +38 −0 examples/kitchensink/SinkList.py
  159. +34 −0 examples/kitchensink/Tables.py
  160. +35 −0 examples/kitchensink/Tabs.py
  161. +76 −0 examples/kitchensink/Text.py
  162. +122 −0 examples/kitchensink/Trees.py
  163. +1 −0 examples/kitchensink/build.sh
  164. +244 −0 examples/kitchensink/public/KitchenSink.css
  165. +13 −0 examples/kitchensink/public/KitchenSink.html
  166. BIN examples/kitchensink/public/images/blanksearching.gif
  167. BIN examples/kitchensink/public/images/searching.gif
  168. +17 −0 examples/kitchensink/public/rembrandt/JohannesElison.html
  169. BIN examples/kitchensink/public/rembrandt/JohannesElison.jpg
  170. +17 −0 examples/kitchensink/public/rembrandt/LaMarcheNocturne.html
  171. BIN examples/kitchensink/public/rembrandt/LaMarcheNocturne.jpg
  172. +17 −0 examples/kitchensink/public/rembrandt/SelfPortrait1628.html
  173. BIN examples/kitchensink/public/rembrandt/SelfPortrait1628.jpg
  174. +17 −0 examples/kitchensink/public/rembrandt/SelfPortrait1640.html
  175. BIN examples/kitchensink/public/rembrandt/SelfPortrait1640.jpg
  176. +17 −0 examples/kitchensink/public/rembrandt/TheArtistInHisStudio.html
  177. BIN examples/kitchensink/public/rembrandt/TheArtistInHisStudio.jpg
  178. +17 −0 examples/kitchensink/public/rembrandt/TheReturnOfTheProdigalSon.html
  179. BIN examples/kitchensink/public/rembrandt/TheReturnOfTheProdigalSon.jpg
  180. BIN examples/kitchensink/public/rembrandt/back.gif
  181. BIN examples/kitchensink/public/rembrandt/forward.gif
  182. +8 −0 examples/kitchensink/public/rembrandt/rembrandt.css
  183. +584 −0 examples/libtest/ArgsTest.py
  184. +254 −0 examples/libtest/ClassTest.py
  185. +10 −0 examples/libtest/LibTest.html
  186. +19 −0 examples/libtest/LibTest.py
  187. +110 −0 examples/libtest/ListTest.py
  188. +75 −0 examples/libtest/SetTest.py
  189. +88 −0 examples/libtest/StringTest.py
  190. +126 −0 examples/libtest/UnitTest.py
  191. +16 −0 examples/libtest/VarsTest.py
  192. +1 −0 examples/libtest/build.sh
  193. +16 −0 examples/libtest/write.py
  194. +51 −0 examples/mail/AboutDialog.py
  195. +76 −0 examples/mail/Contacts.py
  196. +61 −0 examples/mail/Logger.py
  197. +12 −0 examples/mail/Mail.html
  198. +90 −0 examples/mail/Mail.py
  199. +56 −0 examples/mail/MailDetail.py
  200. +6 −0 examples/mail/MailItem.py
  201. +78 −0 examples/mail/MailItems.py
  202. +155 −0 examples/mail/MailList.py
  203. +27 −0 examples/mail/Mailboxes.py
  204. +24 −0 examples/mail/Shortcuts.py
  205. +14 −0 examples/mail/Tasks.py
  206. +50 −0 examples/mail/TopPanel.py
  207. +1 −0 examples/mail/build.sh
  208. +10 −0 examples/onclicktest/OnClickTest.html
  209. +21 −0 examples/onclicktest/OnClickTest.py
  210. +1 −0 examples/onclicktest/build.sh
  211. +74 −0 library/Cookies.py
Sorry, we could not display the entire diff because too many files (454) changed.
View
176 COPYING
@@ -0,0 +1,176 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
View
20 CREDITS
@@ -0,0 +1,20 @@
+Lead Developer
+
+James Tauber - jtauber@jtauber.com
+
+
+Other Commmitters
+
+Willie Gollino - wgollino@yahoo.com
+Dobes Vandermeer - dobesv@gmail.com
+
+Other Contributors
+
+Vicente J. Ruiz Jurado - vjrj@ourproject.org
+Gerard Labadie - gerard.labadie@gmail.com
+Stephan Diehl - stephan.diehl@gmx.net
+John Lehman - j1o1h1n@gmail.com
+
+
+And of course, a huge amount of thanks goes to Google and the engineers
+there that produced GWT, on which pyjamas is based.
View
8 README
@@ -0,0 +1,8 @@
+pyjamas
+
+pyjamas is an attempt to port the Google Web Toolkit to Python and thus enable
+the development of AJAX applications in Python.
+
+For more information, see:
+
+ http://pyjamas.pyworks.org/
View
127 addons/AutoComplete.py
@@ -0,0 +1,127 @@
+# Autocomplete component for Pyjamas
+# Ported by Willie Gollino from Autocomplete component for GWT - Originally by Oliver Albers http://gwt.components.googlepages.com/
+
+from ui import TextBox, PopupPanel, ListBox, KeyboardListener, RootPanel
+
+class AutoCompleteTextBox(TextBox):
+ def __init__(self):
+ self.choicesPopup = PopupPanel(True)
+ self.choices = ListBox()
+ self.items = SimpleAutoCompletionItems()
+ self.popupAdded = False
+ self.visible = False
+
+ TextBox.__init__(self)
+ self.addKeyboardListener(self)
+ self.choices.addChangeListener(self)
+ self.setStyleName("AutoCompleteTextBox")
+
+ self.choicesPopup.add(self.choices)
+ self.choicesPopup.addStyleName("AutoCompleteChoices")
+
+ self.choices.setStyleName("list")
+
+ def setCompletionItems(self, items):
+ if not items.getCompletionItems:
+ items = SimpleAutoCompletionItems(items)
+
+ self.items = items
+
+ def getCompletionItems(self):
+ return self.items
+
+ def onKeyDown(self, arg0, arg1, arg2):
+ pass
+
+ def onKeyPress(self, arg0, arg1, arg2):
+ pass
+
+ def onKeyUp(self, arg0, arg1, arg2):
+ if arg1 == KeyboardListener.KEY_DOWN:
+ selectedIndex = self.choices.getSelectedIndex()
+ selectedIndex += 1
+ if selectedIndex > self.choices.getItemCount():
+ selectedIndex = 0
+
+ self.choices.setSelectedIndex(selectedIndex)
+ return
+
+ if arg1 == KeyboardListener.KEY_UP:
+ selectedIndex = self.choices.getSelectedIndex()
+ selectedIndex -= 1
+ if selectedIndex < 0:
+ selectedIndex = self.choices.getItemCount()
+ self.choices.setSelectedIndex(selectedIndex)
+ return
+
+ if arg1 == KeyboardListener.KEY_ENTER:
+ if self.visible:
+ self.complete()
+ return
+
+ if arg1 == KeyboardListener.KEY_ESCAPE:
+ self.choices.clear()
+ self.choicesPopup.hide()
+ self.visible = False
+ return
+
+ text = self.getText()
+ matches = []
+ if len(text) > 0:
+ matches = self.items.getCompletionItems(text)
+
+ if len(matches) > 0:
+ self.choices.clear()
+
+ for i in range(len(matches)):
+ self.choices.addItem(matches[i])
+
+ if len(matches) == 1 and matches[0] == text:
+ self.choicesPopup.hide()
+ else:
+ self.choices.setSelectedIndex(0)
+ self.choices.setVisibleItemCount(len(matches) + 1)
+
+ if not self.popupAdded:
+ RootPanel().add(self.choicesPopup)
+ self.popupAdded = True
+
+ self.choicesPopup.show()
+ self.visible = True
+ self.choicesPopup.setPopupPosition(self.getAbsoluteLeft(), self.getAbsoluteTop() + self.getOffsetHeight())
+ self.choices.setWidth(self.getOffsetWidth() + "px")
+ else:
+ self.visible = False
+ self.choicesPopup.hide()
+
+ def onChange(self, arg0):
+ self.complete()
+
+ def onClick(self, arg0):
+ self.complete()
+
+ def complete(self):
+ if self.choices.getItemCount() > 0:
+ self.setText(self.choices.getItemText(self.choices.getSelectedIndex()))
+
+ self.choices.clear()
+ self.choicesPopup.hide()
+ self.setFocus(True)
+
+
+class SimpleAutoCompletionItems:
+ def __init__(self, items = None):
+ if items == None:
+ items = []
+ self.completions = items
+
+ def getCompletionItems(self, match):
+ matches = []
+ match = match.lower()
+
+ for i in range(len(self.completions)):
+ lower = self.completions[i].lower()
+ if lower.startswith(match):
+ matches.append(self.completions[i])
+
+ return matches
View
16 addons/BoundMethod.py
@@ -0,0 +1,16 @@
+from __pyjamas__ import JS
+
+def BoundMethod(obj, method):
+ """
+ Return a javascript-compatible callable which can be used as a "bound method".
+
+ Javascript doesn't support callables, and it doesn't support bound methods,
+ so you can't use those in pyjamas currently.
+
+ This is an OK workaround.
+ """
+ JS("""
+ return function() {
+ return method.apply(obj, arguments);
+ };
+ """)
View
141 addons/Canvas.py
@@ -0,0 +1,141 @@
+# Canvas wrapper component for Pyjamas
+# Ported by Willie Gollino from Canvas component for GWT - Originally by Alexei Sokolov http://gwt.components.googlepages.com/
+#
+# Canvas API reference:
+# http://developer.apple.com/documentation/AppleApplications/Reference/SafariJSRef/Classes/Canvas.html#//apple_ref/js/Canvas.clearRect
+#
+# Usage Notes:
+# - IE support requires ExplorerCanvas from excanvas.sourceforge.net
+# - place excanvas.js in your apps public folder
+# - add this to your MainModule.html: <!--[if IE]><script src="excanvas.js" type="text/javascript"></script><![endif]-->
+
+import DOM
+from ui import Image, Widget
+
+class Canvas(Widget):
+ def __init__(self, width, height):
+ self.context = None
+
+ self.setElement(DOM.createDiv())
+ canvas = DOM.createElement("canvas")
+ self.setWidth(width)
+ self.setHeight(height)
+
+ canvas.width=width
+ canvas.height=height
+
+ DOM.appendChild(self.getElement(), canvas)
+ self.setStyleName("gwt-Canvas")
+
+ self.init()
+
+ self.context.fillStyle = "black"
+ self.context.strokeStyle = "black"
+
+ def getContext(self):
+ return self.context
+
+ def isEmulation(self):
+ JS("""
+ return (typeof $wnd.G_vmlCanvasManager != "undefined");
+ """)
+
+ def init(self):
+ JS("""
+ var el = this.getElement().firstChild;
+ if (typeof $wnd.G_vmlCanvasManager != "undefined") {
+ var parent = el.parent;
+
+ el = $wnd.G_vmlCanvasManager.fixElement_(el);
+ el.getContext = function () {
+ if (this.context_) {
+ return this.context_;
+ }
+ return this.context_ = new $wnd.CanvasRenderingContext2D(el);
+ };
+
+ el.attachEvent("onpropertychange", function (e) {
+ // we need to watch changes to width and height
+ switch (e.propertyName) {
+ case "width":
+ case "height":
+ // coord size changed?
+ break;
+ }
+ });
+
+ // if style.height is set
+
+ var attrs = el.attributes;
+ if (attrs.width && attrs.width.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setWidth_(attrs.width.nodeValue);
+ el.style.width = attrs.width.nodeValue + "px";
+ }
+ if (attrs.height && attrs.height.specified) {
+ // TODO: use runtimeStyle and coordsize
+ // el.getContext().setHeight_(attrs.height.nodeValue);
+ el.style.height = attrs.height.nodeValue + "px";
+ }
+ }
+ var ctx = el.getContext("2d");
+
+ ctx._createPattern = ctx.createPattern;
+ ctx.createPattern = function(img, rep) {
+ if (!(img instanceof Image)) img = img.getElement();
+ return this._createPattern(img, rep);
+ }
+
+ ctx._drawImage = ctx.drawImage;
+ ctx.drawImage = function() {
+ var a=arguments;
+ if (!(a[0] instanceof Image)) a[0] = a[0].getElement();
+ if (a.length==9) return this._drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
+ else if (a.length==5) return this._drawImage(a[0], a[1], a[2], a[3], a[4]);
+ return this._drawImage(a[0], a[1], a[2]);
+ }
+
+ this.context = ctx;
+ """)
+
+class CanvasImage(Image):
+ def __init__(self, url="", load_listener = None):
+ Image.__init__(self, url)
+ if load_listener:
+ self.addLoadListener(load_listener)
+ self.onAttach()
+
+ def isLoaded(self):
+ return self.getElement().complete
+
+
+class ImageLoadListener:
+ def __init__(self, listener = None):
+ self.wait_list = []
+ self.loadListeners = []
+
+ if listener:
+ self.addLoadListener(listener)
+
+ def add(self, sender):
+ self.wait_list.append(sender)
+ sender.addLoadListener(self)
+
+ def addLoadListener(self, listener):
+ self.loadListeners.append(listener)
+
+ def isLoaded(self):
+ if len(self.wait_list):
+ return False
+ return True
+
+ def onError(self, sender):
+ for listener in self.loadListeners:
+ listener.onError(sender)
+
+ def onLoad(self, sender):
+ self.wait_list.remove(sender)
+
+ if self.isLoaded():
+ for listener in self.loadListeners:
+ listener.onLoad(self)
View
77 addons/Controls.py
@@ -0,0 +1,77 @@
+""" Control Widgets. Presently comprises a Vertical Slider Demo.
+
+ Copyright (C) 2008 - Luke Kenneth Casson Leighton <lkcl@lkcl.net>
+
+"""
+
+from pyjamas import DOM
+from pyjamas.ui import FocusWidget
+
+class VerticalDemoSlider(FocusWidget):
+
+ def __init__(self, min_value, max_value, start_value=None):
+
+ element = DOM.createDiv()
+ FocusWidget.__init__(self, element)
+
+ self.min_value = min_value
+ self.max_value = max_value
+ if start_value is None:
+ start_value = min_value
+ self.value = start_value
+ self.valuechange_listeners = []
+
+ DOM.setStyleAttribute(element, "position", "relative")
+ DOM.setStyleAttribute(element, "overflow", "hidden")
+
+ self.handle = DOM.createDiv()
+ DOM.appendChild(element, self.handle)
+
+ DOM.setStyleAttribute(self.handle, "border", "1px")
+ DOM.setStyleAttribute(self.handle, "width", "100%")
+ DOM.setStyleAttribute(self.handle, "height", "10px")
+ DOM.setStyleAttribute(self.handle, "backgroundColor", "#808080")
+
+ self.addClickListener(self)
+
+ def onClick(self, sender, event):
+
+ # work out the relative position of cursor
+ mouse_y = DOM.eventGetClientY(event) - \
+ DOM.getAbsoluteTop(sender.getElement())
+ self.moveSlider(mouse_y)
+
+ def moveSlider(self, mouse_y):
+
+ relative_y = mouse_y - DOM.getAbsoluteTop(self.getElement())
+ widget_height = self.getOffsetHeight()
+
+ # limit the position to be in the widget!
+ if relative_y < 0:
+ relative_y = 0
+ height_range = widget_height - 10 # handle height is hard-coded
+ if relative_y >= height_range:
+ relative_y = height_range
+
+ # move the handle
+ DOM.setStyleAttribute(self.handle, "top", "%dpx" % relative_y)
+ DOM.setStyleAttribute(self.handle, "position", "absolute")
+
+ val_diff = self.max_value - self.min_value
+ new_value = ((val_diff * relative_y) / height_range) + self.min_value
+ self.setValue(new_value)
+
+ def setValue(self, new_value):
+
+ old_value = self.value
+ self.value = new_value
+ for listener in self.valuechange_listeners:
+ listener.onControlValueChanged(self, old_value, new_value)
+
+ def addControlValueListener(self, listener):
+ self.valuechange_listeners.append(listener)
+
+ def removeControlValueListener(self, listener):
+ self.valuechange_listeners.remove(listener)
+
+
View
257 addons/CountryListBox.py
@@ -0,0 +1,257 @@
+from ui import ListBox
+
+class CountryListBox(ListBox):
+ country_list = [
+ ['', ''] ,
+ ['Afghanistan', 'AF'] ,
+ ['Åfland Islands', 'AX'] ,
+ ['Albania', 'AL'] ,
+ ['Algeria', 'DZ'] ,
+ ['American Samoa', 'AS'] ,
+ ['Andorra', 'AD'] ,
+ ['Angola', 'AO'] ,
+ ['Anguilla', 'AI'] ,
+ ['Antarctica', 'AQ'] ,
+ ['Antigua And Barbuda', 'AG'] ,
+ ['Argentina', 'AR'] ,
+ ['Armenia', 'AM'] ,
+ ['Aruba', 'AW'] ,
+ ['Australia', 'AU'] ,
+ ['Austria', 'AT'] ,
+ ['Azerbaijan', 'AZ'] ,
+ ['Bahamas', 'BS'] ,
+ ['Bahrain', 'BH'] ,
+ ['Bangladesh', 'BD'] ,
+ ['Barbados', 'BB'] ,
+ ['Belarus', 'BY'] ,
+ ['Belgium', 'BE'] ,
+ ['Belize', 'BZ'] ,
+ ['Benin', 'BJ'] ,
+ ['Bermuda', 'BM'] ,
+ ['Bhutan', 'BT'] ,
+ ['Bolivia', 'BO'] ,
+ ['Bosnia And Herzegovina', 'BA'] ,
+ ['Botswana', 'BW'] ,
+ ['Bouvet Island', 'BV'] ,
+ ['Brazil', 'BR'] ,
+ ['British Indian Ocean Territory', 'IO'] ,
+ ['Brunei Darussalam', 'BN'] ,
+ ['Bulgaria', 'BG'] ,
+ ['Burkina Faso', 'BF'] ,
+ ['Burundi', 'BI'] ,
+ ['Cambodia', 'KH'] ,
+ ['Cameroon', 'CM'] ,
+ ['Canada', 'CA'] ,
+ ['Cape Verde', 'CV'] ,
+ ['Cayman Islands', 'KY'] ,
+ ['Central African Republic', 'CF'] ,
+ ['Chad', 'TD'] ,
+ ['Chile', 'CL'] ,
+ ['China', 'CN'] ,
+ ['Christmas Island', 'CX'] ,
+ ['Cocos (keeling) Islands', 'CC'] ,
+ ['Colombia', 'CO'] ,
+ ['Comoros', 'KM'] ,
+ ['Congo', 'CG'] ,
+ ['Congo, The Democratic Republic Of The', 'CD'] ,
+ ['Cook Islands', 'CK'] ,
+ ['Costa Rica', 'CR'] ,
+ ["Cote D'ivoire", 'CI'] ,
+ ['Croatia', 'HR'] ,
+ ['Cuba', 'CU'] ,
+ ['Cyprus', 'CY'] ,
+ ['Czech Republic', 'CZ'] ,
+ ['Denmark', 'DK'] ,
+ ['Djibouti', 'DJ'] ,
+ ['Dominica', 'DM'] ,
+ ['Dominican Republic', 'DO'] ,
+ ['Ecuador', 'EC'] ,
+ ['Egypt', 'EG'] ,
+ ['El Salvador', 'SV'] ,
+ ['Equatorial Guinea', 'GQ'] ,
+ ['Eritrea', 'ER'] ,
+ ['Estonia', 'EE'] ,
+ ['Ethiopia', 'ET'] ,
+ ['Falkland Islands (malvinas)', 'FK'] ,
+ ['Faroe Islands', 'FO'] ,
+ ['Fiji', 'FJ'] ,
+ ['Finland', 'FI'] ,
+ ['France', 'FR'] ,
+ ['French Guiana', 'GF'] ,
+ ['French Polynesia', 'PF'] ,
+ ['French Southern Territories', 'TF'] ,
+ ['Gabon', 'GA'] ,
+ ['Gambia', 'GM'] ,
+ ['Georgia', 'GE'] ,
+ ['Germany', 'DE'] ,
+ ['Ghana', 'GH'] ,
+ ['Gibraltar', 'GI'] ,
+ ['Greece', 'GR'] ,
+ ['Greenland', 'GL'] ,
+ ['Grenada', 'GD'] ,
+ ['Guadeloupe', 'GP'] ,
+ ['Guam', 'GU'] ,
+ ['Guatemala', 'GT'] ,
+ ['Guernsey', 'GG'] ,
+ ['Guinea', 'GN'] ,
+ ['Guinea-bissau', 'GW'] ,
+ ['Guyana', 'GY'] ,
+ ['Haiti', 'HT'] ,
+ ['Heard Island And Mcdonald Islands', 'HM'] ,
+ ['Holy See (vatican City State)', 'VA'] ,
+ ['Honduras', 'HN'] ,
+ ['Hong Kong', 'HK'] ,
+ ['Hungary', 'HU'] ,
+ ['Iceland', 'IS'] ,
+ ['India', 'IN'] ,
+ ['Indonesia', 'ID'] ,
+ ['Iran, Islamic Republic Of', 'IR'] ,
+ ['Iraq', 'IQ'] ,
+ ['Ireland', 'IE'] ,
+ ['Isle Of Man', 'IM'] ,
+ ['Israel', 'IL'] ,
+ ['Italy', 'IT'] ,
+ ['Jamaica', 'JM'] ,
+ ['Japan', 'JP'] ,
+ ['Jersey', 'JE'] ,
+ ['Jordan', 'JO'] ,
+ ['Kazakhstan', 'KZ'] ,
+ ['Kenya', 'KE'] ,
+ ['Kiribati', 'KI'] ,
+ ["Korea, Democratic People's Republic Of", 'KP'] ,
+ ['Korea, Republic Of', 'KR'] ,
+ ['Kuwait', 'KW'] ,
+ ['Kyrgyzstan', 'KG'] ,
+ ["Lao People's Democratic Republic", 'LA'] ,
+ ['Latvia', 'LV'] ,
+ ['Lebanon', 'LB'] ,
+ ['Lesotho', 'LS'] ,
+ ['Liberia', 'LR'] ,
+ ['Libyan Arab Jamahiriya', 'LY'] ,
+ ['Liechtenstein', 'LI'] ,
+ ['Lithuania', 'LT'] ,
+ ['Luxembourg', 'LU'] ,
+ ['Macao', 'MO'] ,
+ ['Macedonia, The Former Yugoslav Republic Of', 'MK'] ,
+ ['Madagascar', 'MG'] ,
+ ['Malawi', 'MW'] ,
+ ['Malaysia', 'MY'] ,
+ ['Maldives', 'MV'] ,
+ ['Mali', 'ML'] ,
+ ['Malta', 'MT'] ,
+ ['Marshall Islands', 'MH'] ,
+ ['Martinique', 'MQ'] ,
+ ['Mauritania', 'MR'] ,
+ ['Mauritius', 'MU'] ,
+ ['Mayotte', 'YT'] ,
+ ['Mexico', 'MX'] ,
+ ['Micronesia, Federated States Of', 'FM'] ,
+ ['Moldova, Republic Of', 'MD'] ,
+ ['Monaco', 'MC'] ,
+ ['Mongolia', 'MN'] ,
+ ['Montenegro', 'ME'] ,
+ ['Montserrat', 'MS'] ,
+ ['Morocco', 'MA'] ,
+ ['Mozambique', 'MZ'] ,
+ ['Myanmar', 'MM'] ,
+ ['Namibia', 'NA'] ,
+ ['Nauru', 'NR'] ,
+ ['Nepal', 'NP'] ,
+ ['Netherlands', 'NL'] ,
+ ['Netherlands Antilles', 'AN'] ,
+ ['New Caledonia', 'NC'] ,
+ ['New Zealand', 'NZ'] ,
+ ['Nicaragua', 'NI'] ,
+ ['Niger', 'NE'] ,
+ ['Nigeria', 'NG'] ,
+ ['Niue', 'NU'] ,
+ ['Norfolk Island', 'NF'] ,
+ ['Northern Mariana Islands', 'MP'] ,
+ ['Norway', 'NO'] ,
+ ['Oman', 'OM'] ,
+ ['Pakistan', 'PK'] ,
+ ['Palau', 'PW'] ,
+ ['Palestinian Territory, Occupied', 'PS'] ,
+ ['Panama', 'PA'] ,
+ ['Papua New Guinea', 'PG'] ,
+ ['Paraguay', 'PY'] ,
+ ['Peru', 'PE'] ,
+ ['Philippines', 'PH'] ,
+ ['Pitcairn', 'PN'] ,
+ ['Poland', 'PL'] ,
+ ['Portugal', 'PT'] ,
+ ['Puerto Rico', 'PR'] ,
+ ['Qatar', 'QA'] ,
+ ['Reunion', 'RE'] ,
+ ['Romania', 'RO'] ,
+ ['Russian Federation', 'RU'] ,
+ ['Rwanda', 'RW'] ,
+ ['Saint Helena', 'SH'] ,
+ ['Saint Kitts And Nevis', 'KN'] ,
+ ['Saint Lucia', 'LC'] ,
+ ['Saint Pierre And Miquelon', 'PM'] ,
+ ['Saint Vincent And The Grenadines', 'VC'] ,
+ ['Samoa', 'WS'] ,
+ ['San Marino', 'SM'] ,
+ ['Sao Tome And Principe', 'ST'] ,
+ ['Saudi Arabia', 'SA'] ,
+ ['Senegal', 'SN'] ,
+ ['Serbia', 'RS'] ,
+ ['Seychelles', 'SC'] ,
+ ['Sierra Leone', 'SL'] ,
+ ['Singapore', 'SG'] ,
+ ['Slovakia', 'SK'] ,
+ ['Slovenia', 'SI'] ,
+ ['Solomon Islands', 'SB'] ,
+ ['Somalia', 'SO'] ,
+ ['South Africa', 'ZA'] ,
+ ['South Georgia And The South Sandwich Islands', 'GS'] ,
+ ['Spain', 'ES'] ,
+ ['Sri Lanka', 'LK'] ,
+ ['Sudan', 'SD'] ,
+ ['Suriname', 'SR'] ,
+ ['Svalbard And Jan Mayen', 'SJ'] ,
+ ['Swaziland', 'SZ'] ,
+ ['Sweden', 'SE'] ,
+ ['Switzerland', 'CH'] ,
+ ['Syrian Arab Republic', 'SY'] ,
+ ['Taiwan, Province Of China', 'TW'] ,
+ ['Tajikistan', 'TJ'] ,
+ ['Tanzania, United Republic Of', 'TZ'] ,
+ ['Thailand', 'TH'] ,
+ ['Timor-leste', 'TL'] ,
+ ['Togo', 'TG'] ,
+ ['Tokelau', 'TK'] ,
+ ['Tonga', 'TO'] ,
+ ['Trinidad And Tobago', 'TT'] ,
+ ['Tunisia', 'TN'] ,
+ ['Turkey', 'TR'] ,
+ ['Turkmenistan', 'TM'] ,
+ ['Turks And Caicos Islands', 'TC'] ,
+ ['Tuvalu', 'TV'] ,
+ ['Uganda', 'UG'] ,
+ ['Ukraine', 'UA'] ,
+ ['United Arab Emirates', 'AE'] ,
+ ['United Kingdom', 'GB'] ,
+ ['United States', 'US'] ,
+ ['United States Minor Outlying Islands', 'UM'] ,
+ ['Uruguay', 'UY'] ,
+ ['Uzbekistan', 'UZ'] ,
+ ['Vanuatu', 'VU'] ,
+ ['Venezuela', 'VE'] ,
+ ['Viet Nam', 'VN'] ,
+ ['Virgin Islands, British', 'VG'] ,
+ ['Virgin Islands, U.s.', 'VI'] ,
+ ['Wallis And Futuna', 'WF'] ,
+ ['Western Sahara', 'EH'] ,
+ ['Yemen', 'YE'] ,
+ ['Zambia', 'ZM'] ,
+ ['Zimbabwe', 'ZW']
+ ]
+ def __init__(self):
+ ListBox.__init__(self)
+ self.addCountries()
+
+ def addCountries(self):
+ for countryItem in self.country_list:
+ self.addItem(countryItem[0], countryItem[1])
View
23 addons/EventDelegate.py
@@ -0,0 +1,23 @@
+from __pyjamas__ import JS
+
+class EventDelegate:
+ """
+ Create the equivalent of a bound method. This also prepends extra
+ args, if any, to the called method's argument list when it calls it.
+
+ Pass the method name you want to implement (javascript doesn't
+ support callables).
+
+ @type args: list
+ @param args: If given, the arguments will be prepended to the
+ arguments passed to the event callback
+ """
+ def __init__(self, eventMethodName, obj, method, *args):
+ self.obj = obj
+ self.method = method
+ self.args = args
+ JS("this[eventMethodName] = this.onEvent;")
+
+ def onEvent(self, *args):
+ self.method.apply(self.obj, self.args.l.concat(args.l))
+
View
131 addons/RichTextEditor.py
@@ -0,0 +1,131 @@
+"""
+ A rich text editor using FCKeditor.
+
+ Pass "-j fckeditor/fckeditor.js" to build.py in order to include the FCKeditor
+ javascript.
+"""
+import Window
+import DOM
+from __pyjamas__ import console
+from BoundMethod import BoundMethod
+from ui import Widget
+
+from __pyjamas__ import JS
+
+def createFCK(name):
+ JS("""
+ return new FCKeditor(name);
+ """)
+
+JS("""
+ $wnd.FCKeditor_OnComplete = function(editorInstance )
+ {
+ pyjsObject = $doc.getElementById(editorInstance.Name.substr(3)).__listener;
+ console.log("pyjsObject is %o", pyjsObject);
+ if(pyjsObject)
+ pyjsObject.onFCKLoaded(editorInstance);
+ }
+""")
+class RichTextEditor(Widget):
+ def __init__(self, initialValue="", target="", method="POST"):
+ Widget.__init__(self);
+ self.id = "rte"+hash(self)
+ fck = createFCK("fck"+self.id)
+ fck.Height = "600px"
+ self.setElement(DOM.createForm())
+ DOM.setAttribute(self.element, "method", "POST")
+ DOM.setAttribute(self.element, "target", target)
+ JS("""
+ var rte = this;
+ this.element.onsubmit = function() {
+ $wnd.setTimeout(function() { rte.onSave.call(rte) }, 0);
+ return false;
+ }
+ """)
+ self.setID(self.id)
+ self.addStyleName("gwt-RichTextEditor")
+ fck.Value = initialValue
+ fck.BasePath = "fckeditor/"
+ fck.Config.CustomConfigurationsPath = "../../fckconfig.js"
+ fck.pyjsObject = self
+ self.loaded = False
+ self.saveListeners = []
+ self.pendingHTML = None
+ html = fck.CreateHtml()
+ #console.log("fck html = %s", html)
+ html = html
+ DOM.setInnerHTML(self.getElement(), html)
+
+ def addSaveListener(self, listener):
+ """
+ When the user clicks the save button, your listener will be notified.
+
+ Either pass a function (e.g. a BoundMethod) or an object with an onSave()
+ method. Either will be passed the RichtTextEditor instance.
+ """
+ self.saveListeners.append(listener)
+
+ def removeSaveListener(self, listener):
+ """
+ Remove a previously added listener
+ """
+ self.saveListeners.remove(listener)
+
+ def onFCKLoaded(self, fck):
+ """
+ Called when the FCK editor has loaded, and it is ready for use
+ """
+ self.loaded = True
+ self.fck = fck
+ fck.Events.AttachEvent('OnSelectionChange', BoundMethod(self, self.onSelectionChange))
+ fck.Events.AttachEvent('OnBlur', BoundMethod(self, self.onBlur))
+ fck.Events.AttachEvent('OnFocus', BoundMethod(self, self.onFocus))
+ fck.Events.AttachEvent('OnPaste', BoundMethod(self, self.onPaste))
+ if self.pendingHTML:
+ fck.SetHTML(self.pendingHTML)
+ self.pendingHTML = None
+
+ def onSelectionChange(self, sender):
+ pass#console.log("onSelectionChange!")
+
+ def onBlur(self, sender):
+ pass#console.log("onBlur!")
+
+ def onFocus(self, sender):
+ pass#console.log("onFocus!")
+
+ def onPaste(self, sender):
+ pass#console.log("onPaste!")
+
+ def onSave(self):
+ """
+ Handle the save click and pass it onto the listeners
+ """
+ console.log("onSave() in %s", Window.getLocation().getHref())
+ for listener in self.saveListeners:
+ if listener.onSave: listener.onSave(self)
+ else: listener(self)
+ return False
+
+ def setHTML(self, html):
+ """
+ Call this to change the html showing in the editor
+ """
+ if self.loaded:
+ self.fck.SetHTML(html);
+ else:
+ self.pendingHTML = html
+
+ def getHTML(self):
+ """
+ Call this to retrieve the HTML showing in the editor (e.g. to save/preview it)
+ """
+ return self.fck.GetXHTML(True)
+
+ def getDOM(self):
+ return self.fck.EditorDocument()
+
+ def getWindow(self):
+ return self.fck.EditorWindow()
+
+
View
330 addons/TemplatePanel.py
@@ -0,0 +1,330 @@
+from __pyjamas__ import unescape
+from RichTextEditor import RichTextEditor
+import Window
+from __pyjamas__ import encodeURIComponent
+from EventDelegate import EventDelegate
+from ui import Label
+from pyjslib import List
+from ui import ComplexPanel
+from __pyjamas__ import console
+from HTTPRequest import HTTPRequest
+from ui import HTML, SimplePanel
+import DOM
+
+class TemplateLoader:
+ def __init__(self, panel, url):
+ self.panel = panel
+
+ def onCompletion(self, text):
+ self.panel.setTemplateText(text)
+
+ def onError(self, text, code):
+ self.panel.onError(text, code)
+
+ def onTimeout(self, text):
+ self.panel.onTimeout(text)
+
+class ContentSaveHandler:
+ def __init__(self, templatePanel):
+ self.templatePanel = templatePanel
+
+ def onCompletion(self):
+ self.templatePanel.onSaveComplete()
+
+ def onError(self, error):
+ Window.alert("Save failed: "+error)
+
+class PendingAttachOrInsert:
+ def __init__(self, name, widget):
+ self.name = name
+ self.widget = widget
+
+class TemplatePanel(ComplexPanel):
+ """
+ Panel which allows you to attach or insert widgets into
+ a pre-defined template.
+
+ We don't do any caching of our own, since the browser will
+ do caching for us, and probably more efficiently.
+ """
+ templateRoot = ""
+ """Set staticRoot to change the base path of all the templates that are loaded; templateRoot should have a trailing slash"""
+
+ def __init__(self, templateName, allowEdit=False):
+ ComplexPanel.__init__(self)
+ self.loaded = False # Set after widgets are attached
+ self.widgetsAttached = False
+ self.id = None
+ self.templateName = None
+ self.title = None
+ self.elementsById = {}
+ self.metaTags = {}
+ self.body = None
+ self.links = []
+ self.forms = []
+ self.metaTagList = []
+ self.loadListeners = []
+ self.toAttach = []
+ self.toInsert = []
+ self.setElement(DOM.createDiv())
+ self.editor = None
+ self.allowEdit = allowEdit
+ if templateName:
+ self.loadTemplate(templateName)
+
+ def getTemplatePath(self, templateName):
+ return self.templateRoot+'tpl/'+templateName+'.html'
+
+ def loadTemplate(self, templateName):
+ self.templateName = templateName
+ self.id = templateName + str(hash(self))
+ self.httpReq = HTTPRequest()
+ self.httpReq.asyncGet(self.getTemplatePath(templateName), TemplateLoader(self))
+
+ def getCurrentTemplate(self):
+ """Return the template that is currently loaded, or is loading"""
+ return self.templateName
+
+ def isLoaded(self):
+ """Return True if the template is finished loading"""
+ return self.loaded
+
+ def areWidgetsAttached(self):
+ """Return True if the template is loaded and attachWidgets() has been called"""
+ return self.widgetsAttached
+
+ def setTemplateText(self, text):
+ """
+ Set the template text; if the template is not HTML, a subclass could override this
+ to pre-process the text into HTML before passing it to the default implementation.
+ """
+ if self.allowEdit:
+ self.originalText = text
+ # If we have children, remove them all first since we are trashing their DOM
+ for child in List(self.children):
+ self.remove(child)
+
+ DOM.setInnerHTML(self.getElement(), text)
+ self.elementsById = {}
+ self.links = []
+ self.metaTags = {}
+ self.forms = []
+ self.metaTagList = []
+
+ # Make the ids unique and store a pointer to each named element
+ for node in DOM.walkChildren(self.getElement()):
+ #console.log("Passing node with name %s", node.nodeName)
+ if node.nodeName == "META":
+ name = node.getAttribute("name")
+ content = node.getAttribute("content")
+ console.log("Found meta %o name %s content %s", node, name, content)
+ self.metaTags[name] = content
+ self.metaTagList.append(node)
+ elif node.nodeName == "BODY":
+ self.body = node
+ elif node.nodeName == "TITLE":
+ self.title = DOM.getInnerText(node)
+ elif node.nodeName == "FORM":
+ self.forms.append(node)
+
+ nodeId = DOM.getAttribute(node, "id")
+ if nodeId:
+ self.elementsById[nodeId] = node
+ DOM.setAttribute(node, "id", self.id+":"+node.id)
+ nodeHref = DOM.getAttribute(node, "href")
+ if nodeHref:
+ self.links.append(node)
+
+ self.loaded = True
+ if self.attached:
+ self.attachWidgets()
+ self.widgetsAttached = True
+
+ if self.allowEdit:
+ self.editor = None
+ self.editButton = Label("edit "+unescape(self.templateName))
+ self.editButton.addStyleName("link")
+ self.editButton.addStyleName("ContentPanelEditLink")
+ self.editButton.addClickListener(EventDelegate("onClick", self, self.onEditContentClick))
+ ComplexPanel.insert(self, self.editButton, self.getElement(), len(self.children))
+
+ self.notifyLoadListeners()
+
+ def onError(self, html, statusCode):
+ if statusCode == 404 and self.allowEdit:
+ self.editor = None
+ self.originalText = ""
+ DOM.setInnerHTML(self.getElement(), '')
+ self.editButton = Label("create "+unescape(self.templateName))
+ self.editButton.addStyleName("link")
+ self.editButton.addStyleName("ContentPanelEditLink")
+ self.editButton.addClickListener(EventDelegate("onClick", self, self.onEditContentClick))
+ ComplexPanel.insert(self, self.editButton, self.getElement(), len(self.children))
+ return
+
+ # Show the page we got in an iframe, which will hopefully show the error better than we can.
+ # DOM.setInnerHTML(self.getElement(), '<iframe src="'+self.getTemplatePath(self.templateName)+'"/>')
+
+ def onTimeout(self, text):
+ self.onError("Page loading timed out: "+text)
+
+ def getElementsById(self):
+ """Return a dict mapping an id to an element with that id inside the template; useful for post-processing"""
+ return self.elementsById
+
+ def getLinks(self):
+ """Return a list of all the A HREF= elements found in the template."""
+ return self.links
+
+ def getForms(self):
+ """Return a list of all the FORM elements found in the template."""
+ return self.forms
+
+ def onAttach(self):
+ if not self.attached:
+ SimplePanel.onAttach(self)
+ if self.loaded and not self.widgetsAttached:
+ self.attachWidgets()
+ self.widgetsAttached = True
+
+ def attachWidgets(self):
+ """
+ Attach and insert widgets into the DOM now that it has been loaded. If any
+ widgets were attached before loading, they will have been queued and the
+ default implementation will attach them.
+
+ Override this in subclasses to attach your own widgets after loading.
+ """
+ for attach in self.toAttach:
+ self.attach(attach.name, attach.widget)
+ for insert in self.toInsert:
+ self.insert(insert.name, insert.widget)
+
+ def getElementById(self, id):
+ return self.elementsById[id]
+
+ def insert(self, id, widget):
+ """
+ Insert a widget into the element with the given id, at the end
+ of its children.
+ """
+ if not self.loaded:
+ self.toInsert.append(PendingAttachOrInsert(id, widget))
+ else:
+ element = self.getElementById(id)
+ if element:
+ self.adopt(widget, element)
+ self.children.append(widget)
+ else:
+ console.error("Page error: No such element "+id)
+ return widget
+
+ def attachToElement(self, element, widget):
+ events = DOM.getEventsSunk(widget.getElement())
+ widget.unsinkEvents(events)
+ widget.setElement(element)
+ widget.sinkEvents(events)
+ self.adopt(widget, None)
+ self.children.append(widget)
+
+ def replaceElement(self, element, widget):
+ """
+ Replace an existing element with the given widget
+ """
+ DOM.getParent(element).replaceChild(widget.getElement(), element)
+ self.adopt(widget, None)
+ self.children.append(widget)
+
+ def attach(self, id, widget):
+ """
+ Attach a widget onto the element with the given id; the element
+ currently associated with the widget is discarded.
+ """
+ if not self.loaded:
+ self.toAttach.append(PendingAttachOrInsert(id, widget))
+ else:
+ element = self.getElementById(id)
+ if element:
+ self.attachToElement(element, widget)
+ else:
+ console.error("Page error: No such element "+id)
+ return widget
+
+ def getMeta(self, name):
+ """
+ Get the value of a meta-variable found in the template, or None if
+ no meta tags were found with the given name.
+ """
+ return self.metaTags.get(name)
+
+ def getTitle(self):
+ """
+ Return a user-friendly title for the page
+ """
+ if self.title: return self.title
+ else: return self.templateName
+
+ def addLoadListener(self, listener):
+ """
+ The listener should be a function or an object implementing onTemplateLoaded.
+ It will be called this TemplatePanel instance after the template has been
+ loaded and after attachWidgets() is called.
+ """
+ self.loadListeners.append(listener)
+
+ def removeLoadListener(self, listener):
+ self.loadListeners.remove(listener)
+
+ def notifyLoadListeners(self):
+ for listener in self.loadListeners:
+ if listener.onTemplateLoaded: listener.onTemplateLoaded(self)
+ else: listener(self)
+
+ def onEditContentClick(self, sender):
+ if self.editor:
+ editor = self.editor
+ self.editor = None
+ ComplexPanel.remove(self, editor)
+ self.editButton.setText("edit "+unescape(self.templateName))
+ else:
+ self.editor = RichTextEditor(self.originalText)
+ self.editor.addSaveListener(self)
+ ComplexPanel.insert(self, self.editor, self.getElement(), len(self.children))
+ self.editButton.setText("close editor")
+
+ def getTemplateSaveUrl(self, templateName):
+ """
+ Get the URL to post a template to when it is saved in the editor.
+ """
+ return self.getTemplatePath(templateName)
+
+ def saveTemplateText(self, html):
+ """
+ Save the text. This method can be overridden to use a different
+ save method. The default is to POST to the template save URL, passing
+ a single parameter "content" with the html string.
+
+ To change the target of the POST, override getTemplateSaveUrl().
+
+ To preprocess the html, override this method in a subclass and perform
+ processing there.
+ """
+ HTTPRequest().asyncPost(self.getTemplateSaveUrl(self.templateName),
+ "content="+encodeURIComponent(html),
+ ContentSaveHandler(self))
+ def onSave(self, sender):
+ """
+ Called when the user clicks save in the content editor.
+ """
+ html = self.editor.getHTML()
+ self.saveTemplateText(html)
+
+ def onSaveComplete(self):
+ """
+ Called when the template was successfully POSTed to the server; it reloads the template.
+
+ Subclasses which don't use the default method of saving may want to call this after
+ they successfully save the template.
+ """
+ self.loadTemplate(self.templateName)
+
View
107 addons/Tooltip.py
@@ -0,0 +1,107 @@
+# Tooltip component for Pyjamas
+# Ported by Willie Gollino from Tooltip component for GWT - Originally by Alexei Sokolov http://gwt.components.googlepages.com/
+
+from ui import PopupPanel, HTML, RootPanel
+from Timer import Timer
+
+tooltip_hide_timer = None
+
+class Tooltip(PopupPanel):
+ def __init__(self, sender, offsetX, offsetY, text, show_delay, hide_delay, styleName):
+ global tooltip_hide_timer
+
+ PopupPanel.__init__(self, True)
+ self.show_delay = show_delay
+ self.hide_delay = hide_delay
+
+ contents = HTML(text)
+ self.add(contents)
+
+ left = sender.getAbsoluteLeft() + offsetX
+ top = sender.getAbsoluteTop() + offsetY
+
+ self.setPopupPosition(left, top)
+ self.setStyleName(styleName)
+
+ if tooltip_hide_timer:
+ self.tooltip_show_timer = Timer(1, self)
+ else:
+ self.tooltip_show_timer = Timer(self.show_delay, self)
+
+ def show(self):
+ global tooltip_hide_timer
+
+ # activate fast tooltips
+ tooltip_hide_timer=Timer(self.hide_delay, self)
+ PopupPanel.show(self)
+
+ def hide(self):
+ self.tooltip_show_timer.cancel()
+ PopupPanel.hide(self)
+
+ def onTimer(self, id):
+ global tooltip_hide_timer
+
+ # deactivate fast tooltips on last timer
+ if tooltip_hide_timer and id == tooltip_hide_timer.getID():
+ tooltip_hide_timer = None
+
+ if id == self.tooltip_show_timer.getID():
+ self.show()
+ else:
+ self.hide()
+
+
+class TooltipListener:
+ DEFAULT_TOOLTIP_STYLE = "TooltipPopup"
+ DEFAULT_OFFSET_X = 10
+ DEFAULT_OFFSET_Y = 35
+
+ def __init__(self, text, show_delay = 1000, hide_delay = 5000, styleName = ""):
+ if not styleName:
+ styleName = TooltipListener.DEFAULT_TOOLTIP_STYLE
+
+ self.tooltip = None
+ self.text = text
+ self.styleName = styleName
+ self.show_delay = show_delay
+ self.hide_delay = hide_delay
+ self.offsetX = TooltipListener.DEFAULT_OFFSET_X
+ self.offsetY = TooltipListener.DEFAULT_OFFSET_Y
+
+ def onMouseEnter(self, sender):
+ if self.tooltip != None:
+ self.tooltip.hide()
+ self.tooltip = Tooltip(sender, self.offsetX, self.offsetY, self.text, self.show_delay, self.hide_delay, self.styleName)
+
+ def onMouseLeave(self, sender):
+ if self.tooltip != None:
+ self.tooltip.hide()
+
+ def onMouseMove(self, sender, x, y):
+ pass
+
+ def onMouseDown(self, sender, x, y):
+ pass
+
+ def onMouseUp(self, sender, x, y):
+ pass
+
+ def getStyleName(self):
+ return self.styleName
+
+ def setStyleName(self, styleName):
+ self.styleName = styleName
+
+ def getOffsetX(self):
+ return self.offsetX
+
+ def setOffsetX(self, offsetX):
+ self.offsetX = offsetX
+
+ def getOffsetY(self):
+ return self.offsetY
+
+ def setOffsetY(self, offsetY):
+ self.offsetY = offsetY
+
View
99 addons/datetime.py
@@ -0,0 +1,99 @@
+class Datetime:
+ def __init__(self, year=None, month=None, date=None, hours=None, minutes=None, seconds=None):
+ JS("""
+ if (seconds != null)
+ this.date = new Date(year, month, date, hours, minutes, seconds);
+ else if (minutes != null)
+ this.date = new Date(year, month, date, hours, minutes);
+ else if (hours != null)
+ this.date = new Date(year, month, date, hours);
+ else if (date != null)
+ this.date = new Date(year, month, date);
+ else if (month != null)
+ this.date = new Date(year, month);
+ else if (year != null)
+ this.date = new Date(year);
+ else
+ this.date = new Date();
+ """)
+
+ def getDate(self):
+ JS("""
+ return this.date.getDate();
+ """)
+
+ def getDay(self):
+ JS("""
+ return this.date.getDay();
+ """)
+
+ def getHours(self):
+ JS("""
+ return this.date.getHours();
+ """)
+
+ def getMinutes(self):
+ JS("""
+ return this.date.getMinutes();
+ """)
+
+ def getMonth(self):
+ JS("""
+ return this.date.getMonth();
+ """)
+
+ def getSeconds(self):
+ JS("""
+ return this.date.getSeconds();
+ """)
+
+ def getTime(self):
+ JS("""
+ return this.date.getTime();
+ """)
+
+ def getYear(self):
+ JS("""
+ return this.date.getYear();
+ """)
+
+ def setDate(self, value):
+ JS("""
+ this.date.setDate(value);
+ """)
+
+ def setDay(self, value):
+ JS("""
+ this.date.setDay(value);
+ """)
+
+ def setHours(self, value):
+ JS("""
+ this.date.setHours(value);
+ """)
+
+ def setMinutes(self, value):
+ JS("""
+ this.date.setMinutes(value);
+ """)
+
+ def setMonth(self, value):
+ JS("""
+ this.date.setMonth(value);
+ """)
+
+ def setSeconds(self, value):
+ JS("""
+ this.date.setSeconds(value);
+ """)
+
+ def setTime(self, value):
+ JS("""
+ this.date.setTime(value);
+ """)
+
+ def setYear(self, value):
+ JS("""
+ this.date.setYear(value);
+ """)
+
View
39 builder/boilerplate/all.cache.html
@@ -0,0 +1,39 @@
+<html>
+<head>
+<script>
+var $wnd = parent;
+var $doc = $wnd.document;
+var $moduleName = "%(app_name)s";
+</script>
+%(app_headers)s
+</head>
+<body onload="if (parent && parent.__pygwt_webModeFrameOnLoad) parent.__pygwt_webModeFrameOnLoad(window, '%(app_name)s');">
+<font face='arial' size='-1'>This script is part of module</font> <code>%(app_name)s</code>
+
+%(app_body)s
+
+<script><!--
+
+%(app_libs)s
+%(app_code)s
+
+function run() {
+ app = new %(app_name)s();
+ app.onModuleLoad();
+}
+
+function pygwtOnLoad(onLoadError, name) {
+ if (onLoadError)
+ try {
+ run();
+ } catch (exception) {
+ onLoadError(name);
+ }
+ else {
+ run();
+ }
+}
+
+--></script>
+</body>
+</html>
View
23 builder/boilerplate/app.html
@@ -0,0 +1,23 @@
+<html>
+<head>
+<title>Pyjamas application code</title>
+<script type="text/javascript">
+__window = parent;
+__navigator = __window.navigator;
+__screen = __window.screen;
+__history = __window.history;
+__location = __window.location;
+__document = __window.document;
+
+%(app_code)s
+
+try {
+ _%(app_name)s_%(app_name)s([],{}).onModuleLoad([],{});
+} catch(e) {
+ if (e != 'ReferenceError') throw e;
+}
+
+</script>
+</head>
+<body>This page can't be viewed without an application loader.</body>
+</html>
View
20 builder/boilerplate/history.html
@@ -0,0 +1,20 @@
+<html>
+<head>
+<script>
+function hst() {
+ var search = location.search;
+ var historyToken = '';
+ if (location.search.length > 0)
+ historyToken = decodeURIComponent(location.search.substring(1));
+
+ document.getElementById('__historyToken').value = historyToken;
+ if (parent.__onHistoryChanged)
+ parent.__onHistoryChanged(historyToken);
+}
+</script></head>
+<body onload='hst()'>
+
+<input type='text' id='__historyToken'>
+
+</body>
+</html>
View
79 builder/boilerplate/home.nocache.html
@@ -0,0 +1,79 @@
+<html><head><script>
+
+window["provider$user.agent"] = function() {
+ var ua = navigator.userAgent.toLowerCase();
+ if (ua.indexOf('opera') != -1) {
+ return 'opera';
+ }
+ else if (ua.indexOf('safari') != -1) {
+ return 'safari';
+ }
+ else if (ua.indexOf('msie 6.0') != -1) {
+ return 'ie6';
+ }
+ else if (ua.indexOf('msie 7.0') != -1) {
+ return 'ie6';
+ }
+ else if (ua.indexOf('mozilla') != -1) {
+ var geckoIdx = ua.indexOf('gecko/');
+ if (geckoIdx == -1)
+ return 'oldmoz';
+ var spaceIdx = ua.indexOf(' ', geckoIdx);
+ if (spaceIdx == -1)
+ spaceIdx = ua.length;
+ var version = parseInt(ua.substring(geckoIdx + 6, spaceIdx));
+ if (version < 20051107)
+ return 'oldmoz';
+ return 'moz';
+ }
+ return 'unknown';
+}
+;
+
+window["prop$user.agent"] = function() {
+ var v = window["provider$user.agent"]();
+ switch (v) {
+ case "ie6":
+ case "moz":
+ case "oldmoz":
+ case "opera":
+ case "safari":
+ return v;
+ default:
+ parent.__pygwt_onBadProperty("%(app_name)s", "user.agent", ['"ie6"', '"moz"', '"oldmoz"', '"opera"', '"safari"'], v);
+ throw null;
+ }
+};
+
+function O(a,v) {
+ var answer = O.answers;
+ var i = -1;
+ var n = a.length - 1;
+ while (++i < n) {
+ if (!(a[i] in answer)) {
+ answer[a[i]] = [];
+ }
+ answer = answer[a[i]];
+ }
+ answer[a[n]] = v;
+}
+O.answers = [];
+
+function selectScript() {
+ try {
+ var F;
+ var I = ["true", (F=window["prop$user.agent"],F())];
+
+ O(["true","safari"],"%(safari_js)s");
+ O(["true","ie6"],"%(ie6_js)s");
+ O(["true","oldmoz"],"%(oldmoz_js)s");
+ O(["true","moz"],"%(moz_js)s");
+ O(["true","opera"],"%(opera_js)s");
+
+ var strongName = O.answers[I[0]][I[1]];
+ location.replace(strongName + '.cache.html');
+ } catch (e) {
+ // intentionally silent on property failure
+ }
+}
+</script></head><body onload='if (parent && parent.__pygwt_webModeFrameOnLoad) selectScript()'><font face='arial' size='-1'>This script is part of module</font> <code>%(app_name)s</code></body></html>
View
51 builder/boilerplate/index.html
@@ -0,0 +1,51 @@
+<html>
+<head>
+<title>%(app_name)s</title>
+<script type="text/javascript">
+function __get_user_agent() {
+ var ua = navigator.userAgent.toLowerCase();
+ if (ua.indexOf('opera') != -1) {
+ return 'opera';
+ } else if (ua.indexOf('safari') != -1) {
+ return 'safari';
+ } else if (ua.indexOf('msie 6.0') != -1) {
+ return 'ie6';
+ } else if (ua.indexOf('msie 7.0') != -1) {
+ return 'ie6';
+ } else if (ua.indexOf('mozilla') != -1) {
+ var geckoIdx = ua.indexOf('gecko/');
+ if (geckoIdx == -1) return 'oldmoz';
+ var spaceIdx = ua.indexOf(' ', geckoIdx);
+ if (spaceIdx == -1) spaceIdx = ua.length;
+ var version = parseInt(ua.substring(geckoIdx + 6, spaceIdx));
+ if (version < 20051107) return 'oldmoz';
+ return 'moz';
+ }
+ return 'unknown';
+}
+
+function __load_app(name) {
+ document.body.innerHTML = '';
+}
+
+function __load_iframe() {
+ var loader_id = 'loader';
+ var __user_agent = __get_user_agent();
+ var iframe = document.createElement('iframe');
+ iframe.src = '%(app_name)s' + '_' + __user_agent + '.html';
+ iframe.onload = __load_app(loader_id);
+ iframe.style.visibility = 'hidden';
+ iframe.style.position = 'absolute';
+ iframe.style.width = '0px';
+ iframe.style.height = '0px';
+ document.body.appendChild(iframe);
+}
+
+</script>
+</head>
+<body style="margin: 0px;" onload="__load_iframe()">
+ <span style="background: #D00; padding: 4px; font-size: 10pt; color: white; font-weight: bold;">
+ Loading ...
+ </span>
+</body>
+</html>
View
156 builder/boilerplate/pygwt.js
@@ -0,0 +1,156 @@
+// this is almost directly taken from Google's GWT which is now open source
+
+var __PYGWT_JS_INCLUDED;
+
+if (!__PYGWT_JS_INCLUDED) {
+ __PYGWT_JS_INCLUDED = true;
+
+var __pygwt_retryWaitMs = 50;
+var __pygwt_moduleNames = [];
+var __pygwt_isHostPageLoaded = false;
+var __pygwt_onLoadError = null;
+
+
+function __pygwt_processMetas() {
+ var metas = document.getElementsByTagName("meta");
+ for (var i = 0, n = metas.length; i < n; ++i) {
+ var meta = metas[i];
+ var name = meta.getAttribute("name");
+ if (name) {
+ if (name == "pygwt:module") {
+ var content = meta.getAttribute("content");
+ if (content) {
+ __pygwt_moduleNames = __pygwt_moduleNames.concat(content);
+ }
+ }
+ }
+ }
+}
+
+
+function __pygwt_forEachModule(lambda) {
+ for (var i = 0; i < __pygwt_moduleNames.length; ++i) {
+ lambda(__pygwt_moduleNames[i]);
+ }
+}
+
+
+// When nested IFRAMEs load, they reach up into the parent page to announce that
+// they are ready to run. Because IFRAMEs load asynchronously relative to the
+// host page, one of two things can happen when they reach up:
+// (1) The host page's onload handler has not yet been called, in which case we
+// retry until it has been called.
+// (2) The host page's onload handler has already been called, in which case the
+// nested IFRAME should be initialized immediately.
+//
+function __pygwt_webModeFrameOnLoad(iframeWindow, name) {
+ var moduleInitFn = iframeWindow.pygwtOnLoad;
+ if (__pygwt_isHostPageLoaded && moduleInitFn) {
+ var old = window.status;
+ window.status = "Initializing module '" + name + "'";
+ try {
+ moduleInitFn(__pygwt_onLoadError, name);
+ } finally {
+ window.status = old;
+ }
+ } else {
+ setTimeout(function() { __pygwt_webModeFrameOnLoad(iframeWindow, name); }, __pygwt_retryWaitMs);
+ }
+}
+
+
+function __pygwt_hookOnLoad() {
+ var oldHandler = window.onload;
+ window.onload = function() {
+ __pygwt_isHostPageLoaded = true;
+ if (oldHandler) {
+ oldHandler();
+ }
+ };
+}
+
+
+// Returns an array that splits the module name from the meta content into
+// [0] the prefix url, if any, guaranteed to end with a slash
+// [1] the dotted module name
+//
+function __pygwt_splitModuleNameRef(moduleName) {
+ var parts = ['', moduleName];
+ var i = moduleName.lastIndexOf("=");
+ if (i != -1) {
+ parts[0] = moduleName.substring(0, i) + '/';
+ parts[1] = moduleName.substring(i+1);
+ }
+ return parts;
+}
+
+
+//////////////////////////////////////////////////////////////////
+// Called directly from compiled code
+//
+function __pygwt_initHandlers(resize, beforeunload, unload) {
+ var oldOnResize = window.onresize;
+ window.onresize = function() {
+ resize();
+ if (oldOnResize)
+ oldOnResize();
+ };
+
+ var oldOnBeforeUnload = window.onbeforeunload;
+ window.onbeforeunload = function() {
+ var ret = beforeunload();
+
+ var oldRet;
+ if (oldOnBeforeUnload)
+ oldRet = oldOnBeforeUnload();
+
+ if (ret !== null)
+ return ret;
+ return oldRet;