Index: openacs-4/packages/xowiki/tcl/repeat-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/tcl/repeat-procs.tcl,v diff -u -r1.5.2.7 -r1.5.2.8 --- openacs-4/packages/xowiki/tcl/repeat-procs.tcl 6 Dec 2016 11:19:07 -0000 1.5.2.7 +++ openacs-4/packages/xowiki/tcl/repeat-procs.tcl 12 Dec 2016 10:52:38 -0000 1.5.2.8 @@ -13,7 +13,6 @@ # TODO: # - improve styling (e.g. remove/deactivate controls for # addition/deletion, when min/max is reached) - # - allow max to be open-ended (see also "addItem" in .js) # - test for more input types # - maybe deactivate container display for "repeat=1..1" @@ -74,7 +73,7 @@ } repeatContainer instproc initialize {} { ::xo::Page requireJS "/resources/xowiki/repeat.js" - ::xo::Page requireJS "/resources/xowiki/jquery/jquery.min.js" + ::xo::Page requireJS "/resources/ajaxhelper/jquery/jquery-1.11.1.min.js" if {[my exists __initialized_repeat]} {return} next @@ -99,7 +98,8 @@ # Add max content items (1 .. max) and build form fields # set formAction [${:object} form_parameter __form_action {}] - if {$formAction eq ""} { + # TODO: we use for the time being the code for dynamic repeat field + if {0 && $formAction eq ""} { # # The form field is in input mode; as long there is no js # support do incrementally add form fields in js, we have to @@ -147,7 +147,7 @@ # lassign [my item_spec] isRequired itemSpec set componentItemSpec [my component_item_spec $i $itemSpec $isRequired] - ns_log notice "dynamic repeat field: add component on the fly: $componentItemSpec" + #ns_log notice "dynamic repeat field: add component on the fly: $componentItemSpec" my add_component $componentItemSpec } @@ -214,7 +214,7 @@ # without labels for the contained items. # html::fieldset [my get_attributes id {CSSclass class}] { - set i 1 + set i 0 my instvar min max name set clientData "{'min':$min,'max':$max, 'name':'$name'}" set CSSclass "[my form_widget_CSSclass] repeatable" @@ -231,9 +231,7 @@ foreach c [my components] { set atts [list class $CSSclass] lappend atts data-repeat $clientData - set elementIsPrototype [string match "*.0*" [$c name]] - #ns_log notice "[$c name] isDisabled $containerIsDisabled containerIsPrototype $containerIsPrototype elementIsPrototype $elementIsPrototype" - if {$i > $nrItems || $containerIsPrototype || $elementIsPrototype} { + if {$i == 0 || $i >= $nrItems} { lappend atts style "display: none;" } ::html::div $atts { @@ -266,7 +264,7 @@ } template::add_event_listener \ -id $add_id \ - -script [subst {xowiki.repeat.addItem(this,\"$clientData\");}] + -script [subst {xowiki.repeat.newItem(this,\"$clientData\");}] } } } Index: openacs-4/packages/xowiki/www/resources/repeat.js =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/xowiki/www/resources/repeat.js,v diff -u -r1.3.2.1 -r1.3.2.2 --- openacs-4/packages/xowiki/www/resources/repeat.js 6 Dec 2016 11:32:46 -0000 1.3.2.1 +++ openacs-4/packages/xowiki/www/resources/repeat.js 12 Dec 2016 10:52:38 -0000 1.3.2.2 @@ -25,7 +25,7 @@ /* // IPAD HACK START // for ipad we have to set the contenteditiable to true for the ckeditor inline if it is false - var ck_editors = $(currentItem.find('.xowiki-ckeditor.cke_editable.cke_editable_inline.cke_contents_ltr')); + var ck_editors = $(currentItem).find('.xowiki-ckeditor.cke_editable.cke_editable_inline.cke_contents_ltr'); for (var k = 0; k < ck_editors.length; k++) { if ($(ck_editors[k]).attr('contenteditable') == 'false') { console.log('we have to set the contenteditable to true'); @@ -37,8 +37,8 @@ break; } } - - $(".xowiki-ckeditor", currentItem).each(function (i,e) { + + $(".xowiki-ckeditor, .datetimepicker", currentItem).each(function (i,e) { //console.debug('load ckeditor' +e.id); if ($(e).is(':visible')) { var functionname = 'load_' + e.id; @@ -54,12 +54,102 @@ // and renaming the field like in delItems. We have to care as // well in RepeatContainer.initialize() to check, how many // subcomponents must be generated in advance (not max as now). - console.log('could add one more, j ' + j); - console.info(data); + //console.log('could add one more, j ' + j); + //console.info(data); return false; }; /* + * newItem + * + */ +xowiki.repeat.newItem = function(e, json) { + + var data = eval("(" + json + ')'); + var item = e; + + var stats = this.itemStats(item); + //console.info(item); + console.info(stats); + //console.info(data); + + var current = stats['current']; + var last = stats['visible']; + var items = item.parentNode.children; + var divs = stats['divs']; + + //console.info(divs); + + last = last + 1; + //console.log('last:' + last); + + if (last >= data.max) { + // this is the final item: hide add item button + e.style.display = 'none'; + } + if (last > data.max) { + // this is the final item: hide add item button + e.style.display = 'none'; + return; + } + + // We add an empty item at the end to force back-reporting of + // empty content to the instance variables. Otherwise the old + // content would stay. This means, that we should never physically + // delete items. + var clone = divs[0].cloneNode(true); + divs.push(clone); + divs[0].parentNode.insertBefore(clone,divs[last-1].nextSibling); + + var templateid = item.parentNode.id + '.0'; + var newid = item.parentNode.id + '.' + last; + + // due to the fact that the ckeditor are using the ids for reloading we have to recycle them (and for the other cases it doesn't hurt) + this.renameIds(divs[last],templateid,newid); + + // ckeditor releoding + // we are selecting all ckeditor intances which are at the same level and below of the current item + // so we can be sure that in case of a compound field all editors are reloaded correctly + // .xowiki-ckeditor --> normaler ckeditor + // .xowiki-ckeditor.ckeip --> inplace editor + // .xowiki-ckeditor.cke_editable.cke_editable_inline.cke_contents_ltr --> inline editing + var ckclasses = [".xowiki-ckeditor", + ".xowiki-ckeditor.ckeip", + ".xowiki-ckeditor.cke_editable.cke_editable_inline.cke_contents_ltr"]; + for (var i = 0; i < ckclasses.length; i++) { + var ck_editors = $(item.parentNode).find(ckclasses[i]); + for (var j = 0; j < ck_editors.length; j++) { + var idofeditor = ck_editors[j].id; + console.log('reloading ckeditor for id: ' + idofeditor); + var functionname = 'load_' + idofeditor; + try { + window[functionname](); + } catch(err) { + console.log('function: ' + functionname + ' not found maybe it is a template: ' + err); + } + } + } + + //console.log("RENAME LAST"); + this.renameItem(divs[last], divs[last], + data['name'] + '.0', data['name'] + '.' + (last)); + + divs[last].style.display = 'block'; + + // force refresh of tree + item.parentNode.style.display = 'none'; + item.parentNode.style.display = 'block'; + + // make sure add item link is visible + //$(item.parentNode).children(".repeat-add-link").show(); + + this.registerAddDeleteAction(divs[last]); + + +}; + + +/* * itemStats * * Collect statistics of a repeatable container. This function computes @@ -230,8 +320,21 @@ //console.log("RENAME INNER"); this.renameItem(divs[j], divs[j], data['name'] + '.' + (k), data['name'] + '.' + (j)); + + this.registerAddDeleteAction(divs[j]); } }; + + // make sure add item link is visible + $(item.parentNode).children(".repeat-add-link").show(); + + // delet the node until we are reaching the minimum + if (stats['visible'] > data['min']) { + // delete the last node + divs[last].parentNode.removeChild(divs[last]); + } + + /* // We add an empty item at the end to force back-reporting of // empty content to the instance variables. Otherwise the old // content would stay. This means, that we should never physically @@ -280,6 +383,9 @@ // make sure add item link is visible $(item.parentNode).children(".repeat-add-link").show(); + this.registerAddDeleteAction(divs[last]); + */ + //console.log('final html ' + item.parentNode.innerHTML); return false; }; @@ -316,6 +422,38 @@ } /* + * reRegisterAddDeleteAction + * + * ReRegister events for add and delete urls + */ +xowiki.repeat.registerAddDeleteAction = function(element) { + var action_links = $(element).find(".repeat-del-link"); + for (var j = 0; j < action_links.length; j++) { + var e = document.getElementById(action_links[j].id); + if (e !== null) { + var data = e.parentNode.getAttribute('data-repeat'); + e.addEventListener('click', function (event) { + event.preventDefault(); + xowiki.repeat.delItem(this,data); + }, false); + } + } + + var action_links = $(element).find(".repeat-add-link"); + for (var j = 0; j < action_links.length; j++) { + var e = document.getElementById(action_links[j].id); + if (e !== null) { + var data = e.previousElementSibling.getAttribute('data-repeat'); + e.addEventListener('click', function (event) { + event.preventDefault(); + xowiki.repeat.newItem(this,data); + }, false); + } + } + +} + +/* * Local variables: * mode: Javascript * indent-tabs-mode: nil