1.1 --- a/EventAggregatorSupport.py Wed Aug 10 01:03:14 2011 +0200
1.2 +++ b/EventAggregatorSupport.py Wed Aug 31 01:56:22 2011 +0200
1.3 @@ -332,6 +332,17 @@
1.4 parts = header.split(":")
1.5 self.request.headers.add(parts[0], ":".join(parts[1:]))
1.6
1.7 +def get_send_headers(request):
1.8 +
1.9 + "Return a function that can send response headers."
1.10 +
1.11 + if hasattr(request, "http_headers"):
1.12 + return request.http_headers
1.13 + elif hasattr(request, "emit_http_headers"):
1.14 + return request.emit_http_headers
1.15 + else:
1.16 + return send_headers_cls(request)
1.17 +
1.18 def escattr(s):
1.19 return escape(s, 1)
1.20
2.1 --- a/README.txt Wed Aug 10 01:03:14 2011 +0200
2.2 +++ b/README.txt Wed Aug 31 01:56:22 2011 +0200
2.3 @@ -89,6 +89,21 @@
2.4
2.5 @import "event-aggregator.css";
2.6
2.7 +Optional Installation Tasks
2.8 +---------------------------
2.9 +
2.10 +To add the capability of aggregating iCalendar format event sources, the
2.11 +vContent software needs to be obtained and installed. See the "Recommended
2.12 +Software" section below for details.
2.13 +
2.14 +The following command can be run with $VCDIR referring to the vContent
2.15 +distribution directory:
2.16 +
2.17 + python moinsetup.py -f moinsetup.cfg install_extension_package $VCDIR
2.18 +
2.19 +This merely runs the setup.py script provided by that software, installing
2.20 +the software under the configured installation "prefix".
2.21 +
2.22 Useful Pages
2.23 ------------
2.24
2.25 @@ -101,7 +116,9 @@
2.26 python moinsetup.py -f moinsetup.cfg install_page_package pages.zip
2.27
2.28 You may need to switch user in order to have sufficient privileges to copy the
2.29 -page package into the Wiki.
2.30 +page package into the Wiki. For example:
2.31 +
2.32 + sudo -u www-data python moinsetup.py -f moinsetup.cfg install_page_package pages.zip
2.33
2.34 Resource Pages
2.35 --------------
2.36 @@ -119,7 +136,9 @@
2.37 python moinsetup.py -f moinsetup.cfg install_page_package resource_pages.zip
2.38
2.39 You may need to switch user in order to have sufficient privileges to copy the
2.40 -page package into the Wiki.
2.41 +page package into the Wiki. For example:
2.42 +
2.43 + sudo -u www-data python moinsetup.py -f moinsetup.cfg install_page_package resource_pages.zip
2.44
2.45 Using the Macro
2.46 ---------------
2.47 @@ -160,6 +179,10 @@
2.48 Running the Scripts
2.49 -------------------
2.50
2.51 +Note that remote event sources are likely to be more useful than the scripts
2.52 +described below. However, these scripts may be useful for certain kinds of
2.53 +application.
2.54 +
2.55 To import events from an RSS feed, the eventfeed script integrated with the
2.56 moin program can be used as follows:
2.57
2.58 @@ -200,6 +223,13 @@
2.59
2.60 http://moinmo.in/HelpOnXapian
2.61
2.62 +The vContent software is required for the parsing of iCalendar information
2.63 +from remote event sources.
2.64 +
2.65 +See the following page for information on vContent:
2.66 +
2.67 +https://hg.boddie.org.uk/vContent
2.68 +
2.69 Troubleshooting
2.70 ---------------
2.71
2.72 @@ -261,6 +291,8 @@
2.73 * Added remote event aggregation with support for iCalendar event sources.
2.74 * Added support for explicit latitude and longitude event properties.
2.75 * Added support for decimal latitude and longitude values.
2.76 + * Introduced in-page updates of the new event form, avoiding full-page
2.77 + reloads when editing the initial details of an event.
2.78
2.79 New in EventAggregator 0.7.1 (Changes since EventAggregator 0.7)
2.80 ----------------------------------------------------------------
3.1 --- a/actions/EventAggregatorNewEvent.py Wed Aug 10 01:03:14 2011 +0200
3.2 +++ b/actions/EventAggregatorNewEvent.py Wed Aug 31 01:56:22 2011 +0200
3.3 @@ -13,6 +13,7 @@
3.4 from MoinMoin.action import ActionBase
3.5 from MoinMoin.Page import Page
3.6 from MoinMoin.PageEditor import PageEditor
3.7 +from MoinMoin import config
3.8 from EventAggregatorSupport import *
3.9
3.10 try:
3.11 @@ -169,6 +170,7 @@
3.12 # Prepare the output HTML.
3.13
3.14 html = '''
3.15 +<input name="update-form-only" value="false" type="hidden" />
3.16 <table>
3.17 <tr>
3.18 <td class="label"><label>%(title_label)s</label></td>
3.19 @@ -445,7 +447,71 @@
3.20 %(buttons_html)s
3.21 </td>
3.22 </tr>
3.23 -</table>''' % d
3.24 +</table>
3.25 +<script type="text/javascript">
3.26 +function replaceDialog(url, button) {
3.27 + var form = findForm();
3.28 + var dialog = findDialog(document);
3.29 + if (form != null && dialog != null) {
3.30 + var xmlhttp = new XMLHttpRequest();
3.31 + xmlhttp.open("POST", url, false);
3.32 + xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3.33 +
3.34 + var requestBody = encodeURIComponent(button.name) + "=" + encodeURIComponent(button.value);
3.35 + for (var i = 0; i < form.elements.length; i++) {
3.36 + var element = form.elements[i];
3.37 + if (element.type != "submit") {
3.38 + requestBody += "&" + encodeURIComponent(element.name) + "=" + encodeURIComponent(element.value);
3.39 + }
3.40 + }
3.41 + xmlhttp.send(requestBody);
3.42 +
3.43 + var newDialog = xmlhttp.responseText;
3.44 +
3.45 + if (newDialog != null) {
3.46 + dialog.parentNode.innerHTML = newDialog;
3.47 + initForm();
3.48 + return false;
3.49 + }
3.50 + }
3.51 +}
3.52 +
3.53 +function findDialog(d) {
3.54 + var elements = d.getElementsByTagName("div");
3.55 + for (var i = 0; i < elements.length; i++) {
3.56 + var element = elements[i];
3.57 + var cls = element.getAttribute("class");
3.58 + if (cls == "dialog") {
3.59 + return element;
3.60 + }
3.61 + }
3.62 + return null;
3.63 +}
3.64 +
3.65 +function findForm() {
3.66 + for (var i = 0; i < document.forms.length; i++) {
3.67 + var form = document.forms[i];
3.68 + if (form["update-form-only"] != null) {
3.69 + return form;
3.70 + }
3.71 + }
3.72 + return null;
3.73 +}
3.74 +
3.75 +function initForm() {
3.76 + var form = findForm();
3.77 + var url = form.getAttribute("action");
3.78 + form["update-form-only"].value = "true";
3.79 + for (var i = 0; i < form.length; i++) {
3.80 + var element = form[i];
3.81 + if (element.type == "submit" && element.name != "doit" && element.name != "cancel") {
3.82 + element.setAttribute("onclick", "return replaceDialog('" + url + "', this);");
3.83 + }
3.84 + }
3.85 +}
3.86 +
3.87 +initForm();
3.88 +</script>''' % d
3.89
3.90 return html
3.91
3.92 @@ -469,12 +535,32 @@
3.93
3.94 return self.create_event(self.request)
3.95
3.96 - def render_success(self, msg, msgtype=None):
3.97 + def render_msg(self, msg, msgtype):
3.98 +
3.99 + """
3.100 + Render 'msg' and 'msgtype'. If 'msgtype' is "dialog" then the form is
3.101 + rendered, and if only part of the form is being requested, the output
3.102 + will be only the form HTML fragment and not the entire page.
3.103 + """
3.104 +
3.105 + # Either render the form as a fragment of a page.
3.106 +
3.107 + print >>open("/tmp/out.txt", "a"), self.get_form().get("update-form-only")
3.108 + if msgtype == "dialog" and self.get_form().get("update-form-only", ["false"])[0] == "true":
3.109 + send_headers = get_send_headers(self.request)
3.110 + send_headers(["Content-Type: text/html; charset=%s" % config.charset])
3.111 + self.request.write(msg.render())
3.112 +
3.113 + # Or render the message/form within an entire page.
3.114 +
3.115 + else:
3.116 + ActionBase.render_msg(self, msg, msgtype)
3.117 +
3.118 + def render_success(self, msg, msgtype):
3.119
3.120 """
3.121 Render neither 'msg' nor 'msgtype' since redirection should occur
3.122 instead.
3.123 - NOTE: msgtype is optional because MoinMoin 1.5.x does not support it.
3.124 """
3.125
3.126 pass
4.1 --- a/actions/EventAggregatorSummary.py Wed Aug 10 01:03:14 2011 +0200
4.2 +++ b/actions/EventAggregatorSummary.py Wed Aug 31 01:56:22 2011 +0200
4.3 @@ -298,12 +298,7 @@
4.4
4.5 # Output summary data...
4.6
4.7 - if hasattr(request, "http_headers"):
4.8 - send_headers = request.http_headers
4.9 - elif hasattr(request, "emit_http_headers"):
4.10 - send_headers = request.emit_http_headers
4.11 - else:
4.12 - send_headers = send_headers_cls(request)
4.13 + send_headers = get_send_headers(request)
4.14
4.15 # Define headers.
4.16