diff --git a/fields/__init__.py b/fields/__init__.py
index c650f85..431d89b 100644
--- a/fields/__init__.py
+++ b/fields/__init__.py
@@ -76,6 +76,26 @@ class Field:
tagName=field.master and 'slave' or '';
layoutTarget=field">:tool.pxLayoutedObject''')
+ def doRender(self, layoutType, request, context=None, name=None):
+ '''Allows to call pxRender from code, to display the content of this
+ field in some specific context, for example in a Computed field.'''
+ if context == None: context = {}
+ context['layoutType'] = layoutType
+ context['field'] = self
+ context['name'] = name or self.name
+ # We may be executing a PX on a given object or on a given object tied
+ # through a Ref.
+ ctx = request.pxContext
+ if 'obj' not in context:
+ context['obj'] = ('tied' in ctx) and ctx['tied'] or ctx['obj']
+ context['zobj'] = context['obj'].o
+ # Copy some keys from the context of the currently executed PX.
+ for k in ('tool', 'ztool', 'req', '_', 'q', 'url', 'dright', 'dleft', \
+ 'inPopup'):
+ if k in context: continue
+ context[k] = ctx[k]
+ return self.pxRender(context).encode('utf-8')
+
# Displays a field label.
pxLabel = Px('''''')
diff --git a/fields/string.py b/fields/string.py
index 9653f70..f7d599b 100644
--- a/fields/string.py
+++ b/fields/string.py
@@ -113,9 +113,11 @@ class String(Field):
# pxView part for format String.XHTML.
pxViewRich = Px('''
::value or '-'
-
::value or '-'
- ''')
+
+
::value or '-'
+
+ ''')
# PX displaying the language code and name besides the part of the
# multilingual field storing content in this language.
@@ -618,7 +620,6 @@ class String(Field):
def getIndexValue(self, obj, forSearch=False):
'''Pure text must be extracted from rich content; multilingual content
must be concatenated.'''
- print 'INDEX value computing...', self.name, obj.title
isXhtml = self.format == String.XHTML
if self.isMultilingual():
res = self.getValue(obj)
@@ -639,7 +640,6 @@ class String(Field):
# Ugly catalog: if value is an empty string or None, it keeps the
# previous index value.
if res in self.emptyValuesCatalogIgnored: res = ' '
- print 'INDEX value for', self.name, 'is', res
return res
def getPossibleValues(self, obj, withTranslations=False,
@@ -815,8 +815,18 @@ class String(Field):
'''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, self.getStorableValue(rq['fieldContent']))
+ if rq.get('cancel') == 'True': return
+ requestValue = rq['fieldContent']
+ if self.isMultilingual():
+ # We get a partial value, for one language only.
+ language = rq['languageOnly']
+ v = self.getUnilingualStorableValue(requestValue)
+ getattr(obj.aq_base, self.name)[language] = v
+ part = ' (%s)' % language
+ else:
+ self.store(obj, self.getStorableValue(requestValue))
+ part = ''
+ obj.log('Ajax-edited %s%s on %s.' % (self.name, part, obj.id))
def getIndexType(self):
'''Index type varies depending on String parameters.'''
@@ -893,18 +903,20 @@ class String(Field):
return 'CKEDITOR.replace("%s", {%s})' % \
(name, self.getCkParams(obj, language))
- def getJsInlineInit(self, obj, language):
+ def getJsInlineInit(self, obj, name, language):
'''Gets the Javascript init code for enabling inline edition of this
field (rich text only). If the field is multilingual, the current
- p_language is given. Else, p_language is None.'''
+ p_language is given and p_name includes it. Else, p_language is
+ None.'''
uid = obj.id
- name = not language and self.name or ('%s_%s' % (self.name, language))
+ fieldName = language and name.rsplit('_',1)[0] or name
+ lg = language or ''
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, name, self.getCkParams(obj, language), uid, name,
- obj.absolute_url())
+ "doInlineSave('%s','%s','%s',content,'%s')}}})" % \
+ (uid, name, self.getCkParams(obj, language), uid, fieldName,
+ obj.absolute_url(), lg)
def isSelected(self, obj, fieldName, vocabValue, dbValue):
'''When displaying a selection box (only for fields with a validator
diff --git a/gen/ui/appy.js b/gen/ui/appy.js
index 01a10a2..cdedcf8 100644
--- a/gen/ui/appy.js
+++ b/gen/ui/appy.js
@@ -110,6 +110,7 @@ function getAjaxHook(hookId) {
for the result of an ajax request. If p_hookId starts with ':', we search
the element in the top browser window, not in the current one that can be
an iframe.*/
+ if (!hookId) return;
var container = window.document;
var startIndex = 0;
if (hookId[0] == ':') {
@@ -126,7 +127,7 @@ function getAjaxChunk(pos) {
if ( (typeof(xhrObjects[pos]) != 'undefined') &&
(xhrObjects[pos].freed == 0)) {
var hook = xhrObjects[pos].hook;
- if (xhrObjects[pos].xhr.readyState == 1) {
+ if (hook && (xhrObjects[pos].xhr.readyState == 1)) {
// The request has been initialized: display the waiting radar
var hookElem = getAjaxHook(hook);
if (hookElem)
@@ -135,7 +136,8 @@ function getAjaxChunk(pos) {
if (xhrObjects[pos].xhr.readyState == 4) {
// We have received the HTML chunk
var hookElem = getAjaxHook(hook);
- if (hookElem && (xhrObjects[pos].xhr.status == 200)) {
+ var responseOk = (xhrObjects[pos].xhr.status == 200);
+ if (hookElem && responseOk) {
injectChunk(hookElem, xhrObjects[pos].xhr.responseText);
// Call a custom Javascript function if required
if (xhrObjects[pos].onGet) {
@@ -146,8 +148,8 @@ function getAjaxChunk(pos) {
for (var i=0; i