source: products/qPloneTabs/branches/quintagroup.plonetabs/trunk/quintagroup/plonetabs/browser/plonetabs.py @ 139

Last change on this file since 139 was 139, checked in by chervol, 18 years ago

config constants fix

  • Property svn:eol-style set to native
File size: 27.2 KB
Line 
1import copy, sys
2from Acquisition import aq_inner
3from OFS.CopySupport import CopyError
4
5from zope.interface import implements
6from zope.component import getUtility, getMultiAdapter
7from zope.i18n import translate
8from zope.schema.interfaces import IVocabularyFactory
9from zope.exceptions import UserError
10from zope.app.container.interfaces import INameChooser
11
12from Products.CMFCore.utils import getToolByName
13from Products.CMFCore.interfaces import IAction, IActionCategory
14from Products.CMFCore.ActionInformation import Action, ActionCategory
15from Products.CMFCore.Expression import Expression
16from Products.CMFPlone import PloneMessageFactory as _
17from Products.CMFPlone import utils
18from Products.CMFPlone.browser.navigation import get_view_url
19from Products.Five.browser import BrowserView
20from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
21from Products.statusmessages.interfaces import IStatusMessage
22
23from plone.app.layout.navigation.root import getNavigationRoot
24from plone.app.kss.plonekssview import PloneKSSView
25from plone.app.workflow.remap import remap_workflow
26from plone.memoize.instance import memoize
27from kss.core import kssaction, KSSExplicitError
28
29from quintagroup.plonetabs.config import *
30from interfaces import IPloneTabsControlPanel
31
32ACTION_ATTRS = ["id", "title", "url_expr", "available_expr", "visible"]
33
34class PloneTabsControlPanel(PloneKSSView):
35   
36    implements(IPloneTabsControlPanel)
37   
38    template = ViewPageTemplateFile("templates/plonetabs.pt")
39    actionslist_template = ViewPageTemplateFile("templates/actionslist.pt")
40    autogenerated_template = ViewPageTemplateFile("templates/autogenerated.pt")
41   
42    # custom templates used to update page sections
43    sections_template = ViewPageTemplateFile("templates/sections.pt")
44   
45    def __call__(self):
46        """ Perform the update and redirect if necessary, or render the page """
47        postback = True
48        errors = {}
49        context = aq_inner(self.context)
50       
51        form = self.request.form
52        action = form.get("action", "")
53        submitted = form.get('form.submitted', False)
54       
55        # action handler def handler(self, form)
56        if submitted:
57            if form.has_key('add.add'):
58                postback = self.manage_addAction(form, errors)
59            elif form.has_key("edit.save"):
60                postback = self.manage_editAction(form, errors)
61            elif form.has_key("edit.delete"):
62                postback = self.manage_deleteAction(form, errors)
63            elif form.has_key("edit.moveup"):
64                postback = self.manage_moveUpAction(form, errors)
65            elif form.has_key("edit.movedown"):
66                postback = self.manage_moveDownAction(form, errors)
67            elif form.has_key("autogenerated.save"):
68                postback = self.manage_setAutogeneration(form, errors)
69            else:
70                postback = True
71       
72        if postback:
73            return self.template(errors=errors)
74   
75    ########################################
76    # Methods for processing configlet posts
77    ########################################
78   
79    def manage_setAutogeneration(self, form, errors):
80        """ Process managing autogeneration settings """
81       
82        # set excludeFromNav property for root objects
83        portal = getMultiAdapter((aq_inner(self.context), self.request), name='plone_portal_state').portal()
84        generated_tabs = form.get("generated_tabs", '0')
85        nonfolderish_tabs = form.get("nonfolderish_tabs", '0')
86       
87        for item in self.getRootTabs():
88            obj = getattr(portal, item['id'], None)
89            if obj is not None:
90                checked = form.get(item['id'], None)
91                if checked == '1':
92                    obj.update(excludeFromNav=False)
93                else:
94                    obj.update(excludeFromNav=True)
95
96        # set disable_folder_sections property
97        changeProperties = getToolByName(self.context, "portal_properties").site_properties.manage_changeProperties
98       
99        if int(generated_tabs) == 1:
100            changeProperties(disable_folder_sections=False)
101        else:
102            changeProperties(disable_folder_sections=True)
103       
104        # set disable_nonfolderish_sections property
105        if int(nonfolderish_tabs) == 1:
106            changeProperties(disable_nonfolderish_sections=False)
107        else:
108            changeProperties(disable_nonfolderish_sections=True)
109       
110        IStatusMessage(self.request).addStatusMessage(_(u"Changes saved!"), type="info")
111       
112        self.redirect()
113       
114        return False
115   
116    def manage_addAction(self, form, errs):
117        """ Manage method to add a new action to given category,
118            if category doesn't exist, create it """
119        # extract posted data
120        id, cat_name, data = self.parseAddForm(form)
121       
122        # validate posted data
123        errors = self.validateActionFields(cat_name, data)
124       
125        # if not errors find (or create) category and set action to it
126        if not errors:
127            action = self.addAction(cat_name, form)
128            IStatusMessage(self.request).addStatusMessage(_(u"'%s' action successfully added." % action.id), type="info")
129            self.redirect(search="category=%s" % cat_name)
130            return False
131        else:
132            errs.update(errors)
133            IStatusMessage(self.request).addStatusMessage(_(u"Please correct the indicated errors."), type="error")
134            return True
135   
136    def manage_editAction(self, form, errs):
137        """ Manage Method to update action """
138        # extract posted data
139        id, cat_name, data = self.parseEditForm(form)
140       
141        # get category and action to edit
142        category = self.getActionCategory(cat_name)
143        action = category[id]
144       
145        # validate posted data
146        errors = self.validateActionFields(cat_name, data, allow_dup=True)
147       
148        if not errors:
149            action = self.updateAction(id, cat_name, data)
150            IStatusMessage(self.request).addStatusMessage(_(u"'%s' action saved." % action.id), type="info")
151            self.redirect(search="category=%s" % cat_name)
152            return False
153        else:
154            errs.update(self.processErrors(errors, sufix='_%s' % id)) # add edit form sufix to error ids
155            IStatusMessage(self.request).addStatusMessage(_(u"Please correct the indicated errors."), type="error")
156            return True
157   
158    def manage_deleteAction(self, form, errs):
159        """ Manage Method to delete action """
160        # extract posted data
161        id, cat_name, data = self.parseEditForm(form)
162       
163        # get category and action to delete
164        category = self.getActionCategory(cat_name)
165        if id in category.objectIds():
166            self.deleteAction(id, cat_name)
167            IStatusMessage(self.request).addStatusMessage(_(u"'%s' action in '%s' category deleted." % (id, cat_name)), type="info")
168            self.redirect(search="category=%s" % cat_name)
169            return False
170        else:
171            IStatusMessage(self.request).addStatusMessage(_(u"No '%s' action in '%s' category." % (id, cat_name)), type="error")
172            return True
173   
174    def manage_moveUpAction(self, form, errors):
175        """ Move up given action by one position """
176        portal_actions = getToolByName(self.context, "portal_actions")
177       
178        id = form.get("orig_id", "")
179        category = form.get("category", "")
180       
181        if category not in portal_actions.objectIds():
182            IStatusMessage(self.request).addStatusMessage(_(u"Unexistent root portal actions category '%s'" % category), type="error")
183        else:
184            cat_container = portal_actions[category]
185            if id not in map(lambda x: x.id, filter(lambda x: IAction.providedBy(x), cat_container.objectValues())):
186                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action does not exist in '%s' category" % (id, category)), type="error")
187            else:
188                cat_container.moveObjectsUp([id,], 1)
189                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action in '%s' category moved up" % (id, category)), type="info")
190               
191                # redirect to form after successfull deletion
192                self.redirect(search="category=%s" % category)
193                return False
194       
195        # return form with errors
196        return True
197   
198    def manage_moveDownAction(self, form, errors):
199        """ Move up given action by one position """
200        portal_actions = getToolByName(self.context, "portal_actions")
201       
202        id = form.get("orig_id", "")
203        category = form.get("category", "")
204       
205        if category not in portal_actions.objectIds():
206            IStatusMessage(self.request).addStatusMessage(_(u"Unexistent root portal actions category '%s'" % category), type="error")
207        else:
208            cat_container = portal_actions[category]
209            if id not in map(lambda x: x.id, filter(lambda x: IAction.providedBy(x), cat_container.objectValues())):
210                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action does not exist in '%s' category" % (id, category)), type="error")
211            else:
212                cat_container.moveObjectsDown([id,], 1)
213                IStatusMessage(self.request).addStatusMessage(_(u"'%s' action in '%s' category moved down" % (id, category)), type="info")
214               
215                # redirect to form after successfull deletion
216                self.redirect(search="category=%s" % category)
217                return False
218       
219        # return form with errors
220        return True
221   
222    def redirect(self, url="", search="", hash=""):
223        """ Redirect to @@plonetabs-controlpanel configlet """
224       
225        if url == "":
226            portal_url =  getMultiAdapter((self.context, self.request), name=u"plone_portal_state").portal_url()
227            url = "%s/%s" % (portal_url, "@@plonetabs-controlpanel")
228       
229        if search != "":
230            search = "?%s" % search
231       
232        if hash != "":
233            hash = "#%s" % hash
234       
235        self.request.response.redirect("%s%s%s" % (url, search, hash))
236   
237    ###################################
238    #
239    #  Methods - providers for templates
240    #
241    ###################################
242   
243    def getPageTitle(self, category="portal_tabs"):
244        """ See interface """
245        portal_props = getToolByName(self.context, "portal_properties")
246        default_title = "Plone '%s' Configuration" % category
247       
248        if not hasattr(portal_props, PROPERTY_SHEET):
249            return default_title
250       
251        sheet = getattr(portal_props, PROPERTY_SHEET)
252        if not hasattr(sheet, FIELD_NAME):
253            return default_title
254       
255        field = sheet.getProperty(FIELD_NAME)
256        dict = {}
257        for line in field:
258            cat, title = line.split("|", 2)
259            dict[cat] = title
260       
261        return dict.get(category, None) or default_title
262   
263    def hasActions(self, category="portal_tabs"):
264        """ See interface """
265        return len(getToolByName(self.context, "portal_actions").listActions(categories=[category,])) > 0
266   
267    def getPortalActions(self, category="portal_tabs"):
268        """ See interface """
269        portal_actions = getToolByName(self.context, "portal_actions")
270       
271        if category not in portal_actions.objectIds():
272            return []
273       
274        actions = []
275        for item in portal_actions[category].objectValues():
276            if IAction.providedBy(item):
277                actions.append(item)
278       
279        return actions
280   
281    def isGeneratedTabs(self):
282        """ See interface """
283        site_properties = getToolByName(self.context, "portal_properties").site_properties
284        return not site_properties.getProperty("disable_folder_sections", False)
285   
286    def isNotFoldersGenerated(self):
287        """ See interface """
288        site_properties = getToolByName(self.context, "portal_properties").site_properties
289        return not site_properties.getProperty("disable_nonfolderish_sections", False)
290   
291    def getActionsList(self, category="portal_tabs", errors={}):
292        """ See interface """
293        return self.actionslist_template(category=category, errors=errors)
294   
295    def getGeneratedTabs(self):
296        """ See interface """
297        return self.autogenerated_template()
298   
299    def getRootTabs(self):
300        """ See interface """
301        context = aq_inner(self.context)
302       
303        portal_catalog = getToolByName(context, 'portal_catalog')
304        portal_properties = getToolByName(context, 'portal_properties')
305        navtree_properties = getattr(portal_properties, 'navtree_properties')
306       
307        # Build result dict
308        result = []
309       
310        # check whether we only want actions
311        if not self.isGeneratedTabs():
312            return result
313       
314        query = {}
315       
316        rootPath = getNavigationRoot(context)
317        query['path'] = {'query' : rootPath, 'depth' : 1}
318        query['portal_type'] = utils.typesToList(context)
319       
320        sortAttribute = navtree_properties.getProperty('sortAttribute', None)
321        if sortAttribute is not None:
322            query['sort_on'] = sortAttribute
323           
324            sortOrder = navtree_properties.getProperty('sortOrder', None)
325            if sortOrder is not None:
326                query['sort_order'] = sortOrder
327       
328        if navtree_properties.getProperty('enable_wf_state_filtering', False):
329            query['review_state'] = navtree_properties.getProperty('wf_states_to_show', [])
330       
331        query['is_default_page'] = False
332
333        if not self.isNotFoldersGenerated():
334            query['is_folderish'] = True
335
336        # Get ids not to list and make a dict to make the search fast
337        idsNotToList = navtree_properties.getProperty('idsNotToList', ())
338        excludedIds = {}
339        for id in idsNotToList:
340            excludedIds[id]=1
341
342        rawresult = portal_catalog.searchResults(**query)
343
344        # now add the content to results
345        for item in rawresult:
346            if not excludedIds.has_key(item.getId):
347                id, item_url = get_view_url(item)
348                data = {'name'       : utils.pretty_title_or_id(context, item),
349                        'id'         : id,
350                        'url'        : item_url,
351                        'description': item.Description,
352                        'exclude_from_nav' : item.exclude_from_nav}
353                result.append(data)
354       
355        return result
356   
357    def getCategories(self):
358        """ See interface """
359        portal_actions = getToolByName(self.context, "portal_actions")
360        return portal_actions.objectIds()
361   
362    #
363    # Methods to make this class looks like global sections viewlet
364    #
365   
366    def test(self, condition, ifTrue, ifFalse):
367        """ See interface """
368        if condition:
369            return ifTrue
370        else:
371            return ifFalse
372   
373    # methods for rendering global-sections viewlet via kss,
374    # due to bug in macroContent when global-section list is empty,
375    # ul have condition
376    def portal_tabs(self):
377        """ See global-sections viewlet """
378        actions = context_state = getMultiAdapter((self.context, self.request), name=u"plone_context_state").actions()
379        portal_tabs_view = getMultiAdapter((self.context, self.request), name="portal_tabs_view")
380       
381        return portal_tabs_view.topLevelTabs(actions=actions)
382   
383    def selected_portal_tab(self):
384        """ See global-sections viewlet """
385        selectedTabs = self.context.restrictedTraverse('selectedTabs')
386        selected_tabs = selectedTabs('index_html', self.context, self.portal_tabs())
387       
388        return selected_tabs['portal']
389   
390    ##########################
391    #
392    # KSS Server Actions
393    #
394    ##########################
395   
396    def validateAction(self, id, category, prefix="tabslist_"):
397        """ If action with given id and category doesn't exist - raise kss exception """
398        portal_actions = getToolByName(self.context, "portal_actions")
399       
400        # remove prefix, added for making ids on configlet unique ("tabslist_")
401        act_id = id[len("tabslist_"):]
402       
403        if category not in portal_actions.objectIds():
404            raise KSSExplicitError, "Unexistent root portal actions category %s" % category
405       
406        cat_container = portal_actions[category]
407        if act_id not in map(lambda x: x.id, filter(lambda x: IAction.providedBy(x), cat_container.objectValues())):
408            raise KSSExplicitError, "%s action does not exist in %s category" % (act_id, category)
409       
410        return (cat_container, act_id)
411   
412    @kssaction
413    def toggleGeneratedTabs(self, field, checked='0'):
414        """ Toggle autogenaration setting on configlet """
415       
416        changeProperties = getToolByName(self.context, "portal_properties").site_properties.manage_changeProperties
417        if checked == '1':
418            changeProperties(**{field : False})
419        else:
420            changeProperties(**{field : True})
421       
422        ksscore = self.getCommandSet("core")
423        replace_id = "roottabs"
424        content = self.getGeneratedTabs()
425       
426        ksscore.replaceInnerHTML(ksscore.getHtmlIdSelector(replace_id), content, withKssSetup="True")
427       
428        # update global-sections viewlet
429        self.updatePortalTabs()
430   
431    @kssaction
432    def toggleActionsVisibility(self, id, checked='0', category=None):
433        """ Toggle visibility for portal actions """
434        portal_actions = getToolByName(self.context, "portal_actions")
435        cat_container, act_id = self.validateAction(id, category)
436       
437        if checked == '1':
438            checked = True
439        else:
440            checked = False
441       
442        cat_container[act_id].visible = checked
443       
444        ksscore = self.getCommandSet("core")
445        if checked:
446            ksscore.removeClass(ksscore.getHtmlIdSelector(id), value="invisible")
447        else:
448            ksscore.addClass(ksscore.getHtmlIdSelector(id), value="invisible")
449       
450        self.updatePage(category)
451   
452    @kssaction
453    def toggleRootsVisibility(self, id, checked='0'):
454        """ Toggle visibility for portal root objects (exclude_from_nav) """
455        portal = getMultiAdapter((aq_inner(self.context), self.request), name='plone_portal_state').portal()
456       
457        # remove prefix, added for making ids on configlet unique ("roottabs_")
458        obj_id = id[len("roottabs_"):]
459       
460        if obj_id not in portal.objectIds():
461            raise KSSExplicitError, "Object with %s id doesn't exist in portal root" % obj_id
462       
463        if checked == '1':
464            checked = True
465        else:
466            checked = False
467       
468        portal[obj_id].update(excludeFromNav=not checked)
469       
470        ksscore = self.getCommandSet("core")
471        if checked:
472            ksscore.removeClass(ksscore.getHtmlIdSelector(id), value="invisible")
473        else:
474            ksscore.addClass(ksscore.getHtmlIdSelector(id), value="invisible")
475       
476        # update global-sections viewlet
477        self.updatePortalTabs()
478   
479    @kssaction
480    def kss_deleteAction(self, id, category):
481        """ Delete portal action with given id & category """
482        portal_actions = getToolByName(self.context, "portal_actions")
483        cat_container, act_id = self.validateAction(id, category)
484       
485        cat_container.manage_delObjects(ids=[act_id,])
486       
487        # update action list on client
488        ksscore = self.getCommandSet("core")
489       
490        ksscore.deleteNode(ksscore.getHtmlIdSelector(id))
491       
492        # add "noitems" class to Reorder controls to hide it
493        if not filter(lambda x: IAction.providedBy(x), cat_container.objectValues()):
494            ksscore.addClass(ksscore.getHtmlIdSelector("reorder"), value="noitems")
495       
496        # XXX TODO: fade effect during removing, for this kukit js action/command plugin needed
497       
498        self.updatePage(category)
499   
500    @kssaction
501    def oldAddAction(self, id, name, action='', category='portal_tabs', condition='', visible=False):
502        pass
503   
504    @kssaction
505    def editAction(self, id, category):
506        """ Show edit form for given action """
507        cat_container, act_id = self.validateAction(id, category)
508       
509        # collect data
510        action_info = self.copyAction(cat_container[act_id])
511        action_info["editing"] = True
512       
513        ksscore = self.getCommandSet("core")
514        content = self.actionslist_template(tabs=[action_info,])
515        replace_id = id
516       
517        ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), content)
518       
519        # focus name field
520        ksscore.focus(ksscore.getCssSelector("#%s input[name=name_%s]" % (id, act_id)))
521   
522    @kssaction
523    def editCancel(self, id, category):
524        """ Hide edit form for given action """
525        cat_container, act_id = self.validateAction(id, category)
526       
527        ksscore = self.getCommandSet("core")
528        content = self.actionslist_template(tabs=[cat_container[act_id],])
529        replace_id = id
530       
531        ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), content)
532   
533    #
534    # Utility Methods
535    #
536   
537    def copyAction(self, action):
538        """ Copyt action to dictionary """
539        action_info = {}
540        for attr in ACTION_ATTRS:
541            action_info[attr] = getattr(action, attr)
542        return action_info
543   
544    def validateActionFields(self, cat_name, data, allow_dup=False):
545        """ Check action fields on validity """
546        errors = {}
547       
548        if allow_dup:
549            category = ActionCategory(cat_name)           # create dummy category to avoid id duplication during action update
550        else:
551            category = self.getOrCreateCategory(cat_name) # get or create (if necessary) actions category
552       
553        # validate action id
554        chooser = INameChooser(category)
555        try:
556            chooser.checkName(data['id'], self.context)
557        except Exception, e:
558            errors['id'] = "%s" % str(e)
559       
560        # validate action name
561        if not data['title'].strip():
562            errors['title'] = 'Empty or invalid title specified'
563       
564        # validate condition expression
565        if data['available_expr']:
566            try:
567                Expression(data['available_expr'])
568            except Exception, e:
569                errors["available_expr"] = "%s" % str(e)
570       
571        # validate action expression
572        if data['url_expr']:
573            try:
574                Expression(data['url_expr'])
575            except Exception, e:
576                errors["url_expr"] = "%s" % str(e)
577       
578        return errors
579   
580    def processErrors(self, errors, prefix='', sufix=''):
581        """ Add prefixes, sufixes to error ids
582            This is necessary during edit form validation,
583            because every edit form on the page has it's own sufix (id) """
584        if not (prefix or sufix):
585            return errors
586       
587        result = {}
588        for key, value in errors.items():
589            result['%s%s%s' % (prefix, key, sufix)] = value
590       
591        return result
592   
593    def parseEditForm(self, form):
594        """ Extract all needed fields from edit form """
595        # get original id and category
596        info = {}
597        id = form['orig_id']
598        category = form['category']
599       
600        # preprocess 'visible' field (checkbox needs special checking)
601        if form.has_key('visible_%s' % id):
602            form['visible_%s' % id] = True
603        else:
604            form['visible_%s' % id] = False
605       
606        # collect all action fields
607        for attr in ACTION_ATTRS:
608            info[attr] = form['%s_%s' % (attr, id)]
609       
610        return (id, category, info)
611   
612    def parseAddForm(self, form):
613        """ Extract all needed fields from add form """
614        info = {}
615        id = form['id']
616        category = form['category']
617       
618        # preprocess 'visible' field (checkbox needs special checking)
619        if form.has_key('visible'):
620            form['visible'] = True
621        else:
622            form['visible'] = False
623       
624        # collect all action fields
625        for attr in ACTION_ATTRS:
626            info[attr] = form[attr]
627       
628        return (id, category, info)
629   
630    def getActionCategory(self, name):
631        portal_actions = getToolByName(self.context, 'portal_actions')
632        return portal_actions[name]
633   
634    def getOrCreateCategory(self, name):
635        """ Get or create (if necessary) category """
636        portal_actions = getToolByName(self.context, 'portal_actions')
637        if name not in map(lambda x: x.id, filter(lambda x: IActionCategory.providedBy(x), portal_actions.objectValues())):
638            portal_actions._setObject(name, ActionCategory(name))
639        return self.getActionCategory(name)
640   
641    def addAction(self, cat_name, data):
642        """ Create and add new action to category with given name """
643        id = data.pop('id')
644        category = self.getOrCreateCategory(cat_name)
645        action = Action(id, **data)
646        category._setObject(id, action)
647        return action
648   
649    def updateAction(self, id, cat_name, data):
650        """ Update action with given id and category """
651        new_id = data.pop('id')
652        category = self.getActionCategory(cat_name)
653       
654        # rename action if necessary
655        if id != new_id:
656            category.manage_renameObject(id, new_id)
657       
658        # get action
659        action = category[new_id]
660       
661        # update action properties
662        for attr in ACTION_ATTRS:
663            if data.has_key(attr):
664                action._setPropValue(attr, data[attr])
665       
666        return action
667   
668    def deleteAction(self, id, cat_name):
669        """ Delete action with given id from given category """
670        category = self.getActionCategory(cat_name)
671        category.manage_delObjects(ids=[id,])
672        return True
673   
674    #
675    # KSS Methods that are used to update different parts of the page
676    # according to category
677    #
678   
679    def updatePage(self, category):
680        """ Seek for according method in class and calls it if found
681            Example of making up method's name:
682                portal_tabs => updatePortalTabs """
683        method_name = 'update%sPageSection' % ''.join(map(lambda x: x.capitalize(), category.split('_')))
684        if hasattr(self, method_name):
685            getattr(self, method_name)()
686   
687    def updatePortalTabsPageSection(self):
688        """ Method for updating global-sections on client """
689        ksscore = self.getCommandSet("core")
690        ksscore.replaceHTML(
691            ksscore.getHtmlIdSelector("portal-globalnav"),
692            self.sections_template(),
693            withKssSetup="False")
694   
695    def updateSiteActionsPageSection(self):
696        """ Method for updating site action on client """
697        ksszope = self.getCommandSet("zope")
698        ksszope.refreshViewlet(
699            self.getCommandSet("core").getHtmlIdSelector("portal-siteactions"),
700            "plone.portalheader",
701            "plone.site_actions")
702   
703    def updateUserPageSection(self):
704        """ Method for updating site action on client """
705        ksszope = self.getCommandSet("zope")
706        ksszope.refreshViewlet(
707            self.getCommandSet("core").getHtmlIdSelector("portal-personaltools-wrapper"),
708            "plone.portaltop",
709            "plone.personal_bar")
710
711
Note: See TracBrowser for help on using the repository browser.