'+this.options.action.attribute13.split( this.defaultTemplateMarker )[0]+'',
72 | defaultTemplateAfter : this.options.action.attribute13 == null ? null : ''+this.options.action.attribute13.split( this.defaultTemplateMarker )[1]+'
'
73 | };
74 |
75 | this.td = this.element.is('td') ? this.element : this.element.closest('td');
76 |
77 | this.affectedElement = this.options.affectedElements;
78 | //closest table to triggering element
79 | this.table = this.td.closest('table');
80 | //closest row to triggering element
81 | this.row = this.td.closest('tr');
82 | //object describing nested report entity
83 | this.nestedReport = {
84 | ajaxData: null,
85 | tr: null,
86 | td: null,
87 | container: null,
88 | contentHere: null
89 | };
90 |
91 | this.spinner = null;
92 |
93 | this.inception = {
94 | 'type' : undefined,
95 | 'element': undefined,
96 | 'level' : undefined
97 | };
98 |
99 | this.expanded = false;
100 | this.animationRunning = false;
101 | this.queryColumnsNames = this.options.queryColumns;
102 | this.queryItems = this.options.queryItems;
103 | this.queryColumnsValues = [];
104 |
105 | this.ajax = {
106 | id: this.options.action.ajaxIdentifier,
107 | running: false,
108 | forced: false,
109 | isRefresh: false
110 | };
111 |
112 | this.td
113 | .on('mouseenter', $.proxy( this._highlight,this ))
114 | .on('mouseleave', $.proxy( this._removeHighlight,this ));
115 |
116 | this.row
117 | .on('mouseenter', $.proxy( this._overrideApexTrHover,this, true ))
118 | .on('mouseleave', $.proxy( this._overrideApexTrHover,this, false ));
119 |
120 | //?
121 | if ( this.options.throwError != undefined ) {
122 | this.throwError( this.options.throwError, this.errorTypes.configuration );
123 | }
124 |
125 | notMatchedColumn = this._notMatchedColumn();
126 |
127 | this.inception = this._iAmYourFatherLuke();
128 |
129 | if ( notMatchedColumn != null ) {
130 | this.throwError(
131 | {
132 | title: this.errorTypes.configuration.title,
133 | text: 'Marker for column #'+notMatchedColumn+'# not found in row. At least one of listed selectors must return #'+notMatchedColumn+'# value.',
134 | pre : [
135 | '$(\'[headers="'+notMatchedColumn+'"]\').text() //for nested reports embeded directly in Classic Report',
136 | '$(\'[headers="'+notMatchedColumn+'"]\').text() //for nested reports embeded directly in Interactive Report (column static ID is required)',
137 | '$(\'[headers="NR_'+this.inception.level+'_'+notMatchedColumn+'"]\').text() //for nested reports embeded in nested reports',
138 | '$(\'span[class*="'+notMatchedColumn+'"]\').text() //universal column marker (requires changes in APEX Column Formatting)'
139 | ],
140 | hints : []
141 | }
142 | );
143 | //this.destroy();
144 | }
145 |
146 | if ( this.settings.isDefaultTemplate == true && this.settings.isDefaultTempateMarker == false ) {
147 | this.throwError(
148 | {
149 | title: this.errorTypes.configuration.title,
150 | text: 'Marker '+this.defaultTemplateMarker+' not found in definiton of the plugin "Default template HTML" attribute.',
151 | pre : [
152 | 'Make sure the value of "Default template HTML" attribute contains at least '+this.defaultTemplateMarker+' marker."'
153 | ],
154 | hints : []
155 | }
156 | );
157 |
158 | }
159 |
160 |
161 | if ( this.options.forceToggle ) {
162 | this.toggle();
163 | }
164 |
165 | },
166 | //
167 | //
168 | _destroy: function(){
169 | },
170 | //
171 | //
172 | _setOption: function( pKey, pValue ) {
173 | if ( pKey === "value" ) {
174 | pValue = this._constrain( pValue );
175 | }
176 |
177 | this._super( pKey, pValue );
178 | },
179 | options: function( pOptions ){
180 | this._super( pOptions );
181 | },
182 | //
183 | //
184 | _setOptions: function( pOptions ) {
185 | this._super( pOptions );
186 | },
187 | //
188 | // nie uzywane
189 | setContentHere: function( pNode ){
190 | this.nestedReport.contentHere = pNode;
191 | },
192 | //
193 | //
194 | _notMatchedColumn: function(){
195 | var
196 | headerTag,
197 | spanTag,
198 | column;
199 |
200 | for ( var i=0; i < this.queryColumnsNames.length; i++ ){
201 | column = this.queryColumnsNames[i];
202 | headerTag = this.row.find('[headers="'+column+'"]');
203 | nestedHeaderTag = this.row.find('[headers="NR_'+this.inception.level+'_'+column+'"]');
204 | spanTag = this.row.find('span[class*="'+column+'"]');
205 |
206 | if ( headerTag.length == 0 && spanTag.length == 0 && nestedHeaderTag.length == 0) {
207 | return column;
208 | }
209 | else {
210 | if ( spanTag.length != 0 ) {
211 | this.queryColumnsValues.push( spanTag.first().text() );
212 | }
213 | else if ( headerTag.length != 0 ) {
214 | this.queryColumnsValues.push( headerTag.first().text() );
215 |
216 | }
217 | else {
218 | this.queryColumnsValues.push( nestedHeaderTag.first().text() );
219 | }
220 |
221 | }
222 |
223 | }
224 | return null;
225 | },
226 | //
227 | //
228 | _getPlugAttrFlag: function( pAttr, pExpectedValue ){
229 | var pAttr = this.options.action['attribute'+pAttr];
230 |
231 | if ( pAttr == undefined || pAttr == null ) {
232 | return false;
233 | }
234 |
235 | return pAttr.indexOf( pExpectedValue ) > -1;
236 | },
237 | //
238 | //
239 | getParent: function(){
240 | return this.inception;
241 | },
242 | //
243 | //
244 | getLevel: function(){
245 | return this.inception.level;
246 | },
247 | //
248 | //
249 | _getExpandedFrom: function( pElement ) {
250 | var expanded;
251 | apex.debug.log('_getExpandedFrom', ', search in pElement =', pElement);
252 |
253 | expanded = pElement.find('*').filter( function(pIndex, pElement){
254 | var self = $(pElement);
255 |
256 | if ( self.data('pretius-nestedReport') != undefined && self.nestedReport('isExpanded') == true ) {
257 | return true;
258 | }
259 | } );
260 |
261 | apex.debug.log('_getExpandedFrom', ', found elements count = ', expanded.length, ', elements =', expanded);
262 |
263 | return expanded;
264 | },
265 | //
266 | //
267 | _iAmYourFatherLuke: function(){
268 | var
269 | closestContainer = this.td.closest('[class*='+this.classes.nestedReportTrContainer+']'),
270 | vader;
271 |
272 | if ( closestContainer.length > 0 ) {
273 | //na pewno jestem przynajmniej level 1
274 | vader = this._getExpandedFrom( closestContainer.prev() );
275 |
276 | if ( vader != undefined && vader.length > 0 ) {
277 | return {
278 | 'type' : 'nested',
279 | 'element': vader,
280 | 'level' : (vader.nestedReport('getLevel'))+1
281 | };
282 | }
283 | else {
284 | //first level
285 | return {
286 | 'type' : 'Invalid nested report',
287 | 'element': undefined,
288 | 'level' : -1
289 |
290 | };
291 | }
292 |
293 | }
294 | //tu dorobic czy na pewno affectedElements jest najblizszym rodzicem
295 | else {
296 | return {
297 | 'type' : 'affectedElement',
298 | 'element': this.affectedElement,
299 | 'level' : 1
300 |
301 | };
302 | }
303 | },
304 | //
305 | //
306 | throwError: function( pError ){
307 | var
308 | tr = this.createDefaultCallbackRow(),
309 | pre = $('').append( JSON.stringify( pError, null, 2) ),
310 | duration = 400,
311 | closeDuration = 0,
312 | div = this._getErrorTemplate( pError ),
313 | closeBefore = this._expandedSisters();
314 |
315 | this.nestedReport.td = tr.find('td');
316 | this.nestedReport.container = tr.find( '[class*='+this.classes.nestedReportDivContainer+']' );
317 | this.nestedReport.tr = tr;
318 |
319 | closeBefore.nestedReport('collapse', closeDuration);
320 |
321 | if ( closeBefore.length > 0 ) {
322 | closeDuration = this.settings.closeOtherDuration;
323 | }
324 |
325 | setTimeout( $.proxy(function(){
326 | this.nestedReport.container.html( div );
327 | this.nestedReport.tr.insertAfter( this.row );
328 |
329 | this.td.addClass( this.classes.tdExpanded );
330 | this.expanded = true;
331 | this.td.data('pretius-nestedReport-owner', this.element);
332 |
333 | this.changeBorderStyle();
334 | this.nestedReport.tr.show();
335 |
336 | if ( this.settings.isDefaultCallback && this.settings.isAddAnimation == false) {
337 | duration = 0;
338 | }
339 |
340 | this.nestedReport.container.slideDown( duration , $.proxy(function(){
341 | this.callbackExpanded();
342 | }, this));
343 | }, this), closeDuration + 150);
344 |
345 | apex.debug.error(
346 | "Pretius APEX Nested Reports error:\n",
347 | " "+pError.title.replace(/<[^>]+>/g, '')+"\n",
348 | " "+pError.text.replace(/<[^>]+>/g, '')
349 | );
350 |
351 | if ( pError.hints.length > 0 ) {
352 | for ( var i = 0; i < pError.hints.length; i++ ) {
353 | apex.debug.warn(pError.hints[i].label+':', "\n\n"+pError.hints[i].value );
354 | }
355 | }
356 |
357 | if ( arguments.length > 1 ) {
358 | for ( var i = 1; i < arguments.length; i++ ) {
359 | apex.debug.warn('Additional info #'+(i-1)+':', arguments[i] );
360 | }
361 | }
362 |
363 | throw 'Plugin execution stopped.'
364 | },
365 | //
366 | //
367 | isAjaxRunning: function(){
368 | return this.ajax.running;
369 | },
370 | //
371 | //
372 | isExpanded: function(){
373 | return this.expanded;
374 | },
375 | //
376 | //
377 | toggle: function(){
378 | var
379 | closeDuration = 0,
380 | closeBefore;
381 |
382 | if ( this.expanded == true ) {
383 | this.collapse();
384 | }
385 | else {
386 | if ( this.settings.isCollapseExapnded == true) {
387 | closeBefore = this._expandedInReport();
388 | } else {
389 | closeBefore = this._expandedSisters();
390 | }
391 |
392 | if ( closeBefore.length > 0 ) {
393 | closeDuration = this.settings.closeOtherDuration;
394 | closeBefore.nestedReport('collapse', closeDuration);
395 |
396 | setTimeout( $.proxy(function(){
397 | this.show();
398 | }, this), closeDuration + 150);
399 |
400 | }
401 | else {
402 | this.show();
403 | }
404 | }
405 | },
406 |
407 | //
408 | //
409 | show: function(){
410 |
411 | if ( this.nestedReport.ajaxData == null ) {
412 | this.ajax.forced = true;
413 | this.ajaxFetchData();
414 | return void(0);
415 | }
416 | else {
417 |
418 | //dane są, sprawdz czy cache wlaczony
419 | if ( this.settings.isCacheResults == false && this.ajax.forced == false && this.ajax.isRefresh == false) {
420 | //zresetuj zawartość nested report, tak zeby wygenerowac go na nowo
421 | //this.nestedReport.tr.remove();
422 | this.nestedReport.tr = null;
423 | this.ajax.forced = true;
424 | this.ajaxFetchData();
425 | return;
426 | }
427 | else if ( this.settings.isCacheResults == false && this.ajax.forced == true && this.ajax.isRefresh == false) {
428 | this.ajax.forced = false;
429 | }
430 | }
431 |
432 | if ( this.settings.isDefaultCallback ) {
433 | this.doCallbackDefault();
434 | }
435 | else {
436 | this.doCallbackCustom()
437 | }
438 | },
439 | //
440 | //
441 | expand: function( pForceDuration ){
442 | var
443 | duration = this.settings.animationTime;
444 |
445 | if ( this.settings.isAddAnimation == false) {
446 | duration = 0;
447 | }
448 |
449 | if ( pForceDuration != null && pForceDuration != undefined ) {
450 | duration = pForceDuration;
451 | }
452 |
453 | this.animationRunning = true;
454 | //before slide down
455 | apex.event.trigger(this.affectedElement, 'pretius_default_callback', this.getEventData());
456 |
457 | //pretius-nestedReport-owner is used to find out triggering element
458 | //while scanning row or table for expanded cells
459 | this.td.data('pretius-nestedReport-owner', this.element);
460 | this.td.addClass( this.classes.tdExpanded );
461 |
462 | this.expanded = true;
463 | this.changeBorderStyle();
464 |
465 | this.nestedReport.tr.show();
466 |
467 | //after slide down
468 | this.nestedReport.container.slideDown( duration , $.proxy( this.callbackExpanded, this ));
469 | },
470 | //
471 | //
472 | collapse: function( pForceDuration ){
473 | var duration = pForceDuration == undefined ? this.settings.closeOtherDuration : pForceDuration;
474 |
475 | if ( this.settings.isAddAnimation == false) {
476 | duration = 0;
477 | }
478 |
479 | this.animationRunning = true;
480 |
481 | apex.event.trigger(this.affectedElement, 'pretius_default_callback', this.getEventData() );
482 |
483 | this.nestedReport.container.slideUp( duration , $.proxy( this.callbackCollapsed, this) );
484 | },
485 | //
486 | //
487 | doCallbackDefault: function(){
488 | var
489 | newTr,
490 | nestedReportContent;
491 |
492 | if ( this.nestedReport.tr == null ) {
493 | // first drill down
494 |
495 | //create new nested report row
496 | newTr = this.createDefaultCallbackRow()
497 | //this.nestedReport.contentHere points td in newly created tr
498 | this.nestedReport.td = newTr.find('td');
499 | this.nestedReport.container = newTr.find( '[class*='+this.classes.nestedReportDivContainer+']' );
500 | this.nestedReport.tr = newTr;
501 |
502 | this.nestedReport.tr.insertAfter( this.row );
503 |
504 | if ( this.settings.isDefaultTemplate ) {
505 |
506 | nestedReportContent = this.renderTemplateDefault();
507 |
508 | this.nestedReport.contentHere.empty();
509 | this.nestedReport.contentHere.append( this.settings.defaultTemplateBefore );
510 | this.nestedReport.contentHere.append( nestedReportContent );
511 | this.nestedReport.contentHere.append( this.settings.defaultTemplateAfter );
512 |
513 | }
514 | else {
515 | nestedReportContent = this.renderTemplateCustom();
516 | this.nestedReport.contentHere.html( nestedReportContent )
517 | }
518 |
519 | }
520 | else {
521 | // next drill down, the content is only replaced when caching is turned off
522 |
523 | if ( this.ajax.isRefresh ) {
524 | //this.ajax.isRefresh = false;
525 |
526 | this.nestedReport.contentHere.empty();
527 |
528 | if ( this.settings.isDefaultTemplate ) {
529 | nestedReportContent = this.renderTemplateDefault();
530 |
531 | this.nestedReport.contentHere.append( this.settings.defaultTemplateBefore );
532 | this.nestedReport.contentHere.append( nestedReportContent );
533 | this.nestedReport.contentHere.append( this.settings.defaultTemplateAfter );
534 | }
535 | else {
536 | nestedReportContent = this.renderTemplateCustom();
537 | this.nestedReport.contentHere.html( nestedReportContent )
538 | }
539 |
540 | }
541 | else {
542 | //do nothing, the content is already rendered
543 | null;
544 | }
545 | }
546 |
547 |
548 | //bind nested report with manualy triggered event from APEX
549 | //ex: $(this.triggeringElement).trigger('nestedreportrefresh');
550 | this.nestedReport.tr.off('nestedreportrefresh').on('nestedreportrefresh', $.proxy( this.defaultCallbackEvent_refresh, this ) );
551 |
552 | //bind anchors with class ".nestedreport--refresh" to refresh content of nested report
553 | this.nestedReport.tr.off('click', '.nestedreport--refresh') .on('click', '.nestedreport--refresh', $.proxy( this.defaultCallbackEvent_refresh, this ) );
554 | //bind anchors with class ".nestedreport--slideup" to manualy
555 | //collapse nested report
556 | this.nestedReport.tr.off('click', '.nestedreport--slideup') .on('click', '.nestedreport--slideup', $.proxy( this.defaultCallbackEvent_slideup, this ) );
557 | //bind anchors with class ".nestedreport--slideupAll" to manualy
558 | //collapse all nested reports
559 | this.nestedReport.tr.off('click', '.nestedreport--slideupAll').on('click', '.nestedreport--slideupAll', $.proxy( this.defaultCallbackEvent_slideupAll, this ) );
560 | //bind anchors with class ".nestedreport--expandAll" to manualy
561 | //expand all nested reports matched with given selector as anchor attribute
562 | this.nestedReport.tr.off('click', '.nestedreport--expandAll').on('click', '.nestedreport--expandAll', $.proxy( this.defaultCallbackEvent_expandAll, this ) );
563 |
564 | this.expand();
565 |
566 | },
567 | //
568 | defaultCallbackEvent_expandAll: function( pEvent ){
569 | var
570 | anchor = $(pEvent.target),
571 | selector = anchor.attr('selector'),
572 | toBeExpanded = this.nestedReport.tr.find( selector );
573 |
574 | pEvent.stopPropagation();
575 | pEvent.preventDefault();
576 |
577 | //filter to only selectors from this nested report
578 | toBeExpanded = toBeExpanded.filter( $.proxy(function(pIndex, pElem){
579 | var closestNestedContainer = $(pElem).closest('[class*='+this.classes.nestedReportDivContainer+']')
580 | return closestNestedContainer.get(0) == this.nestedReport.container.get(0);
581 | }, this) );
582 |
583 | toBeExpanded.each( $.proxy( function( pIdx, pElem ){
584 | var self = $(pElem);
585 |
586 | if ( self.data('pretius-nestedReport') == undefined ) {
587 | self.trigger('click');
588 | }
589 | else if ( self.nestedReport('isExpanded') == false ) {
590 | self.nestedReport('expand');
591 | }
592 | }, this) );
593 |
594 | },
595 | //
596 | //
597 | defaultCallbackEvent_slideupAll: function( pEvent ){
598 | var
599 | anchor = $(pEvent.target),
600 | anchorAttrDuration = anchor.attr('duration') == undefined ? this.settings.animationTime : parseInt( anchor.attr('duration') ),
601 | duration = isNaN(anchorAttrDuration) ? this.settings.animationTime : anchorAttrDuration,
602 | expanded = this._getExpandedFrom( this.nestedReport.tr );
603 |
604 | pEvent.stopPropagation();
605 | pEvent.preventDefault();
606 |
607 | expanded.nestedReport('collapse', duration);
608 | },
609 | //
610 | //
611 | defaultCallbackEvent_slideup: function( pEvent ){
612 | var
613 | anchor = $(pEvent.target),
614 | anchorAttrDuration = anchor.attr('duration') == undefined ? this.settings.animationTime : parseInt( anchor.attr('duration') ),
615 | duration = isNaN(anchorAttrDuration) ? this.settings.animationTime : anchorAttrDuration;
616 |
617 | pEvent.stopPropagation();
618 | pEvent.preventDefault();
619 |
620 | this.collapse( duration );
621 | },
622 | //
623 | //
624 | defaultCallbackEvent_refresh: function( pEvent ){
625 | pEvent.stopPropagation();
626 | pEvent.preventDefault();
627 |
628 | this.ajaxFetchData( true );
629 | },
630 |
631 | doCallbackCustom: function(){
632 | var
633 | functionBody = " \n"+
634 | "this.callback = { \n"+
635 | " 'sqlResultObj' : data, \n"+
636 | " 'triggeringElement' : $(da.triggeringElement), \n"+
637 | " 'affactedReport' : $(da.affectedElements[0]), \n"+
638 | " 'renderedTemplate' : templateContent, \n"+
639 | " 'browserEvent' : da.browserEvent, \n"+
640 | " //newly added in v1.1 \n"+
641 | " 'dynamicAction' : da, \n"+
642 | " 'pluginSettings' : settings \n"+
643 | "}; \n"+
644 | "//start of custom callback javascript \n"+
645 | this.settings.customCallbackJs +"\n"+
646 | "//end of custom callback javascript \n",
647 |
648 | tempFunc = new Function("templateContent", "settings", "da", "data", functionBody),
649 | template;
650 |
651 | if ( this.settings.isDefaultTemplate ) {
652 | template = $('').addClass( this.classes.nestedReportDivContainer ).append( this.renderTemplateDefault() );
653 | }
654 | else {
655 | template = this.renderTemplateCustom();
656 | }
657 |
658 | try {
659 | tempFunc( template, this.settings, this.options, this.nestedReport.ajaxData );
660 | } catch( thrownError ) {
661 |
662 | this.throwError(
663 | {
664 | title: this.errorTypes.customFunction.title,
665 | text : 'While executing Custom Callback JavaScript error occured',
666 | pre : [thrownError],
667 | hints : [
668 | this._hint( 'Custom callback JavaScript', tempFunc.toString() )
669 | ]
670 | }
671 | );
672 |
673 | }
674 | },
675 | //
676 | //
677 | _ajaxStart: function(){
678 | this.ajax.running = true;
679 |
680 | if ( this.settings.isLoadingIndicator ) {
681 | this._showSpinner();
682 | }
683 |
684 | },
685 | //
686 | //
687 | _ajaxEnd: function(){
688 | this.ajax.running = false;
689 | this._hideSpinner();
690 |
691 | },
692 | //
693 | //
694 | _ajaxSuccess: function(pData, pTextStatus, pJqXHR){
695 | this._ajaxEnd();
696 |
697 | for ( var i=0; i < pData.data.length; i++ ) {
698 | pData.data[i].rowClass = i % 2 == 0 ? 'odd' : 'even';
699 | }
700 |
701 | this.nestedReport.ajaxData = pData;
702 | this.show();
703 | },
704 | //
705 | //
706 | _hint: function( pTitle, pValue ) {
707 | return {
708 | label: pTitle,
709 | value: pValue
710 | }
711 | },
712 | _ajaxError: function( pJqXHR, pTextStatus, pErrorThrown ){
713 | this._ajaxEnd();
714 |
715 | if ( pTextStatus == 'parsererror' ) {
716 | this.throwError({
717 | title: this.errorTypes.ajax.title,
718 | text : 'Ajax response could not be parsed as JSON',
719 | pre : pErrorThrown.message,
720 | hints : [
721 | this._hint( 'Ajax response text', pJqXHR.responseText )
722 | ]
723 | });
724 | return void(0);
725 | }
726 |
727 | this.throwError({
728 | title: this.errorTypes.ajax.title,
729 | text : pJqXHR.responseJSON.addInfo,
730 | pre : pJqXHR.responseJSON.error,
731 | hints : [
732 | this._hint( 'Ajax JSON', pJqXHR.responseJSON ),
733 | this._hint( 'Ajax error info', pJqXHR.responseJSON.addInfo ),
734 | this._hint( 'Ajax error thrown', pErrorThrown )
735 | ]
736 | });
737 | },
738 | //
739 | //
740 | ajaxFetchData: function( pIsRefresh ){
741 | var
742 | pAjaxCallbackName = this.ajax.id,
743 | pData = {
744 | //type : "GET",
745 | //dataType : "json",
746 | x01 : this.queryColumnsNames.join(':'), //nazwy kolumn
747 | x02 : this.queryColumnsValues.join(':') //wartości kolumn
748 | },
749 | pOptions;
750 |
751 | this.ajax.isRefresh = pIsRefresh == undefined ? false : pIsRefresh;
752 |
753 | pOptions = {
754 | success : $.proxy(this._ajaxSuccess, this),
755 | error : $.proxy(this._ajaxError , this)
756 | };
757 |
758 | if ( !this.isAjaxRunning() ) {
759 | this._ajaxStart();
760 |
761 | if ( this.queryItems.length > 0 ) {
762 | pData.pageItems = '#'+this.queryItems.join(',#');
763 | }
764 |
765 | apex.server.plugin ( pAjaxCallbackName, pData, pOptions );
766 | }
767 | },
768 | //
769 | //
770 | _ajaxCreateIndicatorTdIcon: function(){
771 | var
772 | icon = $(''),
773 | div = $('');
774 |
775 | if ( this.settings.isSpinnerTdIcon ) {
776 | div.addClass( this.classes.ajaxIndicatorRight );
777 | }
778 | else if ( this.settings.isSpinnerTdContent ) {
779 | div.addClass( this.classes.ajaxIndicatorContent );
780 | }
781 |
782 | div.append(icon);
783 | return div;
784 | },
785 | //
786 | //
787 | _showSpinner: function(){
788 |
789 | if ( this.settings.isSpinnerTdIcon ) {
790 | this.spinner = this._ajaxCreateIndicatorTdIcon();
791 | this.td.append( this.spinner );
792 | }
793 | else if ( this.settings.isSpinnerReport ) {
794 | this.spinner = apex.util.showSpinner( this.table );
795 | }
796 | else if ( this.settings.isSpinnerTdCell ) {
797 | this.spinner = apex.util.showSpinner( this.td );
798 | }
799 | else if ( this.settings.isSpinnerTdContent ) {
800 | this.spinner = this._ajaxCreateIndicatorTdIcon();
801 | if ( this.td.children().length > 0 ) {
802 | this.td.data('pretius-nestedReport-content', this.td.children().detach() );
803 | }
804 | else {
805 | this.td.data('pretius-nestedReport-content', this.td.text() );
806 | }
807 |
808 | this.td.html( this.spinner );
809 | }
810 | else {
811 |
812 | return this.throwError({
813 | title: this.errorTypes.configuration.title,
814 | text : 'Unknown spinner option',
815 | pre : ['attribute12: '+this.options.action.attribute12],
816 | hints : [],
817 |
818 | addInfo: 'Unknown spinner option',
819 | error: 'attribute12: '+this.options.action.attribute12
820 | }, this.errorTypes.configuration );
821 |
822 | }
823 | },
824 | //
825 | //
826 | _hideSpinner: function(){
827 | if ( this.settings.isLoadingIndicator ) {
828 | this.spinner.fadeOut(400, $.proxy(function(){
829 | this.spinner.remove();
830 |
831 | if ( this.settings.isSpinnerTdContent ) {
832 | this.td.html( this.td.data('pretius-nestedReport-content') )
833 | }
834 | }, this));
835 | }
836 | },
837 |
838 | //
839 | //
840 | renderTemplateCustom: function(){
841 | var
842 | template = this.settings.customTemplate,
843 | rendered,
844 | dataObject = this.nestedReport.ajaxData,
845 | error = {
846 | addInfo: null,
847 | error: null
848 | },
849 | rendered,
850 | errorText;
851 |
852 | if ( dataObject.data.length == 0 ) {
853 | return this._renderNoDataFound();
854 | }
855 |
856 | try {
857 | rendered = Mustache.render( template, dataObject);
858 | } catch( error ) {
859 |
860 | error.addInfo = 'While rendering custom template unexpected error occured: ';
861 | error.error = error;
862 | return this._getErrorTemplate( error, 'configuration' );
863 | }
864 |
865 | return rendered;
866 | },
867 | //
868 | //
869 | _renderNoDataFound: function(){
870 | return ''+this.settings.noDataFound+'
'
871 | },
872 | //
873 | //
874 | getTemplateDefaultBody: function(){
875 | var
876 | dataObject = this.nestedReport.ajaxData,
877 | td_row_template = '',
878 | level = this.inception.level;
879 |
880 |
881 | for ( var i = 0; i < dataObject.headers.length; i++ ) {
882 | td_row_template += '' +
883 | '' +
889 | '{{{'+ dataObject.headers[i].COLUMN_NAME +'}}}' +
890 | ' | ';
891 | }
892 |
893 | td_row_template = '{{#data}}'+td_row_template+'
{{/data}}';
894 | return td_row_template;
895 | },
896 | //
897 | //
898 | getTemplateDefault: function(){
899 | var
900 | th_row_template = '',
901 | dataObject = this.nestedReport.ajaxData,
902 | template,
903 | headerHtml,
904 | headerArr,
905 | isHeaderIcon = false,
906 | tableClass = this.settings.isStrechReport ? this.classes.nestedReportTable+' '+this.classes.tableStrechReport : this.classes.nestedReportTable;
907 |
908 | for ( var i = 0; i < dataObject.headers.length; i++ ) {
909 | //icons fa-iconname
910 | if ( /^derivied[0-9]{1}[0-9]{1}_fa_[a-z]{3,}$/gi.test( dataObject.headers[i].COLUMN_NAME.toLowerCase()) ) {
911 | headerArr = dataObject.headers[i].COLUMN_NAME.split('_');
912 | headerHtml = '';
913 | isHeaderIcon = true;
914 | }
915 | //icons fa-iconname-morename
916 | else if (/^derivied[0-9]{1}[0-9]{1}_fa_[a-z]{3,}_[a-z]{3,}$/gi.test( dataObject.headers[i].COLUMN_NAME.toLowerCase()) ) {
917 | headerArr = dataObject.headers[i].COLUMN_NAME.split('_');
918 | headerHtml = '';
919 | isHeaderIcon = true;
920 | }
921 | else if ( /^derivied[0-9]{1}[0-9]{1}_empty$/gi.test( dataObject.headers[i].COLUMN_NAME.toLowerCase()) ) {
922 | headerHtml = '';
923 | isHeaderIcon = true;
924 | }
925 | else {
926 | isHeaderIcon = false;
927 | headerHtml = dataObject.headers[i].COLUMN_NAME;
928 | }
929 |
930 | if ( this.settings.isSortingSupported && isHeaderIcon == false ) {
931 | th_row_template += ''+
932 | ' '+
934 | ' '+
935 | ' '+
936 | ' '+ headerHtml +' '+
937 | ' '+
938 | ' '+
939 | ' '+
940 | ' '+
941 | ' | ';
942 | }
943 | else {
944 | th_row_template += ''+ headerHtml +' | ';
947 | }
948 | }
949 |
950 | th_row_template = ''+th_row_template+'
';
951 |
952 | template = ''+th_row_template+''+ this.getTemplateDefaultBody() +'
';
953 | return template;
954 |
955 | },
956 | //
957 | // Used by this.sort function to render tbody of nested report
958 | renderTemplateDefaultBody: function(){
959 | return Mustache.render( this.getTemplateDefaultBody(), this.nestedReport.ajaxData );
960 | },
961 | //
962 | //
963 | renderTemplateDefault: function(){
964 | var
965 | content;
966 |
967 | if ( this.nestedReport.ajaxData.data.length == 0 ) {
968 | content = $(this._renderNoDataFound());
969 | }
970 | else {
971 | content = Mustache.render( this.getTemplateDefault(), this.nestedReport.ajaxData );
972 | content = $(content);
973 |
974 | content.css({
975 | 'backgroundColor': this.settings.bgColor
976 | });
977 |
978 | content.find('th a').bind('click', $.proxy(this.sort, this));
979 | }
980 |
981 | return content;
982 | },
983 | //
984 | //
985 | createDefaultCallbackRow: function(){
986 | //do rozwazenia, nadawanie unikalnego ID
987 | var
988 | tr = $('
'),
989 | td = $(' | '),
990 | divInTd = $(''),
991 | divTdOverflow = $('');
992 |
993 | //jesli wykorzystuje maxHeight to ustaw maxHeight oraz ustaw referencje gdzie pisać
994 | if ( this.settings.isSetMaxHeight ) {
995 | divTdOverflow.addClass( this.classes.nestedReportOverflowContainer )
996 | divTdOverflow.css('maxHeight', this.settings.maxHeight);
997 | divTdOverflow.appendTo( divInTd );
998 | this.nestedReport.contentHere = divTdOverflow;
999 | }
1000 | else {
1001 | this.nestedReport.contentHere = divInTd;
1002 | }
1003 |
1004 | tr.attr('nested-level', this.inception.level );
1005 | tr.addClass( this.classes.nestedReportTrContainer );
1006 | td.attr('colspan', this.row.find('td').length);
1007 |
1008 | divInTd.addClass( this.classes.nestedReportDivContainer );
1009 |
1010 | td.on('mouseenter', $.proxy(this._highlight,this))
1011 | td.on('mouseleave', $.proxy(this._removeHighlight,this));
1012 |
1013 | td.append( divInTd );
1014 | tr.append( td );
1015 |
1016 | return tr;
1017 | },
1018 | //
1019 | //
1020 | _getErrorTemplate: function( pError ){
1021 | var
1022 | title, div;
1023 |
1024 |
1025 | if ( pError.pre instanceof Array ) {
1026 | pError.pre = pError.pre.join("\n");
1027 | pError.pre = pError.pre.replace(//gi, '>');
1028 | }
1029 | else if ( pError.pre instanceof Object ) {
1030 | pError.pre = JSON.stringify( pError.pre, null, 2 ).replace(//gi, '>');
1031 | }
1032 | else if ( typeof pError.pre == "string") {
1033 | pError.pre = pError.pre.replace(//gi, '>');
1034 | }
1035 | else {
1036 | apex.debug.info('_getErrorTemplate type of pError.pre:', (typeof pError.pre) )
1037 | }
1038 |
1039 | //zrobic bardziej czytelne
1040 | div = $(''+
1041 | ' '+
1042 | '
'+
1043 | ' '+
1044 | ' '+pError.title+' '+
1045 | '
'+
1046 | '
'+
1047 | ' '+pError.text+' '+
1048 | '
'+
1049 | '
'+
1050 | '
'+pError.pre+'
'+
1051 | '
'+
1052 | '
'+
1053 | '');
1054 |
1055 | return div;
1056 | },
1057 |
1058 | //
1059 | //
1060 | _expandedInReport: function(){
1061 | var expandedElements = $();
1062 |
1063 | this.table.find('td').each( function(){
1064 | var
1065 | self = $(this),
1066 | tdOwner = self.data('pretius-nestedReport-owner');
1067 |
1068 | if ( tdOwner != undefined && tdOwner.nestedReport('isExpanded') == true ) {
1069 | expandedElements = expandedElements.add( tdOwner );
1070 | }
1071 |
1072 |
1073 | } );
1074 |
1075 | return expandedElements;
1076 | },
1077 | //
1078 | //
1079 | _expandedSisters: function(){
1080 | var expandedElements = $();
1081 |
1082 | this.row.find('td').each( function(){
1083 | var
1084 | self = $(this),
1085 | tdOwner = self.data('pretius-nestedReport-owner');
1086 |
1087 | if ( tdOwner != undefined && tdOwner.nestedReport('isExpanded') == true ) {
1088 | expandedElements = expandedElements.add( tdOwner );
1089 | }
1090 | } );
1091 |
1092 | return expandedElements;
1093 | },
1094 | //
1095 | //
1096 | sort: function( pEvent ){
1097 | var
1098 | anchor = $(pEvent.currentTarget),
1099 | th = anchor.closest('th'),
1100 | otherTh = th.prevAll().add( th.nextAll() ),
1101 | div = th.find('.u-Report-sort'),
1102 | headerText = anchor.text();
1103 |
1104 | //apex.debug.log('sort', 'nestedReportData', this.nestedReport.ajaxData);
1105 |
1106 | otherTh.find('.u-Report-sort').removeClass('sort--desc sort--asc sort');
1107 |
1108 | if ( !div.is('.sort') || div.is('.sort--asc')) {
1109 | this.nestedReport.ajaxData.data.sort(this._sortFunc( headerText ));
1110 | this.nestedReport.ajaxData.data.reverse();
1111 | div.removeClass('sort--asc').addClass( 'sort sort--desc' );
1112 | }
1113 | else {
1114 | this.nestedReport.ajaxData.data.sort(this._sortFunc( headerText ));
1115 | div.removeClass('sort--desc').addClass( 'sort sort--asc' );
1116 | }
1117 |
1118 | this.nestedReport.contentHere.find('tbody').html( this.renderTemplateDefaultBody() );
1119 | },
1120 | //
1121 | //
1122 | _sortFunc: function(pProperty) {
1123 | var sortOrder = 1;
1124 |
1125 | if(pProperty[0] === "-") {
1126 | sortOrder = -1;
1127 | pProperty = pProperty.substr(1);
1128 | }
1129 |
1130 | return function (a,b) {
1131 | var result = (a[pProperty] < b[pProperty]) ? -1 : (a[pProperty] > b[pProperty]) ? 1 : 0;
1132 | return result * sortOrder;
1133 | }
1134 | },
1135 | //
1136 | //
1137 | _removeHighlight: function( pEvent ){
1138 | pEvent.stopImmediatePropagation();
1139 |
1140 | if ( this.expanded ) {
1141 | this.td.css( 'backgroundColor', this.settings.bgColor )
1142 | this._forceBackgroundColor( this.td );
1143 |
1144 | this.nestedReport.td.css( 'backgroundColor', this.settings.bgColor );
1145 |
1146 |
1147 | this.row.removeClass('pretius--hover');
1148 | //blad gdy wylaczony cache i nastepuja proba odswiezenia nested report z poziomu nested report
1149 | this.nestedReport.tr.removeClass('pretius--hover');
1150 | }
1151 | },
1152 | //
1153 | //
1154 | _highlight: function( pEvent ){
1155 | pEvent.stopImmediatePropagation();
1156 |
1157 | if ( this.expanded ) {
1158 | this.td.css( 'backgroundColor', this.settings.BgColorhighlight );
1159 | //its needed to override !important from APEX theme css
1160 | this._forceBackgroundColor( this.td );
1161 |
1162 | this.nestedReport.td.css( 'backgroundColor', this.settings.BgColorhighlight );
1163 |
1164 | this.row.addClass('pretius--hover');
1165 | this.nestedReport.tr.addClass('pretius--hover');
1166 | }
1167 | },
1168 | //
1169 | //
1170 | changeBorderStyle: function(){
1171 | var
1172 | otherTds = this.td.prevAll('td').add( this.td.nextAll('td') ),
1173 | borderStyle = 'solid',
1174 | borderWidth = '1px',
1175 | borderColor = this.settings.borderColor,
1176 | bgColor = this.settings.bgColor;
1177 |
1178 | if ( this.expanded ) {
1179 | this.td.css({
1180 | 'border-left' : borderWidth+' '+borderStyle+' '+borderColor,
1181 | 'border-top' : borderWidth+' '+borderStyle+' '+borderColor,
1182 | 'border-right' : borderWidth+' '+borderStyle+' '+borderColor,
1183 | 'border-bottom' : borderWidth+' '+borderStyle+' '+bgColor,
1184 | 'backgroundColor': bgColor
1185 | });
1186 |
1187 | this.nestedReport.td.css({
1188 | 'backgroundColor': bgColor,
1189 | 'borderLeft' : borderWidth+' '+borderStyle+' '+borderColor,
1190 | 'borderRight' : borderWidth+' '+borderStyle+' '+borderColor,
1191 | 'borderBottom' : borderWidth+' '+borderStyle+' '+borderColor
1192 | });
1193 |
1194 | otherTds.css('border-bottom', borderWidth+' '+borderStyle+' '+borderColor);
1195 | }
1196 | else {
1197 | this.td.css({
1198 | 'border-left' : '',
1199 | 'border-top' : '',
1200 | 'border-right' : '',
1201 | 'border-bottom' : '',
1202 | 'backgroundColor': ''
1203 | });
1204 |
1205 | if ( this.nestedReport.tr.is(':last-child') ) {
1206 | this.nestedReport.tr.show();
1207 | this.nestedReport.td.css('borderColor', this.td.css('borderTopColor'));
1208 | }
1209 |
1210 | otherTds.css('border-bottom', '');
1211 | }
1212 | },
1213 | //
1214 | //
1215 | _overrideApexTrHover: function( pFlag ){
1216 | if ( this.isExpanded() ) {
1217 | //ustaw kolor jak z konfiguracji
1218 | this.td.css( 'backgroundColor', this.settings.bgColor );
1219 | //its needed to override !important from APEX theme css
1220 | this._forceBackgroundColor( this.td );
1221 | }
1222 | },
1223 | //
1224 | //
1225 | _forceBackgroundColor: function( pElem ) {
1226 | var
1227 | styles = pElem.attr('style'),
1228 | arr = styles.split(';');
1229 |
1230 | for (var idx in arr) {
1231 | if ( arr[idx].indexOf('background-color') > -1 ) {
1232 | arr[idx] += ' !important'
1233 | }
1234 | }
1235 |
1236 | pElem.attr('style', arr.join(';'));
1237 | },
1238 | //
1239 | //
1240 | callbackExpanded: function(){
1241 | this.animationRunning = false;
1242 | apex.event.trigger(this.affectedElement, 'pretius_default_callback', this.getEventData());
1243 | },
1244 | //
1245 | //
1246 | getEventData: function(){
1247 | var
1248 | isAfterRefresh = false,
1249 | returnObject;
1250 |
1251 | //after refresh but animation is in progress (duration = 0)
1252 | if ( this.ajax.isRefresh == true && this.animationRunning == true && this.expanded == true ) {
1253 | isAfterRefresh = true;
1254 | }
1255 | //after refresh byt row is fully expanded
1256 | else if ( this.ajax.isRefresh == true && this.animationRunning == false && this.expanded == true ) {
1257 | isAfterRefresh = true;
1258 | this.ajax.isRefresh = false;
1259 | }
1260 |
1261 | returnObject = {
1262 | 'isCollapsing' : this.animationRunning == true && this.expanded == true ? true : false,
1263 | 'isCollapsed' : this.animationRunning == false && this.expanded == false ? true : false,
1264 | 'isExpanding' : this.animationRunning == true && this.expanded == false ? true : false,
1265 | 'isExpanded' : this.animationRunning == false && this.expanded == true ? true : false,
1266 | 'animationRunning' : this.animationRunning,
1267 | 'afterRefresh' : isAfterRefresh,
1268 | //'plugin' : this,
1269 | 'report' : this.affectedElement,
1270 | 'triggeringTd' : this.td,
1271 | 'triggeringElement' : this.element,
1272 | 'nestedReportRow' : this.nestedReport.tr,
1273 | 'nestedReportData' : this.nestedReport.ajaxData,
1274 | 'parent' : this.inception
1275 | };
1276 |
1277 |
1278 | return returnObject;
1279 | },
1280 | //
1281 | //
1282 | callbackCollapsed: function(){
1283 | this.td.removeClass( this.classes.tdExpanded );
1284 | this.expanded = false;
1285 |
1286 | this.nestedReport.tr.hide();
1287 | this.changeBorderStyle();
1288 |
1289 | if ( this.settings.isCacheResults == false) {
1290 | this.nestedReport.tr.remove();
1291 | }
1292 | this.animationRunning = false;
1293 | apex.event.trigger(this.affectedElement, 'pretius_default_callback', this.getEventData());
1294 | }
1295 | });
--------------------------------------------------------------------------------
/server/pretius_row_details_styles.css:
--------------------------------------------------------------------------------
1 |
2 | td > .rowDetailsContainer {
3 | display: none;
4 | padding: 10px;
5 | }
6 |
7 | td > .rowDetailsContainer > .overflow {
8 | overflow: auto;
9 | }
10 |
11 | /*
12 | div.rowDetailsContainer table {
13 | background-color: red;
14 | }
15 | */
16 |
17 | .pretius--ajaxIndicator.floatRight {
18 | float:right;
19 | opacity: 0.5;
20 | }
21 |
22 | .pretius--ajaxIndicator.content {
23 | /*text-align:center;*/
24 | opacity: 0.5;
25 | }
26 |
27 | div.pretius--error {
28 | text-align:center;
29 | }
30 |
31 | .pretius--reason {
32 |
33 | }
34 |
35 | .pretius--reason .fa {
36 | font-size: 30px;
37 | line-height: 40px;
38 | display: block;
39 | opacity: 0.7;
40 | }
41 |
42 | .pretius--errorTitle {
43 | font-size: 20px;
44 | line-height: 30px;
45 | }
46 |
47 | .pretius--techError pre,
48 | .pretius--errorAddInfo {
49 | margin: 0px;
50 | line-height: 30px;
51 | font-size:14px;
52 | }
53 |
54 | .pretius--techError pre {
55 | line-height: 16px;
56 | text-align:left;
57 | background-color: rgba(255,255,255, 0.4);
58 | border: 1px dashed rgba(0,0,0,0.3);
59 | padding: 2px 10px;
60 | }
61 |
62 | div.rowDetailsContainer .u-Report-sort.sort--asc .icon-rpt-sort-asc {
63 | display: inline-block;
64 | }
65 |
66 | div.rowDetailsContainer .u-Report-sort.sort--desc .icon-rpt-sort-desc {
67 | display: inline-block;
68 | }
69 |
70 | div.rowDetailsContainer .u-Report-sortIcon {
71 | display: none;
72 | }
73 |
74 | .t-Report-report div.rowDetailsContainer .t-Report-report.pretius--strechReport,
75 | .a-IRR-table div.rowDetailsContainer .t-Report-report.pretius--strechReport,
76 | .t-Report-report.pretius--strechReport {
77 | width: 100%;
78 | }
79 |
80 | .t-Report-report div.rowDetailsContainer .t-Report-report {
81 | width: auto;
82 | }
83 |
84 | /* Default template / border color */
85 | div.rowDetailsContainer td.t-Report-cell:last-child:not(.pretius--expanded),
86 | div.rowDetailsContainer th.t-Report-colHead:last-child,
87 | div.rowDetailsContainer td.t-Report-cell:not(.pretius--expanded),
88 | div.rowDetailsContainer th.t-Report-colHead {
89 | /*border-color: rgba(0,0,0, 0.1) !important;*/
90 | border-color: #dcdcdc;
91 | }
92 |
93 | /* Default template / odd row cells background */
94 | tr.pretius--hover div.rowDetailsContainer table.t-Report-report > tbody > tr.odd td.t-Report-cell:not(.pretius--expanded),
95 | div.rowDetailsContainer table.t-Report-report > tbody > tr.odd td.t-Report-cell:not(.pretius--expanded) {
96 | /*background-color: rgba(255, 255, 255, 0.3) !important;*/
97 | background-color: #f7f7f7 !important;
98 | }
99 | /* Default template / even row cells background */
100 | tr.pretius--hover div.rowDetailsContainer table.t-Report-report > tbody > tr.even td.t-Report-cell:not(.pretius--expanded),
101 | div.rowDetailsContainer table.t-Report-report > tbody > tr.even td.t-Report-cell:not(.pretius--expanded) {
102 | /*background-color: rgba(255, 255, 255, 0.6) !important;*/
103 | background-color: #fcfcfc !important;
104 | }
105 |
106 | /* Default template / highlight cell color */
107 | tr.pretius--hover div.rowDetailsContainer table.t-Report-report > tbody > tr.odd:hover td.t-Report-cell:not(.pretius--expanded),
108 | tr.pretius--hover div.rowDetailsContainer table.t-Report-report > tbody > tr.even:hover td.t-Report-cell:not(.pretius--expanded) {
109 | /*background-color: rgba(255, 255, 255, 0.8) !important;*/
110 | background-color: #f0f0f0 !important;
111 | }
112 |
113 | /* Default template / heading background color */
114 | div.rowDetailsContainer th.t-Report-colHead {
115 | /*background-color: rgba(255, 255, 255, 0.8);*/
116 | background-color: #fff !important;
117 | }
118 |
119 | /* IR */
120 | .a-IRR-table div.rowDetailsContainer tr td:first-child,
121 | .a-IRR-table div.rowDetailsContainer tr th:first-child {
122 | border-left-width: 1px;
123 | }
--------------------------------------------------------------------------------
/src/PRETIUS_APEX_NESTED_REPORTS.plb:
--------------------------------------------------------------------------------
1 | create or replace package body "PRETIUS_APEX_NESTED_REPORTS" is
2 |
3 | ------------------------
4 | function printAttributes(
5 | p_dynamic_action_render_result in apex_plugin.t_dynamic_action_render_result
6 | ) return clob is
7 |
8 | begin
9 |
10 | apex_json.initialize_clob_output;
11 |
12 | apex_json.open_object;
13 | apex_json.write( 'type', 'apex_plugin.t_dynamic_action_render_result' );
14 |
15 | apex_json.write( 'javascript_function' , p_dynamic_action_render_result.javascript_function );
16 | apex_json.write( 'ajax_identifier' , p_dynamic_action_render_result.ajax_identifier );
17 | apex_json.write( 'attribute_01' , p_dynamic_action_render_result.attribute_01 );
18 | apex_json.write( 'attribute_02' , p_dynamic_action_render_result.attribute_02 );
19 | apex_json.write( 'attribute_03' , p_dynamic_action_render_result.attribute_03 );
20 | apex_json.write( 'attribute_04' , p_dynamic_action_render_result.attribute_04 );
21 | apex_json.write( 'attribute_05' , p_dynamic_action_render_result.attribute_05 );
22 | apex_json.write( 'attribute_06' , p_dynamic_action_render_result.attribute_06 );
23 | apex_json.write( 'attribute_07' , p_dynamic_action_render_result.attribute_07 );
24 | apex_json.write( 'attribute_08' , p_dynamic_action_render_result.attribute_08 );
25 | apex_json.write( 'attribute_09' , p_dynamic_action_render_result.attribute_09 );
26 | apex_json.write( 'attribute_10' , p_dynamic_action_render_result.attribute_10 );
27 | apex_json.write( 'attribute_11' , p_dynamic_action_render_result.attribute_11 );
28 | apex_json.write( 'attribute_12' , p_dynamic_action_render_result.attribute_12 );
29 | apex_json.write( 'attribute_13' , p_dynamic_action_render_result.attribute_13 );
30 | apex_json.write( 'attribute_14' , p_dynamic_action_render_result.attribute_14 );
31 | apex_json.write( 'attribute_15' , p_dynamic_action_render_result.attribute_15 );
32 |
33 | apex_json.close_object;
34 |
35 | return apex_json.get_clob_output;
36 |
37 | end printAttributes;
38 |
39 |
40 | ------------------------
41 | function printAttributes(
42 | p_plugin in apex_plugin.t_plugin
43 | ) return clob is
44 |
45 | begin
46 |
47 | apex_json.initialize_clob_output;
48 |
49 | apex_json.open_object;
50 | apex_json.write( 'type', 'apex_plugin.t_plugin' );
51 |
52 | apex_json.write( 'name' , p_plugin.name );
53 | apex_json.write( 'file_prefix' , p_plugin.file_prefix );
54 | apex_json.write( 'attribute_01', p_plugin.attribute_01 );
55 | apex_json.write( 'attribute_02', p_plugin.attribute_02 );
56 | apex_json.write( 'attribute_03', p_plugin.attribute_03 );
57 | apex_json.write( 'attribute_04', p_plugin.attribute_04 );
58 | apex_json.write( 'attribute_05', p_plugin.attribute_05 );
59 | apex_json.write( 'attribute_06', p_plugin.attribute_06 );
60 | apex_json.write( 'attribute_07', p_plugin.attribute_07 );
61 | apex_json.write( 'attribute_08', p_plugin.attribute_08 );
62 | apex_json.write( 'attribute_09', p_plugin.attribute_09 );
63 | apex_json.write( 'attribute_10', p_plugin.attribute_10 );
64 | apex_json.write( 'attribute_11', p_plugin.attribute_11 );
65 | apex_json.write( 'attribute_12', p_plugin.attribute_12 );
66 | apex_json.write( 'attribute_13', p_plugin.attribute_13 );
67 | apex_json.write( 'attribute_14', p_plugin.attribute_14 );
68 | apex_json.write( 'attribute_15', p_plugin.attribute_15 );
69 |
70 | apex_json.close_object;
71 |
72 | return apex_json.get_clob_output;
73 |
74 | end printAttributes;
75 |
76 | ------------------------
77 | function printAttributes(
78 | p_dynamic_action in apex_plugin.t_dynamic_action
79 | ) return clob is
80 |
81 | begin
82 |
83 | apex_json.initialize_clob_output;
84 |
85 | apex_json.open_object;
86 | apex_json.write( 'type', 'apex_plugin.t_dynamic_action' );
87 |
88 | apex_json.write( 'id' , p_dynamic_action.id , false );
89 | apex_json.write( 'action' , p_dynamic_action.action , false );
90 | apex_json.write( 'attribute_01', p_dynamic_action.attribute_01, true );
91 | apex_json.write( 'attribute_02', p_dynamic_action.attribute_02, true );
92 | apex_json.write( 'attribute_03', p_dynamic_action.attribute_03, true );
93 | apex_json.write( 'attribute_04', p_dynamic_action.attribute_04, true );
94 | apex_json.write( 'attribute_05', p_dynamic_action.attribute_05, true );
95 | apex_json.write( 'attribute_06', p_dynamic_action.attribute_06, true );
96 | apex_json.write( 'attribute_07', p_dynamic_action.attribute_07, true );
97 | apex_json.write( 'attribute_08', p_dynamic_action.attribute_08, true );
98 | apex_json.write( 'attribute_09', p_dynamic_action.attribute_09, true );
99 | apex_json.write( 'attribute_10', p_dynamic_action.attribute_10, true );
100 | apex_json.write( 'attribute_11', p_dynamic_action.attribute_11, true );
101 | apex_json.write( 'attribute_12', p_dynamic_action.attribute_12, true );
102 | apex_json.write( 'attribute_13', p_dynamic_action.attribute_13, true );
103 | apex_json.write( 'attribute_14', p_dynamic_action.attribute_14, true );
104 | apex_json.write( 'attribute_15', p_dynamic_action.attribute_15, true );
105 |
106 | apex_json.close_object;
107 |
108 | return apex_json.get_clob_output;
109 |
110 | end printAttributes;
111 |
112 | --------------------------------
113 | function getColumnNamesFromQuery(
114 | p_string in varchar2
115 | ) return clob is
116 | v_count number;
117 | v_pattern varchar2(50) := '#.+?#';
118 |
119 | begin
120 | apex_json.initialize_clob_output;
121 |
122 | v_count := regexp_count(p_string, v_pattern, 1, 'm');
123 |
124 | apex_json.open_object;
125 | apex_json.open_array('queryColumns');
126 |
127 | for i in 1..v_count loop
128 | apex_json.write( trim(both '#' from regexp_substr(p_string, v_pattern, 1, i, 'm') ) );
129 | end loop;
130 |
131 | apex_json.close_array;
132 | apex_json.close_object;
133 |
134 | return apex_json.get_clob_output;
135 | end;
136 |
137 | -------------------------
138 | function getBindVariables(
139 | p_string in varchar2
140 | ) return clob is
141 | l_names DBMS_SQL.VARCHAR2_TABLE;
142 | begin
143 | l_names := WWV_FLOW_UTILITIES.GET_BINDS( p_string );
144 |
145 | apex_json.initialize_clob_output;
146 |
147 | apex_json.open_object;
148 | apex_json.open_array('queryItems');
149 |
150 | for i in 1..l_names.count loop
151 | apex_json.write( trim(both ':' from l_names(i) ) );
152 | end loop;
153 |
154 | apex_json.close_array;
155 | apex_json.close_object;
156 |
157 | return apex_json.get_clob_output;
158 |
159 | end getBindVariables;
160 |
161 | -------------------------------
162 | function getPluginAppAttributes(
163 | p_plugin in apex_plugin.t_plugin
164 | ) return varchar2 is
165 | attr_app_expand_time number := NVL(p_plugin.attribute_01, 200);
166 | attr_app_collapse_time number := NVL(p_plugin.attribute_02, 400);
167 | begin
168 | apex_json.initialize_clob_output;
169 |
170 | apex_json.open_object;
171 | apex_json.open_object('plugin');
172 | apex_json.write('animationTime', attr_app_expand_time );
173 | apex_json.write('closeOtherDuration', attr_app_collapse_time );
174 | apex_json.close_object;
175 | apex_json.close_object;
176 |
177 | return apex_json.get_clob_output;
178 |
179 | end getPluginAppAttributes;
180 |
181 | ----------------------------
182 | function pretius_row_details (
183 | p_dynamic_action in apex_plugin.t_dynamic_action,
184 | p_plugin in apex_plugin.t_plugin
185 | ) return apex_plugin.t_dynamic_action_render_result
186 | is
187 | l_result apex_plugin.t_dynamic_action_render_result;
188 |
189 | l_attr_nestedQuery varchar2(32767) := p_dynamic_action.attribute_01;
190 | l_attr_dc_settings varchar2(100) := p_dynamic_action.attribute_02;
191 |
192 | l_attr_mode varchar2(100) := p_dynamic_action.attribute_03;
193 | l_attr_customTemplate varchar2(32767) := p_dynamic_action.attribute_04;
194 | l_attr_customCallback varchar2(32767) := p_dynamic_action.attribute_05;
195 | l_attr_bgColor varchar2(20) := NVL( p_dynamic_action.attribute_06, '#EBEBEB' );
196 | l_attr_setMaxHeight number := p_dynamic_action.attribute_07;
197 | l_attr_borderColor varchar2(20) := NVL( p_dynamic_action.attribute_08, '#c5c5c5' );
198 | l_attr_highlightColor varchar2(20) := NVL( p_dynamic_action.attribute_09, '#F2F2F2' );
199 | l_attr_cc_settings varchar2(100) := p_dynamic_action.attribute_10;
200 | l_attr_noDataFound varchar2(32767) := p_dynamic_action.attribute_11;
201 | l_attr_spinnerOptions varchar2(100) := NVL( p_dynamic_action.attribute_12, 'ATR' );
202 | l_attr_defaultTemplate varchar2(4000) := NVL(p_dynamic_action.attribute_13, '#DEFAULT_TEMPLATE#');
203 | l_attr_dt_settings varchar2(100) := p_dynamic_action.attribute_14;
204 | /*
205 | p_dynamic_action.attribute_12;
206 | p_dynamic_action.attribute_13;
207 | p_dynamic_action.attribute_14;
208 | p_dynamic_action.attribute_15;
209 | */
210 | attr_app_embedMustache boolean := CASE WHEN p_plugin.attribute_03 = 'Y' then true else false end;
211 |
212 | begin
213 | l_result.ajax_identifier := wwv_flow_plugin.get_ajax_identifier;
214 | l_result.javascript_function := '
215 | function(){
216 | pretiusNestedReport(this, '||getColumnNamesFromQuery( l_attr_nestedQuery )||', '||getBindVariables( l_attr_nestedQuery )||', true, '||getPluginAppAttributes( p_plugin )||');
217 | }
218 | ';
219 | --l_result.attribute_01 := p_dynamic_action.attribute_01; --tajne, bo to zapytaie SQL, ktore mogloby byc dostepne przez this.options
220 | l_result.attribute_02 := l_attr_dc_settings;
221 | l_result.attribute_03 := l_attr_mode;
222 | l_result.attribute_04 := l_attr_customTemplate;
223 | l_result.attribute_05 := l_attr_customCallback;
224 | l_result.attribute_06 := l_attr_bgColor;
225 | l_result.attribute_07 := l_attr_setMaxHeight;
226 | l_result.attribute_08 := l_attr_borderColor;
227 | l_result.attribute_09 := l_attr_highlightColor;
228 | l_result.attribute_10 := l_attr_cc_settings;
229 | l_result.attribute_11 := l_attr_noDataFound;
230 | l_result.attribute_12 := l_attr_spinnerOptions;
231 | l_result.attribute_13 := l_attr_defaultTemplate;
232 | l_result.attribute_14 := l_attr_dt_settings;
233 | --l_result.attribute_15 := p_dynamic_action.attribute_15;
234 |
235 | --add mustache library
236 | if attr_app_embedMustache then
237 |
238 | apex_javascript.add_library(
239 | p_name => 'mustache',
240 | p_directory => p_plugin.file_prefix,
241 | p_version => null
242 | );
243 |
244 | end if;
245 |
246 | if apex_application.G_DEBUG then
247 |
248 | APEX_PLUGIN_UTIL.DEBUG_DYNAMIC_ACTION (
249 | p_plugin => p_plugin,
250 | p_dynamic_action => p_dynamic_action
251 | );
252 |
253 | apex_javascript.add_onload_code ('
254 | apex.debug.info("p_dynamic_action", '||printAttributes( p_dynamic_action )||');
255 | apex.debug.info("p_plugin", '||printAttributes( p_plugin )||');
256 | apex.debug.info("l_result", '||printAttributes( l_result )||');
257 | ');
258 |
259 | end if;
260 |
261 | return l_result;
262 |
263 | end pretius_row_details;
264 |
265 | --------------------
266 | function clean_query(
267 | p_query in varchar2
268 | ) return varchar2 is
269 | l_query varchar2(32767) := p_query;
270 | begin
271 | loop
272 | if substr(l_query,-1) in (chr(10),chr(13),';',' ','/') then
273 | l_query := substr(l_query,1,length(l_query)-1);
274 | else
275 | exit;
276 | end if;
277 | end loop;
278 |
279 | return l_query;
280 |
281 | end clean_query;
282 |
283 | -----------------------
284 | function is_valid_query(
285 | p_query in varchar2
286 | ) return varchar2 is
287 | l_source_query varchar2(32767) := p_query;
288 | l_source_queryv varchar2(32767);
289 | l_report_cursor integer;
290 | begin
291 | if l_source_query is not null then
292 | if
293 | substr(upper(ltrim(l_source_query)),1,6) != 'SELECT'
294 | and substr(upper(ltrim(l_source_query)),1,4) != 'WITH'
295 | then
296 | return 'Query must begin with SELECT or WITH';
297 | end if;
298 |
299 | l_source_query := clean_query( l_source_query );
300 | l_source_queryv := sys.dbms_assert.noop( str => l_source_query );
301 |
302 | begin
303 | l_report_cursor := sys.dbms_sql.open_cursor;
304 | sys.dbms_sql.parse( l_report_cursor, l_source_queryv, SYS.DBMS_SQL.NATIVE );
305 | sys.dbms_sql.close_cursor(l_report_cursor);
306 | exception
307 | when others then
308 | if sys.dbms_sql.is_open( l_report_cursor ) then
309 | sys.dbms_sql.close_cursor( l_report_cursor );
310 | end if;
311 | return sqlerrm;--||': '||chr(10)||chr(10)||l_source_query;
312 | end;
313 | end if;
314 |
315 | return null;
316 | exception
317 | when others then
318 | return SQLERRM;--||':'||chr(10)||chr(10)||p_query;
319 | end is_valid_query;
320 |
321 | ----------------------------
322 | function getColumnTypeString(
323 | p_col_type in number
324 | ) return varchar2 is
325 | l_col_type varchar2(50);
326 | begin
327 | if p_col_type = 1 then
328 | l_col_type := 'VARCHAR2';
329 |
330 | elsif p_col_type = 2 then
331 | l_col_type := 'NUMBER';
332 |
333 | elsif p_col_type = 12 then
334 | l_col_type := 'DATE';
335 |
336 | elsif p_col_type in (180,181,231) then
337 | l_col_type := 'TIMESTAMP';
338 |
339 | if p_col_type = 231 then
340 | l_col_type := 'TIMESTAMP_LTZ';
341 | end if;
342 |
343 | elsif p_col_type = 112 then
344 | l_col_type := 'CLOB';
345 |
346 | elsif p_col_type = 113 then
347 |
348 | l_col_type := 'BLOB';
349 |
350 | elsif p_col_type = 96 then
351 | l_col_type := 'CHAR';
352 |
353 | else
354 | l_col_type := 'OTHER';
355 | end if;
356 |
357 | return l_col_type;
358 |
359 | end getColumnTypeString;
360 |
361 | ---------------------------------
362 | function pretius_row_details_ajax(
363 | p_dynamic_action in apex_plugin.t_dynamic_action,
364 | p_plugin in apex_plugin.t_plugin
365 | ) return apex_plugin.t_dynamic_action_ajax_result
366 | is
367 | l_status number;
368 | l_desc_col_no number := 0;
369 |
370 | l_ajax_column_name varchar2(4000);
371 | l_ajax_column_values varchar2(4000);
372 |
373 | l_sql varchar2(32767);
374 | l_delimeter varchar2(1) := ':';
375 | l_parseResult varchar2(4000);
376 |
377 | l_result apex_plugin.t_dynamic_action_ajax_result;
378 |
379 | l_columnNames apex_application_global.vc_arr2;
380 | l_columnValues apex_application_global.vc_arr2;
381 |
382 | l_sys_cursor sys_refcursor;
383 |
384 | l_cursor pls_integer;
385 |
386 | l_desc_col_info sys.dbms_sql.desc_tab2;
387 |
388 | l_apex_items_names DBMS_SQL.VARCHAR2_TABLE;
389 | begin
390 |
391 | l_ajax_column_name := apex_application.g_x01;
392 | l_ajax_column_values := apex_application.g_x02;
393 |
394 | l_sql := p_dynamic_action.attribute_01;
395 | l_apex_items_names := WWV_FLOW_UTILITIES.GET_BINDS( l_sql );
396 |
397 | l_columnNames := apex_util.string_to_table( l_ajax_column_name , l_delimeter );
398 | l_columnValues := apex_util.string_to_table( l_ajax_column_values, l_delimeter );
399 |
400 | if l_columnNames.count <> l_columnValues.count then
401 | apex_json.open_object;
402 | apex_json.write('addInfo', 'The number of column names must be equal to the number of column values.Check whether the query columns exist in parent report.');
403 | apex_json.write('error', 'Column names = "'||l_ajax_column_name||'"'||chr(10)||'Column values = "'||l_ajax_column_values||'"');
404 | apex_json.close_object;
405 | return null;
406 | end if;
407 |
408 | --replacing space within column name is required to work with column aliases
409 | for i in 1..l_columnNames.count loop
410 | l_sql := replace( l_sql, chr(39)||'#'||l_columnNames(i)||'#'||chr(39) , ':' || replace(l_columnNames(i), ' ', '') );
411 | l_sql := replace( l_sql, '#'||l_columnNames(i)||'#' , ':' || replace(l_columnNames(i), ' ', '') );
412 | end loop;
413 |
414 | l_parseResult := is_valid_query( l_sql );
415 |
416 | if l_parseResult is not null then
417 | apex_json.open_object;
418 | apex_json.write('addInfo', 'Nested report SQL query is not valid');
419 | apex_json.write('error', l_parseResult);
420 | --apex_json.write('query', l_sql);
421 | apex_json.close_object;
422 | return null;
423 | end if;
424 |
425 | -- open l_cursor;
426 | l_cursor := dbms_sql.open_cursor;
427 | dbms_sql.parse (l_cursor, l_sql, dbms_sql.native);
428 |
429 | -- bind items
430 | begin
431 |
432 | for i in 1..l_apex_items_names.count loop
433 | dbms_sql.bind_variable (l_cursor, l_apex_items_names(i), v( trim(both ':' from l_apex_items_names(i)) ) );
434 | end loop;
435 |
436 | exception
437 | when others then
438 | apex_json.open_object;
439 | apex_json.write('addInfo', 'While binding APEX items error occured');
440 | apex_json.write('error', SQLERRM);
441 | apex_json.close_object;
442 | return null;
443 | end;
444 |
445 | --bind all the values
446 | --replacing space within column name is required to work with column aliases
447 | begin
448 | for i in 1 .. l_columnNames.count loop
449 | dbms_sql.bind_variable (l_cursor, replace(l_columnNames(i), ' ', ''), l_columnValues(i));
450 | end loop;
451 | exception
452 | when others then
453 | apex_json.open_object;
454 | apex_json.write('addInfo', 'While binding query variables error occured');
455 | apex_json.write('error', SQLERRM);
456 | apex_json.close_object;
457 | return null;
458 | end;
459 |
460 | -- describe columns
461 | sys.dbms_sql.describe_columns2( l_cursor, l_desc_col_no , l_desc_col_info);
462 |
463 | begin
464 | l_status := dbms_sql.execute(l_cursor);
465 | exception
466 | when others then
467 | apex_json.open_object;
468 | apex_json.write('addInfo', 'While executing query error occured ');
469 | apex_json.write('error', SQLERRM);
470 | apex_json.close_object;
471 | return null;
472 | end;
473 |
474 | l_sys_cursor := dbms_sql.to_refcursor(l_cursor);
475 |
476 | --apex_json.initialize_clob_output;
477 |
478 | apex_json.open_object;
479 | apex_json.write( 'data', l_sys_cursor );
480 | apex_json.open_array('headers');
481 |
482 | for i in 1..l_desc_col_no loop
483 | apex_json.open_object;
484 | apex_json.write('COLUMN_NAME', l_desc_col_info(i).col_name);
485 | apex_json.write('COLUMN_TYPE', getColumnTypeString( l_desc_col_info(i).col_type ) );
486 | apex_json.close_object;
487 | end loop;
488 |
489 | apex_json.close_array;
490 |
491 | apex_json.write( 'x01', l_ajax_column_name, true );
492 | apex_json.write( 'x02', l_ajax_column_values, true );
493 |
494 | apex_json.close_object;
495 |
496 | --htp.p( apex_json.get_clob_output );
497 |
498 | return l_result;
499 | exception
500 | when others then
501 | apex_json.open_object;
502 | apex_json.write('addInfo', 'Unknown ajax error');
503 | apex_json.write('error', SQLERRM);
504 | apex_json.close_object;
505 | htp.p( apex_json.get_clob_output );
506 | return l_result;
507 | end pretius_row_details_ajax;
508 |
509 | end "PRETIUS_APEX_NESTED_REPORTS";
510 |
--------------------------------------------------------------------------------
/src/PRETIUS_APEX_NESTED_REPORTS.sql:
--------------------------------------------------------------------------------
1 | create or replace package PRETIUS_APEX_NESTED_REPORTS as
2 |
3 | function pretius_row_details (
4 | p_dynamic_action in apex_plugin.t_dynamic_action,
5 | p_plugin in apex_plugin.t_plugin
6 | ) return apex_plugin.t_dynamic_action_render_result;
7 |
8 | function pretius_row_details_ajax(
9 | p_dynamic_action in apex_plugin.t_dynamic_action,
10 | p_plugin in apex_plugin.t_plugin
11 | ) return apex_plugin.t_dynamic_action_ajax_result;
12 |
13 | end;
14 |
--------------------------------------------------------------------------------