diff --git a/gen/plone25/mixins/ToolMixin.py b/gen/plone25/mixins/ToolMixin.py index 0f123a8..8cee75b 100644 --- a/gen/plone25/mixins/ToolMixin.py +++ b/gen/plone25/mixins/ToolMixin.py @@ -47,6 +47,10 @@ class ToolMixin(BaseMixin): res['action'] = appyType.action return res + def getSiteUrl(self): + '''Returns the absolute URL of this site.''' + return self.portal_url.getPortalObject().absolute_url() + def generateDocument(self): '''Generates the document from field-related info. UID of object that is the template target is given in the request.''' diff --git a/gen/plone25/mixins/__init__.py b/gen/plone25/mixins/__init__.py index 0291387..24a6b52 100644 --- a/gen/plone25/mixins/__init__.py +++ b/gen/plone25/mixins/__init__.py @@ -18,7 +18,7 @@ class BaseMixin: _appy_meta_type = 'Class' def get_o(self): - '''In some cases, we wand the Zope object, we don't know if the current + '''In some cases, we want the Zope object, we don't know if the current object is a Zope or Appy object. By defining this property, "someObject.o" produces always the Zope object, be someObject an Appy or Zope object.''' @@ -79,6 +79,18 @@ class BaseMixin: '''This methods is self's suicide.''' self.getParentNode().manage_delObjects([self.id]) + def onDelete(self): + rq = self.REQUEST + self.delete() + if self.getUrl(rq['HTTP_REFERER'],mode='raw') ==self.getUrl(mode='raw'): + # We were consulting the object that has been deleted. Go back to + # the main page. + urlBack = self.getTool().getSiteUrl() + else: + urlBack = self.getUrl(rq['HTTP_REFERER']) + self.plone_utils.addPortalMessage(self.translate('delete_done')) + self.goto(urlBack) + def onCreate(self): '''This method is called when a user wants to create a root object in the application folder or an object through a reference field.''' @@ -152,6 +164,7 @@ class BaseMixin: the "final" object in the database. If the object is not a temporary one, this method updates its fields in the database.''' rq = self.REQUEST + tool = self.getTool() errorMessage = self.translate( 'Please correct the indicated errors.', domain='plone') isNew = rq.get('is_new') == 'True' @@ -161,12 +174,12 @@ class BaseMixin: if rq.get('nav', ''): # We can go back to the initiator page. splitted = rq['nav'].split('.') - initiator = self.getTool().getObject(splitted[1]) + initiator = tool.getObject(splitted[1]) initiatorPage = splitted[2].split(':')[1] urlBack = initiator.getUrl(page=initiatorPage, nav='') else: # Go back to the root of the site. - urlBack = self.portal_url.getPortalObject().absolute_url() + urlBack = tool.getSiteUrl() else: urlBack = self.getUrl() self.plone_utils.addPortalMessage( @@ -192,12 +205,21 @@ class BaseMixin: self.plone_utils.addPortalMessage(errorMessage) return self.skyn.edit(self) + # Before saving data, must we ask a confirmation by the user ? + appyObj = self.appy() + saveConfirmed = rq.get('confirmed') == 'True' + if hasattr(appyObj, 'confirm') and not saveConfirmed: + msg = appyObj.confirm(values) + if msg: + rq.set('confirmMsg', msg.replace("'", "\\'")) + return self.skyn.edit(self) + # Create or update the object in the database obj = self.createOrUpdate(isNew, values) # Redirect the user to the appropriate page msg = obj.translate('Changes saved.', domain='plone') - if rq.get('buttonOk.x', None): + if rq.get('buttonOk.x', None) or saveConfirmed: # Go to the consult view for this object obj.plone_utils.addPortalMessage(msg) return self.goto(obj.getUrl()) @@ -237,13 +259,6 @@ class BaseMixin: return self.goto(obj.getUrl()) return obj.skyn.edit(obj) - def onDelete(self): - rq = self.REQUEST - msg = self.translate('delete_done') - self.delete() - self.plone_utils.addPortalMessage(msg) - self.goto(self.getUrl(rq['HTTP_REFERER'])) - def rememberPreviousData(self): '''This method is called before updating an object and remembers, for every historized field, the previous value. Result is a dict @@ -754,17 +769,11 @@ class BaseMixin: rq = self.REQUEST self.portal_workflow.doActionFor(self, rq['workflow_action'], comment = rq.get('comment', '')) - # Where to redirect the user back ? - urlBack = rq['HTTP_REFERER'] - if urlBack.find('?') != -1: - # Remove params; this way, the user may be redirected to correct - # phase when relevant. - urlBack = urlBack[:urlBack.find('?')] - msg = self.translate(u'Your content\'s status has been modified.', - domain='plone') - self.plone_utils.addPortalMessage(msg) self.reindexObject() - return self.goto(urlBack) + # Where to redirect the user back ? + # TODO (?): remove the "phase" param for redirecting the user to the + # next phase when relevant. + return self.goto(self.getUrl(rq['HTTP_REFERER'])) def fieldValueSelected(self, fieldName, vocabValue, dbValue): '''When displaying a selection box (ie a String with a validator being a @@ -916,15 +925,28 @@ class BaseMixin: '''Returns a Appy URL. * If p_base is None, it will be the base URL for this object (ie, self.absolute_url()). - * p_mode can de "edit" or "view". + * p_mode can be "edit", "view" or "raw" (a non-param, base URL) * p_kwargs can store additional parameters to add to the URL. In this dict, every value that is a string will be added to the URL as-is. Every value that is True will be replaced by the value in the request for the corresponding key (if existing; else, the param will not be included in the URL at all).''' - # Define base URL if ommitted + # Define the URL suffix + suffix = '' + if mode != 'raw': suffix = '/skyn/%s' % mode + # Define base URL if omitted if not base: - base = '%s/skyn/%s' % (self.absolute_url(), mode) + base = self.absolute_url() + suffix + # If a raw URL is asked, remove any param and suffix. + if mode == 'raw': + if '?' in base: base = base[:base.index('?')] + base = base.strip('/') + for mode in ('view', 'edit'): + suffix = 'skyn/%s' % mode + if base.endswith(suffix): + base = base[:-len(suffix)].strip('/') + break + return base # Manage default args if not kwargs: kwargs = self.getUrlDefaults if 'page' not in kwargs: kwargs['page'] = True diff --git a/gen/plone25/skin/edit.pt b/gen/plone25/skin/edit.pt index 9971906..d43178f 100644 --- a/gen/plone25/skin/edit.pt +++ b/gen/plone25/skin/edit.pt @@ -11,7 +11,8 @@ page request/page|python:'main'; cssAndJs python: contextObj.getCssAndJs(layoutType, page); css python: cssAndJs[0]; - js python: cssAndJs[1]"> + js python: cssAndJs[1]; + confirmMsg request/confirmMsg | nothing;"> -
+ + +
diff --git a/gen/plone25/skin/page.pt b/gen/plone25/skin/page.pt index cb77e19..b4b5002 100644 --- a/gen/plone25/skin/page.pt +++ b/gen/plone25/skin/page.pt @@ -46,8 +46,13 @@ if (xhrObjects[pos].onGet) { xhrObjects[pos].onGet(xhrObjects[pos], hookElem); } + // Eval inner scripts if any. + var innerScripts = document.getElementsByName("appyHook"); + for (var i=0; iView macro for a Ref.
-
@@ -148,9 +147,6 @@ - - - diff --git a/gen/plone25/workflow.py b/gen/plone25/workflow.py index 35bc18d..f01e048 100644 --- a/gen/plone25/workflow.py +++ b/gen/plone25/workflow.py @@ -142,6 +142,7 @@ def do(transitionName, stateChange, logger): ploneObj = stateChange.object workflow = ploneObj.getWorkflow() transition = workflow._transitionsMapping[transitionName] + msg = '' # Must I execute transition-related actions and notifications? doAction = False if transition.action: @@ -161,11 +162,25 @@ def do(transitionName, stateChange, logger): if doAction or doNotify: obj = ploneObj.appy() if doAction: + msg = '' if type(transition.action) in (tuple, list): # We need to execute a list of actions - for act in transition.action: act(workflow, obj) + for act in transition.action: + msgPart = act(workflow, obj) + if msgPart: msg += msgPart else: # We execute a single action only. - transition.action(workflow, obj) + msgPart = transition.action(workflow, obj) + if msgPart: msg += msgPart if doNotify: notifier.sendMail(obj, transition, transitionName, workflow, logger) + # Produce a message to the user + if hasattr(ploneObj, '_v_appy_do') and not ploneObj._v_appy_do['doSay']: + # We do not produce any message if the transition was triggered + # programmatically. + return + # Produce a default message if no transition has given a custom one. + if not msg: + msg = ploneObj.translate(u'Your content\'s status has been modified.', + domain='plone') + ploneObj.plone_utils.addPortalMessage(msg) # ------------------------------------------------------------------------------ diff --git a/gen/plone25/wrappers/__init__.py b/gen/plone25/wrappers/__init__.py index 5c1aca7..b21a14d 100644 --- a/gen/plone25/wrappers/__init__.py +++ b/gen/plone25/wrappers/__init__.py @@ -90,6 +90,8 @@ class AbstractWrapper: typeName = property(get_typeName) def get_id(self): return self.o.id id = property(get_id) + def get_uid(self): return self.o.UID() + uid = property(get_uid) def get_state(self): return self.o.portal_workflow.getInfoFor(self.o, 'review_state') state = property(get_state) @@ -238,7 +240,8 @@ class AbstractWrapper: # Set in a versatile attribute details about what to execute or not # (actions, notifications) after the transition has been executed by DC # workflow. - self.o._v_appy_do = {'doAction': doAction, 'doNotify': doNotify} + self.o._v_appy_do = {'doAction': doAction, 'doNotify': doNotify, + 'doSay': False} if not doHistory: comment = '_invisible_' # Will not be displayed. # At first sight, I wanted to remove the entry from