Skip to content

Commit

Permalink
Implement feedback from PR at Joomla;
Browse files Browse the repository at this point in the history
- Use a <template> HTML element for the template of the subform rows,
  not a url encoded string inside of a <script> element.
- Fix code style errors reported by phpcs.
- Make the fixing of the unique attributes (name, id, etc) of input elements
  of nested subform rows more errorprone, using the same method as the main
  subform row.
- Manually add a minified version of the javascript file.
  • Loading branch information
Rene Pasing committed Sep 12, 2017
1 parent 09499ed commit c449f1f
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 111 deletions.
90 changes: 44 additions & 46 deletions layouts/joomla/form/field/subform/repeatable-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,66 +67,64 @@
);
}
?>

<div class="row-fluid">
<div class="subform-repeatable-wrapper subform-table-layout subform-table-sublayout-<?php echo $sublayout; ?>">
<div class="subform-repeatable"
<div
class="subform-repeatable"
data-bt-add="a.group-add-<?php echo $unique_subform_id; ?>"
data-bt-remove="a.group-remove-<?php echo $unique_subform_id; ?>"
data-bt-move="a.group-move-<?php echo $unique_subform_id; ?>"
data-repeatable-element="tr.subform-repeatable-group-<?php echo $unique_subform_id; ?>"
data-rows-container="tbody.rows-container-<?php echo $unique_subform_id; ?>"
data-minimum="<?php echo $min; ?>" data-maximum="<?php echo $max; ?>">
data-minimum="<?php echo $min; ?>" data-maximum="<?php echo $max; ?>"
>
<table class="adminlist table table-striped table-bordered">
<thead>
<tr>
<?php echo $table_head; ?>
<?php if (!empty($buttons)) : ?>
<th style="width:8%;">
<?php if (!empty($buttons['add'])) : ?>
<div class="btn-group">
<a class="btn btn-mini button btn-success group-add-<?php echo $unique_subform_id; ?>">
<span class="icon-plus"></span>
</a>
</div>
<?php endif; ?>
</th>
<?php endif; ?>
</tr>
</thead>
<tbody class="rows-container-<?php echo $unique_subform_id; ?>">
<?php foreach ($forms as $k => $form):
echo $this->sublayout(
$sublayout,
array(
'form' => $form,
'basegroup' => $fieldname,
'group' => $fieldname . $k,
'buttons' => $buttons,
'unique_subform_id' => $unique_subform_id,
)
);
endforeach; ?>
</tbody>
</table>

<table class="adminlist table table-striped table-bordered">
<thead>
<tr>
<?php echo $table_head; ?>
<?php if (!empty($buttons)) : ?>
<th style="width:8%;">
<?php if (!empty($buttons['add'])) : ?>
<div class="btn-group">
<a class="btn btn-mini button btn-success group-add-<?php echo $unique_subform_id; ?>">
<span class="icon-plus"></span>
</a>
</div>
<?php endif; ?>
</th>
<?php endif; ?>
</tr>
</thead>
<tbody class="rows-container-<?php echo $unique_subform_id; ?>">
<?php foreach ($forms as $k => $form):
echo $this->sublayout(
<?php if ($multiple) : ?>
<template class="subform-repeatable-template-section"><?php echo trim(
$this->sublayout(
$sublayout,
array(
'form' => $form,
'form' => $tmpl,
'basegroup' => $fieldname,
'group' => $fieldname . $k,
'group' => $fieldname . 'X',
'buttons' => $buttons,
'unique_subform_id' => $unique_subform_id,
)
);
endforeach; ?>
</tbody>
</table>
<?php if ($multiple) : ?>
<script type="text/subform-repeatable-template-section" class="subform-repeatable-template-section">
<?php /** Do a rawurlencode to not tamper with HTML elements, especially with
* nested subforms (subform in subform), this might contain a
* </script> tag, which else blows up our markup. */ ?>
<?php echo rawurlencode(trim($this->sublayout(
$sublayout,
array(
'form' => $tmpl,
'basegroup' => $fieldname,
'group' => $fieldname . 'X',
'buttons' => $buttons,
'unique_subform_id' => $unique_subform_id,
)
))); ?>
</script>
<?php endif; ?>
)
); ?></template>
<?php endif; ?>
</div>
</div>
</div>
28 changes: 13 additions & 15 deletions layouts/joomla/form/field/subform/repeatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@
data-bt-remove="a.group-remove-<?php echo $unique_subform_id; ?>"
data-bt-move="a.group-move-<?php echo $unique_subform_id; ?>"
data-repeatable-element="div.subform-repeatable-group-<?php echo $unique_subform_id; ?>"
data-minimum="<?php echo $min; ?>" data-maximum="<?php echo $max; ?>">
data-minimum="<?php echo $min; ?>" data-maximum="<?php echo $max; ?>"
>

