Added a new feature allowing to create objects by importing them from external sources instead of from filling a web form.

This commit is contained in:
Gaetan Delannay 2009-10-20 16:57:00 +02:00
parent cbc7d257d4
commit 4c4b2d0f87
17 changed files with 502 additions and 181 deletions

View file

@ -2,63 +2,14 @@
##bind context=context
##parameters=action
rq = context.REQUEST
urlBack = rq['HTTP_REFERER']
if action == 'create':
# A user wants to create an object.
if rq.get('initiator', None):
# The object to create will be linked to an initiator object through a
# ref field.
initiatorRes= context.uid_catalog.searchResults(UID=rq.get('initiator'))
rq.SESSION['initiator'] = rq.get('initiator')
rq.SESSION['initiatorField'] = rq.get('field')
rq.SESSION['initiatorTarget'] = rq.get('type_name')
objId = context.generateUniqueId(rq.get('type_name'))
urlBack = '%s/portal_factory/%s/%s/skyn/edit' % \
(context.getParentNode().absolute_url(), rq.get('type_name'), objId)
elif action == 'edit': return context.getParentNode().onUpdate()
elif action == 'appyAction':
# Get the object impacted by the action.
if rq.get('objectUid', None):
obj = context.uid_catalog(UID=rq['objectUid'])[0].getObject()
res, msg = obj.executeAppyAction(rq['fieldName'])
if not msg:
# Use the default i18n messages
suffix = 'ko'
if res:
suffix = 'ok'
label = '%s_action_%s' % (obj.getLabelPrefix(rq['fieldName']), suffix)
msg = obj.translate(label)
context.plone_utils.addPortalMessage(msg)
elif action == 'changeRefOrder':
# Move the item up (-1), down (+1) or at a given position ?
obj = context.getParentNode()
move = -1 # Move up
isDelta = True
if rq.get('moveDown.x', None) != None:
move = 1 # Move down
elif rq.get('moveSeveral.x', None) != None:
try:
move = int(rq.get('moveValue'))
# In this case, it is not a delta value; it is the new position where
# the item must be moved.
isDelta = False
except ValueError:
context.plone_utils.addPortalMessage(
obj.translate('ref_invalid_index'))
obj.changeAppyRefOrder(rq['fieldName'], rq['objectUid'], move, isDelta)
elif action == 'triggerTransition':
obj = context.getParentNode()
from Products.CMFPlone import PloneMessageFactory as _
context.portal_workflow.doActionFor(obj, rq['workflow_action'],
comment=rq.get('comment', ''))
if urlBack.find('?') != -1:
# Remove params; this way, the user may be redirected to correct phase
# when relevant.
urlBack = urlBack[:urlBack.find('?')]
context.plone_utils.addPortalMessage(
_(u'Your content\'s status has been modified.'))
return rq.RESPONSE.redirect(urlBack)
else:
obj = context.getParentNode() # An appy obj or in some cases the app folder.
if obj.portal_type == 'AppyFolder':
from Products.CMFCore.utils import getToolByName
portal = getToolByName(obj, 'portal_url').getPortalObject()
obj = portal.get('portal_%s' % obj.id.lower()) # The tool
return obj.getAppyAttribute('on'+action)()

View file

@ -68,14 +68,14 @@
<body>
<metal:fill fill-slot="main">
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
<form name="edit_form" method="post" enctype="multipart/form-data"
class="enableUnloadProtection atBaseEditForm"
tal:attributes="action python: contextObj.absolute_url()+'/skyn/do'">
<div metal:use-macro="here/skyn/macros/macros/listFields" />
<input type="hidden" name="action" value="edit"/>
<input type="hidden" name="action" value="Update"/>
<input type="hidden" name="fieldset" tal:attributes="value fieldset"/>
<input type="hidden" name="pageName" tal:attributes="value pageName"/>
<input type="hidden" name="phase" tal:attributes="value phase"/>

BIN
gen/plone25/skin/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

BIN
gen/plone25/skin/import.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 705 B

123
gen/plone25/skin/import.pt Normal file
View file

