appy.gen: bugfixes in Ref fields, IE CSS and master/slave relationships.
This commit is contained in:
parent
e821307b4c
commit
4b44f8d565
|
@ -23,11 +23,11 @@ emptyTuple = ()
|
|||
labelTypes = ('label', 'descr', 'help')
|
||||
|
||||
def initMasterValue(v):
|
||||
'''Standardizes p_v as a list.'''
|
||||
'''Standardizes p_v as a list of strings.'''
|
||||
if not v: res = []
|
||||
elif type(v) not in sequenceTypes: res = [v]
|
||||
else: res = v
|
||||
return res
|
||||
return [str(v) for v in res]
|
||||
|
||||
# Descriptor classes used for refining descriptions of elements in types
|
||||
# (pages, groups,...) ----------------------------------------------------------
|
||||
|
@ -1809,6 +1809,43 @@ class Ref(Type):
|
|||
elif nbOfRefs > maxRef:
|
||||
return obj.translate('max_ref_violated')
|
||||
|
||||
def linkObject(self, obj, value, back=False):
|
||||
'''This method links p_value (which can be a list of objects) to p_obj
|
||||
through this Ref field.'''
|
||||
# p_value can be a list of objects
|
||||
if type(value) in sequenceTypes:
|
||||
for v in value: self.linkObject(obj, v, back=back)
|
||||
return
|
||||
# Gets the list of referred objects (=list of uids), or create it.
|
||||
obj = obj.o
|
||||
refs = getattr(obj, self.name, None)
|
||||
if refs == None:
|
||||
refs = obj.getProductConfig().PersistentList()
|
||||
setattr(obj, self.name, refs)
|
||||
# Insert p_value into it.
|
||||
uid = value.o.UID()
|
||||
if uid not in refs:
|
||||
refs.append(uid)
|
||||
# Update the back reference
|
||||
if not back: self.back.linkObject(value, obj, back=True)
|
||||
|
||||
def unlinkObject(self, obj, value, back=False):
|
||||
'''This method unlinks p_value (which can be a list of objects) from
|
||||
p_obj through this Ref field.'''
|
||||
# p_value can be a list of objects
|
||||
if type(value) in sequenceTypes:
|
||||
for v in value: self.unlinkObject(obj, v, back=back)
|
||||
return
|
||||
obj = obj.o
|
||||
refs = getattr(obj, self.name, None)
|
||||
if not refs: return
|
||||
# Unlink p_value
|
||||
uid = value.o.UID()
|
||||
if uid in refs:
|
||||
refs.remove(uid)
|
||||
# Update the back reference
|
||||
if not back: self.back.unlinkObject(value, obj, back=True)
|
||||
|
||||
def store(self, obj, value):
|
||||
'''Stores on p_obj, the p_value, which can be:
|
||||
* None;
|
||||
|
@ -1817,25 +1854,31 @@ class Ref(Type):
|
|||
of UIDs come from Ref fields with link:True edited through the web;
|
||||
* a Zope object;
|
||||
* a Appy object;
|
||||
* a list of Appy or Zope objects.
|
||||
'''
|
||||
# Standardize p_value into a list of uids
|
||||
uids = value
|
||||
if not uids: uids = []
|
||||
if type(uids) not in sequenceTypes: uids = [uids]
|
||||
for i in range(len(uids)):
|
||||
if not isinstance(uids[i], basestring):
|
||||
# Get the UID from the Zope or Appy object
|
||||
uids[i] = uids[i].o.UID()
|
||||
# Update the list of referred uids.
|
||||
* a list of Appy or Zope objects.'''
|
||||
# Standardize p_value into a list of Zope objects
|
||||
objects = value
|
||||
if not objects: objects = []
|
||||
if type(objects) not in sequenceTypes: objects = [objects]
|
||||
tool = obj.getTool()
|
||||
for i in range(len(objects)):
|
||||
if isinstance(objects[i], basestring):
|
||||
# We have a UID here
|
||||
objects[i] = tool.getObject(objects[i])
|
||||
else:
|
||||
# Be sure to have a Zope object
|
||||
objects[i] = objects[i].o
|
||||
uids = [o.UID() for o in objects]
|
||||
# Unlink objects that are not referred anymore
|
||||
refs = getattr(obj, self.name, None)
|
||||
if refs == None:
|
||||
refs = obj.getProductConfig().PersistentList(uids)
|
||||
setattr(obj, self.name, refs)
|
||||
else:
|
||||
# Empty the list and fill it with uids
|
||||
del refs[:]
|
||||
for uid in uids: refs.append(uid)
|
||||
if refs:
|
||||
i = len(refs)-1
|
||||
while i >= 0:
|
||||
if refs[i] not in uids:
|
||||
# Object having this UID must unlink p_obj
|
||||
self.back.unlinkObject(tool.getObject(refs[i]), obj)
|
||||
i -= 1
|
||||
# Link new objects
|
||||
self.linkObject(obj, objects)
|
||||
|
||||
def clone(self, forTool=True):
|
||||
'''Produces a clone of myself.'''
|
||||
|
|
|
@ -84,7 +84,7 @@ class BaseMixin:
|
|||
for field in self.getAllAppyTypes():
|
||||
if field.type != 'Ref': continue
|
||||
for obj in field.getValue(self):
|
||||
obj.unlink(field.back.name, self, back=True)
|
||||
field.back.unlinkObject(obj, self, back=True)
|
||||
# Delete the object
|
||||
self.getParentNode().manage_delObjects([self.id])
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@ p { margin: 0;}
|
|||
acronym {cursor: help;}
|
||||
input[type=image] { border: 0; background: none; }
|
||||
input[type=checkbox] { border: 0; background: none; cursor: pointer;}
|
||||
input[type=radio] { border: 0; background: none; cursor: pointer;}
|
||||
input[type=button] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
||||
cursor: pointer;}
|
||||
cursor: pointer;}
|
||||
input[type=submit] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
||||
cursor: pointer; }
|
||||
input[type=password] { border: 1px solid #cccccc; background-color: #f8f8f8;}
|
||||
input[type=text] { border: 1px solid #cccccc; background-color: #f8f8f8;
|
||||
font-family: Lucida,Helvetica,Arial,sans-serif;
|
||||
margin-bottom: 1px}
|
||||
|
@ -48,8 +50,8 @@ img {border: 0;}
|
|||
.phase { border-style: dashed; border-width: thin; padding: 0 0.6em 0 1em; }
|
||||
.content { padding: 14px 3px 9px 15px;}
|
||||
.grey { display: none; position: absolute; left: 0px; top: 0px;
|
||||
width:100%; height:100%; background:grey; opacity:0.5;
|
||||
-moz-opacity:0.5; -khtml-opacity:0.5; filter:alpha(Opacity=50);}
|
||||
background:grey; opacity:0.5; -moz-opacity:0.5; -khtml-opacity:0.5;
|
||||
filter:alpha(Opacity=50);}
|
||||
.popup { display: none; position: absolute; top: 30%; left: 35%;
|
||||
width: 350px; z-index : 100; background: white; padding: 8px;
|
||||
border: 1px solid grey; }
|
||||
|
|
|
@ -248,7 +248,11 @@ function getSlaves(master) {
|
|||
// Gets all the slaves of master.
|
||||
allSlaves = document.getElementsByName('slave');
|
||||
res = [];
|
||||
slavePrefix = 'slave_' + master.attributes['name'].value + '_';
|
||||
masterName = master.attributes['name'].value;
|
||||
if (master.type == 'checkbox') {
|
||||
masterName = masterName.substr(0, masterName.length-8);
|
||||
}
|
||||
slavePrefix = 'slave_' + masterName + '_';
|
||||
for (var i=0; i < slaves.length; i++){
|
||||
cssClasses = slaves[i].className.split(' ');
|
||||
for (var j=0; j < cssClasses.length; j++) {
|
||||
|
@ -381,13 +385,15 @@ function openPopup(popupId, msg) {
|
|||
// Open the popup
|
||||
var popup = document.getElementById(popupId);
|
||||
// Put it at the right place on the screen
|
||||
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || 0;
|
||||
var scrollTop = document.body.scrollTop || window.pageYOffset || 0;
|
||||
popup.style.top = (scrollTop + 150) + 'px';
|
||||
popup.style.display = "block";
|
||||
// Show the greyed zone
|
||||
var greyed = document.getElementById('grey');
|
||||
greyed.style.top = scrollTop + 'px';
|
||||
greyed.style.display = "block";
|
||||
greyed.style.height = document.body.clientHeight;
|
||||
greyed.style.width = document.body.clientWidth;
|
||||
}
|
||||
|
||||
function closePopup(popupId) {
|
||||
|
|
|
@ -75,7 +75,7 @@
|
|||
</form>
|
||||
|
||||
<h1 tal:content="python: tool.translate('import_title')"></h1><br/>
|
||||
<table cellpadding="0" cellspacing="0" class="listing nosort" width="100%">
|
||||
<table class="list" width="100%">
|
||||
<tr>
|
||||
<th tal:repeat="columnHeader python: importElems[0]">
|
||||
<img tal:condition="python: repeat['columnHeader'].number() == 1"
|
||||
|
@ -107,7 +107,7 @@
|
|||
<span tal:condition="alreadyImported" tal:replace="python: tool.translate('import_already')"/>
|
||||
</td>
|
||||
<td align="center">
|
||||
<input type="checkbox" checked="checked" class="noborder" id="cbElem" name="cbElem"
|
||||
<input type="checkbox" checked="checked" id="cbElem" name="cbElem"
|
||||
tal:attributes="value python: row[0]" tal:condition="not: alreadyImported"/>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
|
@ -7,11 +7,10 @@
|
|||
<tal:comment replace="nothing">Edit macro for an Boolean.</tal:comment>
|
||||
<metal:edit define-macro="edit">
|
||||
<input type="checkbox"
|
||||
tal:attributes="name python: name + '_visible';
|
||||
id name;
|
||||
tal:attributes="name python: name + '_visible'; id name;
|
||||
checked python:contextObj.checkboxChecked(name, rawValue);
|
||||
onClick python:'toggleCheckbox(\'%s\', \'%s_hidden\');;updateSlaves(this)' % (name, name);
|
||||
class python: 'noborder %s' % masterCss"/>
|
||||
class masterCss"/>
|
||||
<input tal:attributes="name name;
|
||||
id string:${name}_hidden;
|
||||
value python: test(contextObj.checkboxChecked(name, rawValue), 'True', 'False')"
|
||||
|
@ -28,15 +27,15 @@
|
|||
tal:define="typedWidget python:'%s*bool' % widgetName">
|
||||
<label tal:attributes="for widgetName" tal:content="python: tool.translate(widget['labelId'])"></label><br>
|
||||
<tal:yes define="valueId python:'%s_yes' % name">
|
||||
<input type="radio" class="noborder" value="True" tal:attributes="name typedWidget; id valueId"/>
|
||||
<input type="radio" value="True" tal:attributes="name typedWidget; id valueId"/>
|
||||
<label tal:attributes="for valueId" i18n:translate="yes" i18n:domain="plone"></label>
|
||||
</tal:yes>
|
||||
<tal:no define="valueId python:'%s_no' % name">
|
||||
<input type="radio" class="noborder" value="False" tal:attributes="name typedWidget; id valueId"/>
|
||||
<input type="radio" value="False" tal:attributes="name typedWidget; id valueId"/>
|
||||
<label tal:attributes="for valueId" i18n:translate="no" i18n:domain="plone"></label>
|
||||
</tal:no>
|
||||
<tal:whatever define="valueId python:'%s_whatever' % name">
|
||||
<input type="radio" class="noborder" value="" tal:attributes="name typedWidget; id valueId" checked="checked"/>
|
||||
<input type="radio" value="" tal:attributes="name typedWidget; id valueId" checked="checked"/>
|
||||
<label tal:attributes="for valueId" tal:content="python: tool.translate('whatever')"></label>
|
||||
</tal:whatever><br/>
|
||||
</metal:search>
|
||||
|
|
|
@ -81,7 +81,7 @@
|
|||
<metal:search define-macro="search"
|
||||
tal:define="years python:range(widget['startYear'], widget['endYear']+1)">
|
||||
<label tal:content="python: tool.translate(widget['labelId'])"></label>
|
||||
<table cellpadding="0" cellspacing="0">
|
||||
<table>
|
||||
<tal:comment replace="nothing">From</tal:comment>
|
||||
<tr tal:define="yearFromName python: '%s*date' % widgetName;
|
||||
monthFromName python: '%s_from_month' % name;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</tal:showFile>
|
||||
<tal:editButtons condition="python: value and value.size">
|
||||
<tal:comment replace="nothing">Keep the file untouched.</tal:comment>
|
||||
<input class="noborder" type="radio" value="nochange"
|
||||
<input type="radio" value="nochange"
|
||||
tal:attributes="checked python:test(value.size!=0, 'checked', None);
|
||||
name string:${name}_delete;
|
||||
id string:${name}_nochange;
|
||||
|
@ -33,7 +33,7 @@
|
|||
<br/>
|
||||
<tal:comment replace="nothing">Delete the file.</tal:comment>
|
||||
<tal:delete condition="not: widget/required">
|
||||
<input class="noborder" type="radio" value="delete"
|
||||
<input type="radio" value="delete"
|
||||
tal:attributes="name string:${name}_delete;
|
||||
id string:${name}_delete;
|
||||
onclick string:document.getElementById('${name}_file').disabled=true;"/>
|
||||
|
@ -42,7 +42,7 @@
|
|||
<br/>
|
||||
</tal:delete>
|
||||
<tal:comment replace="nothing">Replace with a new file.</tal:comment>
|
||||
<input class="noborder" type="radio" value=""
|
||||
<input type="radio" value=""
|
||||
tal:attributes="checked python:test(value.size==0, 'checked', None);
|
||||
name string:${name}_delete;
|
||||
id string:${name}_upload;
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
id slaveId; name slaveId">
|
||||
<tal:comment replace="nothing">First row: the tabs.</tal:comment>
|
||||
<tr valign="middle"><td style="border-bottom: 1px solid #ff8040">
|
||||
<table cellpadding="0" cellspacing="0" style="position:relative; bottom:-1px;">
|
||||
<table style="position:relative; bottom:-1px;">
|
||||
<tr valign="middle">
|
||||
<tal:tab repeat="widgetRow widget/widgets">
|
||||
<tal:id define="tabId python:'tab_%s_%d_%d' % (widget['name'], repeat['widgetRow'].number(), len(widget['widgets']))">
|
||||
|
|
|
@ -90,9 +90,9 @@
|
|||
orName python: '%s_or' % operName;
|
||||
andName python: '%s_and' % operName;"
|
||||
condition="python: widget['multiplicity'][1]!=1">
|
||||
<input type="radio" class="noborder" tal:attributes="name operName; id orName" checked="checked" value="or"/>
|
||||
<input type="radio" tal:attributes="name operName; id orName" checked="checked" value="or"/>
|
||||
<label tal:attributes="for orName" tal:content="python: tool.translate('search_or')"></label>
|
||||
<input type="radio" class="noborder" tal:attributes="name operName; id andName" value="and"/>
|
||||
<input type="radio" tal:attributes="name operName; id andName" value="and"/>
|
||||
<label tal:attributes="for andName" tal:content="python: tool.translate('search_and')"></label><br/>
|
||||
</tal:operator>
|
||||
<tal:comment replace="nothing">The list of values</tal:comment>
|
||||
|
|
|
@ -86,53 +86,15 @@ class AbstractWrapper(object):
|
|||
|
||||
def getField(self, name): return self.o.getAppyType(name)
|
||||
|
||||
def link(self, fieldName, obj, back=False):
|
||||
def link(self, fieldName, obj):
|
||||
'''This method links p_obj (which can be a list of objects) to this one
|
||||
through reference field p_fieldName. As this method is recursive and
|
||||
can be called to update the corresponding back reference, param
|
||||
p_back is there, but, you, as Appy developer, should never set it
|
||||
to True.'''
|
||||
# p_objs can be a list of objects
|
||||
if type(obj) in sequenceTypes:
|
||||
for o in obj: self.link(fieldName, o, back=back)
|
||||
return
|
||||
# Gets the list of referred objects (=list of uids), or create it.
|
||||
selfO = self.o
|
||||
refs = getattr(selfO, fieldName, None)
|
||||
if refs == None:
|
||||
refs = selfO.getProductConfig().PersistentList()
|
||||
setattr(selfO, fieldName, refs)
|
||||
# Insert p_obj into it.
|
||||
uid = obj.o.UID()
|
||||
if uid not in refs:
|
||||
refs.append(uid)
|
||||
# Update the back reference
|
||||
if not back:
|
||||
backName = selfO.getAppyType(fieldName).back.attribute
|
||||
obj.appy().link(backName, self, back=True)
|
||||
through reference field p_fieldName.'''
|
||||
return self.getField(fieldName).linkObject(self.o, obj)
|
||||
|
||||
def unlink(self, fieldName, obj, back=False):
|
||||
def unlink(self, fieldName, obj):
|
||||
'''This method unlinks p_obj (which can be a list of objects) from this
|
||||
one through reference field p_fieldName. As this method is recursive
|
||||
and can be called to update the corresponding back reference, param
|
||||
p_back is there, but, you, as Appy developer, should never set it
|
||||
to True.'''
|
||||
# p_objs can be a list of objects
|
||||
if type(obj) in sequenceTypes:
|
||||
for o in obj: self.unlink(fieldName, o, back=back)
|
||||
return
|
||||
# Get the list of referred objects
|
||||
selfO = self.o
|
||||
refs = getattr(selfO, fieldName, None)
|
||||
if not refs: return
|
||||
# Unlink the object
|
||||
uid = obj.o.UID()
|
||||
if uid in refs:
|
||||
refs.remove(uid)
|
||||
# Update the back reference
|
||||
if not back:
|
||||
backName = selfO.getAppyType(fieldName).back.attribute
|
||||
obj.appy().unlink(backName, self, back=True)
|
||||
one through reference field p_fieldName.'''
|
||||
return self.getField(fieldName).unlinkObject(self.o, obj)
|
||||
|
||||
def sort(self, fieldName, sortKey='title', reverse=False):
|
||||
'''Sorts referred elements linked to p_self via p_fieldName according
|
||||
|
@ -194,8 +156,7 @@ class AbstractWrapper(object):
|
|||
setattr(appyObj, attrName, attrValue)
|
||||
if isField:
|
||||
# Link the object to this one
|
||||
self.link(fieldName, ploneObj)
|
||||
self.o.reindexObject()
|
||||
appyType.linkObject(self.o, ploneObj)
|
||||
# Call custom initialization
|
||||
if externalData: param = externalData
|
||||
else: param = True
|
||||
|
|
Loading…
Reference in a new issue