[Checkins] SVN: zmi.core/trunk/s Copy browser package from zope.app.zptpage.

Yusei Tahara yusei at domen.cx
Sat Nov 21 02:25:52 EST 2009


Log message for revision 105934:
  Copy browser package from zope.app.zptpage.
  

Changed:
  U   zmi.core/trunk/setup.py
  U   zmi.core/trunk/src/zmi/core/configure.zcml
  A   zmi.core/trunk/src/zmi/core/zptpage/
  A   zmi.core/trunk/src/zmi/core/zptpage/__init__.py
  A   zmi.core/trunk/src/zmi/core/zptpage/collector266.txt
  A   zmi.core/trunk/src/zmi/core/zptpage/collector269.txt
  A   zmi.core/trunk/src/zmi/core/zptpage/configure.zcml
  A   zmi.core/trunk/src/zmi/core/zptpage/inlinecode.pt
  A   zmi.core/trunk/src/zmi/core/zptpage/preview.pt
  A   zmi.core/trunk/src/zmi/core/zptpage/tests.py
  A   zmi.core/trunk/src/zmi/core/zptpage/url.txt
  A   zmi.core/trunk/src/zmi/core/zptpage/zpt.gif
  A   zmi.core/trunk/src/zmi/core/zptpage/zptpage.py

-=-
Modified: zmi.core/trunk/setup.py
===================================================================
--- zmi.core/trunk/setup.py	2009-11-21 07:14:14 UTC (rev 105933)
+++ zmi.core/trunk/setup.py	2009-11-21 07:25:52 UTC (rev 105934)
@@ -69,11 +69,11 @@
                         'zope.app.sqlscript',
                         'zope.app.tree',
                         'zope.app.undo',
+                        'zope.app.zptpage',
                         ],
       extras_require=dict(test=['zope.app.testing',
                                 'zope.securitypolicy',
                                 'zope.testbrowser',
-                                'zope.app.zptpage',
                                 'zope.app.preference',
                                 'zope.app.apidoc',
                                 ]),

Modified: zmi.core/trunk/src/zmi/core/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/configure.zcml	2009-11-21 07:14:14 UTC (rev 105933)
+++ zmi.core/trunk/src/zmi/core/configure.zcml	2009-11-21 07:25:52 UTC (rev 105934)
@@ -20,4 +20,5 @@
   <include package=".sqlscript" />
   <include package=".tree" />
   <include package=".undo" />
+  <include package=".zptpage" />
 </configure>

Added: zmi.core/trunk/src/zmi/core/zptpage/__init__.py
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/__init__.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/__init__.py	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,2 @@
+#
+# This file is necessary to make this directory a package.

Added: zmi.core/trunk/src/zmi/core/zptpage/collector266.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/collector266.txt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/collector266.txt	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,232 @@
+http://collector.zope.org/Zope3-dev/266
+
+Two functions in zope.tal.taldefs -- getProgramMode and getProgramVersion --
+fail to work if the 'program' argument is security proxied, because they
+use isinstance. This can happen when a page template comes from the ZODB
+instead of the file system (i.e. inherits AppPT rather than TrustedAppPT,
+and therefore ZopePathExpr adds security proxes during object traversal).
+The symptom is an obscure exception like the following one:
+
+  METALError: macro u'view/macros/page' has incompatible version None,
+  at line 2, column 1
+
+
+We create a page that defines some macros:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 835
+  ... Content-Type: multipart/form-data; boundary=---------------------------78336869011025200592044897763
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <div metal:define-macro="hi">
+  ... Hi world
+  ... </div>
+  ... <div metal:define-macro="greet">
+  ... Hello <span metal:define-slot="name">world</span>
+  ... </div>
+  ... </html>
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... macros
+  ... -----------------------------78336869011025200592044897763--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+We create a page that uses the non-slotted macro from the macros template:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 771
+  ... Content-Type: multipart/form-data; boundary=---------------------------196751392613651805401540383426
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... <div metal:use-macro="container/macros/macros/hi" />
+  ... </body>
+  ... </html>
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... page
+  ... -----------------------------196751392613651805401540383426--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+And run it. 
+
+  >>> print http(r"""
+  ... GET /page HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... """, handle_errors=False)
+  HTTP/1.1 200 OK
+  Content-Length: 51
+  Content-Type: text/html;charset=utf-8
+  <BLANKLINE>
+  <html>
+  <body>
+  <div>
+  Hi world
+  </div>
+  </body>
+  </html>
+
+Let's create another page that uses the slotted macro, but doesn't
+fill it:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 771
+  ... Content-Type: multipart/form-data; boundary=---------------------------196751392613651805401540383426
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... <div metal:use-macro="container/macros/macros/greet" />
+  ... </body>
+  ... </html>
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... page2
+  ... -----------------------------196751392613651805401540383426--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+And run it. 
+
+  >>> print http(r"""
+  ... GET /page2 HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... """, handle_errors=False)
+  HTTP/1.1 200 OK
+  Content-Length: 67
+  Content-Type: text/html;charset=utf-8
+  <BLANKLINE>
+  <html>
+  <body>
+  <div>
+  Hello <span>world</span>
+  </div>
+  </body>
+  </html>
+
+Finally, lets create a page that fills the macro:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 1771
+  ... Content-Type: multipart/form-data; boundary=---------------------------196751392613651805401540383426
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <body>
+  ... <div metal:use-macro="container/macros/macros/greet">
+  ...   <span metal:fill-slot="name">bob</span>
+  ... </div>
+  ... </body>
+  ... </html>
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... page3
+  ... -----------------------------196751392613651805401540383426--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+And run it. 
+
+  >>> print http(r"""
+  ... GET /page3 HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... """, handle_errors=False)
+  HTTP/1.1 200 OK
+  Content-Length: 65
+  Content-Type: text/html;charset=utf-8
+  <BLANKLINE>
+  <html>
+  <body>
+  <div>
+  Hello <span>bob</span>
+  </div>
+  </body>
+  </html>


