provide language switchingby top actions with flags

git-svn-id: svn://svn.cy55.de/Zope3/src/loops/trunk@2241 fd906abe-77d9-0310-91a1-e0d9ade77398
This commit is contained in:
helmutm 2007-12-13 16:42:03 +00:00
parent 49bb669053
commit 10bae7f32d
15 changed files with 104 additions and 71 deletions

View file

@ -4,7 +4,7 @@ loops - Linked Objects for Organization and Processing Services
($Id$)
The loops platform is built up of three parts:
The loops platform consists up of three basic types of objects:
(1) concepts: simple interconnected objects usually representing
meta-information

View file

@ -106,6 +106,7 @@ class BaseView(GenericView, I18NView):
# TODO: get rid of removeSecurityProxy() call
self.context = removeSecurityProxy(context)
self.setSkin(self.loopsRoot.skinName)
self.checkLanguage()
try:
if not canAccess(context, 'title'):
raise Unauthorized

View file

@ -31,6 +31,12 @@ table.listing td {
margin-left: 5px;
}
.top-actions{
position: absolute;
right: 2em;
top: 1em;
}
/*.content-1 h1 { */
h1 {
font-size: 160%;
@ -98,6 +104,14 @@ div.image {
margin-right: 5px;
}
img.selected {
border: 2px solid #d6dcf6;
}
img.notselected {
border: 2px solid #eff8ff;
}
/* search stuff */

View file

@ -46,6 +46,7 @@ from cybertools.browser import configurator
from cybertools.browser.view import GenericView
from cybertools.typology.interfaces import IType, ITypeManager
from cybertools.xedit.browser import ExternalEditorView
from loops.i18n.browser import i18n_macros
from loops.interfaces import IConcept, IResource, IDocument, IMediaAsset, INode
from loops.interfaces import IViewConfiguratorSchema
from loops.resource import MediaAsset
@ -77,6 +78,8 @@ class NodeView(BaseView):
media='all', position=3)
cm.register('js', 'loops.js', resourceName='loops.js')
#cm.register('js', 'loops.js', resourceName='loops1.js')
cm.register('top_actions', 'top_actions', name='multi_actions',
subMacros=[i18n_macros.macros['language_switch']])
cm.register('portlet_left', 'navigation', title='Navigation',
subMacro=node_macros.macros['menu'])
#if not IUnauthenticatedPrincipal.providedBy(self.request.principal):

View file

@ -200,7 +200,12 @@
</metal:menu>
<!-- portlets -->
<!-- portlets and actions -->
<metal:actions define-macro="top_actions">
blubb
</metal:actions>
<metal:actions define-macro="clipboard">
<div class="menu-2">loops Development</div>

View file

@ -10,39 +10,22 @@ package.
Let's first do some basic imports
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
>>> site = placefulSetUp(True)
>>> from zope import interface, component
>>> from zope.interface import Interface
>>> from zope.publisher.browser import TestRequest
and provide a relation registry:
>>> from zope.app.testing.setup import placefulSetUp, placefulTearDown
>>> site = placefulSetUp(True)
>>> from cybertools.relation.tests import IntIdsStub
>>> component.provideUtility(IntIdsStub())
>>> from cybertools.relation.registry import DummyRelationRegistry
>>> component.provideUtility(DummyRelationRegistry())
>>> from loops.tests.setup import TestSite
>>> t = TestSite(site)
>>> concepts, resources, views = t.setup()
and care for some type adapter machinery:
>>> from loops.interfaces import IConcept
>>> from loops.interfaces import ITypeConcept
>>> from loops.type import TypeConcept
>>> component.provideAdapter(TypeConcept, (IConcept,), ITypeConcept)
Now we can setup a simple loops site with its manager objects, using a
loops setup manager:
>>> from loops.base import Loops
>>> loopsRoot = site['loops'] = Loops()
>>> from loops.setup import SetupManager
>>> setup = SetupManager(loopsRoot)
>>> concepts, resources, views = setup.setup()
>>> concepts['hasType'].title
u'has Type'
>>> loopsRoot = site['loops']
We also add some example concepts,
>>> from loops.concept import Concept
@ -217,6 +200,8 @@ for controlling e.g. storage for external files.
>>> ef1_type = IType(ef1)
>>> IType(ef1).options
[]
>>> from loops.type import TypeConcept
>>> extfile_ad = TypeConcept(extfile)
>>> extfile_ad.options = ['dummy', 'storage:varsubdir',
... 'storage_parameters:extfiles']
@ -239,11 +224,9 @@ get a type manager from all loops objects, always with the same context:
True
>>> types = typeManager.types
>>> sorted(t.token for t in types)
['.loops/concepts/domain', '.loops/concepts/file', '.loops/concepts/note',
'.loops/concepts/predicate', '.loops/concepts/query',
'.loops/concepts/textdocument', '.loops/concepts/topic',
'.loops/concepts/type']
>>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens)
9
>>> typeManager.getType('.loops/concepts/topic') == cc1_type
True
@ -252,14 +235,13 @@ The listTypes() method allows us to select types that fulfill a certain
condition:
>>> types = typeManager.listTypes(include=('concept',))
>>> sorted(t.token for t in types)
['.loops/concepts/domain', '.loops/concepts/predicate',
'.loops/concepts/query', '.loops/concepts/topic', '.loops/concepts/type']
>>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens)
6
>>> types = typeManager.listTypes(exclude=('concept',))
>>> sorted(t.token for t in types)
['.loops/concepts/file', '.loops/concepts/note',
'.loops/concepts/textdocument']
>>> typeTokens = sorted(t.token for t in types)
>>> len(typeTokens)
3
Type-based interfaces and adapters
----------------------------------
@ -273,6 +255,7 @@ will be adaptable to. The default for this is None:
For concept objects that provide types (type providers) the value of
the typeInterface attribute is the ITypeConcept interface:
>>> from loops.interfaces import ITypeConcept
>>> topic_type.typeInterface is ITypeConcept
True
@ -286,6 +269,7 @@ i.e. the 'topic' concept, via an adapter:
>>> class Topic(object):
... implements(ITopic)
... def __init__(self, context): pass
>>> from loops.interfaces import IConcept
>>> component.provideAdapter(Topic, (IConcept,), ITopic)
>>> ITypeConcept(topic).typeInterface = ITopic
@ -306,7 +290,7 @@ browser views; among others also some important informations about the
context object's type:
>>> from loops.browser.common import BaseView
>>> view = BaseView(cc1, TestRequest)
>>> view = BaseView(cc1, TestRequest())
>>> view.typeTitle
u'Topic'
>>> view.typeInterface

