[TikiWiki-commits] [Git][tikiwiki/tiki][27.x] [BP][NEW] add tab delimiter to Tabular Import
"Jean-Marc Libs \(@jyhem\) via TikiWiki-cvs" <[email protected]> Fri, 17 Jul 2026 17:23:57 +0000
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <6a5a652d1d538_3819d0345768@gitlab-sidekiq-low-urgency-cpu-bound-v2-596569fc56-lfcj4.mail> |
Jean-Marc Libs pushed to branch 27.x at Tiki Wiki CMS Groupware / Tiki
Commits:
9c8cb945 by Jonny Bradley at 2026-07-17T17:17:42+00:00
[BP][NEW] add tab delimiter to Tabular Import
---
* [FIX] stupid typo, fixed in master as part of monster commit !4708 so was almost impossible to find - but did eventually!
Thanks @jyhem
* [NEW] add tab delimiter to Tabular Import
---
* Fix pipeline: remove superfluous whitespaces
* Update import_items csv form
* Take in account fields that may contains tabs or can be empty on tsv import
* Tabular import: refactor and improve .tsv import, handling data that may have ',' or '"' inside
* Ask for separator when "Import" is clicked in tabular
* [NEW] Importing data from CSV files separated by commas, semicolons, or tabs
* [NEW] add tab delimiter to Tabular Import
See merge request tikiwiki/tiki!5575
(cherry picked from commit 88ccb0003f50ef233ab4e0018f1346f39bb17048)
See merge request tikiwiki/tiki!10660
- - - - -
7 changed files:
- lib/core/Services/Tracker/Controller.php
- lib/core/Services/Tracker/TabularController.php
- lib/core/Services/Tracker/Utilities.php
- lib/core/Tracker/Tabular/Schema.php
- templates/tabular/create_tracker.tpl
- templates/tabular/import_csv.tpl
- templates/tracker/import_items.tpl
Changes:
=====================================
lib/core/Services/Tracker/Controller.php
=====================================
@@ -2706,6 +2706,8 @@ class Services_Tracker_Controller
public function action_import_items($input)
{
$trackerId = $input->trackerId->int();
+ $separator = $input->separator->text();
+ $fileIsTsv = ! ($separator == "," || $separator == ';');
$perms = Perms::get('tracker', $trackerId);
if (! $perms->admin_trackers) {
@@ -2723,6 +2725,11 @@ class Services_Tracker_Controller
throw new Services_Exception(tr('File upload failed.'), 400);
}
+ if ($fileIsTsv) {
+ Services_Tracker_Utilities::parseTsvContentToCsv('importfile');
+ $separator = ',';
+ }
+
if (! $fp = @ fopen($_FILES['importfile']['tmp_name'], "rb")) {
throw new Services_Exception(tr('Uploaded file could not be read.'), 500);
}
@@ -2734,7 +2741,7 @@ class Services_Tracker_Controller
($input->add_items->int() !== 1), // checkbox is "Create as new items" - param is replace_rows
$input->dateFormat->text(),
$input->encoding->text(),
- $input->separator->text(),
+ $separator,
$input->updateLastModif->int(),
$input->convertItemLinkValues->int()
);
=====================================
lib/core/Services/Tracker/TabularController.php
=====================================
@@ -543,7 +543,8 @@ class Services_Tracker_TabularController
{
$lib = TikiLib::lib('tabular');
$info = $lib->getInfo($input->tabularId->int());
- $trackerId = $info['trackerId'];
+ $separator = $input->separator->text();
+ $fileIsTsv = ! ($separator == "," || $separator == ';');
Services_Exception_Denied::checkObject('tiki_p_tabular_import', 'tabular', $info['tabularId']);
@@ -553,7 +554,11 @@ class Services_Tracker_TabularController
$done = false;
if ($_SERVER['REQUEST_METHOD'] == 'POST' && is_uploaded_file($_FILES['file']['tmp_name'])) {
- $source = $schema->getSource($_FILES['file']['tmp_name']);
+ if ($fileIsTsv) {
+ Services_Tracker_Utilities::parseTsvContentToCsv('file');
+ $separator = ',';
+ }
+ $source = $schema->getSource($_FILES['file']['tmp_name'], $separator);
$writer = new TrackerWriter();
return TikiLib::lib('tiki')->allocate_extra(
@@ -919,7 +924,14 @@ class Services_Tracker_TabularController
if (is_uploaded_file($_FILES['file']['tmp_name'])) {
try {
- $delimiter = $input->delimiter->text() == 'comma' ? ',' : ';';
+ $delimiter = ',';
+
+ if ($input->delimiter->text() == 'semicolon') {
+ $delimiter = ';';
+ } elseif ($input->delimiter->text() == 'tab') {
+ $delimiter = "\t";
+ }
+
$source = new CsvSource($schema, $_FILES['file']['tmp_name'], $delimiter);
$writer = new TrackerWriter();
$done = $writer->write($source);
=====================================
lib/core/Services/Tracker/Utilities.php
=====================================
@@ -722,4 +722,41 @@ EXPORT;
$currency = new Math_Formula_Currency($data['amount'], $data['currency'], $rates);
return $currency->convertTo($defaultCurrency)->getAmount();
}
+
+ public static function parseTsvContentToCsv($filename)
+ {
+ $fileContent = file_get_contents($_FILES[$filename]['tmp_name']);
+ $rows = explode("\n", $fileContent);
+ $csvRows = [];
+
+ foreach ($rows as $row) {
+ if (trim($row) === '') {
+ continue;
+ }
+ // since field may have comma or quotes or tab in it
+ $fields = str_getcsv($row, "\t");
+ if (substr($row, -1) === "\t") {
+ $fields[] = '';
+ }
+ $pFields = []; // escape processed fields
+
+ foreach ($fields as $field) {
+ $field = $field ?? '';
+ $hasCommaOrQuoteOrTab = (
+ strpos($field, ',') !== false ||
+ strpos($field, '"') !== false ||
+ strpos($field, "\t") !== false
+ );
+
+ if ($hasCommaOrQuoteOrTab) {
+ $pFields[] = '"' . str_replace('"', '""', $field) . '"';
+ } else {
+ $pFields[] = $field;
+ }
+ }
+ $csvRows[] = implode(',', $pFields);
+ }
+ $_FILES[$filename]['tmp_name'] = tempnam(sys_get_temp_dir(), 'modified_');
+ file_put_contents($_FILES[$filename]['tmp_name'], implode("\n", $csvRows));
+ }
}
=====================================
lib/core/Tracker/Tabular/Schema.php
=====================================
@@ -392,7 +392,7 @@ class Schema
return $writer;
}
- public function getSource($fileName)
+ public function getSource($fileName, $separator = ",")
{
switch ($this->getFormat()) {
case 'json':
@@ -401,7 +401,7 @@ class Schema
case 'ical':
return new Source\IcalSource($this, $fileName, $this->getEncoding());
default:
- return new Source\CsvSource($this, $fileName, ',', $this->getEncoding());
+ return new Source\CsvSource($this, $fileName, $separator, $this->getEncoding());
}
}
=====================================
templates/tabular/create_tracker.tpl
=====================================
@@ -33,6 +33,7 @@
<select class="form-select file-delimiter">
<option value="comma" selected>{tr}Comma (,){/tr}</option>
<option value="semicolon">{tr}Semicolon (;){/tr}</option>
+ <option value="tab">{tr}Tab (\t){/tr}</option>
</select>
<input type="hidden" id="delimiter" name="delimiter" value="comma">
</div>
@@ -40,7 +41,7 @@
<div class="tiki-form-group row file-container">
<label class="col-form-label col-sm-3" for="file">{tr}File{/tr}</label>
<div class="col-sm-9">
- <input type="file" name="file" id="file" accept="text/csv" class="form-control" required>
+ <input type="file" name="file" id="file" accept=".csv, .tsv, text/csv, text/tsv" class="form-control" required>
<div id="file-size-error" class="alert alert-danger mt-3" style="display:none">
{tr _0=$config.upload_max_filesize}<strong>Error:</strong> Selected file has <span id="file-size"></span> bytes. The max file size upload is %0 bytes.{/tr}
</div>
@@ -192,7 +193,15 @@
$('.file-delimiter').on('change', function(e) {
var currentValue = $(this).val();
- delimiter = ((currentValue == 'comma') ? ',' : ';');
+
+ if (currentValue == 'comma') {
+ delimiter = ',';
+ } else if (currentValue == 'semicolon') {
+ delimiter = ';';
+ } else if (currentValue == 'tab') {
+ delimiter = '\t';
+ }
+
delimiterElement.val(currentValue);
fileSelect.trigger("change");
});
@@ -221,9 +230,12 @@
reader.onload = function (e) {
if (delimiter == ';') {
var rows = Plotly.d3.dsv(';').parse(e.target.result);
+ } else if (delimiter == '\t') {
+ var rows = Plotly.d3.dsv('\t').parse(e.target.result);
} else {
var rows = Plotly.d3.csv.parse(e.target.result);
}
+
var columns = Object.keys(rows[0]);
for(i = 0; i < columns.length; i++) {
=====================================
templates/tabular/import_csv.tpl
=====================================
@@ -47,7 +47,15 @@
{elseif $format eq 'ical'}
{createFileInput format='ical' label='iCal File' fileInputId='icalInputFile' fileAccept='text/calendar'}
{else}
- {createFileInput format='csv' label='CSV File' fileInputId='inputFile' fileAccept='text/csv'}
+ {createFileInput format='csv' label='CSV File' fileInputId='inputFile' fileAccept='text/csv, .tsv'}
+ <div class="form-group">
+ <label for="separator">{tr}Select separator:{/tr}</label>
+ <select name="separator" class="form-select" aria-label="CSV File delimiter">
+ <option value=",">{tr}Comma{/tr}(,)</option>
+ <option value=";">{tr}Semicolon{/tr}(;)</option>
+ <option value="\t">{tr}Tab{/tr}(\t)</option>
+ </select>
+ </div>
{/if}
<div class="submit">
<input class="btn btn-primary" type="submit" value="{tr}Import{/tr}">
=====================================
templates/tracker/import_items.tpl
=====================================
@@ -51,8 +51,12 @@
</select>
</div>
<div class="mb-3 row mx-0">
- <label for="separator">{tr}Separator{/tr}</label>
- <input type="text" name="separator" value="," size="2" class="form-control">
+ <label for="separator">{tr}Select separator:{/tr}</label>
+ <select name="separator" class="form-select file-delimiter">
+ <option value="," selected>{tr}Comma{/tr}(,)</option>
+ <option value=";">{tr}Semicolon{/tr}(;)</option>
+ <option value="\t">{tr}Tab{/tr}(\t)</option>
+ </select>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" name="add_items" id="add_items" value="1">
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/9c8cb945252a0a2716b83ed706217e041eca984c
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/9c8cb945252a0a2716b83ed706217e041eca984c
You're receiving this email because of your account on gitlab.com. Manage all notifications: https://gitlab.com/-/profile/notifications | Help: https://gitlab.com/help
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs