Skip to content

Commit

Permalink
zmi(htmx): hilight save-btn after content-edit, applied iterative row…
Browse files Browse the repository at this point in the history
…-inserts in admin-GUI (#303)

* added marker to tab on edit (class=form-modified)
* hilight content fields on edit
* zmi: monotonized multiple insert_row actions for langs, lang_dict, metas, metaobjs
* applying htmx for deleting a lang and lang keys
* added row_inserts/delete to ZMS.permalinks-attr
* moved alpine-docker into separate folder
  • Loading branch information
drfho authored Oct 3, 2024
1 parent ac35c27 commit 13dbd86
Show file tree
Hide file tree
Showing 44 changed files with 1,436 additions and 290 deletions.
39 changes: 17 additions & 22 deletions Products/zms/ZMSMetadictManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ def manage_changeMetaProperties(self, btn, lang, REQUEST, RESPONSE=None):
t0 = time.time()
id = REQUEST.get('id', '')
target = 'manage_metas'
if btn == 'BTN_SAVE' or btn == 'BTN_DELETE':
target = REQUEST.get('target', target)

try:

Expand Down Expand Up @@ -290,21 +292,6 @@ def manage_changeMetaProperties(self, btn, lang, REQUEST, RESPONSE=None):
newDefault = REQUEST.get('attr_default_%s'%oldId, '')
self.setMetadictAttr( oldId, newId, newAcquired, newName, newType, newMandatory, newMultilang, newRepetitive, newCustom, newKeys, newDefault)
message += self.getZMILangStr('MSG_CHANGED')
newId = REQUEST['_id'].strip()
newAcquired = 0
newName = REQUEST['_name'].strip()
newType = REQUEST['_type'].strip()
newMandatory = REQUEST.get('_mandatory', 0)
newMultilang = REQUEST.get('_multilang', 0)
newRepetitive = REQUEST.get('_repetitive', 0)
newCustom = ''
if len(newId) > 0 and len(newName) > 0 and len(newType) > 0:
if newType == 'method':
newCustom += '<dtml-comment>--// BO '+ newId + ' //--</dtml-comment>\n'
newCustom += '\n'
newCustom += '<dtml-comment>--// EO '+ newId + ' //--</dtml-comment>\n'
self.setMetadictAttr( None, newId, newAcquired, newName, newType, newMandatory, newMultilang, newRepetitive, newCustom)
message += self.getZMILangStr('MSG_INSERTED')%newId

# Copy.
# -----
Expand Down Expand Up @@ -383,14 +370,22 @@ def manage_changeMetaProperties(self, btn, lang, REQUEST, RESPONSE=None):
error = str( sys.exc_info()[0])
if sys.exc_info()[1]:
error += ': ' + str( sys.exc_info()[1])
target = standard.url_append_params( target, { 'manage_tabs_error_message':error})
if target=='zmi_manage_tabs_message':
REQUEST.set('manage_tabs_error_message', error)
return self.zmi_manage_tabs_message(lang=lang, id=id, extra=extra)
else:
target = standard.url_append_params( target, { 'manage_tabs_error_message':error})

# Return with message.
target = standard.url_append_params( target, { 'lang':lang, 'id':id})
target = standard.url_append_params( target, extra)
if len( message) > 0:
message += ' (in '+str(int((time.time()-t0)*100.0)/100.0)+' secs.)'
target = standard.url_append_params( target, { 'manage_tabs_message':message})
return RESPONSE.redirect( target)
if target=='zmi_manage_tabs_message':
REQUEST.set('manage_tabs_message', message)
return self.zmi_manage_tabs_message(lang=lang, id=id, extra=extra)
else:
target = standard.url_append_params( target, { 'lang':lang, 'id':id})
target = standard.url_append_params( target, extra)
if len( message) > 0:
message += ' (in '+str(int((time.time()-t0)*100.0)/100.0)+' secs.)'
target = standard.url_append_params( target, { 'manage_tabs_message':message})
return RESPONSE.redirect( target)

################################################################################
3 changes: 2 additions & 1 deletion Products/zms/ZMSMetaobjManager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1201,7 +1201,8 @@ def manage_changeProperties(self, lang, btn='', key='all', REQUEST=None, RESPONS
if (len(attr_id) > 0 and len(newName) > 0 and len(newType) > 0) or newType in self.getMetadictAttrs():
message += self.setMetaobjAttr( id, None, attr_id, newName, newMandatory, newMultilang, newRepetitive, newType, newKeys, newCustom, newDefault)
message += self.getZMILangStr('MSG_INSERTED')%attr_id
# Lang-Dict.
# Insert (multiple) new language keys at once.
# Ref: _multilangmanager.py#L647
for key in REQUEST.form.keys():
if key.startswith('_lang_dict_key_'):
i = int(key[len('_lang_dict_key_'):])
Expand Down
72 changes: 46 additions & 26 deletions Products/zms/_multilangmanager.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,23 +506,28 @@ def manage_changeLanguages(self, lang, btn, REQUEST, RESPONSE):
# Change.
# -------
elif btn == 'BTN_SAVE':
newId = REQUEST.get('language_id','').strip()
# Change available languages.
for id in self.getLangIds():
if id != newId:
newLabel = REQUEST.get('%s_label'%id).strip()
newParent = REQUEST.get('%s_parent'%id).strip()
newManage = REQUEST.get('%s_manage'%id).strip()
self.setLanguage(id, newLabel, newParent, newManage)
# Insert
if len(newId) > 0:
newLabel = REQUEST.get('language_label').strip()
if len(self.getLangIds()) == 0:
newParent = ''
else:
newParent = REQUEST.get('language_parent').strip()
newManage = REQUEST.get('language_manage').strip()
self.setLanguage(newId, newLabel, newParent, newManage)

newLabel = REQUEST.get('%s_label'%id).strip()
newParent = REQUEST.get('%s_parent'%id).strip()
newManage = REQUEST.get('%s_manage'%id).strip()
self.setLanguage(id, newLabel, newParent, newManage)
# Insert new languages
# Ref: _multilangmanager.py#L647
for key in REQUEST.form.keys():
if key.startswith('_lang_id_'):
i = int(key[len('_lang_id_'):])
if REQUEST[key]:
newId = REQUEST[key].strip()
if newId not in self.getLangIds():
newLabel = REQUEST.get('_lang_label_%i'%i).strip()
if len(self.getLangIds()) == 0:
newParent = ''
else:
newParent = REQUEST.get('_lang_parent_%i'%i).strip()
newManage = REQUEST.get('_lang_manage_%i'%i).strip()
self.setLanguage(newId, newLabel, newParent, newManage)

# Return with message.
message = standard.url_quote(self.getZMILangStr('MSG_CHANGED'))
return RESPONSE.redirect('manage_customizeLanguagesForm?lang=%s&manage_tabs_message=%s'%(lang, message))
Expand Down Expand Up @@ -617,6 +622,8 @@ def getLangDict(self):
def manage_changeLangDictProperties(self, lang, btn, REQUEST, RESPONSE=None):
""" MultiLanguageManager.manage_changeLangDictProperties """

target = REQUEST.get('target', None)

# Delete.
# -------
if btn == 'BTN_DELETE':
Expand All @@ -639,14 +646,19 @@ def manage_changeLangDictProperties(self, lang, btn, REQUEST, RESPONSE=None):
enabled = lang_id not in d[key].get('acquired', [])
if enabled:
lang_dict[key][lang_id] = REQUEST['%s_value_%s'%(key, lang_id)].strip()
# Insert
key = REQUEST['_key'].strip()
if len(key) > 0:
lang_dict = self.get_lang_dict()
lang_dict[key] = {}
for lang_id in self.getLangIds():
lang_dict[key][lang_id] = REQUEST['_value_%s'%lang_id].strip()
self.set_lang_dict(lang_dict)
# Insert (multiple) new language keys at once.
# Ref: ZMSMetaobjManager.py#L1294
for key in REQUEST.form.keys():
if key.startswith('_lang_dict_key_'):
i = int(key[len('_lang_dict_key_'):])
if REQUEST[key]:
k = REQUEST[key].strip()
lang_dict[k] = {}
for key2 in REQUEST.form.keys():
if key2.startswith('_lang_dict_value_%i_'%i):
lang_id = key2[len('_lang_dict_value_%i_'%i):]
lang_dict[k][lang_id] = REQUEST[key2].strip()
self.set_lang_dict(lang_dict)

# Export.
# -------
Expand All @@ -667,7 +679,15 @@ def manage_changeLangDictProperties(self, lang, btn, REQUEST, RESPONSE=None):
message = self.getZMILangStr('MSG_IMPORTED')%('<i>%s</i>'%filename)

# Return with message.
message = standard.url_quote(self.getZMILangStr('MSG_CHANGED'))
return RESPONSE.redirect('manage_customizeLanguagesForm?lang=%s&manage_tabs_message=%s#langdict'%(lang, message))
if target=='zmi_manage_tabs_message':
if btn == 'BTN_DELETE' and ids:
message = '%s: %s'%(self.getZMILangStr('MSG_DELETED')%len(ids), id)
else:
message = self.getZMILangStr('MSG_CHANGED')
REQUEST.set('manage_tabs_message', message)
return self.zmi_manage_tabs_message(lang=lang, id=id, extra={}, REQUEST=REQUEST, RESPONSE=RESPONSE)
else:
message = standard.url_quote(self.getZMILangStr('MSG_CHANGED'))
return RESPONSE.redirect('manage_customizeLanguagesForm?lang=%s&manage_tabs_message=%s#langdict'%(lang, message))

################################################################################
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<table class="table table-bordered m-0">
<tbody>
<tr class="row_insert bg-light">
<td class="meta-sort"><span class="btn btn-primary btn-add"><i class="fas fa-plus"></i></td>
<td class="meta-sort"><span class="btn btn-secondary btn-add"><i class="fas fa-plus"></i></td>
<td class="meta-label"><input class="form-control" name="links_label__" placeholder="Enter Label..."/>
<td class="meta-url"><input class="form-control url-input" name="links_url__" placeholder="Select Url..."/>
</tr>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ZMS:
package = "com.zms.foundation"

# Revision
revision = "5.0.1"
revision = "5.0.2"

# Type
type = "ZMSDocument"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,29 +1,130 @@
<!-- ZMS.interface_permalinks -->

<div class="control-group" tal:define="zmscontext options/zmscontext">
<table class="table table-bordered m-0" title="Permalinks">
<table id="permalinks" class="table table-bordered m-0" title="Permalinks">
<tbody tal:define="prefix python:'%s.permalink.'%zmscontext.meta_id;
keys python:[x for x in zmscontext.getConfProperties() if x.startswith(prefix)];
dummy0 python:keys.sort();">
<tal:block tal:repeat="key keys">
<tr tal:define="id python:key[len(prefix):]">
<td class="meta-sort">
<div class="btn-group">
<a class="btn btn-secondary" href="javascript:;" tal:attributes="onclick python:'if (confirm(getZMILangStr(\'MSG_CONFIRM_DELOBJ\'))){$(this).parents(\'tr\').remove()}'; title python:here.getZMILangStr('BTN_DELETE')"
><i class="fas fa-times"></i></a>
</div><!-- .btn-group -->
</td>
<td class="meta-id"><input class="form-control form-control" tal:attributes="name python:'permalink_key_%s'%id; value id;"/></td>
<td class="meta-url form-group"><input class="form-control form-control url-input" tal:attributes="name python:'permalink_val_%s'%id; value python:zmscontext.getConfProperty(key)"/></td>
</tr>
</tal:block>
<tr class="row_insert">
<td class="meta-sort"><span class="btn btn-light"><i class="fas fa-plus"></i></td>
<td class="meta-id"><input class="form-control form-control" name="permalink_key__" placeholder="Enter Id..."/></td>
<td class="meta-url form-group"><input class="form-control form-control url-input" name="permalink_val__" placeholder="Select Url..."/></td>
</tr>
<tal:block tal:repeat="key keys">
<tr class="form-group"
tal:define="id python:key[len(prefix):]">
<td class="meta-sort">
<span class="btn btn-add mr-1 btn-secondary w-100" onclick="javascript:remove_row(this)"
tal:attributes="title python:here.getZMILangStr('BTN_DELETE')">
<i class="fas fa-times"></i>
</span>
</td>
<td class="meta-id"><input class="form-control" tal:attributes="name python:'permalink_key_%s'%id; value id;"/></td>
<td class="meta-url form-group"><input class="form-control url-input" tal:attributes="name python:'permalink_val_%s'%id; value python:zmscontext.getConfProperty(key)"/></td>
</tr>
</tal:block>
<tr class="row_insert form-group">
<td class="meta-sort text-right"><span class="btn btn-add mr-1 btn-secondary"><i class="fas fa-plus"></i></span></td>
<td class="meta-id"><input class="form-control form-control" name="permalink_key__" placeholder="Enter Id..."/></td>
<td class="meta-url form-group"><input class="form-control url-input" name="permalink_val__" placeholder="Select Url..."/></td>
</tr>
</tbody>
</table>
</div>
<style>
/* <!-- */
tr.row_insert > td > .btn-add {
width: 100%;
color:#333 !important;
}
tr.row_insert > td > .btn-add:hover {
color:white !important;
}
tr.row_insert > td:not(.meta-sort) > * {
opacity:.35
}
/* --> */
</style>

<script>
// <!--
/**
* Global vars.
*/
var table_id = 'permalinks';

function remove_row(context) {
// Remove row from table
$(context).closest('tr').hide('slow',function(){$(this).closest('tr').remove()});
// Set form as modified (ZMS.onChangeObjEvt)
$ZMI.set_form_modified(context)
}

/**
* Init (DOM-Ready)
*/
$(function(){
// New field set: initially disable inputs
$('tr.row_insert input').attr('disabled',true);

// ++++++++++++
// Add rows to tables #meta_properties on button click
// ++++++++++++
let new_row_counter = 0;

// Add click event function to add-buttons
$(".row_insert .btn-add").click(function(){
new_row_counter++;
// New field set: clone with enabled inputs
$('tr.row_insert input').attr('disabled',false);

// Where to insert the new row
let $where_insert = $(this).closest('tr');

// Set variables
let new_row_name = `new_row_${table_id}_${new_row_counter}`;
let new_btn_html = `
<span class="btn btn-secondary mr-1 w-100" style="color:#999"
title="Revoke new Permalink"
onclick="javascript:$(this).closest('tr').hide('slow',function(){$(this).closest('tr').remove()})">
<i class="fas fa-undo-alt"></i>
</span>
`;

// Clone(true) to get a deep copy including select options
let $new_row = $where_insert.clone(true);

// Process table cells of the clone like "old" row
$new_row.find('td').each(function() {
$(this).find('input').each(function() {
let tagname = $(this).prop('tagName');
let defname = $(this).attr('name')
let newval = $(this).val();
newname = `${defname}new${new_row_counter}`
newval = `new${new_row_counter}`;
$(this).attr('name',newname);
$(this).val(newval);
$(this).attr('placeholder',`new${new_row_counter}`);
// debugger;
if ( $(this).hasClass('url-input') ) {
// Replace td-content by the new input field
$(this).closest('.input-group').replaceWith(`<input class="form-control url-input" name="${newname}" placeholder="Select Url..."/>`);
};
});
});

// Process td:first-child of the clone
$new_row.find('td.meta-sort').html(new_btn_html);
$new_row.removeClass('row_insert').attr('id',new_row_name)

// Insert the new row
$new_row.insertBefore($where_insert);
// Set form as modified
$ZMI.set_form_modified($('.meta-id input',$new_row));
$ZMI.initUrlInput($("td.meta-url",$new_row));
// Reset the clone template
$where_insert.find('input:not([type="checkbox"]),select,textarea').each(function() {
$(this).val(undefined);
});
// New field set: reset to disabled inputs
$('tr.row_insert input').attr('disabled',true);
});

});
// -->
</script>
<!-- /ZMS.interface_permalinks -->
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

request = zmscontext.REQUEST
# permalinks
if 'permalink_key__' in request and 'permalink_val__' in request:
# permalink_keys = [k for k in request.keys() if k.startswith('permalink_key__')]
# permalink_vals = [k for k in request.keys() if k.startswith('permalink_val__')]
if request.get('form_modified',False):
prefix = '%s.permalink.'%zmscontext.meta_id
# delete all conf-properties
for key in [x for x in zmscontext.getConfProperties() if x.startswith(prefix)]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class ZMSTable:
package = "com.zms.foundation"

# Revision
revision = "5.1.0"
revision = "5.1.1"

# Type
type = "ZMSObject"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -621,13 +621,16 @@
}

function onKeyUpZMSTableDivContenteditable() {
if ($(this).text().length==0) {
$(this).addClass('placeholder');
var $this = $(this);
if ($this.text().length==0) {
$this.addClass('placeholder');
} else {
$(this).removeClass('placeholder');
$this.removeClass('placeholder');
}
var $textarea = $('textarea',$(this).prev());
$textarea.val($(this).html());
var $textarea = $('textarea',$this.prev());
$textarea.val($this.html());
const initialValue = $textarea.attr('data-initial-value');
$ZMI.set_form_modified($textarea,initialValue);
}
//-->
</script>
Expand Down Expand Up @@ -656,6 +659,7 @@
<script>
// <!--
$(function () {
$("textarea[id^='content_']").each((x) => $(this).attr('data-initial-value',$(this).val()));
$('table.table *, table.table *').on('contextmenu', function (e) {
$('table#table_cell_editor .table_cell_editable.current').removeClass('current');
let contextMenu = $('#context-menu');
Expand Down Expand Up @@ -774,7 +778,7 @@
<div class="ZMSTable">
<table style="width:100%" class="ZMSTable">
<tr>
<tal:block tal:content="structure python:'<%s title=\042onDblClick: %s\042 class=\042table_cell_editable\042>'%(['td',cell.get('tag','')][cell.get('tag','')!=''],here.getZMILangStr('ACTION_EDIT_CELL'))">start-tag</tal:block>
<tal:block tal:content="structure python:'<%s title=\042onDblClick: %s\042 class=\042table_cell_editable form-group\042>'%(['td',cell.get('tag','')][cell.get('tag','')!=''],here.getZMILangStr('ACTION_EDIT_CELL'))">start-tag</tal:block>
<input type="hidden" tal:attributes="id python:'tag_%i_%i'%(col_index,row_index); value python:cell.get('tag','')" />
<input type="hidden" tal:attributes="id python:'format_%i_%i'%(col_index,row_index); value cell_format" />
<div tal:attributes="id python:'input_%i_%i'%(col_index,row_index); class python:['','d-none'][richedit_preview]"
Expand Down
Loading

0 comments on commit 13dbd86

Please sign in to comment.