def testVersionPreviewIsNotInlineEditable(self): """If the kss_inline_editable variable is defined to False in a page template, all the fields will be globally prohibited to be editable. This works via the getKssClasses method. Similarly, is suppress_preview is set to true, inline editing is prohibited. This is set from CMFEditions, in the versions_history_form. In this test we check that the versions history is not inline editable at all. """ obj = self.portal['front-page'] # Make sure we actually have a revision pr = self.portal.portal_repository pr.save(obj) # Render versions history of the front page obj.REQUEST.form['version_id'] = '0' rendered = obj.versions_history_form() soup = BeautifulSoup(rendered) # check that inline edit is not active, by looking at body text tag = soup.find(id=re.compile('parent-fieldname-text-*')) klass = tag['class'] # ... and now see we are really not inline editable: self.assert_('inlineEditable' not in klass) # make sure the rest is still there or instant validation and # possibly other stuff will fail self.assert_('kssattr-templateId-' in klass) self.assert_('kssattr-macro-' in klass)
def changeViewTemplate(self, url): '''Replace content region after selecting template from drop-down. Usage:: dl#templateMenu dd a:click { evt-click-preventdefault: True; action-server: changeViewTemplate; changeViewTemplate-url: nodeAttr(href); } REMARK: Cheat at the moment: we render down the whole page but take out the required part only This will be optimized more to replace the main template for the context of the call Warning when we leave the page is not implemented. ''' templateid = url.split('templateId=')[-1].split('&')[0] context = getCurrentContext(self.context) wrapping = acquirerFactory(context) # XXX I believe selectViewTemplate script will be replaced by an # adapter or a view in the new implementation of CMFDynamicFTI context.selectViewTemplate(templateid) # Figure out the template to render. template = wrapping.restrictedTraverse(templateid) # We render it content = template() # Now. We take out the required node from it! # We need this in any way, as we don't know if the template # actually used main_template! In that case we would have # the *whole* html which is wrong. soup = BeautifulSoup(content) replace_id = 'content' tag = soup.find('div', id=replace_id) if tag is None: raise RuntimeError, 'Result content did not contain <div id="%s">' % replace_id # now we send it back to the client result = unicode(tag) ksscore = self.getCommandSet('core') ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), result) self.getCommandSet('plone').refreshContentMenu() self.issueAllPortalMessages() self.cancelRedirect()
def refreshPortletLegacy(self, name, nodeid=None, **kw): 'Refresh portlet by name (old portlets)' if name.startswith('portlet-'): name = name[8:] if nodeid is None: nodeid = name # render it portlet_body = self.view.macroContent('portlet_%s/macros/portlet' % (name, ), **kw) # Good. Now, unfortunately we don't have any marker on the outside div. # So we just select the <dl> for insertion. # This could be spared with smarter templating. soup = BeautifulSoup(portlet_body) tag = soup.find('dl', id=nodeid) result = unicode(tag) # Command the replacement ksscore = self.getCommandSet('core') ksscore.replaceHTML(ksscore.getHtmlIdSelector(nodeid), result)
def cleanHtml(content): soup = BeautifulSoup(content) soup = removeJavascript(soup) soup = replaceEmbedsWithIframes(soup) soup = removeViewFromImages(soup) soup = removeStylesFromInlineImages(soup) soup = removeWidthHeightFromInlineImages(soup) return unicode(soup)
def replaceContentRegion(self, url, tabid=''): '''Replace content region by tab id Usage:: ul.contentViews li a:click { evt-click-preventdefault: True; action-server: replaceContentRegion; replaceContentRegion-tabid: nodeAttr(id, true); replaceContentRegion-url: nodeAttr(href); } REMARK: We use the acquisition context hack to replace the main template with one that only renders the content region. This means that if the target template reuses main_template we win. Otherwise we loose and we get a full page of which we have to take out the required part with BeautifulSoup. Warning ("Do you want to...") when we leave the page is not implemented. ''' # REMARK on error handling: # If KSSExplicitError is raised, the control will be passed # to the error handler defined on the client. I.e. for this rule, # the static plone-followLink should be activated. This means that # if this method decides it cannot handle the situation, it # raises this exception and we fallback to the non-AJAX behaviour. # # XXX The next checks could be left out - but we won't be able to change the tabs. # This could be solved with not using the tabs or doing server side quirks. # This affect management screens, for example, that are not real actions. # and unlock XXX context = aq_inner(self.context) lock = getMultiAdapter((context,self.request), name='plone_lock_operations') lock.safe_unlock() if not tabid or tabid == 'content': raise KSSExplicitError, 'No tabid on the tab' if not tabid.startswith('contentview-'): raise RuntimeError, 'Not a valid contentview id "%s"' % tabid # Split the url into it's components (proto, host, path, query, anchor) = urlsplit(url) # if the url doesn't use http(s) or has a query string or anchor # specification, don't bother if query or anchor or proto not in ('http', 'https'): raise KSSExplicitError, 'Unhandled protocol on the tab' # make the wrapping for the context, to overwrite main_template # note we have to use aq_chain[0] *not* aq_base. # XXX however just context would be good too? Hmmm wrapping = acquirerFactory(context) # Figure out the template to render. # We need the physical path which we can obtain from the url path = list(self.request.physicalPathFromURL(url)) obj_path = list(context.getPhysicalPath()) if path == obj_path: # target is the default view of the method. # url is like: ['http:', '', 'localhost:9777', 'kukitportlets', 'prefs_users_overview'] # physical path is like: ('', 'kukitportlets') # We lookup the default view for the object, which may be # another object, if so we give up, otherwise we use the # appropriate template utils = getToolByName(context, 'plone_utils') if utils.getDefaultPage(context) is not None: raise KSSExplicitError, 'no default page on the tab' viewobj, viewpath = utils.browserDefault(context) if len(viewpath) == 1: viewpath = viewpath[0] template = viewobj.restrictedTraverse(viewpath) else: # see if it is a method on the same context object... # url is like: ['http:', '', 'localhost:9777', 'kukitportlets', 'prefs_users_overview'] # physical path is like: ('', 'kukitportlets') if path[:-1] != obj_path: raise KSSExplicitError, 'cannot reload since the tab visits a different context' method = path[-1] # Action method may be a method alias: Attempt to resolve to a template. try: method = context.getTypeInfo().queryMethodID(method, default=method) except AttributeError: # Don't raise if we don't have a CMF 1.5 FTI pass template = wrapping.restrictedTraverse(method) # We render it content = template() # Now. We take out the required node from it! # We need this in any way, as we don't know if the template # actually used main_template! In that case we would have # the *whole* html which is wrong. soup = BeautifulSoup(content) replace_id = 'content' tag = soup.find('div', id=replace_id) if tag is None: raise RuntimeError, 'Result content did not contain <div id="%s">' % replace_id # now we send it back to the client result = unicode(tag) ksscore = self.getCommandSet('core') ksscore.replaceHTML(ksscore.getHtmlIdSelector(replace_id), result) # to remove old tab highlight,... ksscore.setAttribute(ksscore.getCssSelector("ul.contentViews li"), name='class', value='plain'); # ... and put the highlight to the newly selected tab ksscore.setAttribute(ksscore.getHtmlIdSelector(tabid), name='class', value='selected'); # Update the content menu to show them only in the "view" if tabid.endswith('view'): alsoProvides(self, IViewView) self.getCommandSet('plone').refreshContentMenu()