Skip to content

Commit e0521ca

Browse files
committed
Merge remote-tracking branch 'origin/2.2' into 2.x
2 parents ee729e8 + 23fc32c commit e0521ca

File tree

16 files changed

+297
-153
lines changed

16 files changed

+297
-153
lines changed

public/js/pimcore/asset/tree.js

Lines changed: 91 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -361,61 +361,97 @@
361361
});
362362
}.bind(this);
363363

364-
if(dataTransfer["items"] && dataTransfer.items[0] && dataTransfer.items[0].webkitGetAsEntry) {
365-
// chrome
366-
var traverseFileTree = function (item, path) {
367-
path = path || "";
368-
if (item.isFile) {
369-
// Get file
370-
item.file(function (file) {
371-
doFileUpload(file, path);
372-
}.bind(this));
373-
} else if (item.isDirectory) {
374-
// Get folder contents
375-
var dirReader = item.createReader();
376-
dirReader.readEntries(function (entries) {
377-
for (var i = 0; i < entries.length; i++) {
378-
traverseFileTree(entries[i], path + item.name + "/");
379-
}
380-
});
381-
}
382-
}.bind(this);
383-
384-
for (var i = 0; i < dataTransfer.items.length; i++) {
385-
// webkitGetAsEntry is where the magic happens
386-
var item = dataTransfer.items[i].webkitGetAsEntry();
387-
if (item) {
388-
traverseFileTree(item);
389-
}
390-
}
391-
} else if(dataTransfer["files"]) {
392-
// default filelist upload
393-
for (var i=0; i<dataTransfer["files"].length; i++) {
394-
file = dataTransfer["files"][i];
395-
396-
if (window.FileList && file.name && file.size) { // check for size (folder has size=0)
397-
doFileUpload(file);
398-
} else if (!empty(file.type) && file.size < 1) { //throw error for 0 byte file
399-
Ext.MessageBox.alert(t('error'), t('error_empty_file_upload'));
400-
win.close();
401-
}
402-
}
403-
404-
// if no files are uploaded (doesn't match criteria, ...) close the progress win immediately
405-
if(!this.activeUploads) {
406-
win.close();
407-
}
408-
}
409-
410-
// check in 5 sec. if there're active uploads
411-
// if not, close the progressbar
412-
// this is necessary since the folder upload is async, so we don't know if the progress is
413-
// necessary or not, not really perfect solution, but works as it should
414-
window.setTimeout(function () {
415-
if(!this.activeUploads) {
416-
win.close();
417-
}
418-
}.bind(this), 5000);
364+
if (dataTransfer["items"] && dataTransfer.items[0] && dataTransfer.items[0].webkitGetAsEntry) {
365+
// Chrome-specific folder support
366+
const MAX_DEPTH = 20;
367+
const queue = [];
368+
369+
for (let i = 0; i < dataTransfer.items.length; i++) {
370+
const item = dataTransfer.items[i].webkitGetAsEntry();
371+
if (item) {
372+
queue.push({ item, path: "", depth: 0 });
373+
}
374+
}
375+
376+
const processNext = () => {
377+
if (queue.length === 0) return;
378+
379+
const { item, path, depth } = queue.shift();
380+
381+
if (depth > MAX_DEPTH) {
382+
setTimeout(processNext, 0);
383+
return;
384+
}
385+
386+
if (item.isFile) {
387+
item.file(
388+
(file) => {
389+
doFileUpload(file, path);
390+
setTimeout(processNext, 0);
391+
},
392+
() => {
393+
setTimeout(processNext, 0);
394+
}
395+
);
396+
} else if (item.isDirectory) {
397+
const dirReader = item.createReader();
398+
399+
const readEntries = () => {
400+
dirReader.readEntries(
401+
(entries) => {
402+
if (entries.length === 0) {
403+
setTimeout(processNext, 0);
404+
return;
405+
}
406+
407+
for (let i = 0; i < entries.length; i++) {
408+
queue.push({
409+
item: entries[i],
410+
path: path + item.name + "/",
411+
depth: depth + 1,
412+
});
413+
}
414+
415+
readEntries();
416+
},
417+
() => {
418+
setTimeout(processNext, 0);
419+
}
420+
);
421+
};
422+
423+
readEntries();
424+
} else {
425+
setTimeout(processNext, 0);
426+
}
427+
};
428+
429+
processNext();
430+
} else if (dataTransfer["files"]) {
431+
432+
// Fallback: flat file list
433+
for (let i = 0; i < dataTransfer["files"].length; i++) {
434+
const file = dataTransfer["files"][i];
435+
436+
if (window.FileList && file.name && file.size) {
437+
doFileUpload(file);
438+
} else if (!empty(file.type) && file.size < 1) {
439+
Ext.MessageBox.alert(t('error'), t('error_empty_file_upload'));
440+
win.close();
441+
}
442+
}
443+
444+
if (!this.activeUploads) {
445+
win.close();
446+
}
447+
}
448+
449+
// Close progress window if no uploads detected after delay
450+
setTimeout(function () {
451+
if (!this.activeUploads) {
452+
win.close();
453+
}
454+
}.bind(this), 5000);
419455
},
420456

