appy.gen: reimplemented master/slave-related Javascript code without Plone queryCss.

This commit is contained in:
Gaetan Delannay 2011-10-01 22:40:13 +02:00
parent c9353b46db
commit e821307b4c
14 changed files with 172 additions and 158 deletions

View file

@ -22,6 +22,13 @@ validatorTypes = (types.FunctionType, types.UnboundMethodType,
emptyTuple = () emptyTuple = ()
labelTypes = ('label', 'descr', 'help') labelTypes = ('label', 'descr', 'help')
def initMasterValue(v):
'''Standardizes p_v as a list.'''
if not v: res = []
elif type(v) not in sequenceTypes: res = [v]
else: res = v
return res
# Descriptor classes used for refining descriptions of elements in types # Descriptor classes used for refining descriptions of elements in types
# (pages, groups,...) ---------------------------------------------------------- # (pages, groups,...) ----------------------------------------------------------
class Page: class Page:
@ -153,26 +160,10 @@ class Group:
# Header labels will be used as labels for the tabs. # Header labels will be used as labels for the tabs.
self.hasHeaders = True self.hasHeaders = True
self.css_class = css_class self.css_class = css_class
self.master = None
self.masterValue = None
if master:
self._addMaster(master, masterValue)
self.label = label # See similar attr of Type class.
def _addMaster(self, master, masterValue):
'''Specifies this group being a slave of another field: we will add css
classes allowing to show/hide, in Javascript, its widget according
to master value.'''
self.master = master self.master = master
self.masterValue = masterValue self.masterValue = initMasterValue(masterValue)
classes = 'slave_%s' % self.master.id if master: master.slaves.append(self)
if type(self.masterValue) not in sequenceTypes: self.label = label # See similar attr of Type class.
masterValues = [self.masterValue]
else:
masterValues = self.masterValue
for masterValue in masterValues:
classes += ' slaveValue_%s_%s' % (self.master.id, masterValue)
self.css_class += ' ' + classes
def _setColumns(self): def _setColumns(self):
'''Standardizes field "columns" as a list of Column instances. Indeed, '''Standardizes field "columns" as a list of Column instances. Indeed,
@ -440,17 +431,14 @@ class Type:
# If the widget is in a group with multiple columns, the following # If the widget is in a group with multiple columns, the following
# attribute specifies on how many columns to span the widget. # attribute specifies on how many columns to span the widget.
self.colspan = colspan self.colspan = colspan
# The list of slaves of this field, if it is a master
self.slaves = []
# The behaviour of this field may depend on another, "master" field # The behaviour of this field may depend on another, "master" field
self.master = master self.master = master
self.slaves = [] # The list of slaves of this field, if it is a master
# Every HTML input field corresponding to a master must get some
# CSS classes for controlling its slaves.
self.master_css = ''
if master: if master:
self.master.slaves.append(self) self.master.slaves.append(self)
self.master.master_css = 'appyMaster master_%s' % self.master.id
# When master has some value(s), there is impact on this field. # When master has some value(s), there is impact on this field.
self.masterValue = masterValue self.masterValue = initMasterValue(masterValue)
# If a field must retain attention in a particular way, set focus=True. # If a field must retain attention in a particular way, set focus=True.
# It will be rendered in a special way. # It will be rendered in a special way.
self.focus = focus self.focus = focus
@ -494,7 +482,8 @@ class Type:
# Recompute the ID (and derived attributes) that may have changed if # Recompute the ID (and derived attributes) that may have changed if
# we are in debug mode (because we recreate new Type instances). # we are in debug mode (because we recreate new Type instances).
self.id = id(self) self.id = id(self)
if self.slaves: self.master_css = 'appyMaster master_%s' % self.id # Remember master name on every slave
for slave in self.slaves: slave.masterName = name
# Determine ids of i18n labels for this field # Determine ids of i18n labels for this field
labelName = name labelName = name
trPrefix = None trPrefix = None
@ -591,13 +580,10 @@ class Type:
master, masterValue = masterData master, masterValue = masterData
reqValue = master.getRequestValue(obj.REQUEST) reqValue = master.getRequestValue(obj.REQUEST)
reqValue = master.getStorableValue(reqValue) reqValue = master.getStorableValue(reqValue)
# Manage the fact that values can be lists or single values # reqValue can be a list or not
multiMaster = type(masterValue) in sequenceTypes if type(reqValue) not in sequenceTypes:
multiReq = type(reqValue) in sequenceTypes return reqValue in masterValue
if not multiMaster and not multiReq: return reqValue == masterValue else:
elif multiMaster and not multiReq: return reqValue in masterValue
elif not multiMaster and multiReq: return masterValue in reqValue
else: # multiMaster and multiReq
for m in masterValue: for m in masterValue:
for r in reqValue: for r in reqValue:
if m == r: return True if m == r: return True
@ -674,19 +660,6 @@ class Type:
layouts['cell'] = Table(other=layouts['view'], derivedType='cell') layouts['cell'] = Table(other=layouts['view'], derivedType='cell')
# Put the required CSS classes in the layouts # Put the required CSS classes in the layouts
layouts['cell'].addCssClasses('noStyle') layouts['cell'].addCssClasses('noStyle')
if self.master:
# This type has a master (so is a slave): we add css classes
# allowing to show/hide, in Javascript, its widget according to
# master value.
classes = 'slave_%s' % self.master.id
if type(self.masterValue) not in sequenceTypes:
masterValues = [self.masterValue]
else:
masterValues = self.masterValue
for masterValue in masterValues:
classes += ' slaveValue_%s_%s' % (self.master.id, masterValue)
layouts['view'].addCssClasses(classes)
layouts['edit'].addCssClasses(classes)
if self.focus: if self.focus:
# We need to make it flashy # We need to make it flashy
layouts['view'].addCssClasses('appyFocus') layouts['view'].addCssClasses('appyFocus')

View file

@ -1,5 +1,5 @@
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
import re, os, os.path, time, Cookie, types import re, os, os.path, time, types
from appy.shared import mimeTypes from appy.shared import mimeTypes
from appy.shared.utils import getOsTempFolder from appy.shared.utils import getOsTempFolder
import appy.gen import appy.gen
@ -84,7 +84,6 @@ class ToolMixin(BaseMixin):
'''Returns the (translated) names of fields of p_contentType.''' '''Returns the (translated) names of fields of p_contentType.'''
res = [] res = []
for appyType in self.getAllAppyTypes(className=contentType): for appyType in self.getAllAppyTypes(className=contentType):
if appyType.name == 'title': continue # Will be included by default.
res.append((appyType.name, self.translate(appyType.labelId))) res.append((appyType.name, self.translate(appyType.labelId)))
# Add object state # Add object state
res.append(('state', self.translate('workflow_state'))) res.append(('state', self.translate('workflow_state')))
@ -611,13 +610,6 @@ class ToolMixin(BaseMixin):
res.append(dSearch) res.append(dSearch)
return res return res
def getCookieValue(self, cookieId, default=''):
'''Server-side code for getting the value of a cookie entry.'''
cookie = Cookie.SimpleCookie(self.REQUEST['HTTP_COOKIE'])
cookieValue = cookie.get(cookieId)
if cookieValue: return cookieValue.value
return default
def getQueryUrl(self, contentType, searchName, startNumber=None): def getQueryUrl(self, contentType, searchName, startNumber=None):
'''This method creates the URL that allows to perform a (non-Ajax) '''This method creates the URL that allows to perform a (non-Ajax)
request for getting queried objects from a search named p_searchName request for getting queried objects from a search named p_searchName

View file

@ -14,9 +14,9 @@ class Protos:
protos = {} protos = {}
# List of attributes that can't be given to a Type constructor # List of attributes that can't be given to a Type constructor
notInit = ('id', 'type', 'pythonType', 'slaves', 'isSelect', 'hasLabel', notInit = ('id', 'type', 'pythonType', 'slaves', 'isSelect', 'hasLabel',
'hasDescr', 'hasHelp', 'master_css', 'required', 'filterable', 'hasDescr', 'hasHelp', 'required', 'filterable', 'validable',
'validable', 'backd', 'isBack', 'sync', 'pageName', 'backd', 'isBack', 'sync', 'pageName', 'shownInfoWidths',
'shownInfoWidths') 'masterName')
@classmethod @classmethod
def get(self, appyType): def get(self, appyType):
'''Returns a prototype instance for p_appyType.''' '''Returns a prototype instance for p_appyType.'''

View file

@ -8,18 +8,26 @@ table { font-size: 100%; border-spacing: 0px; border-collapse:collapse;}
form { margin: 0; padding: 0;} form { margin: 0; padding: 0;}
p { margin: 0;} p { margin: 0;}
acronym {cursor: help;} acronym {cursor: help;}
input { border: 1px solid #cccccc; background-color: #f8f8f8; input[type=image] { border: 0; background: none; }
font-family: Lucida,Helvetica,Arial,sans-serif; margin-bottom: 1px} input[type=checkbox] { border: 0; background: none; cursor: pointer;}
input[type=image] { border-width: 0px; background: none; } input[type=button] { border: 1px solid #cccccc; background-color: #f8f8f8;
input[type=button] { cursor: pointer; } cursor: pointer;}
input[type=submit] { border: 1px solid #cccccc; background-color: #f8f8f8;
cursor: pointer; }
input[type=text] { border: 1px solid #cccccc; background-color: #f8f8f8;
font-family: Lucida,Helvetica,Arial,sans-serif;
margin-bottom: 1px}
select { border: 1px solid #cccccc; background-color: #f8f8f8;}
textarea { width: 99%; font: 100% Lucida,Helvetica,Arial,sans-serif; textarea { width: 99%; font: 100% Lucida,Helvetica,Arial,sans-serif;
border: 1px solid #a79e9e; background-color: #f8f8f8;} border: 1px solid #a79e9e; background-color: #f8f8f8;}
label { font-weight: 600; font-style: italic; line-height: 1.4em;} label { font-weight: 600; font-style: italic; line-height: 1.4em;}
legend { padding-bottom: 2px; padding-right: 3px;} legend { padding-bottom: 2px; padding-right: 3px; color: black;}
ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0; ul { line-height: 1.2em; margin: 0 0 0.2em 0.6em; padding: 0;
list-style: none outside none;} list-style: none outside none;}
li { margin: 0; background-image: url("skyn/li.gif"); padding-left: 10px; li { margin: 0; background-image: url("skyn/li.gif"); padding-left: 10px;
background-repeat: no-repeat; background-position: 0 4px;} background-repeat: no-repeat; background-position: 0 4px;}
img {border: 0;}
.main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9; .main { width: 900px; background-color: white; box-shadow: 3px 3px 3px #A9A9A9;
border-style: solid; border-width: 1px; border-color: grey; } border-style: solid; border-width: 1px; border-color: grey; }

View file

@ -177,7 +177,7 @@ function askRefField(hookId, objectUrl, fieldName, innerRef, startNumber,
action, actionParams){ action, actionParams){
// Sends an Ajax request for getting the content of a reference field. // Sends an Ajax request for getting the content of a reference field.
var startKey = hookId + '_startNumber'; var startKey = hookId + '_startNumber';
var params = {'fieldName': fieldName, 'innerRef': innerRef, }; var params = {'fieldName': fieldName, 'innerRef': innerRef };
params[startKey] = startNumber; params[startKey] = startNumber;
if (action) params['action'] = action; if (action) params['action'] = action;
if (actionParams) { if (actionParams) {
@ -201,70 +201,94 @@ function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
} }
// Functions used for master/slave relationships between widgets // Functions used for master/slave relationships between widgets
function getMasterValue(widget) { function getSlaveInfo(slave, infoType) {
// Returns an array of selected options in a select widget // Returns the appropriate info about slavery, depending on p_infoType.
res = new Array(); cssClasses = slave.className.split(' ');
if (widget.type == 'checkbox') { // Find the CSS class containing master-related info.
var mv = widget.checked + ''; for (var j=0; j < cssClasses.length; j++) {
mv = mv.charAt(0).toUpperCase() + mv.substr(1); if (cssClasses[j].indexOf('slave_') == 0) {
res.push(mv); // Extract, from this CSS class, master name or master values.
masterInfo = cssClasses[j].split('_');
if (infoType == 'masterName') return masterInfo[1];
else return masterInfo.slice(2); // Master values
}
}
}
function getMasterValues(master) {
// Returns the list of values that p_master currently has.
if (master.tagName == 'SPAN') {
res = master.attributes['value'].value;
if ((res[0] == '(') || (res[0] == '[')) {
// There are multiple values, split it
values = res.substring(1, res.length-1).split(',');
res = [];
for (var i=0; i < values.length; i++){
v = values[i].replace(' ', '');
res.push(v.substring(1, v.length-1));
}
}
else res = [res]; // A single value
}
else if (master.type == 'checkbox') {
res = master.checked + '';
res = res.charAt(0).toUpperCase() + res.substr(1);
res = [res];
} }
else { // SELECT widget else { // SELECT widget
for (var i=0; i < widget.options.length; i++) { res = [];
if (widget.options[i].selected) res.push(widget.options[i].value); for (var i=0; i < master.options.length; i++) {
if (master.options[i].selected) res.push(master.options[i].value);
} }
} }
return res; return res;
} }
function updateSlaves(masterValues, appyTypeId) { function getSlaves(master) {
// Given the value(s) selected in a master field, this function updates the // Gets all the slaves of master.
// state of all corresponding slaves. allSlaves = document.getElementsByName('slave');
var slaves = cssQuery('table.slave_' + appyTypeId); res = [];
slavePrefix = 'slave_' + master.attributes['name'].value + '_';
for (var i=0; i < slaves.length; i++){ for (var i=0; i < slaves.length; i++){
slaves[i].style.display = "none"; cssClasses = slaves[i].className.split(' ');
for (var j=0; j < cssClasses.length; j++) {
if (cssClasses[j].indexOf(slavePrefix) == 0) {
res.push(slaves[i]);
break;
} }
for (var i=0; i < masterValues.length; i++) {
var activeSlaves = cssQuery('table.slaveValue_' + appyTypeId + '_' + masterValues[i]);
for (var j=0; j < activeSlaves.length; j++){
activeSlaves[j].style.display = "";
} }
} }
return res;
}
function updateSlaves(master) {
// Given the value(s) in a master field, we must update slave's visibility.
slaves = getSlaves(master);
masterValues = getMasterValues(master);
for (var i=0; i < slaves.length; i++) {
showSlave = false;
slaveryValues = getSlaveInfo(slaves[i], 'masterValues');
for (var j=0; j < slaveryValues.length; j++) {
for (var k=0; k< masterValues.length; k++) {
if (slaveryValues[j] == masterValues[k]) showSlave = true;
}
}
if (showSlave) slaves[i].style.display = "";
else slaves[i].style.display = "none";
}
} }
function initSlaves() { function initSlaves() {
// When the current page is loaded, we must set the correct state for all // When the current page is loaded, we must set the correct state for all
// slave fields. // slave fields.
var masters = cssQuery('.appyMaster'); slaves = document.getElementsByName('slave');
for (var i=0; i < masters.length; i++) { walkedMasters = {}; // Remember the already walked masters.
var cssClasses = masters[i].className.split(' '); for (var i=0; i < slaves.length; i++) {
for (var j=0; j < cssClasses.length; j++) { masterName = getSlaveInfo(slaves[i], 'masterName');
if (cssClasses[j].indexOf('master_') == 0) { if (masterName in walkedMasters) continue;
var appyId = cssClasses[j].split('_')[1]; master = document.getElementById(masterName);
var masterValue = []; updateSlaves(master);
if (masters[i].nodeName == 'SPAN'){ walkedMasters[masterName] = 'walked';
var idField = masters[i].id;
if (idField == '') {
masterValue.push(idField);
}
else {
if ((idField[0] == '(') || (idField[0] == '[')) {
// There are multiple values, split it
var subValues = idField.substring(1, idField.length-1).split(',');
for (var k=0; k < subValues.length; k++){
var subValue = subValues[k].replace(' ','');
masterValue.push(subValue.substring(1, subValue.length-1));
}
}
else { masterValue.push(masters[i].id);
}
}
}
else { masterValue = getMasterValue(masters[i]);
}
updateSlaves(masterValue, appyId);
}
}
} }
} }

View file

@ -24,7 +24,7 @@
<!-- <!--
var importedElemsShown = false; var importedElemsShown = false;
function toggleViewableElements() { function toggleViewableElements() {
var rows = cssQuery('#importedElem'); var rows = document.getElementsByName('importedElem');
var newDisplay = 'table-row'; var newDisplay = 'table-row';
if (isIe) newDisplay = 'block'; if (isIe) newDisplay = 'block';
if (importedElemsShown) newDisplay = 'none'; if (importedElemsShown) newDisplay = 'none';
@ -33,10 +33,9 @@
} }
importedElemsShown = !importedElemsShown; importedElemsShown = !importedElemsShown;
} }
var checkBoxesChecked = true; var checkBoxesChecked = true;
function toggleCheckboxes() { function toggleCheckboxes() {
var checkBoxes = cssQuery('#cbElem'); var checkBoxes = document.getElementsByName('cbElem');
var newCheckValue = true; var newCheckValue = true;
if (checkBoxesChecked) newCheckValue = false; if (checkBoxesChecked) newCheckValue = false;
for (var i=0; i<checkBoxes.length; i++) { for (var i=0; i<checkBoxes.length; i++) {
@ -44,18 +43,16 @@
} }
checkBoxesChecked = newCheckValue; checkBoxesChecked = newCheckValue;
} }
function importSingleElement(importPath) { function importSingleElement(importPath) {
var f = document.forms['importElements']; var f = document.forms['importElements'];
f.importPath.value = importPath; f.importPath.value = importPath;
f.submit(); f.submit();
} }
function importManyElements() { function importManyElements() {
var f = document.forms['importElements']; var f = document.forms['importElements'];
var importPaths = ''; var importPaths = '';
// Get the values of the checkboxes // Get the values of the checkboxes
var checkBoxes = cssQuery('#cbElem'); var checkBoxes = document.getElementsByName('cbElem');
for (var i=0; i<checkBoxes.length; i++) { for (var i=0; i<checkBoxes.length; i++) {
if (checkBoxes[i].checked) { if (checkBoxes[i].checked) {
importPaths += checkBoxes[i].value + '|'; importPaths += checkBoxes[i].value + '|';
@ -67,7 +64,6 @@
f.submit(); f.submit();
} }
} }
--> -->
</script> </script>
<tal:comment replace="nothing">Form for importing several meetings at once.</tal:comment> <tal:comment replace="nothing">Form for importing several meetings at once.</tal:comment>
@ -98,9 +94,10 @@
<tr tal:define="alreadyImported python: tool.isAlreadyImported(contentType, row[0]); <tr tal:define="alreadyImported python: tool.isAlreadyImported(contentType, row[0]);
global allAreImported python: allAreImported and alreadyImported; global allAreImported python: allAreImported and alreadyImported;
odd repeat/row/odd" odd repeat/row/odd"
tal:attributes="id python:test(alreadyImported, 'importedElem', 'notImportedElem'); tal:attributes="id python: alreadyImported and 'importedElem' or 'notImportedElem';
style python:test(alreadyImported, 'display:none', 'display:table-row'); name python: alreadyImported and 'importedElem' or 'notImportedElem';
class python:test(odd, 'even', 'odd')"> style python: alreadyImported and 'display:none' or 'display:table-row';
class python: odd and 'even' or 'odd'">
<td tal:repeat="elem python: row[1:]" tal:content="elem"> <td tal:repeat="elem python: row[1:]" tal:content="elem">
</td> </td>
<td> <td>
@ -109,8 +106,10 @@
value python: tool.translate('query_import')"/> value python: tool.translate('query_import')"/>
<span tal:condition="alreadyImported" tal:replace="python: tool.translate('import_already')"/> <span tal:condition="alreadyImported" tal:replace="python: tool.translate('import_already')"/>
</td> </td>
<td align="center"><input type="checkbox" checked="checked" class="noborder" id="cbElem" <td align="center">
tal:attributes="value python: row[0]" tal:condition="not: alreadyImported"/></td> <input type="checkbox" checked="checked" class="noborder" id="cbElem" name="cbElem"
tal:attributes="value python: row[0]" tal:condition="not: alreadyImported"/>
</td>
</tr> </tr>
</tal:row> </tal:row>
<tr tal:condition="python: not importElems[1] or allAreImported"><td colspan="15" tal:content="python: tool.translate('query_no_result')"></td></tr> <tr tal:condition="python: not importElems[1] or allAreImported"><td colspan="15" tal:content="python: tool.translate('query_no_result')"></td></tr>

View file

@ -187,7 +187,7 @@
tal:define="showWorkflow python: tool.getAttr('showWorkflowFor' + contextObj.meta_type); tal:define="showWorkflow python: tool.getAttr('showWorkflowFor' + contextObj.meta_type);
hasHistory contextObj/hasHistory; hasHistory contextObj/hasHistory;
historyMaxPerPage options/maxPerPage|python: 5; historyMaxPerPage options/maxPerPage|python: 5;
historyExpanded python: tool.getCookieValue('appyHistory', default='collapsed') == 'expanded'; historyExpanded python: request.get('appyHistory', 'collapsed') == 'expanded';
creator contextObj/Creator" creator contextObj/Creator"
tal:condition="not: contextObj/isTemporary"> tal:condition="not: contextObj/isTemporary">

View file

@ -56,7 +56,7 @@
<tal:searchOrGroup repeat="searchOrGroup python: tool.getSearches(rootClass)"> <tal:searchOrGroup repeat="searchOrGroup python: tool.getSearches(rootClass)">
<tal:group condition="searchOrGroup/isGroup"> <tal:group condition="searchOrGroup/isGroup">
<tal:expanded define="group searchOrGroup; <tal:expanded define="group searchOrGroup;
expanded python: tool.getCookieValue(group['labelId'], default='collapsed') == 'expanded'"> expanded python: request.get(group['labelId'], 'collapsed') == 'expanded'">
<tal:comment replace="nothing">Group name</tal:comment> <tal:comment replace="nothing">Group name</tal:comment>
<dt class="portletAppyItem portletGroup"> <dt class="portletAppyItem portletGroup">
<img align="left" style="cursor:pointer" <img align="left" style="cursor:pointer"

View file

@ -8,7 +8,7 @@
<tal:comment replace="nothing">Query result</tal:comment> <tal:comment replace="nothing">Query result</tal:comment>
<div id="queryResult"></div> <div id="queryResult"></div>
<script language="javascript" <script type="text/javascript"
tal:define="ajaxUrl python: tool.getQueryUrl(contentType, searchName)" tal:define="ajaxUrl python: tool.getQueryUrl(contentType, searchName)"
tal:content="python: 'askQueryResult(\'queryResult\', \'%s\',\'%s\',\'%s\',0)' % (tool.absolute_url(), contentType, searchName)"> tal:content="python: 'askQueryResult(\'queryResult\', \'%s\',\'%s\',\'%s\',0)' % (tool.absolute_url(), contentType, searchName)">
</script> </script>

View file

@ -1,6 +1,7 @@
<tal:comment replace="nothing">View macro for a Boolean.</tal:comment> <tal:comment replace="nothing">View macro for a Boolean.</tal:comment>
<metal:view define-macro="view"> <metal:view define-macro="view">
<span tal:attributes="class widget/master_css; id rawValue" tal:content="value"></span> <span tal:attributes="class masterCss; value rawValue; name name; id name"
tal:content="value"></span>
</metal:view> </metal:view>
<tal:comment replace="nothing">Edit macro for an Boolean.</tal:comment> <tal:comment replace="nothing">Edit macro for an Boolean.</tal:comment>
@ -9,8 +10,8 @@
tal:attributes="name python: name + '_visible'; tal:attributes="name python: name + '_visible';
id name; id name;
checked python:contextObj.checkboxChecked(name, rawValue); checked python:contextObj.checkboxChecked(name, rawValue);
onClick python:'toggleCheckbox(\'%s\', \'%s_hidden\');;updateSlaves(getMasterValue(this), \'%s\')' % (name, name, widget['id']); onClick python:'toggleCheckbox(\'%s\', \'%s_hidden\');;updateSlaves(this)' % (name, name);
class python: 'noborder ' + widget['master_css']"/> class python: 'noborder %s' % masterCss"/>
<input tal:attributes="name name; <input tal:attributes="name name;
id string:${name}_hidden; id string:${name}_hidden;
value python: test(contextObj.checkboxChecked(name, rawValue), 'True', 'False')" value python: test(contextObj.checkboxChecked(name, rawValue), 'True', 'False')"

View file

@ -1,7 +1,7 @@
<tal:comment replace="nothing">View macro for a Float.</tal:comment> <tal:comment replace="nothing">View macro for a Float.</tal:comment>
<metal:view define-macro="view"> <metal:view define-macro="view">
<span tal:content="value" <span tal:content="value"
tal:attributes="id value; class widget/master_css"></span> tal:attributes="value value; class masterCss; name name; id name"></span>
</metal:view> </metal:view>
<tal:comment replace="nothing">Edit macro for an Float.</tal:comment> <tal:comment replace="nothing">Edit macro for an Float.</tal:comment>

View file

@ -1,6 +1,7 @@
<tal:comment replace="nothing">View macro for an Integer.</tal:comment> <tal:comment replace="nothing">View macro for an Integer.</tal:comment>
<metal:view define-macro="view"> <metal:view define-macro="view">
<span tal:content="value" tal:attributes="id value; class widget/master_css"></span> <span tal:content="value"
tal:attributes="value value; class masterCss; name name; id name"></span>
</metal:view> </metal:view>
<tal:comment replace="nothing">Edit macro for an Integer.</tal:comment> <tal:comment replace="nothing">Edit macro for an Integer.</tal:comment>

View file

@ -9,15 +9,23 @@
contextMacro The base folder containing the macros to call for contextMacro The base folder containing the macros to call for
rendering the elements within the layout. rendering the elements within the layout.
Defaults to app.skyn Defaults to app.skyn
slaveId The name and id of the main tag for this layout (used
for master/slave relationships).
slaveCss The CSS class for a slave.
</tal:comment> </tal:comment>
<metal:show define-macro="layout" <metal:show define-macro="layout"
tal:define="contextMacro contextMacro| python: app.skyn"> tal:define="contextMacro contextMacro| python: app.skyn;
slaveId slaveId|python:'';
slaveCss slaveCss|python:'';
layoutCss layout/css_class;">
<table tal:attributes="cellpadding layout/cellpadding; <table tal:attributes="cellpadding layout/cellpadding;
cellspacing layout/cellspacing; cellspacing layout/cellspacing;
width layout/width; width layout/width;
align layout/align; align layout/align;
class layout/css_class; class python: slaveCss and ('%s %s' % (slaveCss, layoutCss)) or layoutCss;
style layout/style"> style layout/style;
id slaveId;
name slaveId;">
<tal:comment replace="nothing">The table header row</tal:comment> <tal:comment replace="nothing">The table header row</tal:comment>
<tr tal:condition="layout/headerRow" tal:attributes="valign layout/headerRow/valign"> <tr tal:condition="layout/headerRow" tal:attributes="valign layout/headerRow/valign">
<th tal:repeat="cell layout/headerRow/cells" <th tal:repeat="cell layout/headerRow/cells"
@ -52,7 +60,10 @@
inRequest python: request.has_key(name); inRequest python: request.has_key(name);
errors errors | python: (); errors errors | python: ();
inError python: (widget['name'] in errors) and True or False; inError python: (widget['name'] in errors) and True or False;
isMultiple python: (widget['multiplicity'][1] == None) or (widget['multiplicity'][1] &gt; 1)"> isMultiple python: (widget['multiplicity'][1] == None) or (widget['multiplicity'][1] &gt; 1);
masterCss python: widget['slaves'] and ('master_%s' % name) or '';
slaveCss python: widget['master'] and ('slave_%s_%s' % (widget['masterName'], '_'.join(widget['masterValue']))) or '';
slaveId python: widget['master'] and 'slave' or ''">
<metal:layout use-macro="here/skyn/widgets/show/macros/layout"/> <metal:layout use-macro="here/skyn/widgets/show/macros/layout"/>
</metal:field> </metal:field>
@ -65,7 +76,11 @@
layoutType "edit"? "view"? "cell?" layoutType "edit"? "view"? "cell?"
widget The widget to render widget The widget to render
</tal:comment> </tal:comment>
<metal:group define-macro="group"> <metal:group define-macro="group"
tal:define="slaveCss python: widget['master'] and ('slave_%s_%s' % (widget['masterName'], '_'.join(widget['masterValue']))) or '';
widgetCss widget/css_class;
groupCss python: slaveCss and ('%s %s' % (slaveCss, widgetCss)) or widgetCss;
slaveId python: widget['master'] and 'slave' or ''">
<fieldset tal:condition="python: widget['style'] == 'fieldset'"> <fieldset tal:condition="python: widget['style'] == 'fieldset'">
<legend tal:condition="widget/hasLabel"> <legend tal:condition="widget/hasLabel">
<i tal:content="structure python: contextObj.translate(widget['labelId'])"></i> <i tal:content="structure python: contextObj.translate(widget['labelId'])"></i>
@ -81,9 +96,9 @@
<metal:content use-macro="app/skyn/widgets/show/macros/groupContent"/> <metal:content use-macro="app/skyn/widgets/show/macros/groupContent"/>
</tal:asSection> </tal:asSection>
<tal:asTabs condition="python: widget['style'] == 'tabs'"> <tal:asTabs condition="python: widget['style'] == 'tabs'">
<table cellpadding="0" cellspacing="0" <table tal:attributes="width widget/wide;
tal:attributes="width widget/wide; class groupCss;
class widget/css_class"> id slaveId; name slaveId">
<tal:comment replace="nothing">First row: the tabs.</tal:comment> <tal:comment replace="nothing">First row: the tabs.</tal:comment>
<tr valign="middle"><td style="border-bottom: 1px solid #ff8040"> <tr valign="middle"><td style="border-bottom: 1px solid #ff8040">
<table cellpadding="0" cellspacing="0" style="position:relative; bottom:-1px;"> <table cellpadding="0" cellspacing="0" style="position:relative; bottom:-1px;">
@ -132,9 +147,10 @@
tal:define="cellgap widget/cellgap" tal:define="cellgap widget/cellgap"
tal:attributes="width widget/wide; tal:attributes="width widget/wide;
align widget/align; align widget/align;
class widget/css_class; class groupCss;
cellspacing widget/cellspacing; cellspacing widget/cellspacing;
cellpadding widget/cellpadding"> cellpadding widget/cellpadding;
id slaveId; name slaveId">
<tal:comment replace="nothing">Display the title of the group if it is not rendered a fieldset.</tal:comment> <tal:comment replace="nothing">Display the title of the group if it is not rendered a fieldset.</tal:comment>
<tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasLabel']"> <tr tal:condition="python: (widget['style'] != 'fieldset') and widget['hasLabel']">
<td tal:attributes="colspan python: len(widget['columnsWidths']); <td tal:attributes="colspan python: len(widget['columnsWidths']);

View file

@ -2,7 +2,7 @@
<metal:view define-macro="view" <metal:view define-macro="view"
tal:define="fmt widget/format"> tal:define="fmt widget/format">
<span tal:condition="python: fmt in (0, 3)" <span tal:condition="python: fmt in (0, 3)"
tal:attributes="class widget/master_css; id rawValue"> tal:attributes="class masterCss; value rawValue; name name; id name">
<ul tal:condition="python: value and isMultiple"> <ul tal:condition="python: value and isMultiple">
<li tal:repeat="sv value"><i tal:content="structure sv"></i></li> <li tal:repeat="sv value"><i tal:content="structure sv"></i></li>
</ul> </ul>
@ -31,8 +31,8 @@
tal:attributes="name name; tal:attributes="name name;
id name; id name;
multiple python: isMultiple and 'multiple' or ''; multiple python: isMultiple and 'multiple' or '';
onchange python: isMaster and ('updateSlaves(getMasterValue(this), \'%s\')' % widget['id']) or ''; onchange python: isMaster and 'updateSlaves(this)' or '';
class widget/master_css; class masterCss;
size python: isMultiple and widget['height'] or 1"> size python: isMultiple and widget['height'] or 1">
<option tal:repeat="possibleValue possibleValues" <option tal:repeat="possibleValue possibleValues"
tal:attributes="value python: possibleValue[0]; tal:attributes="value python: possibleValue[0];