View file

@ -24,6 +24,7 @@ $Id$
from zope import interface, component
from zope.app.pagetemplate import ViewPageTemplateFile
from zope.app.session.interfaces import ISession
from zope.cachedescriptors.property import Lazy
from zope.i18n.interfaces import IUserPreferredLanguages
from zope.i18n.negotiator import negotiator
@ -31,6 +32,11 @@ from zope.i18n.negotiator import negotiator
from loops.common import adapted
packageId = 'loops.i18n.browser'
i18n_macros = ViewPageTemplateFile('i18n_macros.pt')
class LanguageInfo(object):
def __init__(self, context, request):
@ -80,8 +86,10 @@ class I18NView(object):
return adapted(self.context, self.languageInfo)
def checkLanguage(self):
# get language from session
self.setPreferredLanguage()
session = ISession(self.request)[packageId]
lang = session.get('language')
if lang:
self.setLanguage(lang)
def setLanguage(self, lang=None):
lang = lang or self.request.form.get('lang')
@ -89,10 +97,12 @@ class I18NView(object):
upl = IUserPreferredLanguages(self.request)
upl.setPreferredLanguages([lang])
def switchLanguage(self, lang=None, keep=False):
def switchLanguage(self):
lang = self.request.form.get('loops.language')
keep = self.request.form.get('keep')
if keep:
pass # set in session
self.setPreferredLanguage(lang)
session = ISession(self.request)[packageId]
session['language'] = lang
self.setLanguage(lang)
return self()

View file

@ -5,8 +5,10 @@
xmlns="http://namespaces.zope.org/browser"
i18n_domain="zope">
<resourceDirectory name="i18n.flags" directory="flags" />
<page for="loops.interfaces.INode"
name="language_switch"
name="switch_language"
class="loops.browser.node.NodeView"
attribute="switchLanguage"
permission="zope.Public" />

BIN
i18n/flags/de.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 362 B

BIN
i18n/flags/en.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

BIN
i18n/flags/it.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

BIN
i18n/flags/pl.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

14
i18n/i18n_macros.pt Normal file
View file

@ -0,0 +1,14 @@
<!-- $Id$ -->
<metal:actions define-macro="language_switch"
tal:define="langInfo view/languageInfo">
<tal:lang repeat="lang langInfo/availableLanguages">
<a href="#"
tal:attributes="href string:switch_language?loops.language=$lang&keep=yes;
title lang"><img src="us.gif"
tal:attributes="src string:${resourceBase}i18n.flags/$lang.gif;
title lang; alt lang;
class python: langInfo.language == lang
and 'selected' or 'notselected'" /></a>
</tal:lang>
</metal:actions>

View file