421457
getTreeNodeListeners: function () {

public/js/pimcore/element/helpers/gridColumnConfig.js

Lines changed: 60 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -435,34 +435,63 @@ pimcore.element.helpers.gridColumnConfig = {
435435

436436
editor.fieldConfig.width = 300;
437437

438-
const formPanel = Ext.create('Ext.form.Panel', {
439-
xtype: "form",
440-
border: false,
441-
items: [editor.getLayoutEdit()],
442-
bodyStyle: "padding: 10px;",
443-
buttons: [
444-
{
445-
text: t("clear_relation_filter"),
446-
iconCls: "pimcore_icon_filter_condition pimcore_icon_overlay_delete",
447-
handler: function () {
448-
this.filterByRelationWindow.close();
449-
this.grid.store.filters.removeByKey("x-gridfilter-"+fieldInfo.dataIndex);
450-
}.bind(this)
451-
},
452-
{
453-
text: t("apply_filter"),
454-
iconCls: "pimcore_icon_filter pimcore_icon_overlay_add",
455-
handler: function () {
456-
if (formPanel.isValid() && typeof fieldInfo.getRelationFilter === "function") {
457-
this.grid.filters.getStore().addFilter(
458-
fieldInfo.getRelationFilter(fieldInfo.dataIndex, editor)
459-
);
460-
this.filterByRelationWindow.close();
461-
}
462-
}.bind(this)
438+
const activeFilter = this.grid.getStore().getFilters().items;
439+
440+
for (let filter of activeFilter) {
441+
if (filter.dataIndex !== fieldInfo.dataIndex) {
442+
continue;
463443
}
464-
]
465-
});
444+
editor.data = filter.getValue()
445+
.split(",")
446+
.map(v => ({ id: Number.parseInt(v.trim()) }))
447+
.filter(v => !Number.isNaN(v.id));
448+
editor.store.loadData(items, false);
449+
break;
450+
}
451+
452+
const formPanel = Ext.create('Ext.form.Panel', {
453+
xtype: "form",
454+
border: false,
455+
items: [editor.getLayoutEdit()],
456+
bodyStyle: "padding: 10px;",
457+
buttons: [
458+
{
459+
text: t("clear_relation_filter"),
460+
iconCls: "pimcore_icon_filter_condition pimcore_icon_overlay_delete",
461+
handler: function () {
462+
this.filterByRelationWindow.close();
463+
this.grid.store.filters.removeByKey("x-gridfilter-"+fieldInfo.dataIndex);
464+
}.bind(this)
465+
},
466+
{
467+
text: t("apply_filter"),
468+
iconCls: "pimcore_icon_filter pimcore_icon_overlay_add",
469+
handler: function () {
470+
if (formPanel.isValid() && typeof fieldInfo.getRelationFilter === "function") {
471+
try {
472+
// Sync editor store with its current value (if applicable)
473+
const value = editor.getValue();
474+
let items = [];
475+
if (Array.isArray(value)) {
476+
items = value;
477+
} else if (value) {
478+
items = [value];
479+
}
480+
editor.store.loadData(items, false);
481+
482+
this.grid.filters.getStore().addFilter(
483+
fieldInfo.getRelationFilter(fieldInfo.dataIndex, editor)
484+
);
485+
this.filterByRelationWindow.close();
486+
} catch (e) {
487+
console.error("Error applying relation filter:", e);
488+
pimcore.helpers.showNotification(t("error"), e.message || e, "error");
489+
}
490+
}
491+
}.bind(this)
492+
}
493+
]
494+
});
466495

467496
const title = t("filter_by_relation_field") + " " + fieldInfo.text;
468497
let width = 700;
@@ -970,6 +999,10 @@ pimcore.element.helpers.gridColumnConfig = {
970999
params["only_direct_children"] = this.checkboxOnlyDirectChildren.getValue();
9711000
}
9721001

1002+
if (typeof this.selectObjectType !=='undefined') {
1003+
params['filter_by_object_type'] = this.selectObjectType.getValue();
1004+
}
1005+
9731006
//only unreferenced filter
9741007
if (this.checkboxOnlyUnreferenced) {
9751008
params["only_unreferenced"] = this.checkboxOnlyUnreferenced.getValue();

public/js/pimcore/element/helpers/gridConfigDialog.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ pimcore.element.helpers.gridConfigDialog = Class.create({
285285

286286
this.saveFilters = new Ext.form.field.Checkbox(
287287
{
288-
fieldLabel: "Save filters",
288+
fieldLabel: t("save_filters"),
289289
inputValue: true,
290290
name: "saveFilters",
291291
value: this.settings.saveFilters

public/js/pimcore/object/class.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ pimcore.object.klass = Class.create({
1616

1717
forbiddenNames: [
1818
"abstract", "class", "data", "folder", "list", "permissions", "resource", "concrete", "interface",
19-
"service", "fieldcollection", "localizedfield", "objectbrick", "default"
19+
"service", "fieldcollection", "localizedfield", "objectbrick", "default",
20+
"abstractobject", "classdefinition", "classdefinitioninterface", "classificationstore",
21+
"definitionmodifier", "importdataserviceinterface", "lazyloadedfieldsinterface", "listing",
22+
"objectawarefieldinterface", "ownerawarefieldinterface", "pregetvaluehookinterface",
23+
"selectoptionsinterface"
2024
],
21-
2225
initialize: function () {
2326

2427
this.getTabPanel();

public/js/pimcore/object/classificationstore/groupsPanel.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,13 @@ pimcore.object.classificationstore.groupsPanel = Class.create({
399399
this.relationsPanel.setTitle(t("relations") + " - " + t("group") + " " + record.data.id + " - " + groupName);
400400
this.relationsPanel.enable();
401401
this.relationsStore.getProxy().setExtraParam("groupId", groupId);
402-
this.relationsStore.reload();
402+
403+
// reset paging params
404+
this.relationsStore.reload({
405+
page: 1,
406+
start: 0
407+
});
408+
403409
this.relationsGrid.show();
404410
}
405411
}.bind(this)

public/js/pimcore/object/folder/search.js

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,19 @@ pimcore.object.search = Class.create(pimcore.object.helpers.gridTabAbstract, {
283283
let col = gridColumns[i];
284284
if (col.filter) {
285285
needGridFilter = true;
286-
break;
286+
287+
if (this.filter) {
288+
const filterValue = this.filter.find(filter => filter.property === col.dataIndex)?.value || null;
289+
if (filterValue) {
290+
if (typeof col.filter !== "object") {
291+
col.filter = { type: col.filter };
292+
}
293+
294+
col.filter.value = filterValue;
295+
}
296+
} else {
297+
break;
298+
}
287299
}
288300
}
289301
}
@@ -340,11 +352,11 @@ pimcore.object.search = Class.create(pimcore.object.helpers.gridTabAbstract, {
340352

341353
if (this.filter) {
342354
this.filter.forEach(filt => {
343-
this.store.setFilters(new Ext.util.Filter(filt))
344355
this.filterUpdateFunction(this.grid, this.toolbarFilterInfo, this.clearFilterButton);
345356
});
346357
}
347358

359+
348360
this.grid.on("columnmove", function () {
349361
this.saveColumnConfigButton.show()
350362
}.bind(this));

public/js/pimcore/object/objectbrick.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,13 +182,12 @@ pimcore.object.objectbrick = Class.create(pimcore.object.fieldcollection, {
182182
},
183183

184184
addField: function () {
185-
Ext.MessageBox.prompt(' ', t('enter_the_name_of_the_new_item'),
185+
Ext.MessageBox.prompt(' ', t('enter_the_name_of_the_new_object_brick'),
186186
this.addFieldComplete.bind(this), null, null, "");
187187
},
188188

189189
addFieldComplete: function (button, value, object) {
190-
191-
var isValidName = /^[a-zA-Z][a-zA-Z0-9]*$/;
190+
const isValidName = /^[a-zA-Z]\w*$/;
192191

193192
if (button == "ok" && value.length > 2 && isValidName.test(value) && !in_arrayi(value, this.forbiddenNames)) {
194193
Ext.Ajax.request({

src/Controller/Admin/DataObject/ClassificationstoreController.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,14 @@ private function getTranslatedSearchFilterTerms(string $searchTerm): array
14761476
if ($user instanceof User) {
14771477
$translationListing = new Listing();
14781478
$translationListing->setDomain(Translation::DOMAIN_ADMIN);
1479-
$translationListing->setCondition('language=? AND text LIKE ?', [$user->getLanguage(), '%'.$searchTerm.'%']);
1479+
$translationListing->setCondition(
1480+
$translationListing->quoteIdentifier('language') . ' = ? AND ' .
1481+
$translationListing->quoteIdentifier('text') . ' LIKE ?',
1482+
[
1483+
$user->getLanguage(),
1484+
'%' . $searchTerm . '%',
1485+
]
1486+
);
14801487

14811488
foreach ($translationListing as $translation) {
14821489
$terms[] = $translation->getKey();

0 commit comments

Comments
 (0)