@ -0,0 +1,123 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"
lang="en" xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:i18n="http://xml.zope.org/namespaces/i18n"
metal:use-macro="here/main_template/macros/master">
<tal:comment replace="nothing">Disable standard Plone green tabs</tal:comment>
<div metal:fill-slot="top_slot">
<metal:block metal:use-macro="here/global_defines/macros/defines" />
<div tal:define="dummy python:request.set('disable_border', 1)" />
</div>
<tal:comment replace="nothing">Fill main slot of Plone main_template</tal:comment>
<body>
<metal:fill fill-slot="main"
tal:define="appFolder context/getParentNode;
contentType request/type_name;
tool python: portal.get('portal_%s' % appFolder.id.lower());
importElems python: tool.getImportElements(contentType);
global allAreImported python:True">
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
<script language="javascript">
<!--
var importedElemsShown = false;
function toggleViewableElements() {
var rows = cssQuery('#importedElem');
var newDisplay = 'table-row';
if (importedElemsShown) newDisplay = 'none';
for (var i=0; i<rows.length; i++) {
rows[i].style.display = newDisplay;
}
importedElemsShown = !importedElemsShown;
}
var checkBoxesChecked = true;
function toggleCheckboxes() {
var checkBoxes = cssQuery('#cbElem');
var newCheckValue = true;
if (checkBoxesChecked) newCheckValue = false;
for (var i=0; i<checkBoxes.length; i++) {
checkBoxes[i].checked = newCheckValue;
}
checkBoxesChecked = newCheckValue;
}
function importSingleElement(importPath) {
var f = document.forms['importElements'];
f.importPath.value = importPath;
f.submit();
}
function importManyElements() {
var f = document.forms['importElements'];
var importPaths = '';
// Get the values of the checkboxes
var checkBoxes = cssQuery('#cbElem');
for (var i=0; i<checkBoxes.length; i++) {
if (checkBoxes[i].checked) {
importPaths += checkBoxes[i].value + '|';
}
}
if (! importPaths) alert(no_elem_selected);
else {
f.importPath.value = importPaths;
f.submit();
}
}
-->
</script>
<tal:comment replace="nothing">Form for importing several meetings at once.</tal:comment>
<form name="importElements"
tal:attributes="action python: appFolder.absolute_url()+'/skyn/do'" method="post">
<input type="hidden" name="action" value="ImportObjects"/>
<input type="hidden" name="type_name" tal:attributes="value contentType"/>
<input type="hidden" name="importPath" value=""/>
</form>
<h1 tal:content="python: tool.translate('import_title')"></h1><br/>
<table cellpadding="0" cellspacing="0" class="vertical listing" width="100%">
<tr>
<th tal:repeat="columnHeader python: importElems[0]">
<img tal:condition="python: repeat['columnHeader'].number() == 1"
tal:attributes="src string:$portal_url/skyn/eye.png;
title python: tool.translate('import_show_hide')"
style="cursor:pointer" onClick="javascript:toggleViewableElements()" align="left" />
<span tal:replace="columnHeader"/>
</th>
<th tal:content="python: tool.translate('ref_actions')"></th>
<th width="20px"><img
tal:attributes="src string: $portal_url/skyn/select_elems.png;
title python: tool.translate('select_delesect')"
onClick="javascript:toggleCheckboxes()" style="cursor:pointer"/>
</tr>
<tal:row repeat="row python: importElems[1]">
<tr tal:define="alreadyImported python: tool.isAlreadyImported(contentType, row[0]);
global allAreImported python: allAreImported and alreadyImported"
tal:attributes="id python:test(alreadyImported, 'importedElem', 'notImportedElem');
style python:test(alreadyImported, 'display:none', 'display:table-row')">
<td tal:repeat="elem python: row[1:]" tal:content="elem">
</td>
<td>
<input type="button" tal:condition="not: alreadyImported"
tal:attributes="onClick python: 'javascript:importSingleElement(\'%s\')' % row[0];
value python: tool.translate('query_import')"/>
<span tal:condition="alreadyImported" tal:replace="python: tool.translate('import_already')"/>
</td>
<td align="center"><input type="checkbox" checked="checked" class="noborder" id="cbElem"
tal:attributes="value python: row[0]" tal:condition="not: alreadyImported"/></td>
</tr>
</tal:row>
<tr tal:condition="python: not importElems[1] or allAreImported"><td colspan="15" tal:content="python: tool.translate('query_no_result')"></td></tr>
</table>
<tal:comment replace="nothing">Button for importing several elements at once.</tal:comment>
<p align="right"><br/>
<input type="button" onClick="javascript:importManyElements()"
tal:condition="python: importElems[1] and not allAreImported"
tal:attributes="value python:tool.translate('import_many')"/>
</p>
</metal:fill>
</body>
</html>

View file

