diff --git a/fields/__init__.py b/fields/__init__.py
index 5c281c4..6bcf415 100644
--- a/fields/__init__.py
+++ b/fields/__init__.py
@@ -40,6 +40,7 @@ class Field:
cssFiles = {}
jsFiles = {}
dLayouts = 'lrv-d-f'
+ hLayouts = 'lhrv-f'
wLayouts = Table('lrv-f')
# Render a field. Optional vars:
diff --git a/fields/pod.py b/fields/pod.py
index 92e64c6..6cc3fc4 100644
--- a/fields/pod.py
+++ b/fields/pod.py
@@ -78,7 +78,7 @@ class Pod(Field):
:_('unfreezeField')
+ class="smaller">:_('unfreezeField')
@@ -87,7 +87,7 @@ class Pod(Field):
:_('freezeField')
+ class="smaller">:_('freezeField')
@@ -96,7 +96,7 @@ class Pod(Field):
:_('uploadField')
+ class="smaller">:_('uploadField')
@@ -107,7 +107,7 @@ class Pod(Field):
template. For a single template, the field label already does
the job. -->
:field.getTemplateName(obj, info.template)
+ class="smaller">:field.getTemplateName(obj, info.template)
diff --git a/fields/ref.py b/fields/ref.py
index 576dff0..a874b3d 100644
--- a/fields/ref.py
+++ b/fields/ref.py
@@ -195,24 +195,10 @@ class Ref(Field):
# PX that displays referred objects as a list.
pxViewList = Px('''
-
-
-
-
-
- :_('no_ref')
- :field.pxAdd
-
-
-
- :field.pxObjectTitle
-
-
-
+
+ :_('no_ref')
-
-
+
:_(subLabel)
(
:totalNumber )
@@ -231,10 +217,7 @@ class Ref(Field):
:tool.pxNavigate
-
-
:_('no_ref')
-
-
+
:', '.join(titles) or \
+ _('no_ref')''')
+
# PX that displays referred objects through this field. In mode link="list",
# if, in the request, key "scope" is present and holds value "objs", the
# pick list (containing possible values) will not be rendered.
pxView = Px('''
-
@@ -410,12 +392,11 @@ class Ref(Field):
:field.pxViewList
:field.pxViewList
- :field.pxViewMenus
+ :getattr(field, 'pxView%s' % \
+ render.capitalize())
''')
- # The "menus" render mode is only applicable in "cell", not in "view".
- pxCell = Px(''':field.pxView ''')
-
+ pxCell = pxView
pxEdit = Px('''
::zobj.formatText(value, format='html')
-
- ::value
+
+ ::value or '-'
::value
-
+ id=":'%s_%s_ck' % (zobj.id, name)">::value or '-'
+
+ -
''')
@@ -298,7 +299,7 @@ class String(Field):
label=None, sdefault='', scolspan=1, swidth=None, sheight=None,
persist=True, transform='none',
styles=('p','h1','h2','h3','h4'), allowImageUpload=True,
- inlineEdit=False):
+ spellcheck=False, contentLanguage=None, inlineEdit=False):
# According to format, the widget will be different: input field,
# textarea, inline editor... Note that there can be only one String
# field of format CAPTCHA by page, because the captcha challenge is
@@ -310,6 +311,10 @@ class String(Field):
self.styles = styles
# When format is XHTML, do we allow the user to upload images in it ?
self.allowImageUpload = allowImageUpload
+ # When format is XHTML, do we run the CK spellchecker ?
+ self.spellcheck = spellcheck
+ # What is the language of field content?
+ self.contentLanguage = contentLanguage
# When format in XHTML, can the field be inline-edited (ckeditor)?
self.inlineEdit = inlineEdit
# The following field has a direct impact on the text entered by the
@@ -409,6 +414,12 @@ class String(Field):
type='warning')
Field.store(self, obj, value)
+ def storeFromAjax(self, obj):
+ '''Stores the new field value from an Ajax request, or do nothing if
+ the action was canceled.'''
+ rq = obj.REQUEST
+ if rq.get('cancel') != 'True': self.store(obj, rq['fieldContent'])
+
def getDiffValue(self, obj, value):
'''Returns a version of p_value that includes the cumulative diffs
between successive versions.'''
@@ -656,27 +667,52 @@ class String(Field):
generator).'''
return self.getCaptchaChallenge({})['text']
- def getJsInit(self, obj):
- '''Gets the Javascript init code for displaying a rich editor for this
- field (rich field only).'''
- # Define the attributes that will initialize the ckeditor instance for
- # this field.
+ ckLanguages = {'en': 'en_US', 'pt': 'pt_BR', 'da': 'da_DK', 'nl': 'nl_NL',
+ 'fi': 'fi_FI', 'fr': 'fr_FR', 'de': 'de_DE', 'el': 'el_GR',
+ 'it': 'it_IT', 'nb': 'nb_NO', 'pt': 'pt_PT', 'es': 'es_ES',
+ 'sv': 'sv_SE'}
+ def getCkLanguage(self):
+ '''Gets the language for CK editor SCAYT. We will use
+ self.contentLanguage. If it is not supported by CK, we use
+ english.'''
+ lang = self.contentLanguage
+ if lang and (lang in self.ckLanguages): return self.ckLanguages[lang]
+ return 'en_US'
+
+ def getCkParams(self, obj):
+ '''Gets the base params to set on a rich text field.'''
ckAttrs = {'toolbar': 'Appy',
- 'format_tags': '%s' % ';'.join(self.styles)}
+ 'format_tags': ';'.join(self.styles),
+ 'scayt_sLang': self.getCkLanguage()}
if self.width: ckAttrs['width'] = self.width
+ if self.spellcheck: ckAttrs['scayt_autoStartup'] = True
if self.allowImageUpload:
ckAttrs['filebrowserUploadUrl'] = '%s/upload' % obj.absolute_url()
ck = []
for k, v in ckAttrs.iteritems():
if isinstance(v, int): sv = str(v)
+ if isinstance(v, bool): sv = str(v).lower()
else: sv = '"%s"' % v
ck.append('%s: %s' % (k, sv))
- return 'CKEDITOR.replace("%s", {%s})' % (self.name, ', '.join(ck))
+ return ', '.join(ck)
+
+ def getJsInit(self, obj):
+ '''Gets the Javascript init code for displaying a rich editor for this
+ field (rich field only).'''
+ return 'CKEDITOR.replace("%s", {%s})' % \
+ (self.name, self.getCkParams(obj))
def getJsInlineInit(self, obj):
'''Gets the Javascript init code for enabling inline edition of this
field (rich text only).'''
- uid = obj.UID()
+ uid = obj.id
+ return "CKEDITOR.disableAutoInline = true;\n" \
+ "CKEDITOR.inline('%s_%s_ck', {%s, on: {blur: " \
+ "function( event ) { var content = event.editor.getData(); " \
+ "doInlineSave('%s', '%s', '%s', content)}}})" % \
+ (uid, self.name, self.getCkParams(obj), uid, self.name,
+ obj.absolute_url())
+
return "CKEDITOR.disableAutoInline = true;\n" \
"CKEDITOR.inline('%s_%s_ck', {on: {blur: " \
"function( event ) { var data = event.editor.getData(); " \
diff --git a/gen/model.py b/gen/model.py
index d1881a5..da339b2 100644
--- a/gen/model.py
+++ b/gen/model.py
@@ -12,7 +12,7 @@ class Protos:
# List of attributes that can't be given to a Type constructor
notInit = ('id', 'type', 'pythonType', 'slaves', 'isSelect', 'hasLabel',
'hasDescr', 'hasHelp', 'required', 'filterable', 'validable',
- 'isBack', 'pageName', 'masterName')
+ 'isBack', 'pageName', 'masterName', 'renderLabel')
@classmethod
def get(self, appyType):
'''Returns a prototype instance for p_appyType.'''
diff --git a/gen/tr/Appy.pot b/gen/tr/Appy.pot
index ef47237..fc90a10 100644
--- a/gen/tr/Appy.pot
+++ b/gen/tr/Appy.pot
@@ -79,7 +79,7 @@ msgstr ""
msgid "max_ref_violated"
msgstr ""
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
msgstr ""
diff --git a/gen/tr/ar.po b/gen/tr/ar.po
index cef7ded..db5a41f 100644
--- a/gen/tr/ar.po
+++ b/gen/tr/ar.po
@@ -79,7 +79,7 @@ msgstr ""
msgid "max_ref_violated"
msgstr ""
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
msgstr ""
diff --git a/gen/tr/de.po b/gen/tr/de.po
index 84322f1..d09feaa 100644
--- a/gen/tr/de.po
+++ b/gen/tr/de.po
@@ -79,7 +79,7 @@ msgstr "Hier müssen Sie Elemente auswählen."
msgid "max_ref_violated"
msgstr "Sie haben zuviele Elemente ausgewählt."
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
msgstr "Kein Element"
diff --git a/gen/tr/en.po b/gen/tr/en.po
index 3a5bd77..a3d8794 100644
--- a/gen/tr/en.po
+++ b/gen/tr/en.po
@@ -80,7 +80,7 @@ msgstr "You must choose more elements here."
msgid "max_ref_violated"
msgstr "Too much elements are selected here."
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
msgstr "No object."
diff --git a/gen/tr/es.po b/gen/tr/es.po
index 05f20fc..1eb6ee1 100644
--- a/gen/tr/es.po
+++ b/gen/tr/es.po
@@ -79,7 +79,7 @@ msgstr "Debe elegir más elementos aquí."
msgid "max_ref_violated"
msgstr "Demasiados elementos son seleccionados aquí."
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
msgstr "Ningún elemento."
diff --git a/gen/tr/fr.po b/gen/tr/fr.po
index de56336..bae3355 100644
--- a/gen/tr/fr.po
+++ b/gen/tr/fr.po
@@ -80,9 +80,9 @@ msgstr "Vous devez choisir plus d'éléments ici."
msgid "max_ref_violated"
msgstr "Trop d'éléments sont sélectionnés ici."
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
-msgstr "Aucun élément."
+msgstr "-"
#. Default: "Add a new one"
msgid "add_ref"
diff --git a/gen/tr/it.po b/gen/tr/it.po
index 75a5e43..5c1305e 100644
--- a/gen/tr/it.po
+++ b/gen/tr/it.po
@@ -79,9 +79,9 @@ msgstr "Qui deve scegliere un maggior numero di elementi"
msgid "max_ref_violated"
msgstr "Un numero eccessivo di elementi sono scelti"
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
-msgstr "Nessun elemento"
+msgstr "-"
#. Default: "Add a new one"
msgid "add_ref"
diff --git a/gen/tr/nl.po b/gen/tr/nl.po
index 320b5a8..b549eb1 100644
--- a/gen/tr/nl.po
+++ b/gen/tr/nl.po
@@ -79,9 +79,9 @@ msgstr "U moet hier meerdere elementen selecteren."
msgid "max_ref_violated"
msgstr "U hebt teveel elementen geselecteerd."
-#. Default: "No object."
+#. Default: "-"
msgid "no_ref"
-msgstr "Geen element."
+msgstr "-"
#. Default: "Add a new one"
msgid "add_ref"
diff --git a/gen/ui/appy.css b/gen/ui/appy.css
index 218340f..38347b6 100644
--- a/gen/ui/appy.css
+++ b/gen/ui/appy.css
@@ -100,7 +100,7 @@ td.search { padding-top: 8px }
border: 1px solid grey; box-shadow: 2px 2px 2px #888888}
.dropdown { display:none; position: absolute; border: 1px solid #cccccc;
background-color: white; padding: 3px 4px 0; font-size: 8pt;
- font-weight: normal }
+ font-weight: normal; z-index: 2 }
.dropdownMenu { cursor: pointer; padding-right: 4px; font-size: 93% }
.dropdown a:hover { text-decoration: underline }
.list { margin-bottom: 3px }
@@ -155,7 +155,7 @@ td.search { padding-top: 8px }
.homeTable th { padding-top: 5px; font-size: 105% }
.first { margin-top: 0px }
.error { margin: 5px }
-.podName { font-size: 95% }
+.smaller { font-size: 95% }
.podTable { margin-left: 15px }
.cbCell { width: 10px; text-align: center}
.tabs { position:relative; bottom:-2px }
diff --git a/gen/ui/appy.js b/gen/ui/appy.js
index cd16a2d..ee3be6b 100644
--- a/gen/ui/appy.js
+++ b/gen/ui/appy.js
@@ -275,6 +275,22 @@ function askField(hookId, objectUrl, layoutType, showChanges, masterValues,
askAjaxChunk(hookId, 'GET', objectUrl, px, params, null, evalInnerScripts);
}
+function doInlineSave(objectUid, name, objectUrl, content){
+ /* Ajax-saves p_content of field named p_name on object whose id is
+ p_objectUid and whose URL is p_objectUrl. Asks a confirmation before
+ doing it. */
+ var doIt = confirm('Do it?');
+ var params = {'action': 'storeFromAjax', 'layoutType': 'view'};
+ var hook = null;
+ if (!doIt) {
+ params['cancel'] = 'True';
+ hook = objectUid + '_' + name;
+ }
+ else { params['fieldContent'] = encodeURIComponent(content) }
+ askAjaxChunk(hook, 'POST', objectUrl, name + ':pxRender', params, null,
+ evalInnerScripts);
+}
+
// Used by checkbox widgets for having radio-button-like behaviour.
function toggleCheckbox(visibleCheckbox, hiddenBoolean) {
vis = document.getElementById(visibleCheckbox);