Может кто-нибудь сталкивался с подобной проблемой.
Использую LookupUtilities:
entitySchemaName: "UserReport",
columns: ["Id", "Name", "Parameters", "ReportSchemaUId"],
multiSelect: false,
actionsButtonVisible: false,
lookupPageName: "LookupPage"
};
LookupUtilities.Open(this.sandbox, config, this.onReportSelected, this, null, false, false);
Все красиво, и работает корректно. Открывается окно выбора (
Но предположим, что мне необходимо добавить дополнительную кнопку, либо изменить страницу LookupPage.
Что я делаю - наследую LookupPage.
function() {
return Ext.define("Terrasoft.configuration.CustomLookupPage",
{
extend: "Terrasoft.LookupPage",
alternateClassName: "Terrasoft.CustomLookupPage"
}
);
}
);
Затем, меняю config.lookupPageName = "CustomLookupPage".
entitySchemaName: "UserReport",
columns: ["Id", "Name", "Parameters", "ReportSchemaUId"],
multiSelect: false,
actionsButtonVisible: false,
lookupPageName: "CustomLookupPage"
};
LookupUtilities.Open(this.sandbox, config, this.onReportSelected, this, null, false, false);
Но теперь, при открытии получаю ошибку (
).
Что-то попало в бесконечный цикл, вижу ошибку переполнения стэка.
Как такое лечится?
Нравится
Добрый день, Евгений!
Не понятно, что могло вызвать такой странный результат. Я бы порекомендовал обратиться в support Террасофта, пускай посмотрят.
В итоге не смог разобраться, а официальный саппорт отклоняет подобные запросы по SLA, хотя, здесь явно ошибка в стандартной конфигурации. Вобщем - ничего нового...
Предлагаю поступить немного иначе.
Не наследоваться через зависимости (в карточку),
А унаследоваться от схемы справочника (LookupPageV2) (создать свою схему наследника, не замещающую),
там в схеме "играться" с "дифами" и замещенеим, так как мы это делаем при классическом замещении клиентских схем.
И уже своего наследника подключать в зависимости.
(Мне кажется это более каноничный подход)
PS:У меня в ближайшем будущем есть аналогичная задача - скастомить окно на базе типового окна справочника, со своими кнопками и т.д.
Я планировал действовать так.
Прошу Вас отписаться если предложенный мною вариант окажется рабочим, чтобы душа была спокойна :)
"Севостьянов Илья Сергеевич" написал:
Спасибо за идею, на первой неделе мая попробую реализовать и отпишусь!
Вообщем Вы были изначально на правильном пути, но упустили несколько моментов, по сути Ваши начинания "в купе с моей идеей" и есть итоговое решение, т.к. наследование на уровне схем все равно оказалось необходимым условием (правда через зависимости, а не механизм наследования)
Разобраться помогла схема "MultiLookupModule" входящая в базовую поставку
1) Вы реализуете модуль, зависимости которого необходимо указать не только в исходном коде но и в меню структуры
2) Сам модуль не должен быть чьим либо наследником, всё необходимое идет в его зависимости, в т.ч. и LookupPage который мы идеологически наследуем, но архитектурно через наследование в схемах - это почему-то не работает (Если у казать "Выбор из справочника" как родителя - получаем очень много разного рода ошибок при вызове).
3) Далее вот вообщем-то пример самого кода
define("MyCustomLookupPage", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"], function(LookupPage, LookupPageViewGenerator) { return Ext.define("Terrasoft.configuration.KmGMSLookupPage", { alternateClassName: "Terrasoft.KmGMSLookupPage", extend: "Terrasoft.LookupPage", gridWrapClasses: ["my-custom-lookup-control"] }); });
перчим солим, замещаем, дополняем по вкусу и
ну и вызываем его через LookupUtilites или же есть более простой способ через this.openLookup (что само собой является оберткой над вышеуказанным и "сахаром" по сути).
Уже в таком виде - Ваш "отнаследованный" lookupPage можно вызвать следующим образом
var config = { entitySchemaName: "Lead", columns: ["Id"], multiSelect: false, actionsButtonVisible: false, lookupPageName: "MyCustomLookupPage" }; this.openLookup(config, function(result){console.log(result)})
Вот.
PS:
Были попытки отнаследовать через механизм наследования схем, насколько хватило фантазии и времени - но все безрезультатны.
Хотя очень хотелось бы вот так вот взять и в diff все свои вынести изменения.
Тем не менее описанный способ, предположительно - позволяет делать то что нужно...
"Севостьянов Илья Сергеевич" написал:
Как оказалось - решение было близко)
Спасибо большое, что поделились окончательной реализацией! Я то уже переключился на более приоритетные задачи, так как посчитал эту затею бесперспективной.
На самом деле - решение не окончательное... бой продолжается :)
Есть прям несколько моментов - которые весьма и весьма удивляют... например что кнопки по факту "захардкожены" в LookupPageViewGenerator и собственно не зависят от каких либо конфигурационных параметров вызова этого самого генератора, что приводит к необходимости наследовать и его, с переопределением некоторых функций, в свою очередь "копия" генератора подобным образом не работает полностью или частично, т.к. используя наследника в качестве зависимости - получаем ряд ошибок про "sunbox of undefined" из core.js (что практически убивает надежду "по быстрому разобраться") при попытке выбора записей из такого справочника и т.д.
Кстати по какой-то причине не удается подключить к карточке страницы LookupUtilities
В конечном итоге в контексте карточки нет объекта "LookupUtilities"
define("MyCustomPage", ["LookupUtilities"], function(LookupUtilities) { ...
В конечном итоге в контексте карточки LookupUtilities - undefined
Не поделитесь, как вы подключали LookupUtilities к странице ?
(Я уже и в dependecies структуры добавил его, так же безрезультатно)
Там необходимо использовать V2
define("MyCustomPage", ["LookupUtilitiesV2"], function(LookupUtilities) { ...
Победа.
Кастом окна справочника через наследование его базового Ext-класса возможен, и даже, как оказалось не сложен.
В основном наверное в таком случае требуется юзкейз по управлению панелью с кнопками такого окна - переименование, сокрытие, добавление своих, стилизация и т.д.
HowTo по порядку
1) Создаем пользовательский модуль например "MyCustomLookupWindow"
[color=red]Внимание![/color]
- Модуль не должен являться чьим либо наследником
- В структуре метаданных модуля, дублируем зависимости, которые объявим в самом листинге
схемы при создании необходимо выбирать по заголовкам (давняя боль), облегчаю задачу:
LookupPage - Выбор из справочника ( NUI )
LookupPageCSS - Стили модуля справочника ( NUI )
LookupPageViewGenerator, LookupUtilities, MaskHelper - имеют такие же заголовки как и их имена
define("MyCustomLookupWindow", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"], function(LookupPage, LookupPageViewGenerator) { return Ext.define("Terrasoft.configuration.MyCustomLookupWindow", { alternateClassName: "Terrasoft.MyCustomLookupWindow", extend: "Terrasoft.LookupPage", gridWrapClasses: ["km-gms-lookup-control"] }); });
2) Для вызова lookup-наследника используйте в вашей логике this.openLookup метод (присутствует в контексте любой карточки/схемы/детали), если же случилось так что его нет - то см.выше - надо будет подключить LookupUtilitesV2 в зависимости схемы, и использовать метод Open предоставляемый объектом зависимости. (Примеры использования см.в исходниках и в начале темы)
//Подготовим минимальный конфигурационный объект var config = { //Для примера справочник "нацелен" на раздел "Лиды" entitySchemaName: "Lead", columns: ["Id"], multiSelect: true, actionsButtonVisible: true, //Вот сюда передаем имя модуля-наследника lookupPageName: "MyCustomLookupWindow" }; //пример вызова this..openLookup( //наш конфигурационный объект config, //callback принимающий результат/результаты выбора в виде коллекции function(selected){console.log(selected)}, //контекст для коллбэка this )
3) Для того чтобы закастомить кнопки необходимо в нашем наследнике переопределить метод renderLookupView
в который произвести инъекцию своей логики
define("MyCustomLookupWindow", ["LookupPage", "LookupPageViewGenerator", "LookupUtilities", "css!LookupPageCSS"], function(LookupPage, LookupPageViewGenerator) { return Ext.define("Terrasoft.configuration.MyCustomLookupWindow", { alternateClassName: "Terrasoft.MyCustomLookupWindow", extend: "Terrasoft.LookupPage", gridWrapClasses: ["km-gms-lookup-control"], //Переопределяем метод в котором мы можем управлять сформированной конфигурацией до рендеринга. renderLookupView: function(schema, profile) { var config = this.getLookupConfig(schema, profile); var topPanelConfig = LookupPageViewGenerator.generateFixed(config); //----------------------- инъекция логики (начало) ---------------------- //переменная для хранения ссылки на массив объектов-конфигурайий кнопок var buttonsConfig; //Получаем ссылку на аттрибут-массив конфигурационных объектов-кнопок //Используем Underscore.some с возможностью прерывания переборы по возврату от предиката "true" _.some(topPanelConfig.items, function(target) { //выделяем объект группы кнопок (Wrapper) по id контейнера if (target.id === "selectionControlsContainerLookupPage") { //в нем ищем подчиненные объекты являющиеся массивом _.some(target, function(target) { //согласно структуры конфигурационного объекта панели //"чистым" массивом является только объект с конфигами кнопок if (Array.isArray(target)) { //сохраняем ссылку на него в переменной для дальнейшего использования buttonsConfig = target; //Прерываем перебор return true; } }); //Прерываем перебор return true; } }); //Создаем новую кнопку, клонируя любую, первой как правило идет кнопка "Отмена" var newButton = Terrasoft.deepClone(buttonsConfig[0]); //Используем Underscore.extend для объединения склонированного объекта //с анонимным объектом-разницы в котором опишем необходимые изменения _.extend( newButton, { caption: "Добавленная кнопка", click: { bindTo: "AddTender" }, //Внимаение! свойство "tag" должено быть уникальным для каждой кнопки tag: "AddTender", //меняем стиль style: "green" } ); //Добавляем конфигурационный объект кнрпки в массив конф.объектов buttonsConfig.push(newButton); //Поиск конфигурационного объекта кнопки "Выбрать" в искомом массиве по caption _.some(buttonsConfig, function(target) { if (target.caption === "Выбрать") { //В найденном объекте меняем значение аттрибута caption на "Создать тендеры". target.caption = "Переименованная кнопка" ; return true; } }); //Поиск конфигурационного объекта кнопки "Добавить" в искомом массиве по caption _.some(buttonsConfig, function(target) { if (target.caption === "Действия") { //В найденном объекте меняем значение аттрибута visible на "false" //тем самым скрывая кнопку-меню target.visible = false ; return true; } }); //----------------------- инъекция логики (конец) ---------------------- this.renderLookupControls(config, topPanelConfig); } }); });
Классно и подробно - хоть в официальный SDK добавляй! :)
Илья,
хотел бы уточнить, если правильно понял, то , в результате выполнения данных действий, окно справочника поменяется вообще во всей системе?
Севостьянов Илья Сергеевич, спасибо за подробность, как раз искал подобный кейс
Севостьянов Илья Сергеевич,
Скажите пожалуйста а где вызвать метод
this.openLookup, я никак не могу реализовать пример.