@ -104,7 +104,7 @@
<div metal:define-macro="showActionField">
<form name="executeAppyAction" action="skyn/do" method="POST">
<input type="hidden" name="actionType" value="appyAction"/>
<input type="hidden" name="action" value="ExecuteAppyAction"/>
<input type="hidden" name="objectUid" tal:attributes="value contextObj/UID"/>
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
<input type="submit" name="do" tal:attributes="value label"/>
@ -300,56 +300,72 @@
</dl>
</span>
<div metal:define-macro="showPagePrologue">
<tal:comment replace="nothing">Global Javascript functions, used in edit and
consult views, are defined gere.</tal:comment>
<div metal:define-macro="pagePrologue">
<tal:comment replace="nothing">Global elements used in every page.</tal:comment>
<tal:comment replace="nothing">Javascript messages</tal:comment>
<script language="javascript" tal:content="tool/getJavascriptMessages"></script>
<tal:comment replace="nothing">"Static" javascripts</tal:comment>
<script language="javascript">
<!--
// This function turns a checkbox into a radio button... sort of
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
vis = document.getElementById(visibleCheckbox);
hidden = document.getElementById(hiddenBoolean);
if (vis.checked) hidden.value = 'True';
else hidden.value = 'False';
<!--
// Function used by checkbox widgets for having radio-button-like behaviour
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
vis = document.getElementById(visibleCheckbox);
hidden = document.getElementById(hiddenBoolean);
if (vis.checked) hidden.value = 'True';
else hidden.value = 'False';
}
// Functions used for master/slave relationships between widgets
function getMasterValue(widget) {
// Returns an array of selected options in a select widget
res = new Array();
if (widget.type == 'checkbox') {
var mv = widget.checked + '';
mv = mv.charAt(0).toUpperCase() + mv.substr(1);
res.push(mv);
}
else { // SELECT widget
for (var i=0; i < widget.options.length; i++) {
if (widget.options[i].selected) res.push(widget.options[i].value);
}
// Returns an array of selected options in a select widget
function getMasterValue(widget) {
res = new Array();
if (widget.type == 'checkbox') {
var mv = widget.checked + '';
mv = mv.charAt(0).toUpperCase() + mv.substr(1);
res.push(mv);
}
else { // SELECT widget
for (var i=0; i < widget.options.length; i++) {
if (widget.options[i].selected) res.push(widget.options[i].value);
}
}
return res;
}
return res;
}
function updateSlaves(masterValues, appyTypeId) {
// Given the value(s) selected in a master field, this function updates the
// state of all corresponding slaves.
var slaves = cssQuery('div.slave_' + appyTypeId);
for (var i=0; i< slaves.length; i++){
slaves[i].style.display = "none";
}
for (var i=0; i < masterValues.length; i++) {
var activeSlaves = cssQuery('div.slaveValue_' + appyTypeId + '_' + masterValues[i]);
for (var j=0; j < activeSlaves.length; j++){
activeSlaves[j].style.display = "";
}
// Given the value(s) selected in a master field, this function updates the
// state of all corresponding slaves.
function updateSlaves(masterValues, appyTypeId) {
var slaves = cssQuery('div.slave_' + appyTypeId);
for (var i=0; i< slaves.length; i++){
slaves[i].style.display = "none";
}
for (var i=0; i < masterValues.length; i++) {
var activeSlaves = cssQuery('div.slaveValue_' + appyTypeId + '_' + masterValues[i]);
for (var j=0; j < activeSlaves.length; j++){
activeSlaves[j].style.display = "";
}
}
}
// Triggers a workflow transition
function triggerTransition(transitionId) {
var theForm = document.getElementById('triggerTransitionForm');
theForm.workflow_action.value = transitionId;
theForm.submit();
}
-->
</script>
}
}
// Function used for triggering a workflow transition
function triggerTransition(transitionId) {
var theForm = document.getElementById('triggerTransitionForm');
theForm.workflow_action.value = transitionId;
theForm.submit();
}
function onDeleteObject(objectUid) {
if (confirm(delete_confirm)) {
f = document.getElementById('deleteForm');
f.objectUid.value = objectUid;
f.submit();
}
}
-->
</script>
<tal:comment replace="nothing">Global form for deleting an object</tal:comment>
<form id="deleteForm" method="post" action="skyn/do">
<input type="hidden" name="action" value="Delete"/>
<input type="hidden" name="objectUid"/>
</form>
</div>
<div metal:define-macro="showPageHeader"
@ -681,10 +697,11 @@
<img src="edit.gif" title="Edit" i18n:domain="plone" i18n:attributes="title" />
</a></td>
<tal:comment replace="nothing">Delete the element</tal:comment>
<td class="noPadding"><a tal:attributes="href python: obj.absolute_url() + '/delete_confirmation'"
tal:condition="python: member.has_permission('Delete objects', obj)">
<img src="delete_icon.gif" title="Delete" i18n:domain="plone" i18n:attributes="title" />
</a></td>
<td class="noPadding">
<img tal:condition="python: member.has_permission('Delete objects', obj)"
src="delete_icon.gif" title="Delete" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
tal:attributes="onClick python:'javascript:onDeleteObject(\'%s\')' % obj.UID()"/>
</td>
</tr>
</table>
</td>
@ -740,7 +757,7 @@
tal:condition="transitions">
<form id="triggerTransitionForm" method="post"
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'">
<input type="hidden" name="actionType" value="triggerTransition"/>
<input type="hidden" name="action" value="TriggerTransition"/>
<input type="hidden" name="workflow_action"/>
<table>
<tr>

View file

@ -3,62 +3,74 @@
<tal:comment replace="nothing">This page presents results of queries</tal:comment>
<body>
<div metal:fill-slot="top_slot">
<metal:block metal:use-macro="here/global_defines/macros/defines" />
<div tal:define="dummy python:request.set('disable_border', 1)" />
</div>
<tal:comment replace="nothing">We suppose we are in the app folder here.</tal:comment>
<div metal:fill-slot="main"
tal:define="appFolder context/getParentNode;
appName appFolder/id;
tool python: portal.get('portal_%s' % appName.lower());
queryName python:context.REQUEST.get('query');
flavourNumber python:context.REQUEST.get('flavourNumber');
rootClasses tool/getRootClasses;
rootTypes python: test(flavourNumber=='1', rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
rootClassesQuery python:','.join(rootClasses);
mainTabSelected python: queryName.find(',') != -1">
<tal:comment replace="nothing">Disable standard Plone green tabs</tal:comment>
<div metal:fill-slot="top_slot">
<metal:block metal:use-macro="here/global_defines/macros/defines" />
<div tal:define="dummy python:request.set('disable_border', 1)" />
</div>
<span tal:condition="python: queryName and (queryName != 'none')">
<span tal:define="queryResult python: tool.executeQuery(queryName, int(flavourNumber));
batch queryResult">
<tal:comment replace="nothing">We suppose we are in the app folder here.</tal:comment>
<div metal:fill-slot="main"
tal:define="appFolder context/getParentNode;
appName appFolder/id;
tool python: portal.get('portal_%s' % appName.lower());
queryName python:context.REQUEST.get('query');
flavourNumber python:context.REQUEST.get('flavourNumber');
rootClasses tool/getRootClasses;
rootTypes python: test(flavourNumber=='1', rootClasses, ['%s_%s' % (rc, flavourNumber) for rc in rootClasses]);
rootClassesQuery python:','.join(rootClasses);
mainTabSelected python: queryName.find(',') != -1">
<tal:comment replace="nothing">Tabs</tal:comment>
<ul class="contentViews appyTabs">
<tal:comment replace="nothing">Tab "All objects"</tal:comment>
<li tal:define="selected python:mainTabSelected"
tal:attributes="class python:test(selected, 'selected', 'plain')"
tal:condition="python: len(rootClasses)>1">
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
<span tal:condition="python: queryName and (queryName != 'none')">
<span tal:define="queryResult python: tool.executeQuery(queryName, int(flavourNumber));
batch queryResult">
<a tal:content="python: tool.translate('query_consult_all')"
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
</li>
<tal:comment replace="nothing">One tab for each root content type</tal:comment>
<tal:tab repeat="rootContentType rootTypes">
<li tal:define="selected python:queryName == rootContentType"
tal:attributes="class python:test(selected, 'selected', 'plain')">
<a tal:content="python: tool.translate(rootContentType)"
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootContentType, flavourNumber)"/>
<img style="cursor:pointer" class="appyPlusImg"
tal:define="addPermission python: '%s: Add %s' % (appName, rootContentType)"
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/do?action=create&type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
src string: $portal_url/skyn/plus.png;
title python: tool.translate('query_create')"
tal:condition="python: member.has_permission(addPermission, appFolder)"/>
</li>
</tal:tab>
</ul>
<br/>
<tal:comment replace="nothing">Tabs</tal:comment>
<ul class="contentViews appyTabs">
<tal:comment replace="nothing">Tab "All objects"</tal:comment>
<li tal:define="selected python:mainTabSelected"
tal:attributes="class python:test(selected, 'selected', 'plain')"
tal:condition="python: len(rootClasses)>1">
<tal:comment replace="nothing">Query result</tal:comment>
<span tal:condition="queryResult">
<span metal:use-macro="here/skyn/macros/macros/queryResult"></span>
</span>
<span tal:condition="not: queryResult"
tal:content="python: tool.translate('query_no_result')">No result.</span>
</span>
</span>
</div>
<a tal:content="python: tool.translate('query_consult_all')"
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootClassesQuery, flavourNumber)"></a>
</li>
<tal:comment replace="nothing">One tab for each root content type</tal:comment>
<tal:tab repeat="rootContentType rootTypes">
<li tal:define="selected python:queryName == rootContentType;
addPermission python: '%s: Add %s' % (appName, rootContentType);
userMayAdd python: member.has_permission(addPermission, appFolder);
createMeans python: tool.getCreateMeans(rootContentType)"
tal:attributes="class python:test(selected, 'selected', 'plain')">
<a tal:content="python: tool.translate(rootContentType)"
tal:attributes="href python: '%s/skyn/query?query=%s&flavourNumber=%s' % (appFolder.absolute_url(), rootContentType, flavourNumber)"/>
<tal:comment replace="nothing">Create a new object from a web form</tal:comment>
<img style="cursor:pointer" class="appyPlusImg"
tal:condition="python: ('form' in createMeans) and userMayAdd"
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/do?action=Create&type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
src string: $portal_url/skyn/plus.png;
title python: tool.translate('query_create')"/>
<tal:comment replace="nothing">Create (a) new object(s) by importing data</tal:comment>
<img style="cursor:pointer" class="appyPlusImg"
tal:condition="python: ('import' in createMeans) and userMayAdd"
tal:attributes="onClick python: 'href: window.location=\'%s/skyn/import?type_name=%s\'' % (appFolder.absolute_url(), rootContentType);
src string: $portal_url/skyn/import.png;
title python: tool.translate('query_import')"/>
</li>
</tal:tab>
</ul>
<br/>
<tal:comment replace="nothing">Query result</tal:comment>
<span tal:condition="queryResult">
<span metal:use-macro="here/skyn/macros/macros/queryResult"></span>
</span>
<span tal:condition="not: queryResult"
tal:content="python: tool.translate('query_no_result')">No result.</span>
</span>
</span>
</div>
</body>
</html>