Property changes on: zmi.core/trunk/src/zmi/core/zptpage/collector266.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zmi.core/trunk/src/zmi/core/zptpage/collector269.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/collector269.txt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/collector269.txt	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,141 @@
+=========
+Issue 269
+=========
+
+http://collector.zope.org/Zope3-dev/269
+
+When you use TALES path expressions in a page template that is security
+proxied, you get ForbiddenAttribute errors for PathExpr methods. Other kinds
+of expressions are probably also affected.
+
+To see the error, apply the following diff to collector266.txt and run
+test.py zope.app.zptpage.browser (I'm too lazy to figure out how to
+demonstrate this problem manually in a web browser)::
+
+  Index: src/zope/app/zptpage/browser/collector266.txt
+  ===================================================================
+  --- src/zope/app/zptpage/browser/collector266.txt (revision 27388)
+  +++ src/zope/app/zptpage/browser/collector266.txt (working copy)
+  @@ -29,6 +29,7 @@
+     ... </div>
+     ... <div metal:define-macro="greet">
+     ... Hello <span metal:define-slot="name">world</span>
+  + ... <p tal:condition="nothing">Optional text</p>
+     ... </div>
+     ... </html>
+     ... -----------------------------78336869011025200592044897763
+
+
+We create a page that defines a macro:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 835
+  ... Content-Type: multipart/form-data; boundary=---------------------------78336869011025200592044897763
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ...
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.source"
+  ...
+  ... <html>
+  ... <div metal:define-macro="greet">
+  ... Hello <span metal:define-slot="name">world</span>
+  ... <p tal:condition="nothing">Optional text</p>
+  ... <div tal:define="data python:{'foo': 1, 'bar': {'x': 1, 'y': 0}};
+  ...                  later defer:container">
+  ...    <p tal:content="data/bar/x" />
+  ...    <p tal:condition="not: data/foo" />
+  ...    <p tal:content="string: string expr" />
+  ... </div>
+  ... </div>
+  ... </html>
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ...
+  ...
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ...
+  ...
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ...
+  ... Add
+  ... -----------------------------78336869011025200592044897763
+  ... Content-Disposition: form-data; name="add_input_name"
+  ...
+  ... macros
+  ... -----------------------------78336869011025200592044897763--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+
+Lets create a page that uses the macro:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... Content-Length: 1771
+  ... Content-Type: multipart/form-data; boundary=---------------------------196751392613651805401540383426
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ...
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.source"
+  ...
+  ... <html>
+  ... <body>
+  ... <div metal:use-macro="container/macros/macros/greet">
+  ...   <span metal:fill-slot="name">bob</span>
+  ... </div>
+  ... </body>
+  ... </html>
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ...
+  ...
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ...
+  ...
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ...
+  ... Add
+  ... -----------------------------196751392613651805401540383426
+  ... Content-Disposition: form-data; name="add_input_name"
+  ...
+  ... page
+  ... -----------------------------196751392613651805401540383426--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+  Location: http://localhost/@@contents.html
+  ...
+
+And run it.
+
+  >>> print http(r"""
+  ... GET /page HTTP/1.1
+  ... Authorization: Basic bWdyOm1ncnB3
+  ... """, handle_errors=False)
+  HTTP/1.1 200 OK
+  Content-Length: 118
+  Content-Type: text/html;charset=utf-8
+  <BLANKLINE>
+  <html>
+  <body>
+  <div>
+  Hello <span>bob</span>
+  <BLANKLINE>
+  <div>
+     <p>1</p>
+  <BLANKLINE>
+     <p> string expr</p>
+  </div>
+  </div>
+  </body>
+  </html>


