Дополнительная проверка дропзоны
Здравствуйте.
В одном из гридов у меня есть сортировка через drag'n'drop. Но хитрость там в том, что некоторые позиции для дропа запрещены. Я могу это проверить через beforedrop, выдать сообщение и все такое... Но Было бы более красиво сразу запретить дроп в запрещенную зону, при движении через нее показать красный индикатор с соответствующим текстом. Я стал копаться в исходниках и не нашел ничего полезного, кроме как переписать кое-что в Ext.view.DropZone:
Ext.define('SafetyRound.patch.view.DropZone', {
override: 'Ext.view.DropZone',
isPositionValid: function(overRecord, draggingRecords, pos){
var
me = this,
valid = !Ext.Array.contains(draggingRecords, overRecord) &&
( pos === 'before' && !me.containsRecordAtOffset(draggingRecords, overRecord, -1) ||
pos === 'after' && !me.containsRecordAtOffset(draggingRecords, overRecord, 1)
);
// <-------- some additional validation here
return valid;
},
positionIndicator: function(node, data, e) {
var
me = this,
view = me.view,
pos = me.getPosition(e, node),
overRecord = view.getRecord(node),
draggingRecords = data.records,
indicatorY;
if (me.isPositionValid(overRecord, draggingRecords, pos)) {
me.valid = true;
if (me.overRecord !== overRecord || me.currentPosition !== pos) {
indicatorY = Ext.fly(node).getY() - view.el.getY() - 1;
if (pos === 'after') {
indicatorY += Ext.fly(node).getHeight();
}
// If view is scrolled using CSS translate, account for then when positioning the indicator
if (view.touchScroll === 2) {
indicatorY += view.getScrollY();
}
me.getIndicator().setWidth(Ext.fly(view.el).getWidth()).showAt(0, indicatorY);
// Cache the overRecord and the 'before' or 'after' indicator.
me.overRecord = overRecord;
me.currentPosition = pos;
}
} else {
me.invalidateDrop();
}
}
});
Однако сей вариант очень костыльный. Если вдруг у меня будет более одного места с драгодропом, придется постоянно лепить всякие костыли и проверки. Есть ли более человеческий способ? |
Немного улучшил ситуацию. В базовой дропзоне использовал функцию - заглушку:
isPositionValid: function(overRecord, draggingRecords, pos){
var
me = this,
valid = !Ext.Array.contains(draggingRecords, overRecord) &&
( pos === 'before' && !me.containsRecordAtOffset(draggingRecords, overRecord, -1) ||
pos === 'after' && !me.containsRecordAtOffset(draggingRecords, overRecord, 1)
);
// some additional validation here
return valid && me.validateExtended(overRecord, draggingRecords, pos);
},
// must be re-defined in shildren
validateExtended: function(overRecord, draggingRecords, pos){
return true;
},
При подключении плагина заглушку переписываю:
plugins: {
ptype: 'gridviewdragdrop',
dragText: '## Drag and drop to reorganize',
dropZone: {
validateExtended: function(overRecord, draggingRecords, pos){
// disable draggind to other parent grous
return overRecord.get('SafetyRoundMeasurePoint_ID') == draggingRecords[0].get('SafetyRoundMeasurePoint_ID');
}
}
},
Так все выглядит лучше, но некоторая засада имеет место по прежнему. Если вдруг обновится фреймворк, и метод positionIndicator будет переписан, то может выйти бяка. Кроме того, остался открытым вопрос о драг тексте: как можно его менять динамически? |
Почему не сделать оверрайд вот этого метода: http://docs.sencha.com/extjs/6.0/6.0...hod-onNodeOver ?
Благо он template то есть просто предназначен для этого. вот форк от вашего фидла: https://fiddle.sencha.com/#fiddle/11qe |
Дело в том что я на 5м эксте, а там судя по всему такого метода нет. Кстати, не могли бы вы рассказать, что это за темплейт методы? Или ссылку дайте где можно почитать.
|
есть и в пятой версии: http://docs.sencha.com/extjs/5.1/5.1...hod-onNodeOver
template методы это хуки для вставки своей функциональности при расширении класса. Вот тут описано: https://docs.sencha.com/extjs/5.0/co...mplate_Methods Поскольку по своей природе они являются публичными (или как минимум protected) использовать их безопаснее чем приватные вещи ..меньше вероятность что что-то сломается при апгрейде экста. |
Насчет темплейтов - спасибо! Почитаю про них. А вот насчет всего остального я несколько сомневаюсь. Нашел я таки этот класс: http://docs.sencha.com/extjs/5.1/5.1...hod-onNodeOver . Только вот он приватный. А мне как-то стремно с приватными вещами баловаться. Сама же Сенча и предупреждает: This is a private utility class for internal use by the framework. Don't rely on its existence. Так что этот метод не сильно лучше моего выглядит.
|
Ext.tree.ViewDropZone приватный, однако его предок Ext.dd.DropZone вполне себе публичный. В нём присутствует ваш шаблонный метод onNodeOver
|
{
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
dropZone : {
onNodeOver : function (node, dd) {
var result = this.callParent(arguments);
// we allow to drop to nodes having ID > 3
var record = dd.view.getRecord(node);
var isValid = record && record.getId() > 3;
if (!isValid) {
return this.dropNotAllowed;
}
return result;
}
}
}
},
}
fiddle |
Цитата:
Ведь вы переопределили метод прямо на инстансе дроп зоны. И если воткнуть debugger и зайти в недра callParent вы увидите что вызывается метод класса "Ext.dd.DropTarget", что не есть искомый результат. |
Да, копипаст - это зло. Вот этот вариант должен удовлетворять требованиям задачи:
viewConfig: {
plugins: [{
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
dropZone : {
onNodeOver : function (node, dd) {
// we allow to drop to nodes having ID > 3
var record = dd.view.getRecord(node);
var isValid = record && record.getId() > 3;
return isValid ? this.dropAllowed : this.dropNotAllowed;
}
}
}]
},
Возвращается имя ЦСС-класса. фиддл |
Ну а при таком варианте мы просто затираем функциональность метода класса Ext.view.DropZone.
Вот что он делает:
// The mouse is over a View node
onNodeOver: function(node, dragZone, e, data) {
var me = this;
if (!Ext.Array.contains(data.records, me.view.getRecord(node))) {
me.positionIndicator(node, data, e);
}
return me.valid ? me.dropAllowed : me.dropNotAllowed;
},
То есть вы убрали позиционирование индикатора дропа + валидацию от попыток дропнуть записи на самих себя. |
Но если перечисленное не критично, тогда конечно вариант.
|
Мда, поспешил.
|
В принципе нет ничего невозможного ..как говорится "и зайца можно научить курить" (с).
Можно вот так сделать если хотите без оверрайда:
{
viewConfig: {
plugins: {
ptype: 'gridviewdragdrop',
dragText: 'Drag and drop to reorganize',
dropZone : {
onNodeOver : function (node, dd) {
// это вместо callParent()
var result = this.self.prototype.onNodeOver.apply(this, arguments);
// we allow to drop to nodes having ID > 3
var record = dd.view.getRecord(node);
var isValid = record && record.getId() > 3;
if (!isValid) {
return this.dropNotAllowed;
}
return result;
}
}
}
}
}
|
Увы, заяц не закурил.
https://fiddle.sencha.com/#fiddle/120q Индикатор показывает что дроп запрещен, но де-факто дроп срабатывает, и строки реорганизуются. |
Чтобы дроп не срабатывал, нужно править в другом месте. В событии drop.
|
Это конечно тоже может пригодится в хозяйстве :) Однако в приоритете именно запрет дропа в неположенных местах. Видимо, никуда мне не деться от грязного хака...
|
Цитата:
Я конечно и так могу, но получается как-то избыточно. Одна проверка в beforeDrop, другая в onNodeOver, а делают они по сути одно и то же. А вот так чтоб все в одном месте - не выходит, если по правилам писать. В общем, меня несколько разочаровывает эта функциональность. |
Вы какбы вначале писали что с запретом дропа у вас все уже пучком ..и проблема в том чтоб показывать индикатор как надо.
|
Я хотел все эти вопросы решить переопределив или добавив один метод. А получается что надо и событие обрабатывать, и метод переопределять. Не то чтобы я был такой ленивый, просто не люблю дублировать функционал. А вот придется, если без хаков делать. И кстати, ваш метод не полностью решает вопрос индикатора: класс плавающего сообщения меняется, но вот зеленая полоска, показывающая позицию дропа, не пропадает в запретных зонах.
|
| Часовой пояс GMT +3, время: 21:47. |