@ -17,29 +17,17 @@ and setup a simple loops site with a concept manager and some concepts
(with all the type machinery, what in real life is done via standard
ZCML setup):
>>> from cybertools.relation.registry import DummyRelationRegistry
>>> from cybertools.relation.tests import IntIdsStub
>>> relations = DummyRelationRegistry()
>>> component.provideUtility(relations)
>>> component.provideUtility(IntIdsStub())
>>> from loops.concept import Concept
>>> from loops.type import ConceptType, TypeConcept
>>> from loops.interfaces import ITypeConcept
>>> component.provideAdapter(ConceptType)
>>> component.provideAdapter(TypeConcept)
>>> from loops.base import Loops
>>> loopsRoot = site['loops'] = Loops()
>>> from loops.tests.setup import TestSite
>>> t = TestSite(site)
>>> concepts, resources, views = t.setup()
>>> from loops.setup import SetupManager
>>> setup = SetupManager(loopsRoot)
>>> concepts, resources, views = setup.setup()
>>> typeConcept = concepts['type']
>>> from loops.concept import Concept
>>> topic = concepts['topic'] = Concept(u'Topic')
>>> for c in (topic,): c.conceptType = typeConcept
>>> loopsRoot = site['loops']
>>> query = concepts['query']
>>> topic = concepts['topic'] = Concept(u'Topic')
In addition we create a concept that holds the search page and a node
(page) that links to this concept:
@ -103,7 +91,7 @@ a controller attribute for the search view.
>>> searchView.submitReplacing('1.results', '1.search.form', pageView)
'return submitReplacing("1.results", "1.search.form",
"http://127.0.0.1/loops/views/page/.target10/@@searchresults.html")'
"http://127.0.0.1/loops/views/page/.target29/@@searchresults.html")'
Basic (text/title) search
-------------------------
@ -202,7 +190,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form)
>>> view = Search(page, request)
>>> view.listConcepts()
"[['Zope (Topic)', '12']]"
"[['Zope (Topic)', '33']]"
Preset Concept Types on Search Forms
------------------------------------
@ -213,8 +201,7 @@ a certain qualifier, via the option attribute of the type interface.
Let's start with a new type, the customer type.
>>> customer = concepts['customer'] = Concept('Customer')
>>> customer.conceptType = typeConcept
>>> customer = concepts['customer']
>>> custType = ITypeConcept(customer)
>>> custType.options
[]
@ -239,16 +226,16 @@ and thus include the customer type in the preset search types.
('concept', 'search')
>>> searchView = Search(search, TestRequest())
>>> list(searchView.presetSearchTypes)
[{'token': 'loops:concept:customer', 'title': 'Customer'}]
[{'token': 'loops:concept:customer', 'title': u'Customer'}]
>>> searchView.conceptsForType('loops:concept:customer')
[{'token': 'none', 'title': u'not selected'},
{'token': '18', 'title': u'Zope Corporation'},
{'token': '19', 'title': u'cyberconcepts'}]
{'token': '47', 'title': u'Zope Corporation'},
{'token': '49', 'title': u'cyberconcepts'}]
Let's use this new search option for querying:
>>> form = {'search.4.text_selected': u'18'}
>>> form = {'search.4.text_selected': u'47'}
>>> resultsView = SearchResults(page, TestRequest(form=form))
>>> results = list(resultsView.results)
>>> results[0].title

View file

@ -13,8 +13,11 @@ from zope.app.catalog.text import TextIndex
from zope.app.container.interfaces import IObjectRemovedEvent
from zope.app.security.principalregistry import principalRegistry
from zope.app.security.interfaces import IAuthentication
from zope.app.session.interfaces import IClientIdManager, ISessionDataContainer
from zope.app.session import session
from zope.dublincore.annotatableadapter import ZDCAnnotatableAdapter
from zope.dublincore.interfaces import IZopeDublinCore
from zope.interface import implements
from cybertools.composer.schema.factory import SchemaFactory
from cybertools.composer.schema.field import FieldInstance, NumberFieldInstance
@ -40,6 +43,12 @@ from loops.schema import ResourceSchemaFactory, FileSchemaFactory, NoteSchemaFac
from loops.setup import SetupManager, addObject
from loops.type import LoopsType, ConceptType, ResourceType, TypeConcept
class ClientIdManager(object):
""" dummy, for testing only """
implements(IClientIdManager)
def getClientId(self, request):
return 'dummy'
class TestSite(object):
@ -58,6 +67,10 @@ class TestSite(object):
component.provideAdapter(ZDCAnnotatableAdapter, (ILoopsObject,), IZopeDublinCore)
component.provideAdapter(AttributeAnnotations, (ILoopsObject,))
component.provideUtility(principalRegistry, IAuthentication)
component.provideAdapter(session.ClientId)
component.provideAdapter(session.Session)
component.provideUtility(session.RAMSessionDataContainer(), ISessionDataContainer)
component.provideUtility(ClientIdManager())
component.provideAdapter(LoopsType)
component.provideAdapter(ConceptType)