Property changes on: zmi.core/trunk/src/zmi/core/zptpage/collector269.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zmi.core/trunk/src/zmi/core/zptpage/configure.zcml
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/configure.zcml	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/configure.zcml	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,75 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope"
+    xmlns:browser="http://namespaces.zope.org/browser"
+    i18n_domain="zope"
+    >
+
+  <browser:page
+      name="index.html"
+      for="zope.app.zptpage.interfaces.IZPTPage"
+      class=".zptpage.ZPTPageEval"
+      attribute="index"
+      permission="zope.View"
+      />
+
+  <browser:page
+      name="source.html"
+      for="zope.app.zptpage.interfaces.IZPTPage"
+      class="zope.app.zptpage.zptpage.ZPTSourceView"
+      attribute="__call__"
+      permission="zope.ManageContent"
+      />
+
+  <browser:addMenuItem
+      class="zope.app.zptpage.ZPTPage"
+      title="ZPT Page"
+      description="A simple, content-based Page Template"
+      permission="zope.ManageContent"
+      view="zope.app.zptpage.ZPTPage"
+      />
+
+  <browser:addform
+      schema="zope.app.zptpage.interfaces.IZPTPage"
+      label="Add a ZPT Page"
+      content_factory="zope.app.zptpage.ZPTPage"
+      name="zope.app.zptpage.ZPTPage"
+      permission="zope.ManageContent"
+      />
+
+  <browser:page
+      for="zope.app.zptpage.interfaces.IZPTPage"
+      name="edit.html"
+      class=".zptpage.EditForm"
+      permission="zope.ManageContent" 
+      menu="zmi_views" title="Edit"
+      />
+
+  <browser:editform
+      for="zope.app.zptpage.interfaces.IZPTPage"
+      schema="zope.app.zptpage.interfaces.IZPTPage"
+      name="inlineCode.html"
+      label="Inline Code"
+      fields="evaluateInlineCode"
+      template="inlinecode.pt"
+      permission="zope.ManageContent" 
+      menu="zmi_views" title="Inline Code"
+      />
+
+  <browser:icon 
+      name="zmi_icon"
+      for="zope.app.zptpage.interfaces.IZPTPage" 
+      file="zpt.gif"
+      />
+
+
+  <!-- Preview view - requires zope.app.preview -->
+
+  <browser:page
+      for="zope.app.zptpage.interfaces.IZPTPage"
+      name="preview.html"
+      template="preview.pt"
+      permission="zope.ManageContent"
+      menu="zmi_views" title="Preview"
+      />
+
+</configure>