View file

@ -26,13 +26,13 @@
<img src="delete_icon.gif" title="label_remove" i18n:domain="plone" i18n:attributes="title" />
</a></td>
<tal:comment replace="nothing">Arrows for moving objects up or down</tal:comment>
<td class="noPadding" tal:condition="python: len(objs)>1">
<td class="noPadding" tal:condition="python: len(objs)&gt;1">
<form tal:condition="python: member.has_permission('Modify portal content', obj)"
tal:attributes="action python: contextObj.absolute_url() + '/skyn/do'"
tal:define="objectIndex python:contextObj.getAppyRefIndex(field.getName(), obj)">
<input type="hidden" name="actionType" value="changeRefOrder"/>
<input type="hidden" name="action" value="ChangeRefOrder"/>
<input type="hidden" name="fieldName" tal:attributes="value field/getName"/>
<input type="hidden" name="objectUid" tal:attributes="value obj/UID"/>
<input type="hidden" name="refObjectUid" tal:attributes="value obj/UID"/>
<tal:comment replace="nothing">Arrow up</tal:comment>
<span tal:condition="python: objectIndex &gt; 0">
<input type="image" name="moveUp" class="imageInput"
@ -58,7 +58,7 @@
<img style="cursor:pointer" tal:condition="showPlusIcon"
tal:attributes="src string:$portal_url/skyn/plus.png;
title python: tool.translate('add_ref');
onClick python: 'href: window.location=\'%s/skyn/do?action=create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
onClick python: 'href: window.location=\'%s/skyn/do?action=Create&initiator=%s&field=%s&type_name=%s\'' % (folder.absolute_url(), contextObj.UID(), field.getName(), linkedPortalType)"/>
</metal:plusIcon>
<div metal:define-macro="showReference"

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

View file

@ -27,7 +27,7 @@
phase request/phase|phaseInfo/name;
pageName python: contextObj.getAppyPage(isEdit, phaseInfo);
showWorkflow python: flavour.getAttr('showWorkflowFor' + contextObj.meta_type)">
<div metal:use-macro="here/skyn/macros/macros/showPagePrologue"/>
<div metal:use-macro="here/skyn/macros/macros/pagePrologue"/>
<div metal:use-macro="here/skyn/macros/macros/showPageHeader"/>
<div metal:use-macro="here/skyn/macros/macros/listFields" />
<div metal:use-macro="here/skyn/macros/macros/showPageFooter"/>