[gen] Integrated ckeditor inline editing via boolean parameter field.inlineEdit.
This commit is contained in:
parent
48c7c50122
commit
4e09a40807
|
@ -1072,7 +1072,8 @@ class Float(Type):
|
||||||
|
|
||||||
class String(Type):
|
class String(Type):
|
||||||
# Javascript files sometimes required by this type
|
# Javascript files sometimes required by this type
|
||||||
jsFiles = {'edit': ('ckeditor/ckeditor.js',)}
|
jsFiles = {'edit': ('ckeditor/ckeditor.js',),
|
||||||
|
'view': ('ckeditor/ckeditor.js',)}
|
||||||
|
|
||||||
# Some predefined regular expressions that may be used as validators
|
# Some predefined regular expressions that may be used as validators
|
||||||
c = re.compile
|
c = re.compile
|
||||||
|
@ -1181,7 +1182,7 @@ class String(Type):
|
||||||
masterValue=None, focus=False, historized=False, mapping=None,
|
masterValue=None, focus=False, historized=False, mapping=None,
|
||||||
label=None, sdefault='', scolspan=1, swidth=None, sheight=None,
|
label=None, sdefault='', scolspan=1, swidth=None, sheight=None,
|
||||||
transform='none', styles=('p','h1','h2','h3','h4'),
|
transform='none', styles=('p','h1','h2','h3','h4'),
|
||||||
allowImageUpload=True):
|
allowImageUpload=True, inlineEdit=False):
|
||||||
# According to format, the widget will be different: input field,
|
# According to format, the widget will be different: input field,
|
||||||
# textarea, inline editor... Note that there can be only one String
|
# textarea, inline editor... Note that there can be only one String
|
||||||
# field of format CAPTCHA by page, because the captcha challenge is
|
# field of format CAPTCHA by page, because the captcha challenge is
|
||||||
|
@ -1193,6 +1194,8 @@ class String(Type):
|
||||||
self.styles = styles
|
self.styles = styles
|
||||||
# When format is XHTML, do we allow the user to upload images in it ?
|
# When format is XHTML, do we allow the user to upload images in it ?
|
||||||
self.allowImageUpload = allowImageUpload
|
self.allowImageUpload = allowImageUpload
|
||||||
|
# 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
|
# The following field has a direct impact on the text entered by the
|
||||||
# user. It applies a transformation on it, exactly as does the CSS
|
# user. It applies a transformation on it, exactly as does the CSS
|
||||||
# "text-transform" property. Allowed values are those allowed for the
|
# "text-transform" property. Allowed values are those allowed for the
|
||||||
|
|
|
@ -103,6 +103,19 @@ class BaseMixin:
|
||||||
obj.reindex()
|
obj.reindex()
|
||||||
return obj, msg
|
return obj, msg
|
||||||
|
|
||||||
|
def updateField(self, name, value):
|
||||||
|
'''Updates a single field p_name with new p_value.'''
|
||||||
|
field = self.getAppyType(name)
|
||||||
|
# Remember previous value if the field is historized.
|
||||||
|
previousData = self.rememberPreviousData([field])
|
||||||
|
# Store the new value into the database
|
||||||
|
field.store(self, value)
|
||||||
|
# Update the object history when relevant
|
||||||
|
if previousData: self.historizeData(previousData)
|
||||||
|
# Update last modification date
|
||||||
|
from DateTime import DateTime
|
||||||
|
self.modified = DateTime()
|
||||||
|
|
||||||
def delete(self):
|
def delete(self):
|
||||||
'''This method is self's suicide.'''
|
'''This method is self's suicide.'''
|
||||||
# Call a custom "onDelete" if it exists
|
# Call a custom "onDelete" if it exists
|
||||||
|
@ -1834,6 +1847,19 @@ class BaseMixin:
|
||||||
ck.append('%s: %s' % (k, sv))
|
ck.append('%s: %s' % (k, sv))
|
||||||
return 'CKEDITOR.replace("%s", {%s})' % (name, ', '.join(ck))
|
return 'CKEDITOR.replace("%s", {%s})' % (name, ', '.join(ck))
|
||||||
|
|
||||||
|
def getEditorInlineInit(self, name):
|
||||||
|
'''Gets the Javascript init code for enabling inline edition of a rich
|
||||||
|
field named p_name.'''
|
||||||
|
field = self.getAppyType(name)
|
||||||
|
uid = self.UID()
|
||||||
|
return "CKEDITOR.disableAutoInline = true;\n" \
|
||||||
|
"CKEDITOR.inline('%s_%s_ck', {on: {blur: " \
|
||||||
|
"function( event ) { var data = event.editor.getData(); " \
|
||||||
|
"askAjaxChunk('%s_%s','POST','%s','page','saveField', "\
|
||||||
|
"{'fieldName':'%s', 'fieldContent': encodeURIComponent(data)}, "\
|
||||||
|
"null, evalInnerScripts);}}});"% \
|
||||||
|
(uid, name, uid, name, self.absolute_url(), name)
|
||||||
|
|
||||||
def getCalendarInit(self, name, years):
|
def getCalendarInit(self, name, years):
|
||||||
'''Gets the Javascript init code for displaying a calendar popup for
|
'''Gets the Javascript init code for displaying a calendar popup for
|
||||||
field named p_name.'''
|
field named p_name.'''
|
||||||
|
|
|
@ -59,6 +59,14 @@ function XhrObject() { // Wraps a XmlHttpRequest object
|
||||||
this.info = {}; /* An associative array for putting anything else. */
|
this.info = {}; /* An associative array for putting anything else. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* When inserting HTML at some DOM node in a page via Ajax, scripts defined in
|
||||||
|
this chunk of HTML are not executed. This function, typically used as "onGet"
|
||||||
|
param for the askAjaxChunk function below, will evaluate those scripts. */
|
||||||
|
function evalInnerScripts(xhrObject, hookElem) {
|
||||||
|
var scripts = hookElem.getElementsByTagName('script');
|
||||||
|
for (var i=0; i<scripts.length; i++) { eval(scripts[i].innerHTML) }
|
||||||
|
}
|
||||||
|
|
||||||
function getAjaxChunk(pos) {
|
function getAjaxChunk(pos) {
|
||||||
// This function is the callback called by the AJAX machinery (see function
|
// This function is the callback called by the AJAX machinery (see function
|
||||||
// askAjaxChunk below) when an Ajax response is available.
|
// askAjaxChunk below) when an Ajax response is available.
|
||||||
|
@ -208,7 +216,8 @@ function askField(hookId, objectUrl, layoutType, showChanges){
|
||||||
var fieldName = hookId.split('_')[1];
|
var fieldName = hookId.split('_')[1];
|
||||||
var params = {'fieldName': fieldName, 'layoutType': layoutType,
|
var params = {'fieldName': fieldName, 'layoutType': layoutType,
|
||||||
'showChanges': showChanges};
|
'showChanges': showChanges};
|
||||||
askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/show', 'fieldAjax', params);
|
askAjaxChunk(hookId, 'GET', objectUrl, 'widgets/show', 'fieldAjax', params,
|
||||||
|
null, evalInnerScripts);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function used by checkbox widgets for having radio-button-like behaviour
|
// Function used by checkbox widgets for having radio-button-like behaviour
|
||||||
|
|
|
@ -340,3 +340,14 @@
|
||||||
<span tal:replace="structure messages"></span>
|
<span tal:replace="structure messages"></span>
|
||||||
</div>
|
</div>
|
||||||
</metal:message>
|
</metal:message>
|
||||||
|
|
||||||
|
<tal:comment replace="nothing">
|
||||||
|
Save the content of a rich field and return its consult view.
|
||||||
|
Requires request/fieldContent.
|
||||||
|
</tal:comment>
|
||||||
|
<metal:save define-macro="saveField"
|
||||||
|
tal:define="fieldName request/fieldName;
|
||||||
|
fieldContent request/fieldContent;
|
||||||
|
dummy python: contextObj.updateField(fieldName, fieldContent)">
|
||||||
|
<metal:call use-macro="app/ui/widgets/show/macros/fieldAjax"/>
|
||||||
|
</metal:save>
|
||||||
|
|
|
@ -90,7 +90,7 @@
|
||||||
<tal:comment replace="nothing">Call the previous macro, but from Ajax.</tal:comment>
|
<tal:comment replace="nothing">Call the previous macro, but from Ajax.</tal:comment>
|
||||||
<metal:afield define-macro="fieldAjax"
|
<metal:afield define-macro="fieldAjax"
|
||||||
tal:define="widgetName request/fieldName;
|
tal:define="widgetName request/fieldName;
|
||||||
layoutType request/layoutType;
|
layoutType python: request.get('layoutType', 'view');
|
||||||
showChanges python: request.get('showChanges', 'False') == 'True';
|
showChanges python: request.get('showChanges', 'False') == 'True';
|
||||||
widget python: contextObj.getAppyType(widgetName, asDict=True);
|
widget python: contextObj.getAppyType(widgetName, asDict=True);
|
||||||
page widget/pageName">
|
page widget/pageName">
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
<tal:comment replace="nothing">View macro for a String.</tal:comment>
|
<tal:comment replace="nothing">View macro for a String.</tal:comment>
|
||||||
<metal:view define-macro="view"
|
<metal:view define-macro="view"
|
||||||
tal:define="fmt widget/format; isUrl widget/isUrl">
|
tal:define="fmt widget/format; isUrl widget/isUrl;
|
||||||
|
mayAjaxEdit python: not showChanges and widget['inlineEdit'] and contextObj.mayEdit(widget['writePermission'])">
|
||||||
<span tal:condition="python: fmt in (0, 3)">
|
<span tal:condition="python: fmt in (0, 3)">
|
||||||
<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>
|
||||||
|
@ -20,9 +21,16 @@
|
||||||
<span tal:condition="python: value and (fmt == 1)"
|
<span tal:condition="python: value and (fmt == 1)"
|
||||||
tal:replace="structure python: contextObj.formatText(value, format='html')"/>
|
tal:replace="structure python: contextObj.formatText(value, format='html')"/>
|
||||||
<tal:comment replace="nothing">XHTML text</tal:comment>
|
<tal:comment replace="nothing">XHTML text</tal:comment>
|
||||||
<div tal:condition="python: value and (fmt == 2)" class="xhtml">
|
<tal:xhtml condition="python: value and (fmt == 2)">
|
||||||
<span tal:replace="structure value"/>
|
<div tal:condition="not: mayAjaxEdit" class="xhtml" tal:content="structure value"></div>
|
||||||
</div>
|
<div tal:condition="mayAjaxEdit" class="xhtml" contenteditable="true"
|
||||||
|
tal:attributes="id python: '%s_%s_ck' % (contextObj.UID(), name)"
|
||||||
|
tal:content="structure value">
|
||||||
|
</div>
|
||||||
|
<script tal:condition="mayAjaxEdit"
|
||||||
|
tal:content="python: contextObj.getEditorInlineInit(name)">
|
||||||
|
</script>
|
||||||
|
</tal:xhtml>
|
||||||
<input type="hidden" tal:condition="masterCss"
|
<input type="hidden" tal:condition="masterCss"
|
||||||
tal:attributes="class masterCss; value rawValue; name name; id name"/>
|
tal:attributes="class masterCss; value rawValue; name name; id name"/>
|
||||||
</metal:view>
|
</metal:view>
|
||||||
|
|
Loading…
Reference in a new issue