[Checkins] SVN: zc.preview/trunk/src/zc/preview/ Initial import.
File previews based on mimetype. Currently somewhat minimal.
Gary Poster
gary at zope.com
Tue Aug 15 17:14:00 EDT 2006
Log message for revision 69542:
Initial import. File previews based on mimetype. Currently somewhat minimal.
Changed:
A zc.preview/trunk/src/zc/preview/README.txt
A zc.preview/trunk/src/zc/preview/__init__.py
A zc.preview/trunk/src/zc/preview/configure.zcml
A zc.preview/trunk/src/zc/preview/default.pt
A zc.preview/trunk/src/zc/preview/default.py
A zc.preview/trunk/src/zc/preview/default.zcml
A zc.preview/trunk/src/zc/preview/i18n.py
A zc.preview/trunk/src/zc/preview/iframe.pt
A zc.preview/trunk/src/zc/preview/iframe.py
A zc.preview/trunk/src/zc/preview/iframe.txt
A zc.preview/trunk/src/zc/preview/iframe.zcml
A zc.preview/trunk/src/zc/preview/image.pt
A zc.preview/trunk/src/zc/preview/image.py
A zc.preview/trunk/src/zc/preview/image.txt
A zc.preview/trunk/src/zc/preview/image.zcml
A zc.preview/trunk/src/zc/preview/ntests.py
A zc.preview/trunk/src/zc/preview/test.zcml
A zc.preview/trunk/src/zc/preview/text.py
A zc.preview/trunk/src/zc/preview/text.txt
A zc.preview/trunk/src/zc/preview/text.zcml
-=-
Added: zc.preview/trunk/src/zc/preview/README.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/README.txt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/README.txt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,8 @@
+=========================
+Uploaded content previews
+=========================
+
+This package contains a variety of preview views that are otherwise
+isolated. These may be split up in the future should we decide that
+this combination package doesn't work.
+
Property changes on: zc.preview/trunk/src/zc/preview/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zc.preview/trunk/src/zc/preview/__init__.py
===================================================================
--- zc.preview/trunk/src/zc/preview/__init__.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/__init__.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1 @@
+# This directory is a Python package.
Added: zc.preview/trunk/src/zc/preview/configure.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/configure.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/configure.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,10 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ >
+
+ <include file="text.zcml"/>
+ <include file="iframe.zcml"/>
+ <include file="image.zcml"/>
+ <include file="default.zcml"/>
+
+</configure>
Added: zc.preview/trunk/src/zc/preview/default.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/default.pt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.pt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,11 @@
+<html metal:use-macro="context/@@standard_macros/view"
+ i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+ <p i18n:translate="">The system does not support previewing this file type.
+ </p>
+</metal:block>
+</body>
+</html>
Added: zc.preview/trunk/src/zc/preview/default.py
===================================================================
--- zc.preview/trunk/src/zc/preview/default.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,21 @@
+"""A preview that declares something is not previewable.
+"""
+
+from zope import component, interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+from zope.publisher.interfaces.browser import IBrowserRequest
+
+class Preview(zope.publisher.browser.BrowserPage):
+ interface.implements(interface.Interface)
+
+ template = namedtemplate.NamedTemplate('default')
+
+ def __call__(self):
+ return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+ ViewPageTemplateFile('default.pt'),
+ Preview
+ )
Added: zc.preview/trunk/src/zc/preview/default.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/default.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/default.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,16 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain='zc.preview'>
+
+ <adapter factory=".default.default_template" name="default" />
+
+ <browser:view
+ class=".default.Preview"
+ for="zope.file.interfaces.IFile"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+</configure>
Added: zc.preview/trunk/src/zc/preview/i18n.py
===================================================================
--- zc.preview/trunk/src/zc/preview/i18n.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/i18n.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,8 @@
+"""Internationalization for zc.preview.
+
+"""
+__docformat__ = "reStructuredText"
+
+from zope.i18nmessageid import MessageFactory
+
+_ = MessageFactory('zc.preview')
Added: zc.preview/trunk/src/zc/preview/iframe.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.pt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.pt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,14 @@
+<html metal:use-macro="context/@@standard_macros/view"
+ i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+ <iframe width="100%" height="300" i18n:translate="iframe-not-supported"
+ tal:attributes="src string:${context/@@traversedURL}/@@inline">
+ The inline preview is not possible because your browser
+ does not support inline frames.
+ </iframe>
+</metal:block>
+</body>
+</html>
Added: zc.preview/trunk/src/zc/preview/iframe.py
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,23 @@
+"""Very simple preview-view. It displays content in an iframe with its
+source link pointing to the 'inline' view on the content.
+"""
+
+from zope import component, interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.mimetype.types import IContentTypeMicrosoftWord
+
+class Preview(zope.publisher.browser.BrowserPage):
+ interface.implements(interface.Interface)
+
+ template = namedtemplate.NamedTemplate('iframe')
+
+ def __call__(self):
+ return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+ ViewPageTemplateFile('iframe.pt'),
+ Preview
+ )
Added: zc.preview/trunk/src/zc/preview/iframe.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.txt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.txt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,117 @@
+===============
+iframe previews
+===============
+
+The iframe view is used for any content type that the browser knows
+how to display in an iframe.
+
+Create the browser object we'll be using.
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader('Accept-Language', 'test')
+
+For each content type we will test that the view is registered and
+working, by creating a simple content content object and clicking the
+link to see the resulting view.
+
+Microsoft Word
+--------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+ >>> browser.open('http://localhost/@@contents.html')
+ >>> browser.getLink('[[zope][[top]]]').click()
+ >>> browser.getLink('[[zc.preview][DemoContentMicrosoftWord]]').click()
+ >>> browser.getControl(name='new_value').value = 'test.doc'
+ >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+ >>> browser.getLink('test.doc').click()
+ >>> print browser.contents
+ <...
+ <iframe width="100%" height="300"
+ src="http://localhost/test.doc/@@inline">[[zc.preview][iframe-not-supported (
+ The inline preview is not possible because your browser
+ does not support inline frames.
+ )]]</iframe>
+ ...>
+
+
+Microsoft Excel
+---------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+ >>> browser.open('http://localhost/@@contents.html')
+ >>> browser.getLink('[[zope][[top]]]').click()
+ >>> browser.getLink('[[zc.preview][DemoContentMicrosoftExcel]]').click()
+ >>> browser.getControl(name='new_value').value = 'test.xls'
+ >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+ >>> browser.getLink('test.xls').click()
+ >>> print browser.contents
+ <...
+ <iframe width="100%" height="300"
+ src="http://localhost/test.xls/@@inline">[[zc.preview][iframe-not-supported (
+ The inline preview is not possible because your browser
+ does not support inline frames.
+ )]]</iframe>
+ ...>
+
+
+Microsoft Powerpoint
+--------------------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+ >>> browser.open('http://localhost/@@contents.html')
+ >>> browser.getLink('[[zope][[top]]]').click()
+ >>> browser.getLink('[[zc.preview][DemoContentMicrosoftPowerPoint]]').click()
+ >>> browser.getControl(name='new_value').value = 'test.ppt'
+ >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+ >>> browser.getLink('test.ppt').click()
+ >>> print browser.contents
+ <...
+ <iframe width="100%" height="300"
+ src="http://localhost/test.ppt/@@inline">[[zc.preview][iframe-not-supported (
+ The inline preview is not possible because your browser
+ does not support inline frames.
+ )]]</iframe>
+ ...>
+
+
+Adobe Pdf
+---------
+
+To see how the view works, we'll create an instance of a simple content
+object:
+
+ >>> browser.open('http://localhost/@@contents.html')
+ >>> browser.getLink('[[zope][[top]]]').click()
+ >>> browser.getLink('[[zc.preview][DemoContentPdf]]').click()
+ >>> browser.getControl(name='new_value').value = 'test.pdf'
+ >>> browser.getControl('[[zope][container-apply-button (Apply)]]').click()
+
+Now click on the link to our object to see if we are getting the expected view.
+
+ >>> browser.getLink('test.pdf').click()
+ >>> print browser.contents
+ <...
+ <iframe width="100%" height="300"
+ src="http://localhost/test.pdf/@@inline">[[zc.preview][iframe-not-supported (
+ The inline preview is not possible because your browser
+ does not support inline frames.
+ )]]</iframe>
+ ...>
+
+
Property changes on: zc.preview/trunk/src/zc/preview/iframe.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zc.preview/trunk/src/zc/preview/iframe.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/iframe.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/iframe.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,64 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zc.preview">
+
+ <adapter factory=".iframe.default_template" name="iframe" />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeMicrosoftWord"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeMicrosoftExcel"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeMicrosoftPowerPoint"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypePdf"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeTextHtml"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeHtmlApplication"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".iframe.Preview"
+ for="zope.mimetype.types.IContentTypeXhtml"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+</configure>
Added: zc.preview/trunk/src/zc/preview/image.pt
===================================================================
--- zc.preview/trunk/src/zc/preview/image.pt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.pt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,11 @@
+<html metal:use-macro="context/@@standard_macros/view"
+ i18n:domain="zc.preview">
+<head>
+</head>
+<body>
+<metal:block metal:fill-slot="body">
+<img tal:attributes="src string:${context/@@traversedURL}/@@inline;
+ alt context/zope:name" />
+</metal:block>
+</body>
+</html>
Added: zc.preview/trunk/src/zc/preview/image.py
===================================================================
--- zc.preview/trunk/src/zc/preview/image.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,20 @@
+"""Very simple preview-view for images.
+"""
+
+from zope import interface
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
+from zope.formlib import namedtemplate
+import zope.publisher.browser
+
+class Preview(zope.publisher.browser.BrowserPage):
+ interface.implements(interface.Interface)
+
+ template = namedtemplate.NamedTemplate('image')
+
+ def __call__(self):
+ return self.template()
+
+default_template = namedtemplate.NamedTemplateImplementation(
+ ViewPageTemplateFile('image.pt'),
+ Preview
+ )
Added: zc.preview/trunk/src/zc/preview/image.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/image.txt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.txt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,34 @@
+==============
+Image previews
+==============
+
+Simple preview of images.
+
+Create the browser object we'll be using.
+
+ >>> from zope.testbrowser.testing import Browser
+ >>> browser = Browser()
+ >>> browser.addHeader("Authorization", "Basic user:userpw")
+ >>> browser.addHeader("Accept-Language", "en-US")
+
+Let's start by creating a small "image"::
+
+ >>> import StringIO
+ >>> def createFile(data, name, contentType):
+ ... sio = StringIO.StringIO(data)
+ ... browser.open("http://localhost/@@+/zope.file.File")
+ ... ctrl = browser.getControl(name="form.data")
+ ... ctrl.add_file(sio, contentType, name)
+ ... browser.getControl("Add").click()
+
+ >>> createFile("(pretend this is png data)", "sample-1.png", "image/png")
+
+The preview view shows a simple <img> tag.
+
+ >>> browser.getLink("sample-1.png").click()
+ >>> browser.getLink("Display").click()
+ >>> print browser.contents
+ <...
+ <img src="http://localhost/sample-1.png/@@inline" alt="sample-1.png" />
+ ...
+
Property changes on: zc.preview/trunk/src/zc/preview/image.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zc.preview/trunk/src/zc/preview/image.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/image.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/image.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,31 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zc.preview">
+
+ <adapter factory=".image.default_template" name="image" />
+
+ <browser:view
+ class=".image.Preview"
+ for="zope.mimetype.types.IContentTypeImageGif"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".image.Preview"
+ for="zope.mimetype.types.IContentTypeImageJpeg"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+ <browser:view
+ class=".image.Preview"
+ for="zope.mimetype.types.IContentTypeImagePng"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+</configure>
Added: zc.preview/trunk/src/zc/preview/ntests.py
===================================================================
--- zc.preview/trunk/src/zc/preview/ntests.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/ntests.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,63 @@
+"""Test harness for zc.preview functional tests.
+
+"""
+import os
+import unittest
+
+import pytz
+
+import persistent
+from zope import component, interface
+
+import zope.interface.common.idatetime
+import zope.publisher.interfaces
+
+import zope.testing.module
+from zope.app.testing import functional
+
+#### testing framework ####
+
+ at component.adapter(zope.publisher.interfaces.IRequest)
+ at interface.implementer(zope.interface.common.idatetime.ITZInfo)
+def requestToTZInfo(request):
+ return pytz.timezone('US/Eastern')
+
+#### test setup ####
+
+zope.app.testing.functional.defineLayer('PreviewLayer')
+
+class DemoContentMicrosoftWord(persistent.Persistent):
+ """A content type that claims to be application/vnd.ms-word."""
+
+class DemoContentMicrosoftExcel(persistent.Persistent):
+ """A content type that claims to be application/vnd.ms-excel."""
+
+class DemoContentMicrosoftPowerPoint(persistent.Persistent):
+ """A content type that claims to be application/vnd.ms-powerpoint."""
+
+class DemoContentPdf(persistent.Persistent):
+ """A content type that claims to be appliction/pdf."""
+
+
+def test_text():
+ suite = functional.FunctionalDocFileSuite("text.txt")
+ suite.layer = PreviewLayer
+ return suite
+
+def test_iframe():
+ suite = functional.FunctionalDocFileSuite("iframe.txt")
+ suite.layer = PreviewLayer
+ return suite
+
+def test_image():
+ suite = functional.FunctionalDocFileSuite("image.txt")
+ suite.layer = PreviewLayer
+ return suite
+
+
+def test_suite():
+ suite = unittest.TestSuite()
+ suite.addTest(test_text())
+ suite.addTest(test_iframe())
+ suite.addTest(test_image())
+ return suite
Added: zc.preview/trunk/src/zc/preview/test.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/test.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/test.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,90 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zc.preview"
+ package="zc.preview"
+ >
+
+ <!-- This file is the equivalent of site.zcml and it is -->
+ <!-- used for functional testing setup -->
+
+ <include package="zope.app" />
+ <include package="zope.app.debugskin" />
+ <include package="zope.app.server" />
+ <include package="zope.app.authentication" />
+
+ <authenticatedGroup
+ id="zope.Authenticated"
+ title="Everybody"
+ />
+
+ <unauthenticatedPrincipal
+ id="zope.anybody"
+ title="Unauthenticated User" />
+
+ <!-- Principal that tests generally run as -->
+ <principal
+ id="zope.user"
+ title="User"
+ login="user"
+ password="userpw" />
+
+ <include package="zope.formlib"/>
+ <include package="zope.mimetype" file="meta.zcml"/>
+ <include package="zope.mimetype"/>
+ <include package="zope.file"/>
+ <include package="zc.shortcut"/>
+ <include package="zc.preview"/>
+
+ <securityPolicy
+ component="zope.security.simplepolicies.PermissiveSecurityPolicy"
+ />
+
+ <adapter factory=".ntests.requestToTZInfo"/>
+
+ <!-- Load a "default" i18n domain for debugging purposes
+ production sites shouldn't do this -->
+ <include package="zope.app.i18n.tests" />
+
+ <class class=".ntests.DemoContentMicrosoftWord">
+ <implements interface="zope.mimetype.types.IContentTypeMicrosoftWord" />
+ </class>
+
+ <browser:addMenuItem
+ class=".ntests.DemoContentMicrosoftWord"
+ title="DemoContentMicrosoftWord"
+ permission="zope.ManageContent"
+ />
+
+ <class class=".ntests.DemoContentMicrosoftExcel">
+ <implements interface="zope.mimetype.types.IContentTypeMicrosoftExcel" />
+ </class>
+
+ <browser:addMenuItem
+ class=".ntests.DemoContentMicrosoftExcel"
+ title="DemoContentMicrosoftExcel"
+ permission="zope.ManageContent"
+ />
+
+ <class class=".ntests.DemoContentMicrosoftPowerPoint">
+ <implements interface="zope.mimetype.types.IContentTypeMicrosoftPowerPoint" />
+ </class>
+
+ <browser:addMenuItem
+ class=".ntests.DemoContentMicrosoftPowerPoint"
+ title="DemoContentMicrosoftPowerPoint"
+ permission="zope.ManageContent"
+ />
+
+ <class class=".ntests.DemoContentPdf">
+ <implements interface="zope.mimetype.types.IContentTypePdf" />
+ </class>
+
+ <browser:addMenuItem
+ class=".ntests.DemoContentPdf"
+ title="DemoContentPdf"
+ permission="zope.ManageContent"
+ />
+
+
+</configure>
Added: zc.preview/trunk/src/zc/preview/text.py
===================================================================
--- zc.preview/trunk/src/zc/preview/text.py 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.py 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,126 @@
+"""Very simple preview-view for text/plain content.
+
+A more elaborate approach is needed if we care about supporting
+specific structured flavors used among programmers, but this is
+sufficient for the most basic use.
+
+"""
+__docformat__ = "reStructuredText"
+
+import codecs
+
+import zope.formlib.form
+import zope.mimetype.interfaces
+import zope.mimetype.source
+import zope.schema
+
+from i18n import _
+
+
+class TextPreview(zope.formlib.form.Form):
+
+ actions = ()
+
+ def get_rendered_encoding(self):
+ return self.codec
+
+ def get_rendered_text(self):
+ return self.text
+
+ encoding_field = zope.formlib.form.Field(
+ zope.schema.Choice(
+ __name__=_("encoding"),
+ title=_("Encoding"),
+ description=_("Character data encoding"),
+ source=zope.mimetype.source.codecSource,
+ required=False,
+ ),
+ for_display=True,
+ get_rendered=get_rendered_encoding,
+ )
+
+ text_field = zope.formlib.form.Field(
+ zope.schema.Text(
+ __name__="text",
+ title=_("Text"),
+ description=_("The text of the document."),
+ required=False,
+ ),
+ get_rendered=get_rendered_text,
+ )
+
+ msgTextEncodingNotSpecified = _(
+ "Text encoding not specified and could not be determined.")
+
+ msgErrorDecodingText = _(
+ "Specified text encoding does not match data.")
+
+ def __init__(self, context, request):
+ # set up fields
+ fields = []
+
+ f = context.open("rb")
+ data = f.read()
+ f.close()
+
+ # determine if the text is decodable, or unmarked ASCII
+ ci = zope.mimetype.interfaces.IContentInfo(context)
+ charset = ci.effectiveParameters.get("charset")
+ if not charset:
+ # The `IContentInfo` adapter should have gotten this, but
+ # if not, we fall back to a simple encoding sniff that
+ # only supports a few sure-bet values. This lets us work
+ # with the most common encodings regardless of the
+ # software configuration.
+ #
+ charset = sniffEncoding(data)
+ try:
+ self.text = unicode(data, charset)
+ except UnicodeError:
+ self.status = self.msgTextEncodingNotSpecified
+ self.have_text = False
+ else:
+ self.have_text = True
+ else:
+ try:
+ self.text = ci.decode(data)
+ except UnicodeError:
+ self.status = self.msgErrorDecodingText
+ self.have_text = False
+ else:
+ self.codec = ci.getCodec()
+ fields.append(self.encoding_field)
+ self.have_text = True
+
+ if self.have_text:
+ fields.append(self.text_field)
+
+ self.form_fields = zope.formlib.form.Fields(*fields)
+ super(TextPreview, self).__init__(context, request)
+
+ def setUpWidgets(self, ignore_request=False):
+ super(TextPreview, self).setUpWidgets(ignore_request=ignore_request)
+ if self.have_text:
+ w = self.widgets["text"]
+ w.extra = 'disabled="disabled"'
+ w.cssClass = "display-only"
+ w.width = 80
+
+
+def sniffEncoding(data):
+ """Guess what encoding might work to decode `data`.
+
+ The result is considered the 'most likely' candidate, but decoding
+ might fail.
+
+ """
+ for prefix, charset in _bom_prefix:
+ if data.startswith(prefix):
+ return charset
+ return "ascii"
+
+_bom_prefix = (
+ (codecs.BOM_UTF8, "utf-8"),
+ (codecs.BOM_UTF16_BE, "utf-16be"),
+ (codecs.BOM_UTF16_LE, "utf-16le"),
+ )
Added: zc.preview/trunk/src/zc/preview/text.txt
===================================================================
--- zc.preview/trunk/src/zc/preview/text.txt 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.txt 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,107 @@
+=======================
+Plain text display view
+=======================
+
+The "preview" for plain text is simple. It deals with documents for
+which the encoding is known, including the case of the "known"
+encoding not working with the actual data, and the case where the
+encoding is not known at all. For the later, some attempts to guess
+common text encodings is attempted.
+
+ >>> import StringIO
+ >>> from zope.testbrowser.testing import Browser
+
+We'll be creating many example file objects, so let's create a
+convenience function to make one for us::
+
+ >>> browser = Browser()
+ >>> browser.addHeader("Authorization", "Basic user:userpw")
+ >>> browser.addHeader("Accept-Language", "en-US")
+
+ >>> def createFile(data, name, contentType="text/plain"):
+ ... sio = StringIO.StringIO(data)
+ ... browser.open("http://localhost/@@+/zope.file.File")
+ ... ctrl = browser.getControl(name="form.data")
+ ... ctrl.add_file(sio, contentType, name)
+ ... browser.getControl("Add").click()
+
+Let's start by creating a plain text file in a simple, known
+encoding::
+
+ >>> createFile("Plain text in Latin-1: \xd8.",
+ ... "sample-1.txt", "text/plain; charset=iso-8859-1")
+
+Using the display view, we can see the document plainly, as well as a
+note about the current encoding (since it is known)::
+
+ >>> browser.getLink("sample-1.txt").click()
+ >>> print browser.contents
+ <...utf-8...
+ ...Plain text in Latin-1: ...
+
+If we don't provide encoding information when we create the document,
+but use an encoding that's easily recognizable, we'll still be able to
+see the document text, but won't get the annotation about the encoding
+that's been used, since some guesswork was involved::
+
+ >>> createFile("Plain text in US-ASCII.", "sample-2.txt")
+
+ >>> browser.getLink("sample-2.txt").click()
+ >>> print browser.contents
+ <...Plain text in US-ASCII...
+
+A number of UTF encodings are recognized if they include a byte-order
+mark. We'll use some Japanese example text (maybe; text is from a spam
+email) for subsequent tests::
+
+ >>> text = u"\u4f1a\u91d1\u30fb\u4f1a\u8cbb\u3092\u6255\u3063\u3066"
+ >>> utf8 = text.encode("utf-8")
+
+UTF-8 with the byte-order mark::
+
+ >>> import codecs
+
+ >>> createFile(codecs.BOM_UTF8 + text.encode("utf-8"), "sample-3.txt")
+
+ >>> browser.getLink("sample-3.txt").click()
+ >>> utf8 in browser.contents
+ True
+
+UTF-16 big-endian with the byte-order mark::
+
+ >>> createFile(codecs.BOM_UTF16_BE + text.encode("utf-16be"), "sample-4.txt")
+
+ >>> browser.getLink("sample-4.txt").click()
+ >>> utf8 in browser.contents
+ True
+
+UTF-16 little-endian with the byte-order mark::
+
+ >>> createFile(codecs.BOM_UTF16_LE + text.encode("utf-16le"), "sample-5.txt")
+
+ >>> browser.getLink("sample-5.txt").click()
+ >>> utf8 in browser.contents
+ True
+
+Handling un-decodable text
+--------------------------
+
+On the other hand, if we upload a file for which the encoding is not
+recognized automatically and don't provide encoding information, we
+get a message that the encoding is not known::
+
+ >>> createFile(text.encode("utf-8"), "bad-1.txt")
+
+ >>> browser.getLink("bad-1.txt").click()
+ >>> print browser.contents
+ <...Text encoding not specified and could not be determined...
+
+For an encoding that's specified in the initial upload of the file,
+but which is incorrect, a different error message is provided::
+
+ >>> createFile(text.encode("utf-8"),
+ ... "bad-2.txt", "text/plain; charset=utf-16le")
+
+ >>> browser.getLink("bad-2.txt").click()
+ >>> print browser.contents
+ <...Specified text encoding does not match data...
Property changes on: zc.preview/trunk/src/zc/preview/text.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: zc.preview/trunk/src/zc/preview/text.zcml
===================================================================
--- zc.preview/trunk/src/zc/preview/text.zcml 2006-08-15 21:11:43 UTC (rev 69541)
+++ zc.preview/trunk/src/zc/preview/text.zcml 2006-08-15 21:13:59 UTC (rev 69542)
@@ -0,0 +1,31 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ xmlns:browser="http://namespaces.zope.org/browser"
+ i18n_domain="zc.preview"
+ >
+
+ <browser:view
+ class=".text.TextPreview"
+ for="zope.mimetype.types.IContentTypeTextPlain"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".text.TextPreview"
+ for="zope.mimetype.types.IContentTypeJavaScript"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+ <browser:view
+ class=".text.TextPreview"
+ for="zope.mimetype.types.IContentTypeCss"
+ name="display.html"
+ menu="zmi_views" title="Display"
+ permission="zope.View"
+ />
+
+</configure>
More information about the Checkins
mailing list