Added: zmi.core/trunk/src/zmi/core/zptpage/inlinecode.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/inlinecode.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/inlinecode.pt	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,78 @@
+<tal:tag condition="view/update"
+/><html metal:use-macro="context/@@standard_macros/view" i18n:domain="zope">
+  <body>
+  <div metal:fill-slot="body">
+
+  <div metal:define-macro="body">
+
+    <form action="." tal:attributes="action request/URL" method="post"
+          enctype="multipart/form-data">
+
+      <div metal:define-macro="formbody">
+
+        <h3 tal:condition="view/label"
+            tal:content="view/label"
+            metal:define-slot="heading"
+            i18n:translate=""
+            >Edit something</h3>
+
+        <div style="color:red; font-weight: bold">
+          <p i18n:translate="">
+            This screen allows you to activate Inline Code Evaluation. This
+            means that you can say
+            <span i18n:name="code-example-1"><pre>
+               &lt;script type="text/server-python"&gt;<br/>
+               &nbsp;&nbsp;print "Hello World!"<br/>
+               &lt;/script&gt;
+            </pre></span>
+            or
+            <span i18n:name="code-example-2"><pre>
+               &lt;p tal:script="text/server-python"&gt;<br/>
+               &nbsp;&nbsp;print "Hello World!"<br/>
+               &lt;/p&gt;
+            </pre></span>
+          </p>
+          <p i18n:translate="">
+            Many Zope 3 developers consider inline code blocks something
+            very bad, since it does not follow the design of Page Templates
+            or Zope 3 in general. However, application and application server
+            developers are not the only audience for Zope 3. Scripters are
+            used to inline code from other technologies like PHP and it fits
+            their brain, which is very important.
+          </p>
+        </div>
+
+        <p tal:define="status view/update"
+           tal:condition="status"
+           tal:content="status" i18n:translate=""/>
+
+         <p tal:condition="view/errors" i18n:translate="">
+           There are  <strong tal:content="python:len(view.errors)"
+                              i18n:name="num_errors">6</strong> input errors.
+        </p>
+
+        <tal:block repeat="error view/errors">
+          <div class="error" tal:content="error" i18n:translate="">error</div>
+        </tal:block>
+
+        <div metal:use-macro="context/@@form_macros/widget_rows" />
+
+      </div>
+
+      <div class="row">
+        <div class="controls">
+          <input type="submit" value="Refresh" 
+              i18n:attributes="value refresh-button" />
+          <input type="submit" name="UPDATE_SUBMIT" value="Submit" 
+              i18n:attributes="value submit-button"/>
+        </div>
+      </div>
+
+    </form>
+
+  </div>
+
+  </div>
+  </body>
+
+</html>

Added: zmi.core/trunk/src/zmi/core/zptpage/preview.pt
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/preview.pt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/preview.pt	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,9 @@
+<html metal:use-macro="context/@@standard_macros/view">
+<body>
+<div metal:fill-slot="body">
+
+  <iframe src="." height="500" width="100%"></iframe>
+
+</div>
+</body>
+</html>

