Иногда это бывает необходимо - например, для ручного тестирования результатов отчета.
Существуют различные окольные решения:
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...
в Мозиле
ОтветитьУдалитьпрошу прощения