r715 - in zope-atextensions/branches: . upstream upstream/0.8.0
upstream/0.8.0/Extensions upstream/0.8.0/datatype
upstream/0.8.0/examples upstream/0.8.0/field
upstream/0.8.0/i18n upstream/0.8.0/skins
upstream/0.8.0/skins/at_extensions upstream/0.8.0/validator
upstream/0.8.0/widget
Alastair McKinstry
mckinstry at alioth.debian.org
Wed Mar 21 14:43:16 UTC 2007
Author: mckinstry
Date: 2007-03-21 14:43:10 +0000 (Wed, 21 Mar 2007)
New Revision: 715
Added:
zope-atextensions/branches/upstream/
zope-atextensions/branches/upstream/0.8.0/
zope-atextensions/branches/upstream/0.8.0/CHANGES.txt
zope-atextensions/branches/upstream/0.8.0/Extensions/
zope-atextensions/branches/upstream/0.8.0/Extensions/Install.py
zope-atextensions/branches/upstream/0.8.0/Extensions/__init__.py
zope-atextensions/branches/upstream/0.8.0/Extensions/utils.py
zope-atextensions/branches/upstream/0.8.0/README
zope-atextensions/branches/upstream/0.8.0/__init__.py
zope-atextensions/branches/upstream/0.8.0/ateapi.py
zope-atextensions/branches/upstream/0.8.0/config.py
zope-atextensions/branches/upstream/0.8.0/datatype/
zope-atextensions/branches/upstream/0.8.0/datatype/__init__.py
zope-atextensions/branches/upstream/0.8.0/datatype/formattablename.py
zope-atextensions/branches/upstream/0.8.0/datatype/formattablenames.py
zope-atextensions/branches/upstream/0.8.0/examples/
zope-atextensions/branches/upstream/0.8.0/examples/__init__.py
zope-atextensions/branches/upstream/0.8.0/examples/demo.py
zope-atextensions/branches/upstream/0.8.0/examples/formattablename.py
zope-atextensions/branches/upstream/0.8.0/field/
zope-atextensions/branches/upstream/0.8.0/field/__init__.py
zope-atextensions/branches/upstream/0.8.0/field/comment.py
zope-atextensions/branches/upstream/0.8.0/field/datetime.py
zope-atextensions/branches/upstream/0.8.0/field/email.py
zope-atextensions/branches/upstream/0.8.0/field/formattablename.py
zope-atextensions/branches/upstream/0.8.0/field/formattablenames.py
zope-atextensions/branches/upstream/0.8.0/field/record.py
zope-atextensions/branches/upstream/0.8.0/field/record_examples.py
zope-atextensions/branches/upstream/0.8.0/field/records.py
zope-atextensions/branches/upstream/0.8.0/field/records_examples.py
zope-atextensions/branches/upstream/0.8.0/field/remotetext.py
zope-atextensions/branches/upstream/0.8.0/field/url.py
zope-atextensions/branches/upstream/0.8.0/i18n/
zope-atextensions/branches/upstream/0.8.0/i18n/i18nCall.sh
zope-atextensions/branches/upstream/0.8.0/i18n/plone-da.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-de.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-en.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-fr.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-generated.pot
zope-atextensions/branches/upstream/0.8.0/i18n/plone-it.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-manual.pot
zope-atextensions/branches/upstream/0.8.0/i18n/plone-nl.po
zope-atextensions/branches/upstream/0.8.0/i18n/plone-pt.po
zope-atextensions/branches/upstream/0.8.0/skins/
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/address_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/combo_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/comment_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/customize_remotefield.cpy
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/datetime_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/deadlines_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/email_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formatdemo.py
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formattablename_view.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/getDisplayView.py
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy.metadata
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/record_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/records_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/remotetext_widget.pt
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/uncustomize_remotefield.cpy
zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/url_widget.pt
zope-atextensions/branches/upstream/0.8.0/svn-commit.tmp
zope-atextensions/branches/upstream/0.8.0/validator/
zope-atextensions/branches/upstream/0.8.0/validator/__init__.py
zope-atextensions/branches/upstream/0.8.0/validator/isPartialUrl.py
zope-atextensions/branches/upstream/0.8.0/version.txt
zope-atextensions/branches/upstream/0.8.0/widget/
zope-atextensions/branches/upstream/0.8.0/widget/__init__.py
zope-atextensions/branches/upstream/0.8.0/widget/combo.py
zope-atextensions/branches/upstream/0.8.0/widget/comment.py
zope-atextensions/branches/upstream/0.8.0/widget/datetime.py
zope-atextensions/branches/upstream/0.8.0/widget/deadlines.py
zope-atextensions/branches/upstream/0.8.0/widget/email.py
zope-atextensions/branches/upstream/0.8.0/widget/formattablename.py
zope-atextensions/branches/upstream/0.8.0/widget/formattablenames.py
zope-atextensions/branches/upstream/0.8.0/widget/record.py
zope-atextensions/branches/upstream/0.8.0/widget/records.py
zope-atextensions/branches/upstream/0.8.0/widget/remotetext.py
zope-atextensions/branches/upstream/0.8.0/widget/url.py
Log:
Upstream 0.8.0
Added: zope-atextensions/branches/upstream/0.8.0/CHANGES.txt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/CHANGES.txt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/CHANGES.txt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,94 @@
+from 0.7.2 to 0.8
+
+ - improved i18n support [Mike Gabriel]
+
+ - added 'comment' field (lets you include formattable narrative
+ in edit forms)
+
+ - first draft of a 'remotetext' field (not yet working)
+ (the idea is to have a field pull its text from a remote source
+ but also to be able to customize the text if needed)
+
+from 0.7.1 to 0.7.2
+
+ - fixed bug when deleting more than one entry from a list of records
+ using the records widget (thanks to Mike Gabriel for spotting the
+ bug and to Frank Bennett for the fix)
+
+from 0.7 to 0.7.1
+
+ - fixed references to deprecated calendar_slot [David Siedband]
+
+ - extended Record.getVocabularyFor to accept the use of DisplayLists
+ as subfield_vocabulary entries and to raise errors if a valid
+ DisplayLists was not returned from an expression. [DWM]
+
+from 0.6 to 0.7
+
+ - add the 'formattable name(s)' data types, fields, and widgets
+
+from 0.5 to 0.6
+
+ - rearranged almost everything to be inline with AT-1.4's
+ architecture
+
+ - made it backwards compatible with AT-1.2 again
+ (hopefully)
+
+ - added postprocessing to the URL widget to supply http as
+ default protocol if no-one is supplied.
+
+from 0.4 to 0.5
+
+ - added ComboWidget and combo_widget.pt to create combo boxes
+ where users can select a value or specify one freely
+ it they select 'other'.
+
+ - added a 'delete' flag to each record in RecordsWidget's
+ edit macro.
+
+ - added an optional 'maxlenth' attribute for subfields
+
+ - added subfield validation; from now on AT 1.3 is required
+ (I think)
+
+ - updated the demo type (WorkingGroup) to use subfield validation
+ for the 'homepage' subfield in e-contact
+
+from 0.3 to 0.4:
+
+ - added a 'delete all entries' checkbox to the records widget
+
+ - added 'minimalSize' and 'maximalSize' to the RecordsField's
+ properties to enable better control of the number of lines
+ offered in the edit form
+
+ - do not override 'content_edit' anymore; configure the form
+ controller on install instead and add a custom 'more_edit'
+ to be called when 'more' is pressed (only slight extension
+ to the original 'content_edit' but I couldn't get around
+ otherwise with the references - thanks to Roché Compaan
+ for a valuable hint).
+
+ - Record(s)Field should now work with schemata or portal_factory
+ without the risc of data loss
+
+ - adapted the demo content type ('WorkingGroup') to reflect the
+ above changes and made it demonstrate how to enable the
+ date picker box for a DateTime subfield
+
+ - added support for 'int', 'long' and 'float' as subfield types
+ in RecordField and RecordsField.
+
+from 0.2 to 0.3:
+
+ - made compliant with the new security policy for archetypes 1.3:
+ Registered the UrlField/Widget and replaced 'getRaw' in the
+ Record(s)Widget by an appropriate indirect call to the edit
+ accessor.
+
+from 0.1 to 0.2:
+
+ - added a RecordsField and -Widget (records are a list of record objects)
+
+ - improved the RecordWidget's view macro (empty subfields are not rendered)
Added: zope-atextensions/branches/upstream/0.8.0/Extensions/Install.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/Extensions/Install.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/Extensions/Install.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,96 @@
+##########################################################################
+# #
+# copyright (c) 2004 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+"""plone installer script"""
+
+from StringIO import StringIO
+
+from Products.CMFCore.utils import getToolByName
+from Products.CMFFormController.FormAction import FormActionKey
+from Products.CMFFormController.FormValidator import FormValidatorKey
+
+from Products.Archetypes.public import listTypes
+from Products.Archetypes.Extensions.utils \
+ import installTypes, install_subskin
+
+from Products.ATExtensions.config import *
+
+
+def setupProperties(self, out):
+ ptool = getToolByName(self, 'portal_properties')
+ psheet = getattr(ptool, 'extensions_properties', None)
+
+ if not psheet:
+ ptool.addPropertySheet('extensions_properties',
+ 'Properties of the ATExtension product')
+ ps = getattr(ptool, 'extensions_properties')
+
+ ps._properties = ps._properties + (
+ {'id':'phone_number_types', 'type':'lines', 'mode':'w'},
+ {'id':'country_names', 'type':'lines', 'mode':'w'},
+ )
+ ps._updateProperty('phone_number_types', PHONE_NUMBER_TYPES)
+ ps._updateProperty('country_names', COUNTRY_NAMES)
+ out.write("Added %s's properties." % PROJECTNAME)
+ else:
+ out.write("Found %s's properties." % PROJECTNAME)
+
+def configureFormController(self, out):
+ pfc = getToolByName(self, 'portal_form_controller')
+ pfc.addFormValidators('base_edit',
+ '', # context_type
+ 'more',
+ '') # validators
+ pfc.addFormAction('base_edit',
+ 'success',
+ '', # context_type
+ 'more',
+ 'traverse_to',
+ 'string:more_edit')
+ out.write("Added validator and action for the 'more' button to the form controller.")
+
+
+
+def install(self):
+ out = StringIO()
+ ## don't install the demao type as it's broken in Zope 2.10/CMF 2.0
+ ## anyways
+ ## installTypes(self, out, listTypes(PROJECTNAME), PROJECTNAME)
+ install_subskin(self, out, GLOBALS)
+ setupProperties(self, out)
+ configureFormController(self, out)
+ out.write("Successfully installed %s." % PROJECTNAME)
+ return out.getvalue()
+
+# for the uninstall we need to take care of the form controller
+# explicitly
+
+def reconfigureFormController(self, out):
+ pfc = getToolByName(self, 'portal_form_controller')
+
+ #BAAH no Python API for deleting actions or validators in FormController
+ #lets get our hands dirty
+ container = pfc.actions
+ try:
+ container.delete(FormActionKey('base_edit', 'success', '',
+ 'more', pfc))
+ except KeyError: pass
+
+ container = pfc.validators
+ try:
+ container.delete(FormValidatorKey('base_edit', '',
+ 'more', pfc))
+ except KeyError: pass
+
+ out.write("Removed validator and action for the 'more' button from the form controller.")
+
+def uninstall(self):
+ out = StringIO()
+ reconfigureFormController(self, out)
+ # all the rest we leave to the quick installer
+ out.write("Uninstalled %s." % PROJECTNAME)
+ return out.getvalue()
Added: zope-atextensions/branches/upstream/0.8.0/Extensions/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/Extensions/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/Extensions/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,2 @@
+# lifting it up
+from utils import getDisplayList
Added: zope-atextensions/branches/upstream/0.8.0/Extensions/utils.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/Extensions/utils.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/Extensions/utils.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,31 @@
+##########################################################################
+# #
+# copyright (c) 2004 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+""" utilities for the ATExtensions product """
+
+from Products.CMFCore.utils import getToolByName
+from Products.Archetypes.public import DisplayList
+
+def getValues(self, prop_name):
+ ptool = getToolByName(self, 'portal_properties', None)
+ if ptool and hasattr(ptool, 'extensions_properties'):
+ return ptool.extensions_properties.getProperty(prop_name, None)
+ else:
+ return None
+
+def makeDisplayList(values=None):
+ if values and type(values) not in [type([]), type(())]:
+ values = (values,)
+ if not values: values = []
+ results = [['', 'Select'],]
+ for x in values:
+ results.append([x,x])
+ values_tuple = tuple(results)
+ return DisplayList(values_tuple)
+
+def getDisplayList(self, prop_name=None):
+ return makeDisplayList(getValues(self, prop_name))
Added: zope-atextensions/branches/upstream/0.8.0/README
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/README 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/README 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,33 @@
+
+Welcome to ATExtensions
+
+
+This is a development release.
+
+USE AT YOUR OWN RISC. NO REAL TESTING DONE SO FAR.
+
+This package just provides some extensions to archetypes.
+
+So far, there are only a few custom fields and widgets,
+the Record(s)Field/Widget being the most generic ones.
+
+To demonstrate usage, there is a demo content type
+'WorkingGroup'. To enable it after install, go to
+portal types and make it implicitly addable or include
+it in some folderish type's 'allowed_content_types'.
+
+Updating
+
+If yo have been using ATExtensions before from your
+products you may encounter some broken imports. This
+is due to the reorganization of the source code and
+easily fixed by linking the new 'ateapi.py' module
+under the old 'at_extensions.py' name.
+
+Enjoy,
+
+ Raphael (r.ritz at biologie.hu-berlin.de)
+
+
+
+
Added: zope-atextensions/branches/upstream/0.8.0/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,40 @@
+##########################################################################
+# #
+# copyright (c) 2004 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+"""package installer"""
+
+from Products.CMFCore import utils
+from Products.CMFCore.DirectoryView import registerDirectory
+from Products.Archetypes.public import process_types, listTypes
+from config import *
+
+# the custom validator
+from Products.validation import validation
+from validator.isPartialUrl import PartialUrlValidator
+validation.register(PartialUrlValidator('isPartialUrl'))
+
+# the demo content types
+from examples import demo, formattablename
+
+# backwards compatibility
+import sys
+import ateapi
+sys.modules['Products.ATExtensions.at_extensions'] = ateapi
+
+registerDirectory(SKINS_DIR, GLOBALS)
+
+def initialize(context):
+ content_types, constructors, ftis = process_types(
+ listTypes(PROJECTNAME),
+ PROJECTNAME)
+ utils.ContentInit(
+ PROJECTNAME + ' Content',
+ content_types = content_types,
+ permission = ADD_CONTENT_PERMISSION,
+ extra_constructors = constructors,
+ fti = ftis,
+ ).initialize(context)
Added: zope-atextensions/branches/upstream/0.8.0/ateapi.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/ateapi.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/ateapi.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,8 @@
+# the datatypes
+from Products.ATExtensions.datatype import *
+# the fields
+from Products.ATExtensions.field import *
+# the widgets
+from Products.ATExtensions.widget import *
+# the utilities
+from Products.ATExtensions.Extensions.utils import getDisplayList
Added: zope-atextensions/branches/upstream/0.8.0/config.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/config.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/config.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,266 @@
+# just to be compatible with the general AT approach
+
+from Products.CMFCore.permissions import AddPortalContent
+
+ADD_CONTENT_PERMISSION = AddPortalContent
+PROJECTNAME = "ATExtensions"
+SKINS_DIR = 'skins'
+GLOBALS = globals()
+
+try:
+ from Products.validation import ValidationChain
+ HAS_VALIDATION_CHAIN = 1
+except ImportError:
+ HAS_VALIDATION_CHAIN = 0
+
+PHONE_NUMBER_TYPES = [
+ "Office",
+ "Secretariat",
+ "Laboratory",
+ "Mobile",
+ "Fax",
+ "Private",
+ ]
+
+COUNTRY_NAMES = [
+ "Afghanistan",
+ "Albania",
+ "Algeria",
+ "American Samoa",
+ "Andorra",
+ "Angola",
+ "Anguilla",
+ "Antarctica",
+ "Antigua Barbuda",
+ "Argentina",
+ "Armenia",
+ "Aruba",
+ "Australia",
+ "Austria",
+ "Azerbaijan",
+ "Bahamas",
+ "Bahrain",
+ "Bangladesh",
+ "Barbados",
+ "Belarus",
+ "Belgium",
+ "Belize",
+ "Benin",
+ "Bermuda",
+ "Bhutan",
+ "Bolivia",
+ "Bosnia Herzegovina",
+ "Botswana",
+ "Bouvet Island",
+ "Brazil",
+ "British Indian Ocean Territory",
+ "Brunei Darussalam",
+ "Bulgaria",
+ "Burkina Faso",
+ "Burundi",
+ "Cambodia",
+ "Cameroon",
+ "Canada",
+ "Cape Verde",
+ "Cayman Islands",
+ "Central African Republic",
+ "Chad",
+ "Chile",
+ "China",
+ "Christmas Island",
+ "Cocos (Keeling) Islands",
+ "Colombia",
+ "Comoros",
+ "Congo",
+ "Congo, Democratic Republic",
+ "Cook Islands",
+ "Costa Rica",
+ "Cote D'Ivoire",
+ "Croatia",
+ "Cuba",
+ "Cyprus",
+ "Czech Republic",
+ "Denmark",
+ "Djibouti",
+ "Dominica",
+ "Dominican Republic",
+ "Ecuador",
+ "Egypt",
+ "El Salvador",
+ "Equatorial Guinea",
+ "Eritrea",
+ "Estonia",
+ "Ethiopia",
+ "Falkland Islands (Malvinas)",
+ "Faroe Islands",
+ "Fiji",
+ "Finland",
+ "France",
+ "French Guiana",
+ "French Polynesia",
+ "French Southern Territories",
+ "Gabon",
+ "Gambia",
+ "Georgia",
+ "Germany",
+ "Ghana",
+ "Gibraltar",
+ "Greece",
+ "Greenland",
+ "Grenada",
+ "Guadeloupe",
+ "Guam",
+ "Guatemala",
+ "Guinea",
+ "Guinea-Bissau",
+ "Guyana",
+ "Haiti",
+ "Heard Island Mcdonald Islands",
+ "Holy See (Vatican City State)",
+ "Honduras",
+ "Hong Kong",
+ "Hungary",
+ "Iceland",
+ "India",
+ "Indonesia",
+ "Iran, Islamic Republic",
+ "Iraq",
+ "Ireland",
+ "Israel",
+ "Italy",
+ "Jamaica",
+ "Japan",
+ "Jordan",
+ "Kazakhstan",
+ "Kenya",
+ "Kiribati",
+ "Korea, Democratic People's Republic",
+ "Korea, Republic",
+ "Kuwait",
+ "Kyrgyzstan",
+ "Lao People's Democratic Republic",
+ "Latvia",
+ "Lebanon",
+ "Lesotho",
+ "Liberia",
+ "Libyan Arab Jamahiriya",
+ "Liechtenstein",
+ "Lithuania",
+ "Luxembourg",
+ "Macao",
+ "Macedonia, Former Yugoslav Republic",
+ "Madagascar",
+ "Malawi",
+ "Malaysia",
+ "Maldives",
+ "Mali",
+ "Malta",
+ "Marshall Islands",
+ "Martinique",
+ "Mauritania",
+ "Mauritius",
+ "Mayotte",
+ "Mexico",
+ "Micronesia, Federated States",
+ "Moldova, Republic",
+ "Monaco",
+ "Mongolia",
+ "Montserrat",
+ "Morocco",
+ "Mozambique",
+ "Myanmar",
+ "Namibia",
+ "Nauru",
+ "Nepal",
+ "Netherlands",
+ "Netherlands Antilles",
+ "New Caledonia",
+ "New Zealand",
+ "Nicaragua",
+ "Niger",
+ "Nigeria",
+ "Niue",
+ "Norfolk Island",
+ "Northern Mariana Islands",
+ "Norway",
+ "Oman",
+ "Pakistan",
+ "Palau",
+ "Palestinian Territory, Occupied",
+ "Panama",
+ "Papua New Guinea",
+ "Paraguay",
+ "Peru",
+ "Philippines",
+ "Pitcairn",
+ "Poland",
+ "Portugal",
+ "Puerto Rico",
+ "Qatar",
+ "Reunion",
+ "Romania",
+ "Russian Federation",
+ "Rwanda",
+ "Saint Helena",
+ "Saint Kitts Nevis",
+ "Saint Lucia",
+ "Saint Pierre Miquelon",
+ "Saint Vincent Grenadines",
+ "Samoa",
+ "San Marino",
+ "Sao Tome Principe",
+ "Saudi Arabia",
+ "Senegal",
+ "Serbia Montenegro",
+ "Seychelles",
+ "Sierra Leone",
+ "Singapore",
+ "Slovakia",
+ "Slovenia",
+ "Solomon Islands",
+ "Somalia",
+ "South Africa",
+ "South Georgia South Sandwich Islands",
+ "Spain",
+ "Sri Lanka",
+ "Sudan",
+ "Suriname",
+ "Svalbard Jan Mayen",
+ "Swaziland",
+ "Sweden",
+ "Switzerland",
+ "Syrian Arab Republic",
+ "Taiwan, Province China",
+ "Tajikistan",
+ "Tanzania, United Republic",
+ "Thailand",
+ "Timor-Leste",
+ "Togo",
+ "Tokelau",
+ "Tonga",
+ "Trinidad Tobago",
+ "Tunisia",
+ "Turkey",
+ "Turkmenistan",
+ "Turks Caicos Islands",
+ "Tuvalu",
+ "Uganda",
+ "Ukraine",
+ "United Arab Emirates",
+ "United Kingdom",
+ "United States",
+ "United States Minor Outlying Islands",
+ "Uruguay",
+ "Uzbekistan",
+ "Vanuatu",
+ "Venezuela",
+ "Vietnam",
+ "Virgin Islands, British",
+ "Virgin Islands, U.S.",
+ "Wallis Futuna",
+ "Western Sahara",
+ "Yemen",
+ "Zambia",
+ "Zimbabwe",
+ ]
+
Added: zope-atextensions/branches/upstream/0.8.0/datatype/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/datatype/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/datatype/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,2 @@
+from formattablename import FormattableName
+from formattablenames import FormattableNames
Added: zope-atextensions/branches/upstream/0.8.0/datatype/formattablename.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/datatype/formattablename.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/datatype/formattablename.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,192 @@
+##########################################################################
+# #
+# copyright (c) 2005 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+from string import punctuation
+filtered_punctuation = [c for c in punctuation \
+ if c not in "()[]{}<>"]
+
+default_format="%T %F %M %P %L %S"
+
+default_formatter = {'T':'title',
+ 'F':'firstname',
+ 'M':'middlename',
+ 'P':'prefix',
+ 'L':'lastname',
+ 'S':'suffix',
+ 'H':'homepage',
+ 'E':'email',
+ }
+
+default_abbreviations = {}
+
+
+def abbreviate(value, abbr=None, join_abbr=''):
+ """
+ return an abbreviation for 'value'
+
+ 1. from the abbreviations mapping
+ 2. or the first letter (or letters if value is multivalued)
+ 3. return '' if value is empty
+ """
+ if not value:
+ return ''
+ abbreviations = abbr or default_abbreviations
+ special = abbreviations.get(value, None)
+ if special is not None:
+ return special
+ values = [v[0] for v in value.split()]
+ return join_abbr.join(values)
+
+
+class FormattableName:
+
+ __allow_access_to_unprotected_subobjects__ = 1
+
+ def __init__(self, mapping={}):
+ """sets defaults and updates from kw"""
+ self._keys = ()
+ self.update(mapping)
+
+ def __call__(self, *args, **kwargs):
+ value = self.stringformat(*args, **kwargs)
+ if kwargs.get('withURL', False):
+ homepage = self.getHomePage(*args, **kwargs)
+ if homepage:
+ value = '<a href="%s">%s</a>' % (homepage, value)
+ return value
+
+ def getHomePage(self, context=None, methodname='', *args, **kwargs):
+ if self.get('homepage'):
+ return self.get('homepage')
+ try:
+ return getattr(context, methodname)(self)
+ except AttributeError:
+ return None
+
+ def __str__(self):
+ return self.stringformat()
+
+ def __repr__(self):
+ return str(dict(self.items()))
+
+ def __add__(self, other):
+ from formattablenames import FormattableNames
+ if isinstance(other, FormattableName):
+ return FormattableNames([self, other])
+ if isinstance(other, FormattableNames):
+ return FormattableNames([self]) + other
+
+ def stringformat(self,
+ format=default_format,
+ formatter=default_formatter,
+ abbr=None,
+ join_abbr='',
+ abbrev=None, # backwards compat
+ lastnamefirst=None, # backwards compat
+ **kw
+ ):
+ """Takes a format string to control the rendering
+ of the name (inspired by DateTime).
+
+ Default format is '%T %F %M %P %L %S' where the
+ keys mapped to by the default formatter are:
+
+ %T -> title: for a leading title (e.g. academic)
+ %F -> firstname: for the first first (or given) name
+ %M -> middlename: for the middle name(s)
+ %P -> prefix: for a last name prefix (e.g. a title of nobility)
+ %L -> lastname: for the last name
+ %S -> suffix: for a suffix (e.g. a trailing 'PhD' or 'SA')
+
+ Use lowercase keys to get the abbreviated value
+ (default: first letter; use the 'abbr' mapping
+ to define exceptions; for multi-worded values the first letter
+ of each word, joined by the value of 'join_abbr', is returned)
+
+ Pass in a mapping to 'formatter' for custom format key mapping.
+
+ Usage of 'abbrev' and 'lastnamefirst' is deprecated and for
+ backwards compatibility only.
+
+ See the test suite for example usages.
+ """
+ if lastnamefirst:
+ format = "L, %F, %P"
+ if abbrev: format = format.replace("%F", "%f")
+
+ for key in formatter.keys():
+ match = "%"+key
+ value = self[formatter[key]]
+ format = format.replace(match, value)
+ if match.lower() in format:
+ format = format.replace(match.lower(),
+ abbreviate(value, abbr, join_abbr))
+
+ return self._normalize(format)
+
+ def _normalize(self, format):
+ """Remove leading, stray, and trailing punctuation
+ and collapse whitespece"""
+ format = self._remove_punctuation(format.strip())
+ for match in [' ', '()', '[]', '{}', '<>']:
+ while match in format:
+ format = format.replace(match,' ')
+ return format.strip()
+
+ def _remove_punctuation(self, format):
+ for c in filtered_punctuation:
+ match = ' ' + c + ' '
+ format = format.replace(match, ' ')
+ while format.startswith(c):
+ format = format[1:]
+ while format.endswith(c):
+ format = format[:-1]
+ return format
+
+
+ # behave like a dict
+
+ def __getitem__(self, key, default=''):
+ return getattr(self, key, default)
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+ if key not in self._keys:
+ self._keys += (key,)
+
+ def get(self, key, default=''):
+ return getattr(self, key, default) or default
+
+ def update(self, kw=None):
+ if not kw:
+ return None
+ for k,v in kw.items():
+ self[k] = v
+
+ def keys(self):
+ return self._keys
+
+ def items(self):
+ return [(k, self[k]) for k in self._keys]
+
+ # our one hard-coded exception
+
+ def __setattr__(self, name, value):
+ if value and name == 'firstnames':
+ self['firstname'] = value.split()[0]
+ self['middlename'] = ' '.join(value.split()[1:]).strip()
+ else:
+ self.__dict__[name] = value
+
+ def __getattr__(self, name):
+ if name == 'firstnames':
+ value = ' '.join([self['firstname'], self['middlename']])
+ return value.strip()
+ else:
+ raise AttributeError
+
+
Added: zope-atextensions/branches/upstream/0.8.0/datatype/formattablenames.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/datatype/formattablenames.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/datatype/formattablenames.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,59 @@
+##########################################################################
+# #
+# copyright (c) 2005 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+from formattablename import FormattableName
+
+class FormattableNames:
+ def __init__(self,names=[]):
+ self.names = ()
+ for name in names:
+ self.append(name)
+
+ def __call__(self, *args, **kwargs):
+ return self.strfmt(*args, **kwargs)
+
+ def __getitem__(self,key):
+ return self.names[key]
+
+ def __len__(self):
+ return len(self.names)
+
+ def append(self,name):
+ self.names += (FormattableName(name),)
+
+ def __add__(self, other):
+ if isinstance(other, FormattableNames):
+ return FormattableNames(self.names + other.names)
+ sum = FormattableNames(self.names)
+ sum.append(other)
+ return sum
+
+ def __str__(self):
+ return self()
+
+ def __repr__(self):
+ return str(self.names)
+
+ def strfmt(self, *args, **kw):
+ length = len(self)
+ empty_marker = kw.get('empty_marker', "No names specified")
+ sep = kw.get('sep', ', ')
+ lastsep = kw.get('lastsep', ', and ')
+
+ if length == 0:
+ return empty_marker
+ if length == 1:
+ return self.names[0](**kw)
+ if length == 2:
+ if ',' in lastsep:
+ lastsep = lastsep.replace(',','')
+ return lastsep.join([a(**kw) for a in self.names])
+
+ return sep.join([a(**kw) for a in self.names[:-1]]) \
+ + lastsep + self.names[-1](**kw)
+
+
Added: zope-atextensions/branches/upstream/0.8.0/examples/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/examples/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/examples/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1 @@
+# I'm a package ;-)
Added: zope-atextensions/branches/upstream/0.8.0/examples/demo.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/examples/demo.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/examples/demo.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,167 @@
+##########################################################################
+# #
+# copyright (c) 2004, 2005 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+""" demonstrates the use of ATExtensions """
+
+from Products.Archetypes.public import *
+from Products.ATExtensions.ateapi import *
+
+
+schema = BaseSchema + Schema((
+ SimpleNameField('principal_investigator',
+ widget=RecordWidget(label='Principal Investigator',
+ description='The person leading the group',
+ ),
+ ),
+ StringField('home_institute',
+ required=0,
+ widget=StringWidget(label='Institution',
+ description='Name of the institution hosting the group'),
+ ),
+ PhoneNumbersField('phone',
+ schemata="contact",
+ ),
+ NetAddressField('e_address',
+ schemata="contact",
+ widget= RecordWidget(label='E-Contact',
+ description='Electronic contact addresses'),
+ ),
+ AddressField('street_address',
+ schemata="contact",
+ required=1,
+ widget=RecordWidget(label='Address',
+ description='Street (or postal) contact address'),
+ ),
+ # separate schemata page for members and partner groups;
+ # the useage of minimalSize and maximalSize is for demonstration only
+ MultipleNamesField('group_members',
+ schemata='members',
+ minimalSize = 1, # effectively 2 because 'More' is enabled
+ maximalSize = 4,
+ widget=RecordsWidget(label="Group Members",
+ description="Members of this group; press 'more' to enable additional entries (restricted to 4 at most)."),
+ ),
+ # and a relation field for partner groups
+ ReferenceField('partners',
+ schemata='members',
+ relationship="partner_groups",
+ multiValued=1,
+ allowed_types=("WorkingGroup",),
+ widget=ReferenceWidget(description="Groups with which this group has a collaborations",
+ addable=1,
+ destination="/",
+ ),
+ ),
+ # and here a record field configured in the schema declaration
+ RecordsField('seminars',
+ schemata='seminars',
+ subfields = ('speaker', 'room', 'date'),
+ subfield_types = {'date':'datetime'},
+ subfield_sizes = {'speaker' : 15, 'room': 6},
+ innerJoin = ', ',
+ outerJoin = '<br />',
+ widget = RecordsWidget(
+ helper_js=('jscalendar/calendar_stripped.js',
+ 'jscalendar/calendar-en.js'),
+ helper_css=('jscalendar/calendar-system.css',),
+ )
+
+ ),
+ TextField('short_description',
+ widget=TextAreaWidget(label='Description',
+ description="A short (plain text) description of the research group's focus.",
+ ),
+ accessor='getShortDescription',
+ edit_accessor='getShortDescription',
+ mutator='setShortDescription',
+ ),
+ StringField('test_combo',
+ schemata='testing',
+ vocabulary='DemoVocab',
+ widget=ComboWidget(description="You need to select 'other' if you want to specify the value yourself below."),
+ ),
+ UrlField('url',
+ schemata='testing',
+ ),
+ RemoteTextField('remote',
+ schemata='remote',
+ default_output_type='text/html',
+ allowable_content_types = ('text/plain',
+ 'text/html',
+ 'text/structured',
+ ),
+ ),
+ ))
+
+class WorkingGroup(BaseContent):
+ """
+ Demo from ATExtensions
+ stores information about a research group
+ """
+ content_icon = "group.gif"
+ schema = schema
+ _at_rename_after_creation = True
+
+ # enable field sharing between 'short_description' and 'description'
+
+ def getShortDescription(self, **kw):
+ """ get the 'description' and put it in the 'short_description'
+ """
+ return self.Description()
+
+ def setShortDescription(self, val, **kw):
+ """ synchronize 'short_description' and 'description'
+ """
+ self.setDescription(val)
+
+ # for the catalog metadata
+
+ def Name(self):
+ """
+ the name of the group
+ """
+ return self.Title() + ', ' + self.getHome_institute()
+
+ def LastName(self):
+ """PI's last name; needed by the catalog for sorting"""
+ return self.getPrincipal_investigator().get('last_name','')
+
+
+ def PI(self):
+ """
+ the name of the principal investigator
+ """
+ pi_name = self.getPrincipal_investigator().get('first_name','') \
+ + ' ' + \
+ self.getPrincipal_investigator().get('last_name','')
+ return pi_name.strip()
+
+ def City(self):
+ """ subfield of street address """
+ return self.getStreet_address().get('city','')
+
+ def Country(self):
+ """ subfield of street address """
+ return self.getStreet_address().get('country','')
+
+ # the demo vocab
+
+ def DemoVocab(self):
+ """just to have some display list"""
+ return getDisplayList(self, 'phone_number_types')
+
+
+def modify_fti(fti):
+ fti['allow_discussion'] = 1
+ fti['global_allow'] = 0
+ # hide unnecessary tabs (usability enhancement)
+ for a in fti['actions']:
+ if a['id'] in ('references',):
+ a['visible'] = 0
+ return fti
+
+registerType(WorkingGroup)
Added: zope-atextensions/branches/upstream/0.8.0/examples/formattablename.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/examples/formattablename.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/examples/formattablename.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,43 @@
+##########################################################################
+# #
+# copyright (c) 2005 ITB, Humboldt-University Berlin #
+# written by: Raphael Ritz, r.ritz at biologie.hu-berlin.de #
+# #
+##########################################################################
+
+""" demonstrates the use of the formattable name(s) field"""
+
+from Products.Archetypes.public import *
+from Products.ATExtensions.ateapi import *
+
+
+schema = BaseSchema + Schema((
+ FormattableNameField('name1'),
+ FormattableNameField('name2',
+ subfields = ('title',
+ 'firstnames',
+ 'lastname',
+ 'homepage'),
+ widget = FormattableNameWidget(
+ format="%f%l: %F %m. %L (%T)",
+ join_abbr=".",
+ withURL = True,
+ ),
+ ),
+ FormattableNamesField('friends',
+ widget = FormattableNamesWidget(format="%L %f%m"),
+ )
+ ))
+
+class FormattableNameDemo(BaseContent):
+ """
+ Demo from ATExtensions
+ Illustrates useage of the formattable name(s) field
+ """
+ content_icon = "user.gif"
+ schema = schema
+ global_allow = 0
+
+ _at_rename_after_creation = True
+
+registerType(FormattableNameDemo)
Added: zope-atextensions/branches/upstream/0.8.0/field/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,14 @@
+# import the individual fields
+
+from datetime import DateTimeField
+from url import UrlField
+from email import EmailField
+from record import RecordField
+from records import RecordsField
+from record_examples import SimpleNameField, LocationField,\
+ AddressField, ContactField, NetAddressField
+from records_examples import MultipleNamesField, PhoneNumbersField
+from formattablename import FormattableNameField
+from formattablenames import FormattableNamesField
+from comment import CommentField
+from remotetext import RemoteTextField
Added: zope-atextensions/branches/upstream/0.8.0/field/comment.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/comment.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/comment.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,46 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.CMFCore.utils import getToolByName
+from Products.Archetypes.Field import StringField
+from Products.Archetypes.Registry import registerField
+from Products.Archetypes.Registry import registerPropertyType
+
+from Products.ATExtensions.widget import CommentWidget
+
+class CommentField(StringField):
+ """specific field for URLs"""
+ _properties = StringField._properties.copy()
+ _properties.update({
+ 'type' : 'comment',
+ 'comment' : ' ',
+ 'comment_type' : 'text/structured',
+ 'comment_msgid' : '',
+ 'widget' : CommentWidget,
+ })
+ security = ClassSecurityInfo()
+
+ def get(self, instance, **kwargs):
+ domain = self.widget.i18n_domain
+ if self.comment_msgid:
+ comment = instance.translate(domain=domain, msgid=self.comment_msgid, default=self.comment)
+ else:
+ comment = instance.translate(domain=domain, msgid=self.comment, default=self.comment)
+ transforms = getToolByName(instance, 'portal_transforms', None)
+ if transforms is None:
+ return comment
+ return transforms.convertTo('text/html',
+ comment,
+ context=instance,
+ mimetype=self.comment_type).getData()
+
+ def set(self, instance, value, **kwargs):
+ pass
+
+InitializeClass(CommentField)
+
+registerField(CommentField,
+ title="Comment",
+ description="Used for inserting comments into the views",
+ )
+registerPropertyType('comment', 'string', CommentField)
+registerPropertyType('comment_type', 'string', CommentField)
Added: zope-atextensions/branches/upstream/0.8.0/field/datetime.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/datetime.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/datetime.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,43 @@
+# -*- coding: UTF-8 -*-
+
+##################################################
+# #
+# Copyright (C), 2004, Thomas Förster #
+# <t.foerster at biologie.hu-berlin.de> #
+# #
+# Humboldt University of Berlin #
+# #
+##################################################
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import DateTimeField as BaseField
+from Products.Archetypes.Registry import registerField, \
+ registerPropertyType
+
+from Products.ATExtensions.widget.datetime import DateTimeWidget
+
+class DateTimeField(BaseField):
+ """
+ An improved DateTime Field. It allows to specify
+ whether only dates or only times are interesting.
+ """
+
+ _properties = BaseField._properties.copy()
+ _properties.update({
+ 'type' : 'datetime_ng',
+ 'widget' : DateTimeWidget,
+ 'with_time' : 1, # set to False if you want date only objects
+ 'with_date' : 1, # set to False if you want time only objects
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(DateTimeField)
+
+registerField(DateTimeField,
+ title="DateTime Field",
+ description="An improved DateTimeField, which also allows time or date only specifications.",
+ )
+
+registerPropertyType('with_time', 'boolean', DateTimeField)
+registerPropertyType('with_date', 'boolean', DateTimeField)
Added: zope-atextensions/branches/upstream/0.8.0/field/email.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/email.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/email.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,23 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Field import StringField
+from Products.Archetypes.Registry import registerField
+
+from Products.ATExtensions.widget import EmailWidget
+
+class EmailField(StringField):
+ """specific field for emails"""
+ _properties = StringField._properties.copy()
+ _properties.update({
+ 'type' : 'email',
+ 'validators' : ('isEmail'),
+ 'widget' : EmailWidget,
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(EmailField)
+
+registerField(EmailField,
+ title="Email",
+ description="Used for storing a validated email.",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/field/formattablename.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/formattablename.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/formattablename.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,32 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerField
+from Products.Archetypes.Field import ObjectField
+from Products.ATExtensions.datatype.formattablename \
+ import FormattableName
+from Products.ATExtensions.widget import FormattableNameWidget
+from record import RecordField
+
+class FormattableNameField(RecordField):
+ """ field for managing a 'FormattableName' (custom type)"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'formattable_name',
+ 'default' : FormattableName(),
+ 'subfields' : ('title','firstname','middlename','lastname',),
+ 'widget' : FormattableNameWidget,
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('set')
+ def set(self, instance, value, **kwargs):
+ value = self._decode_strings(value, instance, **kwargs)
+ value = FormattableName(value)
+ ObjectField.set(self, instance, value, **kwargs)
+
+InitializeClass(FormattableNameField)
+
+registerField(FormattableNameField,
+ title="Formattable Name",
+ description="Used for storing a formattable name",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/field/formattablenames.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/formattablenames.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/formattablenames.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,41 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerField
+from Products.Archetypes.Field import ObjectField
+from Products.ATExtensions.datatype.formattablenames \
+ import FormattableNames
+from Products.ATExtensions.widget import FormattableNamesWidget
+from records import RecordsField
+
+class FormattableNamesField(RecordsField):
+ """ field for managing 'FormattableNames' (custom type)"""
+ _properties = RecordsField._properties.copy()
+ _properties.update({
+ 'type' : 'formattable_names',
+ 'default' : FormattableNames(),
+ 'subfields' : ('title','firstname','middlename','lastname',),
+ 'subfield_sizes' : {'title':10,
+ 'firstname': 15,
+ 'middlename':15,
+ 'lastname':30},
+ 'widget' : FormattableNamesWidget,
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePrivate('get')
+ def get(self, instance, **kwargs):
+ value = RecordsField.get(self, instance, **kwargs)
+ return FormattableNames(value)
+
+ security.declarePrivate('set')
+ def set(self, instance, value, **kwargs):
+ value = self._decode_strings(value, instance, **kwargs)
+ value = FormattableNames(value)
+ ObjectField.set(self, instance, value, **kwargs)
+
+InitializeClass(FormattableNamesField)
+
+registerField(FormattableNamesField,
+ title="Formattable Names",
+ description="Used for storing formattable names",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/field/record.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/record.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/record.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,364 @@
+from types import ListType, TupleType, ClassType, FileType, DictType, IntType
+from types import StringType, UnicodeType, StringTypes
+
+from Globals import InitializeClass
+from DateTime import DateTime
+from AccessControl import ClassSecurityInfo
+from Products.PythonScripts.standard import html_quote
+from Products.CMFCore.Expression import Expression
+from Products.CMFCore.Expression import createExprContext
+from Products.Archetypes.debug import log
+from Products.Archetypes.atapi import DisplayList
+from Products.Archetypes.Field import ObjectField
+from Products.Archetypes.Field import encode, decode
+from Products.Archetypes.Registry import registerField, registerPropertyType
+
+# we have to define our own validation handling
+try:
+ from Products.validation import ValidationChain
+ from Products.validation import UnknowValidatorError
+ from Products.validation import FalseValidatorError
+ from Products.validation.interfaces.IValidator \
+ import IValidator, IValidationChain
+ HAS_VALIDATION_CHAIN = 1
+except ImportError:
+ HAS_VALIDATION_CHAIN = 0
+
+from Products.ATExtensions.Extensions.utils import getDisplayList
+from Products.ATExtensions.widget import RecordWidget
+
+class RecordField(ObjectField):
+ """A field that stores a 'record' (dictionary-like) construct"""
+ _properties = ObjectField._properties.copy()
+ _properties.update({
+ 'type' : 'record',
+ 'default' : {},
+ 'subfields' : (),
+ 'subfield_types' : {},
+ 'subfield_vocabularies' : {},
+ 'subfield_labels' : {},
+ 'subfield_sizes' : {},
+ 'subfield_maxlength' : {},
+ 'required_subfields': (),
+ 'subfield_validators': {},
+ 'subfield_conditions': {},
+ 'innerJoin' : ', ',
+ 'outerJoin' : ', ',
+ 'widget' : RecordWidget,
+ })
+
+ security = ClassSecurityInfo()
+
+ def getSubfields(self):
+ """the tuple of sub-fields"""
+ return self.subfields
+
+ def getSubfieldType(self, subfield):
+ """
+ optional type declaration
+ default: string
+ """
+ return self.subfield_types.get(subfield, 'string')
+
+ def getSubfieldLabel(self, subfield):
+ """
+ optional custom label for the subfield
+ default: the id of the subfield
+ """
+ return self.subfield_labels.get(subfield, subfield.capitalize())
+
+ def getSubfieldSize(self, subfield, default=40):
+ """
+ optional custom size for the subfield
+ default: 40
+ only effective for string type subfields
+ """
+ return self.subfield_sizes.get(subfield, default)
+
+ def getSubfieldMaxlength(self, subfield):
+ """
+ otional custom maxlength size for the subfield
+ only effective for string type subfields
+ """
+ return self.subfield_maxlength.get(subfield, 40)
+
+ def isRequired(self,subfield):
+ """
+ looks whether subfield is included in the list of required subfields
+ """
+ return subfield in self.required_subfields
+
+ def isSelection(self,subfield):
+ """select box needed?"""
+
+ return self.subfield_vocabularies.has_key(subfield)
+
+ def testSubfieldCondition(self, subfield, folder, portal, object):
+ """Test the subfield condition."""
+ try:
+ condition = self.subfield_conditions.get(subfield, None)
+ if condition is not None:
+ __traceback_info__ = (folder, portal, object, condition)
+ ec = createExprContext(folder, portal, object)
+ return Expression(condition)(ec)
+ else:
+ return True
+ except AttributeError:
+ return True
+
+ def getVocabularyFor(self, subfield, instance=None):
+ """the vocabulary (DisplayList) for the subfield"""
+ ## XXX rr: couldn't we just rely on the field's
+ ## Vocabulary method here?
+ value = None
+ vocab = self.subfield_vocabularies.get(subfield, None)
+ if not vocab:
+ raise AttributeError, 'no vocabulary found for %s' %subfield
+
+ if isinstance(vocab, DisplayList):
+ return vocab
+
+ if type(vocab) in StringTypes:
+ value = None
+ method = getattr(self, vocab, None)
+ if method and callable(method):
+ value = method(instance)
+ else:
+ if instance is not None:
+ method = getattr(instance, vocab, None)
+ if method and callable(method):
+ value = method()
+ if not isinstance(value, DisplayList):
+ raise TypeError, '%s is not a DisplayList %s' %(value, subfield)
+ return value
+
+ raise TypeError, '%s niether a StringType or a DisplayList for %s' %(vocab, subfield)
+
+ def getViewFor(self, instance, subfield, joinWith=', '):
+ """
+ formatted value of the subfield for display
+ """
+ raw = self.getRaw(instance).get(subfield,'')
+ if type(raw) in (type(()), type([])):
+ raw = joinWith.join(raw)
+ # Prevent XSS attacks by quoting all user input
+ raw = html_quote(str(raw))
+ # this is now very specific
+ if subfield == 'email':
+ return self.hideEmail(raw)
+ if subfield == 'phone':
+ return self.labelPhone(raw)
+ if subfield == 'fax':
+ return self.labelFax(raw)
+ if subfield == 'homepage':
+ return '<a href="%s">%s</a>' % (raw, raw)
+ return raw
+
+ def getSubfieldViews(self,instance,joinWith=', '):
+ """
+ list of subfield views for non-empty subfields
+ """
+ result = []
+ for subfield in self.getSubfields():
+ view = self.getViewFor(instance,subfield,joinWith)
+ if view:
+ result.append(view)
+ return result
+
+ # this is really special purpose and in no ways generic
+ def hideEmail(self,email=''):
+ return 'email: ' + email.replace('@', ' (at) ').replace('.', ' (dot) ')
+
+ def labelPhone(self,phone=''):
+ return 'phone: ' + phone
+
+ def labelFax(self,fax=''):
+ return 'fax: ' + fax
+
+ # enable also a string representation of a dictionary
+ # to be passed in (external edit may need this)
+ # store string values as unicode
+
+ def set(self, instance, value, **kwargs):
+ if type(value) in StringTypes:
+ try:
+ value = eval(value)
+ # more checks to add?
+ except: # what to chatch here?
+ pass
+ value = self._to_dict(value)
+ value = self._decode_strings(value, instance, **kwargs)
+ ObjectField.set(self, instance, value, **kwargs)
+
+ def _to_dict(self, value):
+ if type(value) != type({}) and hasattr(value, 'keys'):
+ new_value = {}
+ new_value.update(value)
+ return new_value
+ return value
+
+ def _decode_strings(self, value, instance, **kwargs):
+ new_value = value
+ for k, v in value.items():
+ if type(v) is type(''):
+ nv = decode(v, instance, **kwargs)
+ try:
+ new_value[k] = nv
+ except AttributeError: # Records don't provide __setitem__
+ setattr(new_value, k , nv)
+
+ # convert datetimes
+ if self.subfield_types.get(k, None) == 'datetime':
+ try:
+ val = DateTime(v)
+ except:
+ val = None
+
+ new_value[k] = val
+
+ return new_value
+
+ # Return strings using the site's encoding
+
+ def get(self, instance, **kwargs):
+ value = ObjectField.get(self, instance, **kwargs)
+ return self._encode_strings(value, instance, **kwargs)
+
+ def _encode_strings(self, value, instance, **kwargs):
+ new_value = value
+ for k, v in value.items():
+ if type(v) is type(u''):
+ nv = encode(v, instance, **kwargs)
+ try:
+ new_value[k] = nv
+ except AttributeError: # Records don't provide __setitem__
+ setattr(new_value, k , nv)
+ return new_value
+
+ if HAS_VALIDATION_CHAIN:
+ def _validationLayer(self):
+ """
+ Resolve that each validator is in the service. If validator is
+ not, log a warning.
+
+ We could replace strings with class refs and keep things impl
+ the ivalidator in the list.
+
+ Note: XXX this is not compat with aq_ things like scripts with __call__
+ """
+ for subfield in self.getSubfields():
+ self.subfield_validators[subfield] = self._subfieldValidationLayer(subfield)
+
+ def _subfieldValidationLayer(self, subfield):
+ """
+ for the individual subfields
+ """
+ chainname = 'Validator_%s_%s' % (self.getName(), subfield)
+ current_validators = self.subfield_validators.get(subfield, ())
+
+ if type(current_validators) is DictType:
+ raise NotImplementedError, 'Please use the new syntax with validation chains'
+ elif IValidationChain.isImplementedBy(current_validators):
+ validators = current_validators
+ elif IValidator.isImplementedBy(current_validators):
+ validators = ValidationChain(chainname, validators=current_validators)
+ elif type(current_validators) in (TupleType, ListType, StringType):
+ if len(current_validators):
+ # got a non empty list or string - create a chain
+ try:
+ validators = ValidationChain(chainname, validators=current_validators)
+ except (UnknowValidatorError, FalseValidatorError), msg:
+ log("WARNING: Disabling validation for %s/%s: %s" % (self.getName(), subfield, msg))
+ validators = ()
+ else:
+ validators = ()
+ else:
+ log('WARNING: Unknow validation %s. Disabling!' % current_validators)
+ validators = ()
+
+ if not subfield in self.required_subfields:
+ if validators == ():
+ validators = ValidationChain(chainname)
+ if len(validators):
+ # insert isEmpty validator at position 0 if first validator
+ # is not isEmpty
+ if not validators[0][0].name == 'isEmpty':
+ validators.insertSufficient('isEmpty')
+ else:
+ validators.insertSufficient('isEmpty')
+
+ return validators
+
+ security.declarePublic('validate')
+ def validate(self, value, instance, errors={}, **kwargs):
+ """
+ Validate passed-in value using all subfield validators.
+ Return None if all validations pass; otherwise, return failed
+ result returned by validator
+ """
+ name = self.getName()
+ if errors and errors.has_key(name):
+ return True
+
+ if self.required_subfields:
+ for subfield in self.required_subfields:
+ sub_value = value.get(subfield, None)
+ res = self.validate_required(instance, sub_value, errors)
+ if res is not None:
+ return res
+
+ # not touched yet
+ if self.enforceVocabulary:
+ res = self.validate_vocabulary(instance, value, errors)
+ if res is not None:
+ return res
+
+ # can this part stay like it is?
+ res = instance.validate_field(name, value, errors)
+ if res is not None:
+ return res
+
+ # this should work
+ if self.subfield_validators:
+ res = self.validate_validators(value, instance, errors, **kwargs)
+ if res is not True:
+ return res
+
+ # all ok
+ return None
+
+ def validate_validators(self, value, instance, errors, **kwargs):
+ result = True
+ total = ''
+ for subfield in self.getSubfields():
+ subfield_validators = self.subfield_validators.get(subfield, None)
+ if subfield_validators:
+ result = subfield_validators(value.get(subfield),
+ instance=instance,
+ errors=errors,
+ field=self,
+ **kwargs
+ )
+ if result is not True:
+ total += result
+ return total or result
+
+
+InitializeClass(RecordField)
+
+registerField(RecordField,
+ title="Record",
+ description="Used for storing a 'record' (dictionary-like) construct",
+ )
+
+registerPropertyType('subfields', 'lines', RecordField)
+registerPropertyType('required_subfields', 'lines', RecordField)
+registerPropertyType('subfield_validators', 'mapping', RecordField)
+registerPropertyType('subfield_types', 'mapping', RecordField)
+registerPropertyType('subfield_vocabularies', 'mapping', RecordField)
+registerPropertyType('subfield_labels', 'mapping', RecordField)
+registerPropertyType('subfield_sizes', 'mapping', RecordField)
+registerPropertyType('subfield_maxlength', 'mapping', RecordField)
+registerPropertyType('innerJoin', 'string', RecordField)
+registerPropertyType('outerJoin', 'string', RecordField)
+
Added: zope-atextensions/branches/upstream/0.8.0/field/record_examples.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/record_examples.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/record_examples.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,115 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerField
+
+from Products.ATExtensions.Extensions.utils import getDisplayList
+
+from record import RecordField
+
+class AddressField(RecordField):
+ """ dedicated address field"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'address',
+ 'subfields' : ('street1','street2','zip','city', 'country'),
+ 'required_subfields': ('city', 'country'),
+ 'subfield_labels':{'zip':'ZIP code'},
+ 'subfield_vocabularies' :{'country':'CountryNames'},
+ 'outerJoin':'<br />',
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic("CountryNames")
+ def CountryNames(self, instance=None):
+ if not instance:
+ instance = self
+ return getDisplayList(instance, 'country_names')
+
+InitializeClass(AddressField)
+
+class LocationField(RecordField):
+ """ dedicated location (city, country) field"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'location',
+ 'subfields' : ('city', 'country'),
+ 'subfield_types' : {'country' : 'selection'},
+ 'subfield_vocabularies' :{'country':'CountryNames'},
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic("CountryNames")
+ def CountryNames(self, instance=None):
+ if not instance:
+ instance = self
+ return getDisplayList(instance, 'country_names')
+
+InitializeClass(LocationField)
+
+class ContactField(RecordField):
+ """name, phone, fax, email, address field"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'contact',
+ 'subfields' : ('name','phone','fax','email', 'address'),
+ 'innerJoin' : '<br>',
+ 'subfield_types' : {'address': 'lines'},
+ 'subfield_maxlength' : {'email' : 256},
+ 'outerJoin':'<br />',
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(ContactField)
+
+class SimpleNameField(RecordField):
+ """just first and last name"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'simple_name',
+ 'subfields' : ('first_name','last_name'),
+ 'subfield_labels':{'first_name':'First or given name(s)',
+ 'last_name':'Last or family name(s)',
+ },
+ 'outerJoin':' ',
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(SimpleNameField)
+
+class NetAddressField(RecordField):
+ """ dedicated net address field"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'net_address',
+ 'subfields' : ('email','homepage'),
+ 'subfield_validators':{'homepage':'isURL'},
+ 'outerJoin':'<br />',
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(NetAddressField)
+
+registerField(SimpleNameField,
+ title="SimpleName",
+ description="Used for storing a structured (first, last) name",
+ )
+
+registerField(LocationField,
+ title="Location",
+ description="Used for storing a location (city, country)",
+ )
+
+registerField(AddressField,
+ title="Address",
+ description="Used for storing an address (street1, street2, zip, city, country)",
+ )
+
+registerField(ContactField,
+ title="Contact",
+ description="Used for storing contact information (name, phone, fax, email, address)",
+ )
+
+registerField(NetAddressField,
+ title="NetAddress",
+ description="Used for storing email and homepage",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/field/records.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/records.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/records.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,148 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.PythonScripts.standard import html_quote
+from Products.Archetypes.Registry import registerField, registerPropertyType
+from Products.ATExtensions.config import HAS_VALIDATION_CHAIN
+from Products.ATExtensions.field import RecordField
+from Products.ATExtensions.widget import RecordsWidget
+
+
+class RecordsField(RecordField):
+ """A field that stores a 'record' (dictionary-like) construct"""
+ _properties = RecordField._properties.copy()
+ _properties.update({
+ 'type' : 'records',
+ 'default' : [],
+ 'fixedSize': 0,
+ 'minimalSize': 0,
+ 'maximalSize': 9999,
+ 'innerJoin' : ' ',
+ 'outerJoin' : ', ',
+ 'widget' : RecordsWidget,
+ })
+
+ security = ClassSecurityInfo()
+
+ def getSize(self, instance):
+ """number of records to store"""
+ return len(self.getRaw(instance))
+
+ def isSizeFixed(self):
+ """do we need an additional line of entry?"""
+ return self.fixedSize
+
+ def showMore(self, values):
+ """
+ return True if the 'More' button should be shown
+ False otherwise
+ """
+ data_length = len(values)
+ if data_length < self.maximalSize and not self.fixedSize:
+ return True
+ else:
+ return False
+
+ def getEditSize(self, instance):
+ """
+ number of record entries to offer in the form
+ at least 'minimalSize' or length of the current
+ list of records (+1 if 'more' is enabled)
+ """
+ data_length = len(self.getRaw(instance))
+ minimum = max(self.minimalSize, data_length)
+ if minimum >= self.maximalSize:
+ return minimum # not to lose data if uploads had added more
+ if not self.fixedSize:
+ return minimum + 1
+ return minimum
+
+ def getSubfieldValue(self, values, idx, subfield, default=None):
+ """
+ return values[idx].get(key) if existing
+ 'default' otherwise
+ """
+ try:
+ return values[idx].get(subfield, default)
+ except IndexError:
+ return default
+
+ def getViewFor(self, instance, idx, subfield, joinWith=', '):
+ """
+ formatted value of the subfield for display
+ """
+ raw = self.getRaw(instance)[idx].get(subfield,'')
+ if type(raw) in (type(()), type([])):
+ raw = joinWith.join(raw)
+ # Prevent XSS attacks by quoting all user input
+ raw = html_quote(str(raw))
+ # this is now very specific
+ if subfield == 'email':
+ return self.hideEmail(raw)
+ if subfield == 'homepage':
+ return '<a href="%s">%s</a>' % (raw, raw)
+ return raw.strip()
+
+ # store string type subfield values as unicode
+
+ def _encode_strings(self, value, instance, **kwargs):
+ new_value = []
+ for entry in value:
+ new_value.append(
+ RecordField._encode_strings(self, entry, instance, **kwargs)
+ )
+ return new_value
+
+ def _decode_strings(self, value, instance, **kwargs):
+ new_value = []
+ for entry in value:
+ new_value.append(
+ RecordField._decode_strings(self, entry, instance, **kwargs)
+ )
+ return new_value
+
+ # convert the records to persistent dictionaries
+ def _to_dict(self, value):
+ return [RecordField._to_dict(self, entry) for entry in value]
+
+ if HAS_VALIDATION_CHAIN:
+ security.declarePublic('validate')
+ def validate(self, value, instance, errors={}, **kwargs):
+ """
+ Validate passed-in value using all subfield validators.
+ Return None if all validations pass; otherwise, return failed
+ result returned by validator
+ """
+ name = self.getName()
+ if errors and errors.has_key(name):
+ return True
+
+ result = None
+ for record in value:
+ result = RecordField.validate(self,
+ record,
+ instance,
+ errors={},
+ **kwargs
+ )
+ if result: return result
+ return result
+
+InitializeClass(RecordsField)
+
+registerField(RecordsField,
+ title="Records",
+ description="Used for storing a list of records",
+ )
+
+registerPropertyType('subfields', 'lines', RecordsField)
+registerPropertyType('required_subfields', 'lines', RecordField)
+registerPropertyType('subfield_validators', 'mapping', RecordField)
+registerPropertyType('subfield_types', 'mapping', RecordsField)
+registerPropertyType('subfield_vocabularies', 'mapping', RecordsField)
+registerPropertyType('subfield_labels', 'mapping', RecordsField)
+registerPropertyType('subfield_sizes', 'mapping', RecordsField)
+registerPropertyType('subfield_maxlength', 'mapping', RecordsField)
+registerPropertyType('innerJoin', 'string', RecordsField)
+registerPropertyType('fixedSize', 'boolean', RecordsField)
+registerPropertyType('minimalSize', 'int', RecordsField)
+registerPropertyType('maximalSize', 'int', RecordsField)
Added: zope-atextensions/branches/upstream/0.8.0/field/records_examples.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/records_examples.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/records_examples.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,54 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerField
+
+from Products.ATExtensions.Extensions.utils import getDisplayList
+
+from records import RecordsField
+
+
+class MultipleNamesField(RecordsField):
+ """a list of stuctured names (first, last)"""
+ _properties = RecordsField._properties.copy()
+ _properties.update({
+ 'type' : 'multiple_names',
+ 'subfields' : ('first_name','last_name'),
+ 'subfield_labels':{'first_name':'First or given name(s)',
+ 'last_name':'Last or family name(s)',
+ },
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(MultipleNamesField)
+
+class PhoneNumbersField(RecordsField):
+ """a list of phone numbers (number, type)"""
+ _properties = RecordsField._properties.copy()
+ _properties.update({
+ 'type' : 'phone_numbers',
+ 'subfields' : ('type','number'),
+ 'subfield_vocabularies':{'type':'PhoneNumberTypes',},
+ 'innerJoin':': ',
+ 'outerJoin':'<br />',
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic("PhoneNumberTypes")
+ def PhoneNumberTypes(self, instance=None):
+ """phone number types"""
+ if not instance:
+ instance = self
+ return getDisplayList(instance, 'phone_number_types')
+
+InitializeClass(PhoneNumbersField)
+
+registerField(MultipleNamesField,
+ title="MultipleNames",
+ description="Used for storing a list of structured names (first_name, last_name)",
+ )
+
+registerField(PhoneNumbersField,
+ title="PhoneNumbers",
+ description="Used for storing a list of phone numbers (type, number)",
+ )
+
Added: zope-atextensions/branches/upstream/0.8.0/field/remotetext.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/remotetext.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/remotetext.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,180 @@
+import os, urllib
+from DateTime.DateTime import DateTime
+from Products.Archetypes.public import TextField, DisplayList
+from Products.Archetypes.Registry import registerField
+from Products.Archetypes.Registry import registerPropertyType
+from Products.Archetypes.annotations import AT_ANN_STORAGE as KEY
+from Products.Archetypes.annotations import getAnnotation
+
+from Products.ATExtensions.widget.remotetext import RemoteTextWidget
+
+def _pipe(command, input=''):
+ # XXX TODO what kind of pipe do we want?
+ fi, fo, fe = os.popen3(command, 't')
+ fi.write(input)
+ fi.close()
+ output = fo.read()
+ fo.close()
+ error = fe.read()
+ fe.close()
+ return output, error
+
+
+class RemoteTextField(TextField):
+ """Field to represent text coming from a remote source like
+ another web site (url) or a subversion repository"""
+
+ _properties = TextField._properties.copy()
+ _properties.update({
+ 'type' : 'remote_text',
+ 'source_types' : ('svn', 'web'),
+ 'timeout' : 1, # should be one day
+ 'customized' : False,
+ 'widget' : RemoteTextWidget,
+ })
+
+ def getSourceTypeVocabulary(self):
+ """All supported repository types """
+ d = DisplayList()
+ for t in self.source_types:
+ d.add(t,t)
+ return d
+
+ # source handling
+ def getSourcePath(self, instance):
+ """the source path from the instance annotations or empty string"""
+ ann = getAnnotation(instance)
+ subkey = "%s-source-path" % self.getName()
+ return ann.getSubkey(KEY, subkey, default='')
+
+ def setSourcePath(self, instance, value):
+ """Stores source path in the instance annotations"""
+ ann = getAnnotation(instance)
+ subkey = "%s-source-path" % self.getName()
+ return ann.setSubkey(KEY, value, subkey)
+
+ def getSourceType(self, instance):
+ """the source path from the instance annotations or empty string"""
+ ann = getAnnotation(instance)
+ subkey = "%s-source-type" % self.getName()
+ return ann.getSubkey(KEY, subkey, default='')
+
+ def setSourceType(self, instance, value):
+ """Stores source path in the instance annotations"""
+ ann = getAnnotation(instance)
+ subkey = "%s-source-type" % self.getName()
+ return ann.setSubkey(KEY, value, subkey)
+
+ def getTimeout(self, instance):
+ """the timeout from the instance annotations or empty string"""
+ ann = getAnnotation(instance)
+ subkey = "%s-timeout" % self.getName()
+ return ann.getSubkey(KEY, subkey, default=self.timeout)
+
+ def setTimeout(self, instance, value):
+ """Stores the timeout in the instance annotations"""
+ ann = getAnnotation(instance)
+ subkey = "%s-timeout" % self.getName()
+ return ann.setSubkey(KEY, value, subkey)
+
+ def getLastUpdate(self, instance):
+ """time of the last update or None"""
+ ann = getAnnotation(instance)
+ subkey = "%s-last-update" % self.getName()
+ return ann.getSubkey(KEY, subkey, default=None)
+
+ def setLastUpdate(self, instance, value):
+ """Stores the time of the last update in the instance annotations"""
+ ann = getAnnotation(instance)
+ subkey = "%s-last-update" % self.getName()
+ return ann.setSubkey(KEY, value, subkey)
+
+ def is_customized(self, instance):
+ """Flag whether this field has been customized"""
+ ann = getAnnotation(instance)
+ subkey = "%s-customized" % self.getName()
+ return ann.getSubkey(KEY, subkey, default=self.customized)
+
+ def customize(self, instance):
+ """Set the customize flag to True"""
+ ann = getAnnotation(instance)
+ subkey = "%s-customized" % self.getName()
+ ann.setSubkey(KEY, True, subkey)
+ return None
+
+ def uncustomize(self, instance):
+ """Set the customize flag to False"""
+ ann = getAnnotation(instance)
+ subkey = "%s-customized" % self.getName()
+ ann.setSubkey(KEY, False, subkey)
+ return None
+
+ def get(self, instance, **kw):
+ if self._isexpired(instance):
+ self.set(instance)
+ return TextField.get(self, instance, **kw)
+
+ def _isexpired(self, instance):
+ if self.is_customized(instance):
+ return False
+ last_update = self.getLastUpdate(instance)
+ if last_update is None:
+ return False # not yet loaded -> not expired
+ timeout = self.getTimeout(instance)
+ now = DateTime()
+ if (now - timeout) > last_update:
+ return True
+ return False
+
+ def set(self, instance, value=None, **kw):
+ source_text = None
+ if value is None or not self.is_customized(instance):
+ source_text = self.getSourceText(instance, **kw)
+ if source_text:
+ value = source_text
+ now = DateTime()
+ self.setLastUpdate(instance, now)
+ TextField.set(self, instance, value, **kw)
+
+ def getSourceText(self, instance, **kw):
+ """main method to fetch the value from the remote site"""
+ stype = self.getSourceType(instance)
+ value = ''
+ if stype == 'web':
+ value = self.getTextFromUrl(instance)
+ if stype == 'svn':
+ value = self.getTextFromSvn(instance)
+ return value or ''
+
+ def getTextFromUrl(self, instance):
+ source_path = self.getSourcePath(instance)
+ try:
+ # better use Tiran's 'urlupload'?
+ value = urllib.urlopen(source_path).read()
+ except: # XXX FIXME what to catch here?
+ value = ''
+
+ return value
+
+ def getTextFromSvn(self, instance):
+ source_path = self.getSourcePath(instance)
+ error = None
+ command = "svn export %s" % source_path
+ try:
+ value, error = _pipe(command)
+ except: # XXX FIXME what to catch here? - or is pipe
+ # robust enough never to blow up??
+ value = ''
+
+ if error:
+ return ''
+ return value
+
+registerField(RemoteTextField,
+ title="Remote Text Field",
+ description="Populate a field from a remote source")
+
+registerPropertyType('source_types', 'lines', RemoteTextField)
+registerPropertyType('timeout', 'DateTime', RemoteTextField)
+registerPropertyType('customized', 'boolean', RemoteTextField)
+
Added: zope-atextensions/branches/upstream/0.8.0/field/url.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/field/url.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/field/url.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,23 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Field import ObjectField
+from Products.Archetypes.Registry import registerField
+
+from Products.ATExtensions.widget import UrlWidget
+
+class UrlField(ObjectField):
+ """specific field for URLs"""
+ _properties = ObjectField._properties.copy()
+ _properties.update({
+ 'type' : 'url',
+ 'validators' : ('isPartialUrl'),
+ 'widget' : UrlWidget,
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(UrlField)
+
+registerField(UrlField,
+ title="Url",
+ description="Used for storing a validated url",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/i18n/i18nCall.sh
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/i18nCall.sh 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/i18nCall.sh 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,5 @@
+#!/bin/bash
+cd ..
+#i18ndude rebuild-pot --pot i18n/atextensions-generated.pot --create atextensions --merge i18n/atextensions-manual.pot ./skins
+cp i18n/plone-manual.pot i18n/plone-generated.pot
+cd i18n
\ No newline at end of file
Property changes on: zope-atextensions/branches/upstream/0.8.0/i18n/i18nCall.sh
___________________________________________________________________
Name: svn:executable
+
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-da.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-da.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-da.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,19 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-02-07 12:45+0000\n"
+"PO-Revision-Date: 2005-02-07 12:45-0300\n"
+"Last-Translator: Jonas Nielsen <jonasn at mail.tele.dk>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language-code: da\n"
+"Language-name: Danish\n"
+"Domain: plone\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Preferred-encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: da-dk\n"
+
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-de.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-de.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-de.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,34 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-04-13 21:25+0000\n"
+"PO-Revision-Date: 2007-01-04 11:07-0000\n"
+"Last-Translator: Mike Gabriel <m.gabriel at sunweavers.net>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Domain: plone\n"
+"Language-Code: de\n"
+"Language-Name: German\n"
+"Preferred-Encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: de-at de-li de-lu de-ch de-de\n"
+
+#. Default: "delete"
+#: records widget
+msgid "delete_this_entry"
+msgstr "löschen"
+
+#. Default: "delete all entries"
+#: records widget
+msgid "delete_all_entries"
+msgstr "alle löschen"
+
+#. Default: " More "
+#: records widget
+msgid "more_entries"
+msgstr " Mehr "
+
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-en.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-en.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-en.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,34 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-04-13 21:25+0000\n"
+"PO-Revision-Date: 2007-01-04 11:07-0000\n"
+"Last-Translator: Mike Gabriel <m.gabriel at sunweavers.net>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Domain: plone\n"
+"Language-Code: en\n"
+"Language-Name: English\n"
+"Preferred-Encodings: latin1\n"
+"X-Is-Fallback-For: en-au en-bz en-ca en-ie en-jm en-nz en-ph en-za en-tt en-gb en-us en-zw\n"
+
+#. Default: "delete"
+#: records widget
+msgid "delete_this_entry"
+msgstr "delete"
+
+#. Default: "delete all entries"
+#: records widget
+msgid "delete_all_entries"
+msgstr "delete all entries"
+
+#. Default: " More "
+#: records widget
+msgid "more_entries"
+msgstr " More "
+
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-fr.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-fr.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-fr.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,18 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-04-13 21:25+0000\n"
+"PO-Revision-Date: 2004-04-16 21:01+0100\n"
+"Last-Translator: David Convent <david.convent at naturalsciences.be>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Domain: plone\n"
+"Language-Code: fr\n"
+"Language-Name: French\n"
+"Preferred-Encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: fr-be fr-ca fr-lu fr-mc fr-ch\n"
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-generated.pot
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-generated.pot 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-generated.pot 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,29 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"Report-Msgid-Bugs-To: m.gabriel at sunweavers.net\n"
+"POT-Creation-Date: 2006-04-01 16:06+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Domain: plone\n"
+
+#: records widget
+#. Default: "delete"
+msgid "delete_this_entry"
+msgstr ""
+
+#: records widget
+#. Default: "delete all entries"
+msgid "delete_all_entries"
+msgstr ""
+
+#: records widget
+#. Default: " More "
+msgid "more_entries"
+msgstr ""
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-it.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-it.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-it.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,19 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-05-14 12:45+0000\n"
+"PO-Revision-Date: 2004-05-18 12:45-0300\n"
+"Last-Translator: Enzo Cesanelli <enzo at noiza.com>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language-code: it\n"
+"Language-name: Italian\n"
+"Domain: plone\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Preferred-encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: it-it it-hr it-sm it-si it-ch\n"
+
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-manual.pot
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-manual.pot 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-manual.pot 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,29 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"Report-Msgid-Bugs-To: m.gabriel at sunweavers.net\n"
+"POT-Creation-Date: 2006-04-01 16:06+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL at ADDRESS>\n"
+"Language-Team: LANGUAGE <LL at li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Domain: plone\n"
+
+#: records widget
+#. Default: "delete"
+msgid "delete_this_entry"
+msgstr ""
+
+#: records widget
+#. Default: "delete all entries"
+msgid "delete_all_entries"
+msgstr ""
+
+#: records widget
+#. Default: " More "
+msgid "more_entries"
+msgstr ""
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-nl.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-nl.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-nl.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,18 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-04-13 21:25+0000\n"
+"PO-Revision-Date: 2004-04-16 21:01+0100\n"
+"Last-Translator: David Convent <david.convent at naturalsciences.be>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Domain: plone\n"
+"Language-Code: nl\n"
+"Language-Name: Nederlands\n"
+"Preferred-Encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: nl-be\n"
Added: zope-atextensions/branches/upstream/0.8.0/i18n/plone-pt.po
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/i18n/plone-pt.po 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/i18n/plone-pt.po 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,18 @@
+# Gettext Message File for ATExtensions.
+# Raphael Ritz <r.ritz at biologie.hu-berlin.de>, 2002-2006
+msgid ""
+msgstr ""
+"Project-Id-Version: ATExtensions\n"
+"POT-Creation-Date: 2004-05-14 12:45+0000\n"
+"PO-Revision-Date: 2005-04-26 07:34+0100\n"
+"Last-Translator: J M Cerqueira Esteves <jmce at artenumerica.com>\n"
+"Language-Team: ATExtensions i18n <r.ritz at biologie.hu-berlin.de>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=iso-8859-1\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language-code: pt\n"
+"Language-name: Português\n"
+"Domain: plone\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+"Preferred-encodings: latin1 utf-8\n"
+"X-Is-Fallback-For: pt-pt pt-br\n"
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/address_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/address_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/address_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,82 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ i18n:domain="plone">
+
+ <body>
+
+ <!-- Address Widgets -->
+ <metal:view_macro define-macro="view"
+ tal:replace="structure python:accessor().replace('\n','<br />')" />
+
+
+ <metal:define define-macro="edit">
+ <fieldset><legend>Address</legend>
+
+ <tal:block tal:define="addr python:request.form.get('address', here.getAddress());
+ street1 python:addr.get('street1','');
+ street2 python:addr.get('street2','');
+ zip python:addr.get('zip','');
+ city python:addr.get('city','');
+ state python:addr.get('state','');
+ country python:addr.get('country','');">
+ <div class="label">Street</div>
+ <div class="field">
+ <input name="address.street1:record:ignore_empty"
+ tal:attributes="value street1;
+ tabindex tabindex/next" />
+ </div>
+ <div class="label">Street (cont)</div>
+ <div class="field">
+ <input name="address.street2:record:ignore_empty"
+ tal:attributes="value street2;
+ tabindex tabindex/next" />
+ </div>
+ <div class="label">ZIP Code</div>
+ <div class="field">
+ <input name="address.zip:record:ignore_empty"
+ tal:attributes="value zip;
+ tabindex tabindex/next" />
+ </div>
+ <div class="label">City</div>
+ <div class="field">
+ <input name="address.city:record:ignore_empty"
+ tal:attributes="value city;
+ tabindex tabindex/next" />
+ </div>
+ <div class="label">State</div>
+ <div class="field">
+ <input name="address.state:record:ignore_empty"
+ tal:attributes="value state;
+ tabindex tabindex/next" /> <br />
+ </div>
+ <div class="label">Country</div>
+ <div class="field">
+ <select name="address.country:record:ignore_empty" size="1"
+ tal:attributes="tabindex tabindex/next"
+ tal:define="values python:here.portal_properties.nip_properties.getProperty('country_names')">
+ <option tal:repeat="value values"
+ tal:content="value"
+ tal:attributes="value value;
+ selected python:test(value==country, 'selected', '');"> #
+ </option>
+ </select>
+ </div>
+ </tal:block>
+
+
+ </fieldset>
+
+
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/edit">
+ </div>
+ </div>
+
+ </body>
+
+</html>
+
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/combo_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/combo_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/combo_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,97 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+
+<head>
+ <title></title>
+</head>
+
+<body>
+
+ <!-- Selection Widgets -->
+
+ <metal:view_macro define-macro="view"
+ tal:define="vocab python:field.Vocabulary(here);
+ value python:accessor();
+ display python:here.displayValue(vocab, value)"
+ tal:replace="structure display" />
+
+ <metal:define define-macro="edit">
+
+ <metal:use use-macro="field_macro | here/widgets/field/macros/edit">
+
+ <metal:fill fill-slot="widget_body"
+ tal:define="vocab python:field.Vocabulary(here);
+ vlen python:len(vocab);
+ format python:widget.format">
+
+ <tal:shortVocab condition="python:(vlen < 4 and format == 'flex') or (format == 'radio')">
+
+ <!-- Radio when the vocab is short < 4 -->
+
+ <tal:radios repeat="item vocab">
+
+ <input class="noborder"
+ tabindex=""
+ type="radio"
+ tal:define="tabindex tabindex/next"
+ tal:attributes="name fieldName;
+ id string:${fieldName}_${tabindex};
+ checked python:here.checkSelected(item, value);
+ value item;
+ tabindex tabindex;"
+ />
+
+ <label tal:content="python:here.translate(vocab.getMsgId(item), default=vocab.getValue(item))"
+ tal:attributes="for string:${fieldName}_${tabindex/pos}" />
+
+ <br />
+
+ </tal:radios>
+
+ </tal:shortVocab>
+
+ <tal:longVocab condition="python:(vlen >= 4 and format == 'flex') or (format in ('select', 'pulldown'))">
+
+ <!-- Pulldown when longer -->
+
+ <select tal:attributes="name fieldName;
+ id fieldName;
+ tabindex tabindex/next;">
+
+ <option tal:repeat="item vocab"
+ tal:attributes="value item;
+ selected python:test(here.checkSelected(item, value), 'selected', None);"
+ tal:content="python:here.translate(vocab.getMsgId(item), default=vocab.getValue(item))"
+ i18n:translate=""
+ />
+
+ </select>
+
+ </tal:longVocab>
+ <span>or specify:
+ <input type="text"
+ name=""
+ value=""
+ size="30"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}_other;
+ value value;
+ tabindex tabindex/next;"
+ />
+ </span>
+ </metal:fill>
+
+ </metal:use>
+
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/selection/macros/edit" />
+ </div>
+
+</body>
+
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/comment_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/comment_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/comment_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,26 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+
+<head><title></title></head>
+<body>
+
+ <!-- Comment Widgets -->
+
+ <div metal:define-macro="view">
+ <div metal:use-macro="here/widgets/string/macros/view">
+ </div>
+ </div>
+ <div metal:define-macro="edit">
+ <div metal:use-macro="here/widgets/string/macros/view">
+ </div>
+ </div>
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/view">
+ </div>
+ </div>
+
+</body>
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/customize_remotefield.cpy
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/customize_remotefield.cpy 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/customize_remotefield.cpy 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,18 @@
+## Controller Python Script "customize_remotefield"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind state=state
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+field_id = context.REQUEST.get('customize_field', None)
+
+if field_id is not None:
+ field = context.getField(field_id)
+ field.customize(context)
+
+# Always make sure to return the ControllerState object
+return state
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/datetime_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/datetime_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/datetime_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,282 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+
+ <head><title></title></head>
+
+ <body>
+
+ <!-- Calendar Widgets -->
+
+ <metal:view_macro define-macro="view"
+ tal:define="d accessor;
+ d python:test(d and d=='None','',d);
+ format widget/format;
+ formatted python:format and d and d.strftime(format);
+ result python:(format and formatted) or (d and here.toPortalTime(d, long_format=1));"
+ tal:replace="structure python:result" />
+
+ <metal:define define-macro="edit"
+ tal:define="format widget/format">
+ <metal:use use-macro="field_macro | here/widgets/field/macros/edit">
+ <metal:fill fill-slot="widget_body">
+ <tal:define define="id fieldName;
+ inputname fieldName;
+ formname string:edit_form;
+ inputvalue python:test(value!='None', value, '');">
+ <metal:use use-macro="here/datetime_widget/macros/calendarDatePickerBoxNG">
+ a calendar, hopefully
+ </metal:use>
+ </tal:define>
+ </metal:fill>
+ </metal:use>
+ </metal:define>
+
+ <metal:define define-macro="search">
+ <metal:field use-macro="here/widgets/field/macros/edit">
+ <metal:slot fill-slot="widget_body">
+ <tal:from define="id fieldName;
+ inputname fieldName;
+ formname string:search_form;
+ inputvalue python:min(request.form.get(fieldName, None) or request.other.get(fieldName, None) or ('1975-05-26',)).strip();
+ tabindex tabindex/next">
+ <metal:box use-macro="here/datetime_widget/macros/calendarDatePickerBoxNG">
+ a calendar, hopefully
+ </metal:box>
+ </tal:from>
+ -
+ <tal:to define="id fieldName;
+ inputname fieldName;
+ formname string:search_form;
+ inputvalue python:max(request.form.get(fieldName, None) or request.other.get(fieldName, None) or ('2975-05-26',)).strip();
+ tabindex tabindex/next">
+ <metal:box use-macro="here/datetime_widget/macros/calendarDatePickerBoxNG">
+ a calendar, hopefully
+ </metal:box>
+ </tal:to>
+ <input type="hidden"
+ name="field_usage"
+ value="range:min:max"
+ tal:attributes="name string:${fieldName}_usage"
+ />
+ </metal:slot>
+ </metal:field>
+ </metal:define>
+
+ <div metal:define-macro="calendarDatePickerBoxNG" tal:define="
+ tabindex tabindex/next|tabindex|nothing;
+ input_id string:${formname}_${inputname}_${tabindex};
+ values python:here.date_components_support(inputvalue);
+ days values/days; months values/months; years values/years;
+ minutes values/minutes; hours values/hours;
+ yearStart python:years[0]['value'];
+ yearEnd python:years[-1]['value'];">
+
+ <input type="hidden" tal:attributes="name string:$inputname;
+ id input_id;
+ value inputvalue;" />
+
+ <span>
+ <select name="ic_year"
+ id="ic_year"
+ size="1"
+ tal:attributes="tabindex tabindex;
+ name string:${inputname}_year;
+ id string:${input_id}_year;
+ onfocus onfocus|nothing;
+ onblur onblur|nothing;
+ onchange
+ string:update_date_field('${input_id}','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute');"
+ tal:condition="field/with_date">
+
+ <option value="year"
+ tal:repeat="year years"
+ tal:attributes="value year/value; selected year/selected"
+ i18n:translate=""
+ tal:content="year/id">year</option>
+
+ </select>
+
+ <input name="ic_year" id="ic_year" type="hidden" tal:attributes="name
+ string:${inputname}_year; id string:${input_id}_year;
+ value yearStart;" tal:condition="not:field/with_date"/>
+ </span>
+
+ <span i18n:translate="date_separator" tal:condition="field/with_date">/</span>
+
+ <span>
+ <select name="ic_month"
+ id="ic_month"
+ size="1"
+ tal:attributes="tabindex tabindex;
+ name string:${inputname}_month;
+ id string:${input_id}_month;
+ onfocus onfocus|nothing;
+ onblur onblur|nothing;
+ onchange
+ string:update_date_field('${input_id}','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute');"
+ tal:condition="field/with_date">
+
+ <option value="subj"
+ tal:repeat="month months"
+ tal:attributes="value month/value; selected month/selected"
+ i18n:translate=""
+ tal:content="month/id">month name</option>
+
+ </select>
+
+ <input name="ic_month" id="ic_month" type="hidden" tal:attributes="name
+ string:${inputname}_month; id string:${input_id}_month;
+ value python: months[1]['value'];"
+ tal:condition="not:field/with_date"/>
+
+ </span>
+
+ <span i18n:translate="date_separator" tal:condition="field/with_date">/</span>
+
+ <span>
+ <select name="ic_day"
+ id="ic_day"
+ size="1"
+ tal:attributes="tabindex tabindex;
+ name string:${inputname}_day;
+ id string:${input_id}_day;
+ onfocus onfocus|nothing;
+ onblur onblur|nothing;
+ onchange
+ string:update_date_field('${input_id}','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute');"
+ tal:condition="field/with_date">
+
+ <option value="subj"
+ tal:repeat="day days"
+ tal:attributes="value day/value; selected day/selected"
+ i18n:translate=""
+ tal:content="day/id">day</option>
+
+ </select>
+
+ <input name="ic_day" id="ic_day" type="hidden" tal:attributes="name
+ string:${inputname}_day; id string:${input_id}_day;
+ value python: days[1]['value'];" tal:condition="not:field/with_date"/>
+ </span>
+
+ <a tal:attributes="onclick string:return showJsCalendar('${input_id}_month','$input_id','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute',$yearStart,$yearEnd);"
+ tal:condition="field/with_date"><img tal:replace="structure here/popup_calendar.gif" /></a>
+
+ <span>
+ <select name="ic_hour"
+ id="ic_hour"
+ size="1"
+ tal:attributes="tabindex tabindex;
+ name string:${inputname}_hour;
+ id string:${input_id}_hour;
+ onfocus onfocus|nothing;
+ onblur onblur|nothing;
+ onchange
+ string:update_date_field('${input_id}','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute');"
+ tal:condition="field/with_time">
+
+ <option value="subj"
+ tal:repeat="hour hours"
+ tal:attributes="value hour/value; selected hour/selected"
+ i18n:translate=""
+ tal:content="hour/id">hour</option>
+
+ </select>
+
+ <input name="ic_hour" id="ic_hour" type="hidden" tal:attributes="name
+ string:${inputname}_hour; id string:${input_id}_hour;
+ value string:0;" tal:condition="not:field/with_time"/>
+ </span>
+
+ <span i18n:translate="time_separator" tal:condition="field/with_time">:</span>
+
+ <span>
+ <select name="ic_minute"
+ id="ic_minute"
+ size="1"
+ tal:attributes="tabindex tabindex;
+ name string:${inputname}_minute;
+ id string:${input_id}_minute;
+ onfocus onfocus|nothing;
+ onblur onblur|nothing;
+ onchange
+ string:update_date_field('${input_id}','${input_id}_year','${input_id}_month','${input_id}_day','${input_id}_hour','${input_id}_minute');"
+ tal:condition="field/with_time">
+
+ <option value="subj"
+ tal:repeat="minute minutes"
+ tal:attributes="value minute/value; selected minute/selected"
+ i18n:translate=""
+ tal:content="minute/id">hour</option>
+
+ </select>
+
+ <input name="ic_minute" id="ic_minute" type="hidden" tal:attributes="name
+ string:${inputname}_minute; id string:${input_id}_minute;
+ value string:0;" tal:condition="not:field/with_time"/>
+ </span>
+
+ </div>
+
+ <div metal:define-macro="calendarDatePickerBoxPopupNG"
+ class="container"
+ tal:define="DateTime python:modules['DateTime'].DateTime;
+ current python:DateTime();
+ month python:request.get('month', DateTime().month());
+ year python:request.get('year', DateTime().year());
+ prevMonthTime python:here.getPreviousMonth(month, year);
+ nextMonthTime python:here.getNextMonth(month, year);
+ weeks python:here.portal_calendar.getWeeksList(month=month, year=year);
+ input_id string:${formname}_${inputname}_${tabindex};">
+
+ <table cellpadding="2" cellspacing="0" border="0" class="calendar" id="thecalendar">
+ <tr tal:define="calendarurl python:'%s?input_id=%s' % (path('template/absolute_url'),input_id) ">
+ <th>
+ <a href="" tal:attributes="href python:'%s&month:int=%d&year:int=%d' % (calendarurl,prevMonthTime.month(),prevMonthTime.year())">«</a>
+ </th>
+ <th colspan="5" tal:define="date string:$month/1/$year">
+ <span i18n:translate="" tal:omit-tag="">
+ <span i18n:name="monthname">
+ <span i18n:translate="" tal:content="python:DateTime(date).strftime('%B').capitalize()" tal:omit-tag="" />
+ </span>
+ <span i18n:name="year" tal:content="python:DateTime(date).year()" tal:omit-tag=""/>
+ </span>
+ </th>
+
+ <th>
+ <a href="" tal:attributes="href python:'%s&month:int=%d&year:int=%d' % (calendarurl,nextMonthTime.month(),nextMonthTime.year())">»</a>
+ </th>
+ </tr>
+
+ <tr tal:define="weekdays here/portal_calendar/getDays">
+ <tal:block repeat="weekday weekdays">
+ <td class="weekdays" i18n:translate="" tal:content="weekday">Su</td>
+ </tal:block>
+ </tr>
+ <tr tal:repeat="week weeks">
+ <tal:block define="days week">
+ <tal:block repeat="day days" tal:omit-tag="">
+ <td tal:condition="not: python: day">
+
+ </td>
+ <td class="noevent" tal:condition="python: day"
+ tal:define="datestring python:'%d/%0.2d/%0.2d'%(year,month,day)"
+ tal:attributes="class python:test(current.year()==year and current.month()==month and current.day()==int(day), 'todaynoevent', 'noevent')">
+ <a href="" tal:attributes="onclick string:returndate('${datestring}');; return false" tal:content="day">
+ day number
+ </a>
+ </td>
+ </tal:block>
+ </tal:block>
+ </tr>
+
+ </table>
+
+ </div>
+
+ </body>
+
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/deadlines_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/deadlines_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/deadlines_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,106 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ i18n:domain="plone">
+
+ <body>
+
+ <!-- Deadlines Widgets -->
+ <metal:view_macro define-macro="view"
+ tal:replace="structure accessor" />
+
+
+ <metal:define define-macro="edit">
+ <fieldset><legend>Deadlines</legend>
+ <table>
+ <tr>
+ <th>Type</th><th>Date</th><th>Comment</th>
+ </tr>
+ <tr>
+ <td>the deadline's type</td>
+ <td>YYYY/MM/DD</td>
+ <td>optional; e.g., specific time</td>
+ </tr>
+ <div tal:condition="python:here.getDeadlineList()"
+ tal:repeat="dl python:request.get('deadlines',here.getDeadlineList())">
+ <div tal:define="deadline_type python:dl.get('deadline_type','');
+ date python:dl.get('date','');
+ comment python:dl.get('comment','');">
+ <tr>
+ <td><select name="deadlines.deadline_type:records:ignore_empty" size="1"
+ tal:attributes="tabindex tabindex/next"
+ tal:define="values python:here.portal_properties.nip_properties.getProperty('deadline_types')">
+ <option tal:repeat="value values"
+ tal:content="value"
+ tal:attributes="value value;
+ selected python:test(value==deadline_type, 'selected', '');"> #
+ </option>
+ </select>
+ </td>
+ <td><input name="deadlines.date:records:ignore_empty" size="15"
+ tal:attributes="value date;
+ tabindex tabindex/next" /></td>
+ <td><input name="deadlines.comment:records:ignore_empty" size="35"
+ tal:attributes="value comment;
+ tabindex tabindex/next" /></td>
+ </tr>
+ </div>
+ </div>
+ <div>
+ <tr tal:define="dl python:request.form.get('nextdeadline', {});
+ deadline_type python:dl.get('deadline_type','');
+ date python:dl.get('date','');
+ comment python:dl.get('comment','');">
+ <td><select name="nextdeadline.deadline_type:record:ignore_empty" size="1"
+ tal:attributes="tabindex tabindex/next"
+ tal:define="values python:here.portal_properties.nip_properties.getProperty('deadline_types')">
+ <option tal:repeat="value values"
+ tal:content="value"
+ tal:attributes="value value;
+ selected python:test(value==deadline_type, 'selected', '');"> #
+ </option>
+ </select>
+ </td>
+<!-- <td tal:define="id date;
+ inputname date;
+ formname string:edit_form;
+ inputvalue python: test(date, date, '');
+ tabindex tabindex/next;"
+ tal:omit-tag="">
+ <div metal:use-macro="here/calendar_macros/macros/calendarDatePickerBox|here/calendar_slot/macros/calendarDatePickerBox">
+ a calendar, hopefully
+ </div>
+ </td>
+rr: could not get this to work -->
+ <td><input name="nextdeadline.date:record:ignore_empty" size="15"
+ tal:attributes="value date;
+ tabindex tabindex/next" /></td>
+ <td><input name="nextdeadline.comment:record:ignore_empty" size="35"
+ tal:attributes="value comment;
+ tabindex tabindex/next" /></td>
+ </tr>
+ </div>
+ </table>
+
+ <div class="row">
+ <div class="label"></div>
+ <div class="field">
+ <input class="context" type="submit" name="more_deadlines" value=" More Deadlines "
+ tal:attributes="tabindex tabindex/next" />
+ </div>
+ </div>
+ </fieldset>
+
+
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/edit">
+ </div>
+ </div>
+
+ </body>
+
+</html>
+
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/email_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/email_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/email_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,27 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <head><title></title></head>
+ <body>
+
+ <!-- Email Widgets -->
+ <metal:view_macro define-macro="view"
+ tal:define="email accessor;
+ at_mask python:widget.at_mask">
+ <div
+ tal:condition="isAnon"
+ tal:content="python:email.replace('@',at_mask)">
+ email
+ </div>
+ <a href="#"
+ tal:condition="not:isAnon"
+ tal:attributes="href string:mailto:$email"
+ tal:content="email">
+ email
+ </a>
+ </metal:view_macro>
+ </body>
+
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formatdemo.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formatdemo.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formatdemo.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,26 @@
+## Script (Python) "formatdemo"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+# This is s special purpose script to illustrate
+# the formatting capabilities of the formattable name(s)
+#
+# it can only be applied to 'Formattable Name Demo' objects
+#
+n1 = context.getName1()
+n2 = context.getName2()
+g = context.getFriends()
+print n1
+print n1("%f %L")
+print n2
+print n2("%f%l (%F %L)")
+print n1+n2
+print (n1+n2)(lastsep=' & ')
+print g
+print (n1+n2+g)(format="%L %f%m", lastsep=' & ')
+return printed
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formattablename_view.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formattablename_view.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/formattablename_view.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,21 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <head><title></title></head>
+ <body>
+
+ <!-- FormattedName view macro -->
+ <metal:view_macro define-macro="view">
+ <div tal:define="name accessor;
+ kwargs widget/getKwArgs;
+ value python:name(**kwargs)"
+ tal:content="structure value">
+ -- the formatted name goes here --
+ </div>
+ </metal:view_macro>
+ </body>
+
+</html>
+
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/getDisplayView.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/getDisplayView.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/getDisplayView.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,15 @@
+## Script (Python) "getDisplayView"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind subpath=traverse_subpath
+##parameters=value, join=', '
+##title=
+##
+if same_type(value, '') or same_type(value, u''):
+ return value
+try:
+ return join.join(value)
+except TypeError:
+ return value
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,149 @@
+## Script (Python) "content_edit"
+##title=Edit content
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind state=state
+##bind subpath=traverse_subpath
+##parameters=id=''
+##
+REQUEST = context.REQUEST
+SESSION = REQUEST.SESSION
+
+old_id = context.getId()
+
+try:
+ new_context = context.portal_factory.doCreate(context, id)
+except AttributeError:
+ # Fallback for AT + plain CMF where we don't have a portal_factory
+ new_context = context
+new_context.processForm()
+
+# Get the current language and put it in request/LANGUAGE
+form = REQUEST.form
+if form.has_key('current_lang'):
+ form['language'] = form.get('current_lang')
+
+
+portal_status_message = context.translate(
+ msgid='message_content_changes_saved',
+ domain='archetypes',
+ default='Content changes saved.')
+
+portal_status_message = REQUEST.get('portal_status_message', portal_status_message)
+
+# handle navigation for multi-page edit forms
+next = not REQUEST.get('form_next', None) is None
+previous = not REQUEST.get('form_previous', None) is None
+fieldset = REQUEST.get('fieldset', None)
+schemata = new_context.Schemata()
+
+# check for the more button
+more = not REQUEST.get('form.button.more', None) is None
+
+if next or previous:
+ s_names = [s for s in schemata.keys() if s != 'metadata']
+
+ if previous:
+ s_names.reverse()
+
+ next_schemata = None
+ try:
+ index = s_names.index(fieldset)
+ except ValueError:
+ raise 'Non-existing fieldset: %s' % fieldset
+ else:
+ index += 1
+ if index < len(s_names):
+ next_schemata = s_names[index]
+ return state.set(status='next_schemata',
+ context=new_context,
+ fieldset=next_schemata,
+ portal_status_message=portal_status_message)
+
+ if next_schemata != None:
+ return state.set(status='next_schemata', \
+ context=new_context, \
+ fieldset=next_schemata, \
+ portal_status_message=portal_status_message)
+ else:
+ raise 'Unable to find next field set after %s' % fieldset
+
+env = state.kwargs
+reference_source_url = env.get('reference_source_url')
+if not more and reference_source_url is not None:
+ reference_source_url = env['reference_source_url'].pop()
+ reference_source_field = env['reference_source_field'].pop()
+ reference_source_fieldset = env['reference_source_fieldset'].pop()
+ portal = context.portal_url.getPortalObject()
+ reference_obj = portal.restrictedTraverse(reference_source_url)
+ portal_status_message = context.translate(
+ msgid='message_reference_added',
+ domain='archetypes',
+ default='Reference Added.')
+
+ edited_reference_message = context.translate(
+ msgid='message_reference_edited',
+ domain='archetypes',
+ default='Reference Edited.')
+
+ # update session saved data
+ uid = new_context.UID()
+ SESSION = context.REQUEST.SESSION
+ saved_dic = SESSION.get(reference_obj.getId(), None)
+ if saved_dic:
+ saved_value = saved_dic.get(reference_source_field, None)
+ if same_type(saved_value, []):
+ # reference_source_field is a multiValued field, right!?
+ if uid in saved_value:
+ portal_status_message = edited_reference_message
+ else:
+ saved_value.append(uid)
+ else:
+ if uid == saved_value:
+ portal_status_message = edited_reference_message
+ else:
+ saved_value = uid
+ saved_dic[reference_source_field] = saved_value
+ SESSION.set(reference_obj.getId(), saved_dic)
+
+ context.remove_creation_mark(old_id)
+
+ kwargs = {
+ 'status':'success_add_reference',
+ 'context':reference_obj,
+ 'portal_status_message':portal_status_message,
+ 'fieldset':reference_source_fieldset,
+ 'field':reference_source_field,
+ 'reference_focus':reference_source_field,
+ }
+ return state.set(**kwargs)
+
+if state.errors:
+ errors = state.errors
+ s_items = [(s, schemata[s].keys()) for s in schemata.keys()]
+ fields = []
+ for s, f_names in s_items:
+ for f_name in f_names:
+ fields.append((s, f_name))
+ for s_name, f_name in fields:
+ if errors.has_key(f_name):
+ REQUEST.set('fieldset', s_name)
+ return state.set(
+ status='failure',
+ context=new_context,
+ portal_status_message=portal_status_message)
+
+try:
+ context.remove_creation_mark(old_id)
+except AttributeError: # for backwards compatibility
+ pass
+
+if not state.errors:
+ from Products.CMFPlone import transaction_note
+ transaction_note('Edited %s %s at %s' % (new_context.meta_type, new_context.title_or_id(), new_context.absolute_url()))
+
+return state.set(status='success',
+ context=new_context,
+ portal_status_message=portal_status_message)
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy.metadata
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy.metadata 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/more_edit.cpy.metadata 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,13 @@
+[default]
+title = More Edit
+
+[validators]
+validators..more =
+validators = validate_base
+
+[actions]
+action.success..more = traverse_to_action:string:edit
+action.success = traverse_to:string:validate_integrity
+action.success_add_reference = redirect_to_action:string:edit
+action.failure = traverse_to_action:string:edit
+action.next_schemata = traverse_to_action:string:edit
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/record_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/record_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/record_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,129 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <head><title></title></head>
+ <body>
+
+ <!-- Record Widgets -->
+ <metal:view_macro define-macro="view">
+ <div tal:define="values_dict python:field.getAccessor(here)();
+ innerJoin field/innerJoin;
+ outerJoin field/outerJoin">
+
+ <table>
+ <tal:keys tal:repeat="key field/getSubfields">
+ <tr tal:condition="python:field.testSubfieldCondition(key,here,portal,template)">
+ <tal:value tal:define="value python:values_dict.get(key)"
+ tal:condition="value">
+ <td valign=top>
+ <span class="label"
+ tal:replace="python:field.getSubfieldLabel(key)+':'">Label</span></td>
+ <td>
+ <span tal:replace="structure python:here.getDisplayView(value,'<br />')">value</span>
+ </td>
+ </tal:value></tr>
+ </tal:keys></table>
+ </div>
+ </metal:view_macro>
+ <metal:define define-macro="edit">
+ <metal:use use-macro="here/widgets/field/macros/edit">
+ <table metal:fill-slot="widget_body"
+ tal:define="values python:field.getEditAccessor(here)();
+ session_values python:here.session_restore_value(fieldName, values);
+ cached_values python:request.get(fieldName,session_values);
+ values python:cached_values or values">
+ <tal:keys tal:repeat="key python:field.getSubfields()">
+ <tr tal:condition="python:field.testSubfieldCondition(key,here,portal,template)">
+ <td class="field">
+ <label i18n:translate=""
+ tal:content="python:field.getSubfieldLabel(key)"
+ tal:attributes="for string:${fieldName}_${key}">
+ </label>
+ <span class="fieldRequired"
+ tal:condition="python:field.isRequired(key)"
+ title="Required"> #
+ </span>
+ </td>
+ <td tal:define="type python: field.getSubfieldType(key)">
+ <tal:string condition="python: type == 'string' and not field.isSelection(key)">
+ <input type="text"
+ name=""
+ value=""
+ size="30"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:record:ignore_empty;
+ value python:values.get(key);
+ size python:field.getSubfieldSize(key);
+ maxlength python:field.getSubfieldMaxlength(key);
+ tabindex tabindex/next;"
+ />
+ </tal:string>
+ <tal:selection condition="python: field.isSelection(key)">
+ <tal:block tal:define="value python:values.get(key);
+ vocab python:field.getVocabularyFor(key, here)">
+ <select tal:attributes="name string:${fieldName}.${key}:record:ignore_empty;
+ id fieldName;
+ tabindex tabindex/next;">
+ <option tal:repeat="item vocab"
+ tal:attributes="value item;
+ selected python:test(here.checkSelected(item, value), 'selected', None);"
+ tal:content="python: vocab.getValue(item)"
+ i18n:translate=""
+ />
+ </select>
+ </tal:block>
+ </tal:selection>
+ <tal:text condition="python:type == 'lines'">
+ <textarea name=""
+ cols="30"
+ rows="4"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:record:lines:ignore_empty;
+ tabindex tabindex/next;"
+ tal:content="python:'\n'.join(values.get(key,[]))" >
+ </textarea>
+ </tal:text>
+ <tal:date condition="python:type == 'datetime'">
+ <div tal:define="id string:${fieldName}_${key};
+ value python:values.get(key);
+ inputname string:${fieldName}.${key}:record;
+ formname string:edit_form;
+ inputvalue python: test(value, value, '');
+ tabindex tabindex/next;"
+ tal:omit-tag="">
+ <div metal:use-macro="here/calendar_macros/macros/calendarDatePickerBox|here/calendar_slot/macros/calendarDatePickerBox">
+ a calendar, hopefully
+ </div>
+ </div>
+ </tal:date>
+ <tal:number condition="python: type in ['float', 'int', 'long']">
+ <input type="text"
+ name=""
+ value=""
+ size="10"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:${type}:record;
+ value python:values.get(key);
+ size python:field.getSubfieldSize(key);
+ maxlength python:field.getSubfieldMaxlength(key);
+ tabindex tabindex/next;"
+ />
+ </tal:number>
+ </td>
+ </tr>
+ </tal:keys> <!-- the condition-->
+ </table>
+ </metal:use>
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/edit">
+ </div>
+ </div>
+
+ </body>
+
+</html>
+
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/records_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/records_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/records_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,156 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <head><title></title></head>
+ <body>
+
+ <!-- Records Widgets -->
+ <metal:view_macro define-macro="view">
+ <tal:block tal:repeat="idx python:range(field.getSize(here))"
+ tal:define="outerJoin field/outerJoin;
+ innerJoin field/innerJoin;"><span
+ tal:define="subfieldValues python:[field.getViewFor(here,idx,key,innerJoin) for key in field.getSubfields()]"
+ tal:replace="structure python:innerJoin.join(subfieldValues)" /><span
+ tal:replace="structure outerJoin"
+ tal:condition="not: repeat/idx/end" />
+ </tal:block>
+ </metal:view_macro>
+
+ <metal:define define-macro="edit">
+ <metal:use use-macro="here/widgets/field/macros/edit">
+ <tal:block metal:fill-slot="widget_body">
+ <fieldset tal:define="values python:field.getEditAccessor(here)();
+ session_values python:here.session_restore_value(fieldName, values);
+ cached_values python:request.get(fieldName,session_values);
+ values python:cached_values or values">
+ <table>
+ <tr>
+ <tal:block repeat="key python:field.getSubfields()">
+ <td tal:condition="python:field.testSubfieldCondition(key,here,portal,template)"
+ tal:content="python: here.translate(domain=field.widget.i18n_domain, msgid=field.getSubfieldLabel(key), default=field.getSubfieldLabel(key))">
+ Label
+ </td>
+ </tal:block>
+ <td>
+ <span i18n:translate="delete_this_entry"
+ id="delete_this_entry">
+ delete</span>
+ </td>
+ </tr>
+ <tr tal:repeat="idx python:range(field.getEditSize(here))">
+ <tal:keys tal:repeat="key python:field.getSubfields()">
+ <td tal:condition="python:field.testSubfieldCondition(key,here,portal,template)">
+ <tal:block define="type python:field.getSubfieldType(key)">
+ <tal:string condition="python: type == 'string' and not field.isSelection(key)">
+ <input type="text"
+ name=""
+ value=""
+ size="30"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:records:ignore_empty;
+ value python:field.getSubfieldValue(values, idx, key);
+ size python:field.getSubfieldSize(key);
+ maxlength python:field.getSubfieldMaxlength(key);
+ tabindex tabindex/next;"
+ />
+ </tal:string>
+ <tal:selection condition="python: field.isSelection(key)">
+ <tal:block tal:define="value python:field.getSubfieldValue(values, idx, key);
+ vocab python:field.getVocabularyFor(key, here)">
+ <select tal:attributes="name string:${fieldName}.${key}:records:ignore_empty;
+ id fieldName;
+ tabindex tabindex/next;"
+ i18n:domain="python: field.widget.i18n_domain">
+ <option tal:repeat="item vocab"
+ tal:attributes="value item;
+ selected python:test(here.checkSelected(item, value), 'selected', None);"
+ tal:content="python: vocab.getValue(item)"
+ i18n:translate=""
+ />
+ </select>
+ </tal:block>
+ </tal:selection>
+ <tal:text condition="python: type == 'lines'">
+ <textarea name=""
+ cols="30"
+ rows="5"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:records:ignore_empty:lines;
+ tabindex tabindex/next;"
+ tal:content="python:'\n'.join(field.getSubfieldValue(values, idx, key, []))" >
+ </textarea>
+ </tal:text>
+ <tal:date condition="python:type == 'datetime'">
+ <div tal:define="id string:${fieldName}_${key}_${idx};
+ value python:field.getSubfieldValue(values, idx, key);
+ inputname string:${fieldName}.${key}:ignore_empty:records;
+ formname string:edit_form;
+ inputvalue python: test(value, value, '');
+ tabindex tabindex/next;"
+ tal:omit-tag="">
+ <div metal:use-macro="here/calendar_macros/macros/calendarDatePickerBox|here/calendar_slot/macros/calendarDatePickerBox">
+ a pop-up calendar
+ </div>
+ </div>
+ </tal:date>
+ <tal:number condition="python: type in ['float', 'int', 'long']">
+ <input type="text"
+ name=""
+ value=""
+ size="10"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}.${key}:${type}:records:ignore_empty;
+ value python:field.getSubfieldValue(values, idx, key);
+ size python:field.getSubfieldSize(key);
+ maxlength python:field.getSubfieldMaxlength(key);
+ tabindex tabindex/next;"
+ />
+ </tal:number>
+ </tal:block>
+ </td>
+ </tal:keys>
+ <td>
+ <input class="noborder"
+ type="checkbox"
+ value="off"
+ tabindex=""
+ tal:attributes="tabindex tabindex/next;
+ name string:${fieldName}_delete_${idx};
+ id string:${fieldName}_checkbox_${idx};"
+ />
+ </td>
+ </tr>
+ </table>
+ <input type="submit" name="form.button.more" class="context"
+ tal:condition="python: field.showMore(values)"
+ tal:attributes="tabindex tabindex/next"
+ i18n:attributes="value more_entries" />
+ <div tal:condition="values">
+ <input class="noborder"
+ type="checkbox"
+ value="off"
+ tabindex=""
+ tal:attributes="tabindex tabindex/next;
+ name string:${fieldName}_delete;
+ id string:${fieldName}_checkbox;"
+ />
+ <span i18n:translate="delete_all_entries"
+ id="delete_all_entries">
+ delete all entries</span>
+ </div>
+ </fieldset>
+ </tal:block>
+ </metal:use>
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/edit">
+ </div>
+ </div>
+
+ </body>
+
+</html>
+
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/remotetext_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/remotetext_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/remotetext_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,93 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+
+<head>
+ <title></title>
+</head>
+
+<body>
+
+ <!-- Selection Widgets -->
+
+ <div metal:define-macro="view">
+ <div metal:use-macro="here/widgets/rich/macros/view" />
+ <div class="discreet"
+ tal:condition="python: not field.is_customized(here)">
+ Mirroring <a href="#"
+ tal:define="url python:field.getSourcePath(here)"
+ tal:attributes="href url"
+ tal:content="url">
+ #</a>
+ </div>
+ </div>
+
+ <div metal:define-macro="edit">
+ <div tal:condition="python: not field.is_customized(here)">
+ <metal:use use-macro="field_macro | here/widgets/field/macros/edit">
+ <metal:fill fill-slot="widget_body"
+ tal:define="spath python:field.getSourcePath(here);
+ stype python:field.getSourceType(here);
+ vocab field/getSourceTypeVocabulary">
+ <br />
+ <span class="label">Source path:</span>
+ <input type="text"
+ name=""
+ value=""
+ size="60"
+ tabindex="#"
+ tal:attributes="name string:${fieldName}_source_path;
+ value spath;
+ tabindex tabindex/next;"
+ />
+ <br /> <br />
+ <span class="label">Source type:</span>
+ <tal:radios repeat="item vocab">
+
+ <input class="noborder"
+ tabindex=""
+ type="radio"
+ tal:define="tabindex tabindex/next"
+ tal:attributes="name string:${fieldName}_source_type;
+ id string:${fieldName}_source_type_${tabindex};
+ checked python:here.checkSelected(item, stype);
+ value item;
+ tabindex tabindex;"
+ />
+
+ <label tal:content="python:here.translate(vocab.getMsgId(item), default=vocab.getValue(item))"
+ tal:attributes="for string:${fieldName}_source_type_${tabindex/pos}" />
+
+ </tal:radios>
+ <br /> <br />
+ <input type="hidden" name="customize_field" value=""
+ tal:attributes="value string:${fieldName}" />
+ <input type="submit" name="form.button.customize" class="context"
+ tal:attributes="value python:' Customize ';
+ tabindex tabindex/next" />
+
+ </metal:fill>
+ </metal:use>
+ </div>
+
+ <div tal:condition="python:field.is_customized(here)">
+ <div metal:use-macro="here/widgets/rich/macros/edit" />
+ <input type="hidden" name="uncustomize_field" value=""
+ tal:attributes="value string:${fieldName}" />
+ <input type="submit"
+ name="form.button.uncustomize"
+ class="context"
+ tal:attributes="value python:' Undo Customization ';
+ tabindex tabindex/next" />
+ </div>
+ </div>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/rich/macros/search" />
+ </div>
+
+</body>
+
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/uncustomize_remotefield.cpy
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/uncustomize_remotefield.cpy 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/uncustomize_remotefield.cpy 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,18 @@
+## Controller Python Script "uncustomize_remotefield"
+##bind container=container
+##bind context=context
+##bind namespace=
+##bind script=script
+##bind state=state
+##bind subpath=traverse_subpath
+##parameters=
+##title=
+##
+field_id = context.REQUEST.get('uncustomize_field', None)
+
+if field_id is not None:
+ field = context.getField(field_id)
+ field.uncustomize(context)
+
+# Always make sure to return the ControllerState object
+return state
Added: zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/url_widget.pt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/url_widget.pt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/skins/at_extensions/url_widget.pt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,41 @@
+<html xmlns="http://www.w3.org/1999/xhtml"
+ xmlns:tal="http://xml.zope.org/namespaces/tal"
+ xmlns:metal="http://xml.zope.org/namespaces/metal"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
+ i18n:domain="plone">
+ <head><title></title></head>
+ <body>
+
+ <!-- Url Widgets -->
+ <metal:view_macro define-macro="view"
+ tal:define="url accessor">
+ <a href=""
+ tal:attributes="href url"
+ tal:content="url">#</a>
+ </metal:view_macro>
+
+ <metal:define define-macro="edit">
+ <metal:use use-macro="here/widgets/field/macros/edit">
+ <input metal:fill-slot="widget_body"
+ type="text"
+ name=""
+ value=""
+ size="30"
+ tabindex="#"
+ tal:attributes="name fieldName;
+ value value;
+ size widget/size;
+ maxlength widget/maxlength;
+ tabindex tabindex/next;"
+ />
+ </metal:use>
+ </metal:define>
+
+ <div metal:define-macro="search">
+ <div metal:use-macro="here/widgets/string/macros/edit">
+ </div>
+ </div>
+
+ </body>
+
+</html>
Added: zope-atextensions/branches/upstream/0.8.0/svn-commit.tmp
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/svn-commit.tmp 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/svn-commit.tmp 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,4 @@
+0.8.0 branch.
+--This line, and those below, will be ignored--
+
+A .
Added: zope-atextensions/branches/upstream/0.8.0/validator/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/validator/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/validator/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1 @@
+# blub, I'm a package
Added: zope-atextensions/branches/upstream/0.8.0/validator/isPartialUrl.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/validator/isPartialUrl.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/validator/isPartialUrl.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,19 @@
+import re
+from Products.validation.interfaces import ivalidator
+
+class PartialUrlValidator:
+ __implements__ = (ivalidator,)
+ def __init__(self, name):
+ self.name = name
+ def __call__(self, value, *args, **kwargs):
+ # field gets passed in via kwargs
+ if '://' not in value:
+ widget = kwargs.get('field').widget
+ default_p = getattr(widget,'default_protocol','http')
+ value = default_p + '://' + value
+ pattern = re.compile(r'(ht|f)tps?://[^\s\r\n]+')
+ m = pattern.match(value)
+ if not m:
+ return ("Validation failed(%s): value is %s"%(self.name,
+ repr(value)))
+ return 1
Added: zope-atextensions/branches/upstream/0.8.0/version.txt
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/version.txt 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/version.txt 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1 @@
+0.8.0
Added: zope-atextensions/branches/upstream/0.8.0/widget/__init__.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/__init__.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/__init__.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,13 @@
+# import the individual widgets
+
+from combo import ComboWidget
+from datetime import DateTimeWidget
+from deadlines import DeadlinesWidget
+from record import RecordWidget
+from records import RecordsWidget
+from url import UrlWidget
+from email import EmailWidget
+from formattablename import FormattableNameWidget
+from formattablenames import FormattableNamesWidget
+from comment import CommentWidget
+from remotetext import RemoteTextWidget
Added: zope-atextensions/branches/upstream/0.8.0/widget/combo.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/combo.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/combo.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,39 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import SelectionWidget
+from Products.Archetypes.Registry import registerWidget
+
+
+class ComboWidget(SelectionWidget):
+ _properties = SelectionWidget._properties.copy()
+ _properties.update({
+ 'type' : 'combobox',
+ 'macro' : "combo_widget",
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic('process_form')
+ def process_form(self, instance, field, form, empty_marker=None,
+ emptyReturnsMarker=False):
+ """
+ if no value or value equals 'other'
+ replace it with the optionally entered one
+ """
+ value = form.get(field.getName(), empty_marker)
+ if not value or value.lower() in ('other', u'other'):
+ # XXX is this generic enough?
+ other_name = "%s_other" % field.getName()
+ value = form.get(other_name, empty_marker)
+ if value is empty_marker:
+ return empty_marker
+ if emptyReturnsMarker and value == '':
+ return empty_marker
+ return value, {}
+
+InitializeClass(ComboWidget)
+
+registerWidget(ComboWidget,
+ title='ComboBox',
+ description="Select box together with a string field.",
+ used_for=('Products.Archetypes.Field.StringField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/comment.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/comment.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/comment.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,23 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import StringWidget
+from Products.Archetypes.Registry import registerWidget
+
+class CommentWidget(StringWidget):
+ _properties = StringWidget._properties.copy()
+ _properties.update({
+ 'macro' : "comment_widget",
+ 'i18n_domain': "plone",
+ 'visible' : {'edit' : 'visible',
+ 'view' : 'invisible',
+ }
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(CommentWidget)
+
+registerWidget(CommentWidget,
+ title='Comment',
+ description="Renders a comment in 'base_edit'.",
+ used_for=('Products.ATExtensions.fields.CommentField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/datetime.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/datetime.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/datetime.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,31 @@
+# -*- coding: UTF-8 -*-
+
+##################################################
+# #
+# Copyright (C), 2004, Thomas Förster #
+# <t.foerster at biologie.hu-berlin.de> #
+# #
+# Humboldt University of Berlin #
+# #
+##################################################
+
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import CalendarWidget
+from Products.Archetypes.Registry import registerWidget
+
+class DateTimeWidget(CalendarWidget):
+ _properties = CalendarWidget._properties.copy()
+ _properties.update({
+ 'macro' : "datetime_widget",
+ })
+
+ security = ClassSecurityInfo()
+
+InitializeClass(DateTimeWidget)
+
+registerWidget(DateTimeWidget,
+ title='DateTime',
+ description="An improved DateTime Widget.",
+ used_for=('Products.ATExtensions.fields.DateTimeField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/deadlines.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/deadlines.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/deadlines.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,21 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Widget import TypesWidget
+from Products.Archetypes.Registry import registerWidget
+
+## rr: this has gotten nowhere so far
+
+class DeadlinesWidget(TypesWidget):
+ _properties = TypesWidget._properties.copy()
+ _properties.update({
+ 'macro' : "deadlines_widget",
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(DeadlinesWidget)
+
+registerWidget(DeadlinesWidget,
+ title='Deadlines',
+ description="Manage a list of deadlines.",
+ ## rr: ?? used_for=('Products.ATExtensions.fields.UrlField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/email.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/email.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/email.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,22 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import StringWidget
+from Products.Archetypes.Registry import registerWidget
+from Products.Archetypes.Registry import registerPropertyType
+
+class EmailWidget(StringWidget):
+ _properties = StringWidget._properties.copy()
+ _properties.update({
+ 'macro_view' : "email_widget",
+ 'at_mask' : '(at)',
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(EmailWidget)
+
+registerWidget(EmailWidget,
+ title='Email',
+ description="Renders an email address (masked for anonymous).",
+ used_for=('Products.ATExtensions.fields.EmailField',)
+ )
+registerPropertyType('at_mask', 'string', EmailWidget)
Added: zope-atextensions/branches/upstream/0.8.0/widget/formattablename.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/formattablename.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/formattablename.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,37 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerWidget
+from record import RecordWidget
+
+class FormattableNameWidget(RecordWidget):
+ _properties = RecordWidget._properties.copy()
+ _properties.update({
+ 'macro_view' : "formattablename_view",
+ 'format' : '%T %F %M %P %L %S',
+ 'formatter' : {},
+ 'abbr' : {},
+ 'join_abbr' : '',
+ 'withURL' : False,
+ })
+ _format_properties = ['format', 'formatter', 'abbr',
+ 'join_abbr', 'withURL']
+
+ security = ClassSecurityInfo()
+
+ security.declarePublic('getKwArgs')
+ def getKwArgs(self):
+ """mapping of all non-empty formatting properties"""
+ result = {}
+ for property in self._format_properties:
+ value = getattr(self, property, None)
+ if value:
+ result[property] = value
+ return result
+
+InitializeClass(FormattableNameWidget)
+
+registerWidget(FormattableNameWidget,
+ title='FormattableName',
+ description="Renders a formattable name.",
+ used_for=('Products.ATExtensions.fields.FormattableNameField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/formattablenames.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/formattablenames.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/formattablenames.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,31 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.Registry import registerWidget
+from records import RecordsWidget
+from formattablename import FormattableNameWidget
+
+class FormattableNamesWidget(RecordsWidget, FormattableNameWidget):
+ _properties = RecordsWidget._properties.copy()
+ _properties.update({
+ 'macro_view' : "formattablename_view",
+ 'format' : '%T %F %M %P %L %S',
+ 'formatter' : {},
+ 'abbr' : {},
+ 'join_abbr' : '',
+ 'withURL' : False,
+ 'sep' : '',
+ 'lastsep' : '',
+ 'empty_marker' : '',
+ })
+ _format_properties = ['format', 'formatter', 'abbr', 'join_abbr',
+ 'withURL', 'sep', 'lastsep', 'empty_marker']
+ security = ClassSecurityInfo()
+
+
+InitializeClass(FormattableNamesWidget)
+
+registerWidget(FormattableNamesWidget,
+ title='FormattableNames',
+ description="Renders formattable names.",
+ used_for=('Products.ATExtensions.fields.FormattableNamesField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/record.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/record.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/record.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,19 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import StringWidget
+from Products.Archetypes.Registry import registerWidget
+
+class RecordWidget(StringWidget):
+ _properties = StringWidget._properties.copy()
+ _properties.update({
+ 'macro' : "record_widget",
+ })
+ security = ClassSecurityInfo()
+
+InitializeClass(RecordWidget)
+
+registerWidget(RecordWidget,
+ title='Record',
+ description="Renders a group of subfields.",
+ used_for=('Products.ATExtensions.fields.RecordField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/records.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/records.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/records.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,47 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import StringWidget
+from Products.Archetypes.Registry import registerWidget
+
+from Products.ATExtensions.widget import RecordWidget
+
+class RecordsWidget(RecordWidget):
+ _properties = RecordWidget._properties.copy()
+ _properties.update({
+ 'macro' : "records_widget",
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic('process_form')
+ def process_form(self, instance, field, form, empty_marker=None,
+ emptyReturnsMarker=False):
+ """
+ Basic impl for form processing in a widget plus clearing
+ of the value if the 'delete all entries' flag is set
+ """
+ ## check to see if the delete all entries flag was selected
+ delete = form.get('%s_delete' % field.getName(), empty_marker)
+ if delete is not empty_marker: return {}, {}
+
+ value = form.get(field.getName(), empty_marker)
+ if value is empty_marker:
+ return empty_marker
+ if emptyReturnsMarker and value == '':
+ return empty_marker
+
+ ## now check to see if we need to delete an individual item
+ for idx in range(len(value)-1,-1,-1):
+ flag_name = '%s_delete_%s' % (field.getName(),idx)
+ delete = form.get(flag_name, None)
+ if delete:
+ del value[idx]
+ del form[flag_name]
+ return value, {}
+
+InitializeClass(RecordsWidget)
+
+registerWidget(RecordsWidget,
+ title='Records',
+ description="Renders a list of records.",
+ used_for=('Products.ATExtensions.fields.RecordsField',)
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/remotetext.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/remotetext.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/remotetext.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,50 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import RichWidget
+from Products.Archetypes.Registry import registerWidget
+
+class RemoteTextWidget(RichWidget):
+ _properties = RichWidget._properties.copy()
+ _properties.update({
+ 'macro' : 'remotetext_widget',
+ })
+
+ # what to handle now where?
+ # customization; triggering upload
+ # all in process_form?
+ # or do we customize via an extra button with custom action?
+ # wouldn't an empty value be sufficient for the non-customized case?
+ security = ClassSecurityInfo()
+
+ security.declarePublic('process_form')
+ def process_form(self, instance, field, form, empty_marker=None,
+ emptyReturnsMarker=False):
+ """
+ Basic impl for form processing in a widget plus setting
+ additional values used by our associated field
+ """
+ value = form.get(field.getName(), empty_marker)
+ if value is empty_marker:
+ return empty_marker
+ if emptyReturnsMarker and value == '':
+ return empty_marker
+
+ ## now check to see if we need to take care of some
+ ## extra values
+ stname = "%s_source_type" % field.getName()
+ spname = "%s_source_path" % field.getName()
+ stype = form.get(stname, None)
+ spath = form.get(spname, None)
+ if stype:
+ field.setSourceType(instance, stype)
+ if spath:
+ field.setSourcePath(instance, spath)
+ return value, {}
+
+InitializeClass(RemoteTextWidget)
+
+registerWidget(RemoteTextWidget,
+ title="Remote Text Widget",
+ description="Populate a field from a remote source",
+ used_for="Products.ATExtensions.field.remotetext.RemoteTextField",
+ )
Added: zope-atextensions/branches/upstream/0.8.0/widget/url.py
===================================================================
--- zope-atextensions/branches/upstream/0.8.0/widget/url.py 2007-03-21 14:32:46 UTC (rev 714)
+++ zope-atextensions/branches/upstream/0.8.0/widget/url.py 2007-03-21 14:43:10 UTC (rev 715)
@@ -0,0 +1,37 @@
+from Globals import InitializeClass
+from AccessControl import ClassSecurityInfo
+from Products.Archetypes.public import StringWidget
+from Products.Archetypes.Registry import registerWidget
+from Products.Archetypes.Registry import registerPropertyType
+
+class UrlWidget(StringWidget):
+ _properties = StringWidget._properties.copy()
+ _properties.update({
+ 'macro' : "url_widget",
+ 'default_protocol' : 'http',
+ })
+ security = ClassSecurityInfo()
+
+ security.declarePublic('process_form')
+ def process_form(self, instance, field, form, empty_marker=None,
+ emptyReturnsMarker=False):
+ """
+ add the default protocol if there is none
+ """
+ value = form.get(field.getName(), empty_marker)
+ if value is empty_marker:
+ return empty_marker
+ if emptyReturnsMarker and value == '':
+ return empty_marker
+ if value and '://' not in value:
+ value = self.default_protocol + '://' + value
+ return value, {}
+
+InitializeClass(UrlWidget)
+
+registerWidget(UrlWidget,
+ title='Url',
+ description="Renders a URL in an anchor tag.",
+ used_for=('Products.ATExtensions.fields.UrlField',)
+ )
+registerPropertyType('default_protocol', 'string', UrlWidget)
More information about the pkg-zope-commits
mailing list