Иногда это бывает необходимо - например, для ручного тестирования результатов отчета.
Существуют различные окольные решения:
1) Использовать выгрузку результатов отчета в Excel - но это долго.
2) Использовать Chrome-браузер, который позволяет выделять и копировать значения ячеек в BI отчетах - но BIEE не всегда корректно отображается под Chrome (проблема с графиками/диаграммами).
3) Есть и другие ухищрения, требующие настройки каждого отчета (например, через ActionsFramework)...
Я хочу предложить вам более элегантный вариант - осуществление копирования с помощью контекстного меню.

Как видно из рисунка выше - по щелчку правой кнопкой мыши на ячейку, значение которой вы хотите скопировать, отображается контекстное меню с пользовательским элементом -
"Copy (Ctrl-C)"
Нажав на который отобразиться модальное окошко с необходимым значением. Теперь достаточно нажать комбинацию клавиш Сtrl-C, и искомое значение в буфере обмена.
Причем эта настройка сделана для всех элементов BI отчета - для ячеек данных, для ячеек заголовков столбцов, для ячеек значений иерархических столбцов.

Итак, что нужно сделать для описанного функционала.
/* Сразу скажу, что эта кастомизация затрагивает javascript-файлы, которые, УВЕРЕН, будут правиться Oracle в каждом серьезном патче/релизе. Поэтому взвесьте ЗА и ПРОТИВ. И если преимущества перевешивают недостатки, то обязательно делайте бекапы, и при накате каждого патча сравнивайте (например, SVN-diff'ом) подправленные файлы с новыми версиями этих файлов
*/
Далее все подправленные javascript-файлы приводятся в beauty-формате, тогда как оригинальные js-файлы OBIEE "ужаты" (удалены все лишние пробелы, символы табуляции, перевода каретки - короче говоря, все что делает код читабельным).
Я для "расжатия" использую онлайн-ресурс jsbeautifier.org/
b_mozilla\views\obips.viewmodel.js
1) добавим константу функции копирования
...
obips.ViewModel.EventType = new Object();
obips.ViewModel.EventType.NO_EVENT = 0;
obips.ViewModel.EventType.PIVOT_SWAP_EVENT = 1;
obips.ViewModel.EventType.SELECTION_EVENT = 2;
obips.ViewModel.EventType.DROP_COLUMN_MEMBER_EVENT = 3;
obips.ViewModel.EventType.PRIMARY_SORT_ASC_MENU_EVENT = 4;
obips.ViewModel.EventType.PRIMARY_SORT_DESC_MENU_EVENT = 5;
obips.ViewModel.EventType.ADD_SORT_ASC_MENU_EVENT = 6;
obips.ViewModel.EventType.ADD_SORT_DESC_MENU_EVENT = 7;
obips.ViewModel.EventType.CLEAR_ALL_SORTS_MENU_EVENT = 8;
obips.ViewModel.EventType.REGULAR_DRILL_MENU_EVENT = 9;
obips.ViewModel.EventType.HIER_EXPAND_MENU_EVENT = 10;
obips.ViewModel.EventType.HIER_COLLAPSE_MENU_EVENT = 11;
obips.ViewModel.EventType.MASTER_DETAIL_MENU_EVENT = 12;
obips.ViewModel.EventType.REMOVE_COLUMN_MENU_EVENT = 13;
obips.ViewModel.EventType.MOVE_BEFORE_MENU_EVENT = 14;
obips.ViewModel.EventType.MOVE_AFTER_MENU_EVENT = 15;
obips.ViewModel.EventType.MOVE_TO_PROMPTS_MENU_EVENT = 16;
obips.ViewModel.EventType.MOVE_TO_SECTIONS_MENU_EVENT = 17;
obips.ViewModel.EventType.MOVE_TO_COLUMNS_MENU_EVENT = 18;
obips.ViewModel.EventType.MOVE_TO_ROWS_MENU_EVENT = 19;
obips.ViewModel.EventType.MOVE_TO_MEASURES_MENU_EVENT = 20;
obips.ViewModel.EventType.HIER_COLLAPSE_ALL_MENU_EVENT = 21;
obips.ViewModel.EventType.HIER_COLLAPSE_LAYER_MENU_EVENT = 22;
obips.ViewModel.EventType.EXCLUDE_COLUMN_MENU_EVENT = 23;
obips.ViewModel.EventType.VIEW_CUSTOM_GROUP_EVENT = 24;
obips.ViewModel.EventType.VIEW_CALCITEM_EVENT = 25;
obips.ViewModel.EventType.INCLUDE_COLUMN_MENU_EVENT = 26;
obips.ViewModel.EventType.SELN_SELECT_MEMBERS_MENU_EVENT = 27;
obips.ViewModel.EventType.SELN_HIER_RELATED_MENU_EVENT = 28;
obips.ViewModel.EventType.CREATE_CUSTOM_GROUP_MENU_EVENT = 29;
obips.ViewModel.EventType.CREATE_CALC_ITEM_MENU_EVENT = 30;
obips.ViewModel.EventType.SELN_COL_INTERACTION_MENU_EVENT = 31;
obips.ViewModel.EventType.DRILL_REG_COL_MENU_EVENT = 32;
obips.ViewModel.EventType.INCL_HIER_FAMILY_REL_MENU_EVENT = 33;
obips.ViewModel.EventType.SHOW_HIER_LEVELS_MENU_EVENT = 34;
obips.ViewModel.EventType.SELN_TOPX_EVENT = 35;
obips.ViewModel.EventType.SELN_BOTTOMX_EVENT = 36;
obips.ViewModel.EventType.SELN_ADD_MEMBERS = 37;
obips.ViewModel.EventType.SELN_ADD_CUSTOM_CALC_ITEM = 38;
obips.ViewModel.EventType.SELN_XGTVALUE_MENU_EVENT = 39;
obips.ViewModel.EventType.SELN_XGTY_MENU_EVENT = 40;
obips.ViewModel.EventType.SELN_SPECIFIC_MEMBERS = 41;
obips.ViewModel.EventType.SELN_CUSTOM_CONDITION_MENU_EVENT = 42;
obips.ViewModel.EventType.RUNNING_SUM_COLUMN_MENU_EVENT = 43;
obips.ViewModel.EventType.SHOW_SUBTOTAL_MENU_EVENT = 44;
obips.ViewModel.EventType.EDIT_CUSTOM_GROUP_MENU_EVENT = 45;
obips.ViewModel.EventType.DELETE_CUSTOM_GROUP_MENU_EVENT = 46;
obips.ViewModel.EventType.EDIT_CALCITEM_MENU_EVENT = 47;
obips.ViewModel.EventType.DELETE_CALCITEM_MENU_EVENT = 48;
obips.ViewModel.EventType.SHOW_GRANDTOTAL_MENU_EVENT = 49;
obips.ViewModel.EventType.SELN_REMOVE_ALL_STEPS = 50;
obips.ViewModel.EventType.HIDE_COLUMN = 51;
//jack carver start
obips.ViewModel.EventType.XX_COPY_CELL_VALUE = 100;
//jack carver end
...
2) добавим обработку нажатия на создаваемый элемент контекстного меню
...
obips.ViewModel.onContextMenuItemSelected = function (d) {
var e = d.context;
var b = e.menuOption;
var a = b.eventType;
var c = b.eventData;
if (!a || !c) {
return
}
obips.ViewModel.ptCurrentEvent.eventType = a;
obips.ViewModel.ptCurrentEvent.eventData = c;
switch (a) {
//jack carver start
case obips.ViewModel.EventType.XX_COPY_CELL_VALUE:
var b = obips.EdgeCoords.findCoords(c.getElement());
var a = b.getId();
var f = b.getEdge();
var d = b.getLayer();
var g = b.getSlice();
if (g == -1)
var eId = "hl_" + a + "_" + f + "_" + d;
else
var eId = "e_" + a + "_" + f + "_" + d + "_" + g;
var cell = document.getElementById(eId);
var cellValue = cell.innerHTML;
if (cellValue) {
cellValue = cellValue.toString().replace(/\s*\<.*?\>\s*/g, '');
cellValue = cellValue.toString().replace(/</g, '<');
cellValue = cellValue.toString().replace(/>/g, '>');
cellValue = cellValue.toString().replace(/"/g, '"');
cellValue = cellValue.toString().replace(/ /g, ' ');
}
window.prompt('To copy -> Ctrl+C', cellValue );
break;
//jack carver end
case obips.ViewModel.EventType.PRIMARY_SORT_ASC_MENU_EVENT:
obips.ViewModel.sortMenuHandler(c, "ascending", true, b.pos, b.slice);
break;
...
b_mozilla\views\viewrightclickmenu.js
1) добавим новый пункт меню для простых Таблиц
...
obips.ViewRightClickMenu.prototype.onEdgeContextMenu = function (b, r) {
var i = new Array();
var l = obips.ViewModel.EventType.NO_EVENT;
var w = "views/obips.viewrightclickmenu.xml";
var n = obips.ResourceManager.getSingleton();
if (b) {
var f = b;
b.bDatabody = false;
var h = b.getEdge();
var G = b.getLayer();
var t = b.getSlice();
var H = b.getId();
var z = this.viewModel;
G = this.viewModel.getPhysicalLayer(h, G);
var g = this.viewModel.getEdgeDefinition(b.getId());
var d = g.isMeasureLabelsLayer(h, G);
var s = g.isMeasureLayer(h, G);
var x = this.isHeaderLabelCell(t);
var j = this.viewModel.getLayerCount(h);
if (j == 0) {
return
}
var E = "";
var k = g.isLayerHierarchical(h, G);
var u = obips.ViewRightClickMenu.isRuntimeMode();
//jack carver start
E = "Copy (Ctrl-C)";
l = obips.ViewModel.EventType.XX_COPY_CELL_VALUE
var p = obips.ViewRightClickMenu.CreateContextMenuOption(E, E, null, null, l, f);
i.push(p)
//jack carver end
var D = this.supportsFeature(obips.ViewRightClickMenu.FEATURE_DRILL);
...
b_mozilla\views\pivot\pivotview.js
1) добавим новый пункт меню для Таблиц Среза
...
obips.PivotTable.onDatabodyContextMenu = function (h, n, s) {
var g = new Array();
var i = obips.ViewModel.EventType.NO_EVENT;
var t = "views/pivot/obips.gridview.xml";
var k = obips.ResourceManager.getSingleton();
var f = obips.PivotTable.isRuntimeMode();
if (h) {
h.bDatabody = true;
var e = h;
var C = h.getRow();
var z = h.getCol();
var B = h.getId();
var w = obips.ViewModel.getViewModelById(B);
var x = w.getBodyDefinition(B);
var q = x.getValue(C, z);
var r = x.getID(C, z);
var c = w.getPivotViewXML();
var p = obips.PivotTable.containsNestedViews(c);
if (p && !obips.PivotTable.isShowingNumbers(c, r)) {
return
}
var o = h.getElement();
var A = obips.PivotTable.getActionLinkIdsFromElement(o);
var m = new ActionLinksModel(w, B, obips.EdgeDefinition.DATA_EDGE, C, z, false, w.actionLinksXmlId);
m.setDataValue(r, q);
var a = new ActionLinksRenderer(m, A);
//jack carver start
linkText = "Copy (Ctrl-C)";
i = obips.ViewModel.EventType.XX_COPY_CELL_VALUE;
var l = obips.PivotTable.CreateContextMenuOption(linkText, linkText, null, null, i, e);
g.push(l)
//jack carver end
...
2) добавим обработку нажатия нового пункта контекстного меню для ячеек Таблицы Среза
...
obips.PivotTable.onContextMenuItemSelected = function (d) {
var e = d.context;
var b = e.menuOption;
var a = b.eventType;
var c = b.eventData;
if (!a || !c) {
return
}
obips.PivotTable.ptCurrentEvent.eventType = a;
obips.PivotTable.ptCurrentEvent.eventData = c;
switch (a) {
//jack carver start
case obips.ViewModel.EventType.XX_COPY_CELL_VALUE:
var a = c.getId();
var e = c.getRow();
var h = c.getCol();
var eId = "db_" + a + "_" + e + "_" + h;
var cell = document.getElementById(eId);
var cellValue = cell.innerHTML;
if (cellValue) {
cellValue = cellValue.toString().replace(/\s*\<.*?\>\s*/g, '');
cellValue = cellValue.toString().replace(/</g, '<');
cellValue = cellValue.toString().replace(/>/g, '>');
cellValue = cellValue.toString().replace(/"/g, '"');
cellValue = cellValue.toString().replace(/ /g, ' ');
}
window.prompt('To copy -> Ctrl+C', cellValue );
break;
//jack carver end
...
Вот и все! Надеюсь, этот текст будет кому-нибудь полезен!
P.S. Решение приведено для версии OBIEE 11.1.1.6.2 (Build 120604.0813 BP1 64-bit)
В BI 11.1.1.7 в меню пункт появился, но при нажатии ничего не происходит.
ОтветитьУдалитьЕсть подозрение, что не отрабатывает window.prompt('To copy -> Ctrl+C', cellValue );
Может сталкивались?
Проблема была связана с ошибкой в переменных(в моих конфигах название переменных отличны от приведенных).
ОтветитьУдалитьСоветую для FF использовать FireBug - очень помогает)
Спасибо огромное автору!
Респект таким читателям ;)
ОтветитьУдалитьСергей, спасибо за Ваш блог и консультации на sql.ru :)
ОтветитьУдалитьЯ попробовал сделать немного проще и у меня работает, но, возможно, это неправильно и может привести где-то к ошибке.
Посмотрите, пожалуйста, возможно ли использовать данный вариант в продакшене?
Все изменения в pivotview.js
в методе obips.PivotTable.onKeyDown = function (f) {
.........
var h = obips.PivotTable.isCtrlKeyPressed(f);
var i = obips.PivotTable.isShiftKeyPressed(f);
// Начало моего кода
if (h && (f.keyCode == 67 || f.keyCode == 99)) {
var l_viewmodel = obips.ViewModel.getViewModelById(e);
var l_edge = l_viewmodel.focusedCellCoords.edge;
var l_layer = l_viewmodel.focusedCellCoords.layer;
var l_slice = l_viewmodel.focusedCellCoords.slice;
var col_Id = obips.PivotTable.getCellId(e, l_edge, l_layer, l_slice);
var l_value = document.getElementById(col_Id).innerHTML;
window.prompt("Copy to clipboard: Ctrl+C", l_value);
}
// Окончание моего кода
switch (f.keyCode) {
.......
Как по мне - решение супер! Проще и очевиднее для пользователей!
УдалитьВот только у вас обработчик "слушает" нажатия Ctrl-C только с PivotTable. Нужно аналогичные действия выполнить и для обычных таблиц (или obips.PivotTable.onKeyDown слушает и нажатия на простых TableView?)
Здравствуйте :)
УдалитьВ версии 11.1.1.7.140114 "слушатель"(obips.PivotTable.onKeyDown) у них общий и это работает для сводных и для обычных таблиц. Как в других версиях не знаю, пока нету возможности проверить. К сожалению, на сводных работает только для строк, для показателей значение не копируется, пока разбираюсь. Для обычных таблиц работает всё корректно, но нужно добавить регэксп l_value = l_value .toString().replace(/\s*\<.*?\>\s*/g, ''); для корректной обработки объеденных ячеек и ячеек содержащих ссылки на действие.
Забыл добавить, я делал не через контекстное меню, а через вызов по CTRL+C
ОтветитьУдалитьДобрый день
ОтветитьУдалитьсделал как написано. меню с копированием нет
посмотрел исходный код отчета BI
подгружается почему-то не измененный файл. в Могиле трейс показывает, что послан запрос на сервер, ответа нет, взят из кеша
что надо сделать, чтобы появился пункт меню?
Спасибо
Скажите, в какой именно папке правили javascript файлы?
УдалитьИх оказывается 2 папки
Удалитьу меня правильные расположены тут:
bifoundation_domain\servers\bi_server1\tmp\_WL_user\analytics_11.1.1\7dezjl\war\res\b_mozilla\views
все сделал, изменил переменные, все работает
а каким образом можно копировать значения нескольких ячеек из отчета?
Спасибо
а каким образом можно копировать значения нескольких ячеек из отчета?
УдалитьК сожалению, решения на эту проблему у меня нет.
УдалитьНужно ковыряться в javascript...
в Мозиле
ОтветитьУдалитьпрошу прощения