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$) ($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 (1) concepts: simple interconnected objects usually representing
meta-information meta-information

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -5,8 +5,10 @@
xmlns="http://namespaces.zope.org/browser" xmlns="http://namespaces.zope.org/browser"
i18n_domain="zope"> i18n_domain="zope">
<resourceDirectory name="i18n.flags" directory="flags" />
<page for="loops.interfaces.INode" <page for="loops.interfaces.INode"
name="language_switch" name="switch_language"
class="loops.browser.node.NodeView" class="loops.browser.node.NodeView"
attribute="switchLanguage" attribute="switchLanguage"
permission="zope.Public" /> 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 (with all the type machinery, what in real life is done via standard
ZCML setup): ZCML setup):
>>> from cybertools.relation.registry import DummyRelationRegistry >>> from loops.concept import Concept
>>> from cybertools.relation.tests import IntIdsStub
>>> relations = DummyRelationRegistry()
>>> component.provideUtility(relations)
>>> component.provideUtility(IntIdsStub())
>>> from loops.type import ConceptType, TypeConcept >>> from loops.type import ConceptType, TypeConcept
>>> from loops.interfaces import ITypeConcept >>> from loops.interfaces import ITypeConcept
>>> component.provideAdapter(ConceptType)
>>> component.provideAdapter(TypeConcept)
>>> from loops.base import Loops >>> 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 >>> loopsRoot = site['loops']
>>> 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
>>> query = concepts['query'] >>> query = concepts['query']
>>> topic = concepts['topic'] = Concept(u'Topic')
In addition we create a concept that holds the search page and a node In addition we create a concept that holds the search page and a node
(page) that links to this concept: (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) >>> searchView.submitReplacing('1.results', '1.search.form', pageView)
'return submitReplacing("1.results", "1.search.form", '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 Basic (text/title) search
------------------------- -------------------------
@ -202,7 +190,7 @@ of the concepts' titles:
>>> request = TestRequest(form=form) >>> request = TestRequest(form=form)
>>> view = Search(page, request) >>> view = Search(page, request)
>>> view.listConcepts() >>> view.listConcepts()
"[['Zope (Topic)', '12']]" "[['Zope (Topic)', '33']]"
Preset Concept Types on Search Forms 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. Let's start with a new type, the customer type.
>>> customer = concepts['customer'] = Concept('Customer') >>> customer = concepts['customer']
>>> customer.conceptType = typeConcept
>>> custType = ITypeConcept(customer) >>> custType = ITypeConcept(customer)
>>> custType.options >>> custType.options
[] []
@ -239,16 +226,16 @@ and thus include the customer type in the preset search types.
('concept', 'search') ('concept', 'search')
>>> searchView = Search(search, TestRequest()) >>> searchView = Search(search, TestRequest())
>>> list(searchView.presetSearchTypes) >>> list(searchView.presetSearchTypes)
[{'token': 'loops:concept:customer', 'title': 'Customer'}] [{'token': 'loops:concept:customer', 'title': u'Customer'}]
>>> searchView.conceptsForType('loops:concept:customer') >>> searchView.conceptsForType('loops:concept:customer')
[{'token': 'none', 'title': u'not selected'}, [{'token': 'none', 'title': u'not selected'},
{'token': '18', 'title': u'Zope Corporation'}, {'token': '47', 'title': u'Zope Corporation'},
{'token': '19', 'title': u'cyberconcepts'}] {'token': '49', 'title': u'cyberconcepts'}]
Let's use this new search option for querying: 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)) >>> resultsView = SearchResults(page, TestRequest(form=form))
>>> results = list(resultsView.results) >>> results = list(resultsView.results)
>>> results[0].title >>> 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.container.interfaces import IObjectRemovedEvent
from zope.app.security.principalregistry import principalRegistry from zope.app.security.principalregistry import principalRegistry
from zope.app.security.interfaces import IAuthentication 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.annotatableadapter import ZDCAnnotatableAdapter
from zope.dublincore.interfaces import IZopeDublinCore from zope.dublincore.interfaces import IZopeDublinCore
from zope.interface import implements
from cybertools.composer.schema.factory import SchemaFactory from cybertools.composer.schema.factory import SchemaFactory
from cybertools.composer.schema.field import FieldInstance, NumberFieldInstance 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.setup import SetupManager, addObject
from loops.type import LoopsType, ConceptType, ResourceType, TypeConcept 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): class TestSite(object):
@ -58,6 +67,10 @@ class TestSite(object):
component.provideAdapter(ZDCAnnotatableAdapter, (ILoopsObject,), IZopeDublinCore) component.provideAdapter(ZDCAnnotatableAdapter, (ILoopsObject,), IZopeDublinCore)
component.provideAdapter(AttributeAnnotations, (ILoopsObject,)) component.provideAdapter(AttributeAnnotations, (ILoopsObject,))
component.provideUtility(principalRegistry, IAuthentication) 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(LoopsType)
component.provideAdapter(ConceptType) component.provideAdapter(ConceptType)