Added: zmi.core/trunk/src/zmi/core/zptpage/tests.py
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/tests.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/tests.py	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,224 @@
+##############################################################################
+#
+# Copyright (c) 2003, 2004 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Functional tests for ZPT Page.
+
+$Id: tests.py 87230 2008-06-07 18:01:59Z philikon $
+"""
+
+import re
+import unittest
+from zope.testing import renormalizing
+from zope.app.testing.functional import BrowserTestCase
+from zope.app.zptpage.zptpage import ZPTPage
+from xml.sax.saxutils import escape
+from zope.app.zptpage.testing import ZPTPageLayer
+
+
+class ZPTPageTest(BrowserTestCase):
+
+    content = u'<html><body><h1 tal:content="request/URL/1" /></body></html>'
+
+    def addZPTPage(self):
+        zptpage = ZPTPage()
+        zptpage.source = self.content
+        root = self.getRootFolder()
+        root['zptpage'] = zptpage
+        self.commit()
+
+    def testAddForm(self):
+        response = self.publish(
+            '/+/zope.app.zptpage.ZPTPage=',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Add a ZPT Page' in body)
+        self.assert_('Source' in body)
+        self.assert_('Expand macros' in body)
+        self.assert_('Evaluate Inline Code' in body)
+        self.assert_('Object Name' in body)
+        self.assert_('"Add"' in body)
+        self.checkForBrokenLinks(body, '/+/zope.app.zptpage.ZPTPage=',
+                                 'mgr:mgrpw')
+
+    def testAdd(self):
+        response = self.publish(
+            '/+/zope.app.zptpage.ZPTPage=',
+            form={'type_name': u'zope.app.zptpage.ZPTPage',
+                  'field.source': u'<h1>A ZPT Page</h1>',
+                  'field.expand.used': u'',
+                  'field.evaluateInlineCode.used': u'',
+                  'add_input_name': u'zptpage',
+                  'UPDATE_SUBMIT': u'Add'},
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 302)
+        self.assertEqual(response.getHeader('Location'),
+                         'http://localhost/@@contents.html')
+        root = self.getRootFolder()
+        self.assert_('zptpage' in root)
+        zptpage = root['zptpage']
+        self.assertEqual(zptpage.source, '<h1>A ZPT Page</h1>')
+        self.assertEqual(zptpage.expand, False)
+        self.assertEqual(zptpage.evaluateInlineCode, False)
+
+        response = self.publish(
+            '/+/zope.app.zptpage.ZPTPage=',
+            form={'type_name': u'zope.app.zptpage.ZPTPage',
+                  'field.source': u'<h1>A ZPT Page</h1>',
+                  'field.expand.used': u'',
+                  'field.expand': u'on',
+                  'field.evaluateInlineCode.used': u'',
+                  'field.evaluateInlineCode': u'on',
+                  'add_input_name': u'zptpage1',
+                  'UPDATE_SUBMIT': u'Add'},
+            basic='mgr:mgrpw')
+        root = self.getRootFolder()
+        zptpage = root['zptpage1']
+        self.assertEqual(zptpage.source, '<h1>A ZPT Page</h1>')
+        self.assertEqual(zptpage.expand, True)
+        self.assertEqual(zptpage.evaluateInlineCode, True)
+
+    def testEditForm(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@edit.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Source' in body)
+        self.assert_('Expand macros' in body)
+        self.assert_('Content Type' in body)
+        self.assert_(escape(self.content) in body)
+        self.checkForBrokenLinks(body, '/zptpage/@@edit.html', 'mgr:mgrpw')
+
+    def testEdit(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@edit.html',
+            form={'form.source': u'<h1>A ZPT Page</h1>',
+                  'form.expand.used': u'',
+                  'form.expand': u'on',
+                  'form.content_type': u'text/html',
+                  'form.actions.apply': u'Apply'},
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Source' in body)
+        self.assert_(escape(u'<h1>A ZPT Page</h1>') in body)
+        root = self.getRootFolder()
+        zptpage = root['zptpage']
+        self.assertEqual(zptpage.source, '<h1>A ZPT Page</h1>')
+        self.assertEqual(zptpage.expand, True)
+        self.assertEqual(zptpage.content_type, 'text/html')
+
+    def testIssue199(self):
+        # This is a test to protect us against issue 199 in the future
+        self.addZPTPage()
+        source = u"""<html metal:use-macro="container/@@standard_macros/page">
+         <body>
+           <div metal:fill-slot="body">
+            write this in the body slot.
+           </div>
+         </body>
+         </html>"""
+
+        response = self.publish(
+            '/zptpage/@@edit.html',
+            form={'form.source': source,
+                  'form.expand.used': u'',
+                  'form.expand': u'on',
+                  'form.actions.apply': u'Apply'},
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        # Check for a string from the default template
+        self.assert_(escape(u'Z3 UI') in body)
+        self.failIf(u"Macro expansion failed" in body)
+
+    def testIndex(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@index.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        self.assertEqual(response.getBase(), '')
+        body = response.getBody()
+        self.assertEqual(
+            body,
+            '<html><body><h1>http://localhost/zptpage</h1></body></html>')
+        self.checkForBrokenLinks(body, '/zptpage/@@index.html', 'mgr:mgrpw')
+
+    def testPreview(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@preview.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('<iframe src="."' in body)
+        self.checkForBrokenLinks(body, '/zptpage/@@preview.html', 'mgr:mgrpw')
+
+    def testSource(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@source.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assertEqual(body, self.content)
+
+    def testInlineCode(self):
+        self.addZPTPage()
+        response = self.publish(
+            '/zptpage/@@inlineCode.html',
+            form={'field.evaluateInlineCode.used': u'',
+                  'field.evaluateInlineCode': u'on',
+                  'UPDATE_SUBMIT': u'Edit'},
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        body = response.getBody()
+        self.assert_('Inline Code' in body)
+        self.assert_('Evaluate Inline Code' in body)
+        self.checkForBrokenLinks(body, '/zptpage/@@edit.html', 'mgr:mgrpw')
+
+        response = self.publish(
+            '/zptpage/@@inlineCode.html',
+            basic='mgr:mgrpw')
+        self.assertEqual(response.getStatus(), 200)
+        root = self.getRootFolder()
+        zptpage = root['zptpage']
+        self.assertEqual(zptpage.evaluateInlineCode, True)
+
+
+checker = renormalizing.RENormalizing([
+    (re.compile(r"HTTP/1\.1 (\d\d\d) .*"), r"HTTP/1.1 \1 <MESSAGE>"),
+    ])
+
+
+def test_suite():
+    from zope.app.testing.functional import FunctionalDocFileSuite
+    collector = FunctionalDocFileSuite(
+        'collector266.txt', 'collector269.txt', checker=checker)
+    url = FunctionalDocFileSuite('url.txt', checker=checker)
+    collector.layer = ZPTPageLayer
+    ZPTPageTest.layer = ZPTPageLayer
+    url.layer = ZPTPageLayer
+    return unittest.TestSuite((
+        unittest.makeSuite(ZPTPageTest),
+        collector,
+        url,
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')

Added: zmi.core/trunk/src/zmi/core/zptpage/url.txt
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/url.txt	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/url.txt	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,73 @@
+Special URL handling for DTML pages
+===================================
+
+When a ZPT page containing a head tag is visited, without a trailing
+slash, the base href isn't set.  When visited with a slash, it is:
+
+  >>> print http(r"""
+  ... POST /+/zope.app.zptpage.ZPTPage%3D HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... Content-Length: 764
+  ... Content-Type: multipart/form-data; boundary=---------------------------178869070917677183891223841261
+  ... Referer: http://localhost:8081/+/zope.app.zptpage.ZPTPage=
+  ... 
+  ... -----------------------------178869070917677183891223841261
+  ... Content-Disposition: form-data; name="field.source"
+  ... 
+  ... <html>
+  ... <head></head>
+  ... <body>
+  ... <a href="eek.html">Eek</a>
+  ... </body>
+  ... </html>
+  ... -----------------------------178869070917677183891223841261
+  ... Content-Disposition: form-data; name="field.expand.used"
+  ... 
+  ... 
+  ... -----------------------------178869070917677183891223841261
+  ... Content-Disposition: form-data; name="field.evaluateInlineCode.used"
+  ... 
+  ... 
+  ... -----------------------------178869070917677183891223841261
+  ... Content-Disposition: form-data; name="UPDATE_SUBMIT"
+  ... 
+  ... Add
+  ... -----------------------------178869070917677183891223841261
+  ... Content-Disposition: form-data; name="add_input_name"
+  ... 
+  ... zpt.html
+  ... -----------------------------178869070917677183891223841261--
+  ... """)
+  HTTP/1.1 303 See Other
+  ...
+
+  >>> print http(r"""
+  ... GET /zpt.html HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... """)
+  HTTP/1.1 200 OK
+  ...
+  <html>
+  <head></head>
+  <body>
+  <a href="eek.html">Eek</a>
+  </body>
+  </html>
+  <BLANKLINE>
+
+
+  >>> print http(r"""
+  ... GET /zpt.html/ HTTP/1.1
+  ... Authorization: Basic mgr:mgrpw
+  ... """)
+  HTTP/1.1 200 OK
+  ...
+  <html>
+  <head>
+  <base href="http://localhost/zpt.html" />
+  </head>
+  <body>
+  <a href="eek.html">Eek</a>
+  </body>
+  </html>
+  <BLANKLINE>


Property changes on: zmi.core/trunk/src/zmi/core/zptpage/url.txt
___________________________________________________________________
Added: svn:eol-style
   + native

Added: zmi.core/trunk/src/zmi/core/zptpage/zpt.gif
===================================================================
(Binary files differ)


Property changes on: zmi.core/trunk/src/zmi/core/zptpage/zpt.gif
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Added: zmi.core/trunk/src/zmi/core/zptpage/zptpage.py
===================================================================
--- zmi.core/trunk/src/zmi/core/zptpage/zptpage.py	                        (rev 0)
+++ zmi.core/trunk/src/zmi/core/zptpage/zptpage.py	2009-11-21 07:25:52 UTC (rev 105934)
@@ -0,0 +1,56 @@
+##############################################################################
+#
+# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""Define view component for ZPT page eval results.
+
+$Id: zptpage.py 73434 2007-03-22 02:05:14Z yusei $
+"""
+
+import zope.formlib.form
+
+import zope.app.zptpage.interfaces
+
+class ZPTPageEval(object):
+
+    def index(self, **kw):
+        """Call a Page Template"""
+
+        template = self.context
+        request = self.request
+
+        request.response.setHeader('content-type',
+                                   template.content_type)
+
+        return template.render(request, **kw)
+
+class EditForm(zope.formlib.form.EditForm):
+    """Edit form for ZPT pages."""
+
+    form_fields = zope.formlib.form.Fields(
+            zope.app.zptpage.interfaces.IZPTPage,
+            zope.app.zptpage.interfaces.IRenderZPTPage,
+            render_context=True).omit('evaluateInlineCode')
+
+    def setUpWidgets(self, ignore_request=False):
+        self.adapters = {}
+
+        # We need to extract the data directly, as we can not pass on the
+        # request for macro expansion otherwise.
+        data = {}
+        data['source'] = self.context.getSource(self.request)
+
+        self.widgets = zope.formlib.form.setUpWidgets(
+            self.form_fields, self.prefix, self.context, self.request,
+            data=data, form=self, adapters=self.adapters,
+            ignore_request=ignore_request)
+



More information about the checkins mailing list