<?php if (!empty($buttons['add'])) : ?>
<div class="btn-toolbar">
Expand All @@ -69,21 +70,18 @@
endforeach;
?>
<?php if ($multiple) : ?>
<script type="text/subform-repeatable-template-section" class="subform-repeatable-template-section">
<?php /** Do a rawurlencode to not tamper with HTML elements, especially with
* nested subforms (subform in subform), this might contain a
* </script> tag, which else blows up our markup. */ ?>
<?php echo rawurlencode(trim($this->sublayout(
$sublayout,
array(
'form' => $tmpl,
'basegroup' => $fieldname,
'group' => $fieldname . 'X',
'buttons' => $buttons,
'unique_subform_id' => $unique_subform_id,
<template class="subform-repeatable-template-section"><?php echo trim(
$this->sublayout(
$sublayout,
array(
'form' => $tmpl,
'basegroup' => $fieldname,
'group' => $fieldname . 'X',
'buttons' => $buttons,
'unique_subform_id' => $unique_subform_id,
)
)
))); ?>
</script>
); ?></template>
<?php endif; ?>
</div>
</div>
Expand Down
10 changes: 6 additions & 4 deletions libraries/joomla/form/fields/subform.php
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,13 @@ protected function getInput()
$data['fieldname'] = $this->fieldname;
$data['groupByFieldset'] = $this->groupByFieldset;

// For each rendering process of a subform element, we want to have a
// separate unique subform id present to could distinguish the eventhandlers
// regarding adding/moving/removing rows from nested subforms from their parents.
/**
* For each rendering process of a subform element, we want to have a
* separate unique subform id present to could distinguish the eventhandlers
* regarding adding/moving/removing rows from nested subforms from their parents.
*/
static $unique_subform_id = 0;
$data['unique_subform_id'] = ('sr-' . $unique_subform_id++);
$data['unique_subform_id'] = ('sr-' . ($unique_subform_id++));

// Prepare renderer
$renderer = $this->getRenderer($this->layout);
Expand Down
70 changes: 25 additions & 45 deletions media/system/js/subform-repeatable-uncompressed.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,8 @@
$.subformRepeatable.prototype.prepareTemplate = function(){
// create from template
if (this.options.rowTemplateSelector) {
var tmplElement = this.$container.find(this.options.rowTemplateSelector).last()[0] || {};
// do a decodeURIComponent() here, because the text value is url encoded
// to make sure we dont destroy our markup
this.template = decodeURIComponent($.trim(tmplElement.text || tmplElement.textContent)); //(text || textContent) is IE8 fix
// Find the template element and get its HTML content, this is our template.
this.template = $.trim(this.$container.find(this.options.rowTemplateSelector).html()) || '';
}
// create from existing rows
else {
Expand Down Expand Up @@ -144,13 +142,18 @@
$row.remove();
};

// fix names ind id`s for field that in $row
$.subformRepeatable.prototype.fixUniqueAttributes = function($row, count){
var group = $row.attr('data-group'),// current group name
basename = $row.attr('data-base-name'), // group base name, without count
count = count || 0,
// fix names and id`s for fields in $row
$.subformRepeatable.prototype.fixUniqueAttributes = function(
$row, // the jQuery object to do fixes in
count, // existing count of rows
group, // current group name, e.g. 'optionsX'
basename // group base name, without count, e.g. 'options'
) {
var group = (typeof group === 'undefined' ? $row.attr('data-group') : group),
basename = (typeof basename === 'undefined' ? $row.attr('data-base-name') : basename),
count = (typeof count === 'undefined' ? 0 : count),
countnew = Math.max(this.lastRowNum, count),
groupnew = basename + countnew; // new group name
groupnew = basename + countnew;

this.lastRowNum = countnew;
$row.attr('data-group', groupnew);
Expand Down Expand Up @@ -203,43 +206,20 @@
$row.find('label[for="' + forOldAttr + '"]').attr('for', idNew);
}

// Create 2 strings: basename + old group, and basename + new group
var search = '[' + basename + '][' + group + ']',
replace = '[' + basename + '][' + groupnew + ']';
// Does our row still contain the basename + old group? This should not happen!
if ($row.html().indexOf(search) !== -1) {
console.log('Old basename+group still existant in $row html');
}
// Recursively replace our basename + old group with basename + new group
// inside of nested subform template elements.
this.recursiveReplaceNested($row, search, replace);
};

$.subformRepeatable.prototype.recursiveReplaceNested = function($row, search, replace) {
// Try to find the row remplate selector in $row
/**
* Recursively replace our basename + old group with basename + new group
* inside of nested subform template elements. First we try to find such
* template elements, then we iterate through them and do the same replacements
* that we have made here inside of them.
*/
var nestedTemplates = $row.find(this.options.rowTemplateSelector);
if (nestedTemplates.length < 1) {
return;
}
// If we found it, iterate over the found ones (might be more than one!)
for (var i = 0; i < nestedTemplates.length; i++) {
// Get the element
var nestedTemplate = $(nestedTemplates[i]);
// Do our replacement; the HTML content is urlencoded, so we urlencode
// our search/replace parameters, also because we then don't need to
// regexp escape the search parameter (we are using regexp to globally replace).
nestedTemplate.html(nestedTemplate.html().replace(
new RegExp(encodeURIComponent(search), 'g'),
encodeURIComponent(replace)
));
// URI decode its HTML content to could have access to deeper nested ones
var nestedTemplateContent = decodeURIComponent(nestedTemplate.html());
// Create a new element out of it
var nestedElement = $(nestedTemplateContent);
// And recursively do the replacements more times
this.recursiveReplaceNested(nestedElement, search, replace);
// Now re-insert the replaced html content into our element
nestedTemplate.html(encodeURIComponent(nestedElement.prop('outerHTML')));
// Get the nested templates content (as DocumentFragment) and cast it
// to a jQuery object
var nestedTemplate = $($(nestedTemplates[i]).prop('content'));
// Fix the attributes for this nested template.
this.fixUniqueAttributes(nestedTemplate, count, group, basename);
}
};

Expand Down Expand Up @@ -312,7 +292,7 @@
repeatableElement: ".subform-repeatable-group",
// selector for the row template element with URL-encoded template inside it,
// must *NOT* be unique per nested subform!
rowTemplateSelector: 'script.subform-repeatable-template-section',
rowTemplateSelector: 'template.subform-repeatable-template-section',
// container for rows, same as main container by default
rowsContainer: null
};
Expand Down
Loading

0 comments on commit c449f1f

Please sign in to comment.