webstaff: throw a kitchen sink at double-scrollbar issues
authorGalen Charlton <gmc@esilibrary.com>
Wed, 30 Nov 2016 10:25:52 +0000 (05:25 -0500)
committerKathy Lussier <klussier@masslnc.org>
Mon, 9 Jan 2017 15:58:59 +0000 (10:58 -0500)
This patch ameliorates, but does not eliminate, a bunch
of cases where double-scrollbars could appear.

[1] Adds iframe-resizer (https://github.com/davidjbradshaw/iframe-resizer, MIT license)
    as an option for automatically adjusting the height of an iframe
    to fit the contents.  This can be enabled by ensuring that
    the page to be embedded brings in

    /js/ui/default/staff/build/js/iframeResizer.contentWindow.min.j

    and adding an 'autoresize' attribute to the egEmbedFrame directive.

    This is now used by the legacy reports page.

[2] Gives a 'min-height' attribute to egEmbedFrame and sets a
    value for Dojo grid interfaces embedded by local and server admistration.
[3] Adds a 'allow-escape' attribute to egEmbedFrame; when set to
    true, adds buttons to allow the user to open the embedded page
    in a new tab.
[4] Removes some extraneous <div>s that were interferring with resizing
    for some grids.

Signed-off-by: Galen Charlton <gmc@esilibrary.com>
Signed-off-by: Kathy Lussier <klussier@masslnc.org>
19 files changed:
Open-ILS/src/templates/conify/global/cat/authority/browse_axis.tt2
Open-ILS/src/templates/conify/global/cat/authority/browse_axis_authority_field_map.tt2
Open-ILS/src/templates/conify/global/cat/authority/control_set.tt2
Open-ILS/src/templates/conify/global/cat/authority/control_set_authority_field.tt2
Open-ILS/src/templates/conify/global/cat/authority/control_set_bib_field.tt2
Open-ILS/src/templates/conify/global/cat/authority/thesaurus.tt2
Open-ILS/src/templates/conify/global/config/actor_sip_fields.tt2
Open-ILS/src/templates/conify/global/config/asset_sip_fields.tt2
Open-ILS/src/templates/conify/global/config/global_flag.tt2
Open-ILS/src/templates/conify/global/config/rule_circ_duration.tt2
Open-ILS/src/templates/staff/base_js.tt2
Open-ILS/src/templates/staff/reporter/t_legacy.tt2
Open-ILS/src/templates/staff/share/t_eframe.tt2
Open-ILS/web/js/ui/default/staff/Gruntfile.js
Open-ILS/web/js/ui/default/staff/admin/local/app.js
Open-ILS/web/js/ui/default/staff/admin/server/app.js
Open-ILS/web/js/ui/default/staff/bower.json
Open-ILS/web/js/ui/default/staff/services/eframe.js
Open-ILS/web/reports/oils_rpt_common.xhtml

index 676edbb..e9c580a 100644 (file)
@@ -8,7 +8,6 @@
             <button dojoType="dijit.form.Button" onClick="aba_grid.deleteSelected()">[% l('Delete Selected') %]</button>
         </div>
     </div>
-    <div>
         <table  jsId="aba_grid"
                 dojoType="openils.widget.AutoGrid"
                 autoHeight="true"
@@ -19,7 +18,6 @@
                 fmClass="aba"
                 editOnEnter="true">
         </table>
-    </div>
 </div>
 <script type="text/javascript">
     dojo.require("openils.widget.AutoGrid");
index adae8d0..f64937e 100644 (file)
@@ -12,7 +12,6 @@
         [% l('Showing only browse axis-authority field maps linked to authority field:') %]
         <a id="authority-field-metadata"></a>
     </div>
-    <div>
         <table  jsId="abaafm_grid"
                 dojoType="openils.widget.AutoGrid"
                 autoHeight="true"
@@ -23,7 +22,6 @@
                 fmClass="abaafm"
                 editOnEnter="true">
         </table>
-    </div>
 </div>
 <script type="text/javascript"
     src="[% ctx.media_prefix %]/js/ui/default/conify/global/cat/authority/common.js"></script>
index 8c440a4..564d162 100644 (file)
@@ -8,7 +8,6 @@
             <button dojoType="dijit.form.Button" onClick="acs_grid.deleteSelected()">[% l('Delete Selected') %]</button>
         </div>
     </div>
-    <div>
     <table  jsId="acs_grid"
             dojoType="openils.widget.AutoGrid"
             autoHeight="true"
index bc232e6..92c8239 100644 (file)
@@ -12,7 +12,6 @@
         [% l('Showing only authority fields linked to control set:') %]
         <a id="control-set-metadata"></a>
     </div>
-    <div>
         <table  jsId="acsaf_grid"
                 dojoType="openils.widget.AutoGrid"
                 autoHeight="true"
@@ -31,7 +30,6 @@
                 </tr>
             </thead>
         </table>
-    </div>
 </div>
 <script type="text/javascript"
     src="[% ctx.media_prefix %]/js/ui/default/conify/global/cat/authority/common.js"></script>
index 7929cae..e496b5d 100644 (file)
@@ -12,7 +12,6 @@
         [% l('Showing only control set bib fields linked to authority field:') %]
         <a id="authority-field-metadata"></a>
     </div>
-    <div>
         <table  jsId="acsbf_grid"
                 dojoType="openils.widget.AutoGrid"
                 autoHeight="true"
@@ -23,7 +22,6 @@
                 fmClass="acsbf"
                 editOnEnter="true">
         </table>
-    </div>
 </div>
 <script type="text/javascript"
     src="[% ctx.media_prefix %]/js/ui/default/conify/global/cat/authority/common.js"></script>
index 2b6673b..45846e7 100644 (file)
@@ -12,7 +12,6 @@
         [% l('Showing only thesauri linked to control set:') %]
         <a id="control-set-metadata"></a>
     </div>
-    <div>
         <table  jsId="at_grid"
                 dojoType="openils.widget.AutoGrid"
                 autoHeight="true"
@@ -29,7 +28,6 @@
                 </tr>
             </thead>
         </table>
-    </div>
 </div>
 <script type="text/javascript"
     src="[% ctx.media_prefix %]/js/ui/default/conify/global/cat/authority/common.js"></script>
index c3ff16a..3ea23bf 100644 (file)
@@ -8,7 +8,6 @@
             <button dojoType='dijit.form.Button' onClick='actorSipFieldsGrid.deleteSelected()'>[% l('Delete Selected') %]</button>
         </div>
     </div>
-    <div>
     <table  jsId="actorSipFieldsGrid"
             dojoType="openils.widget.AutoGrid"
             fieldOrder="['field', 'name', 'one_only']"
index 82a0dae..bba754c 100644 (file)
@@ -8,7 +8,6 @@
             <button dojoType='dijit.form.Button' onClick='assetSipFieldsGrid.deleteSelected()'>[% l('Delete Selected') %]</button>
         </div>
     </div>
-    <div>
     <table  jsId="assetSipFieldsGrid"
             dojoType="openils.widget.AutoGrid"
             fieldOrder="['field', 'name', 'one_only']"
index d0a87be..3074012 100644 (file)
@@ -5,7 +5,6 @@
         <div>[% l('Global Flags') %]</div>
         <div></div>
     </div>
-    <div>
     <table  jsId="gfGrid"
             dojoType="openils.widget.AutoGrid"
             fieldOrder="['name', 'label', 'enabled', 'value']"
index b089800..1cdd497 100644 (file)
@@ -8,7 +8,6 @@
             <button dojoType='dijit.form.Button' onClick='ruleCircDurationGrid.deleteSelected()'>[% l('Delete Selected') %]</button>
         </div>
     </div>
-    <div>
     <table  jsId="ruleCircDurationGrid"
             dojoType="openils.widget.AutoGrid"
             fieldOrder="['name', 'max_renewals', 'shrt', 'normal', 'extended']"
index 3a8f50c..fac9711 100644 (file)
@@ -16,6 +16,7 @@
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-cookies.min.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/ngToast.min.js"></script>
 <script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/angular-tree-control.js"></script>
+<script src="[% ctx.media_prefix %]/js/ui/default/staff/build/js/iframeResizer.min.js"></script>
 
 <!-- IDL / opensrf (network) -->
 <script src="[% ctx.media_prefix %]/js/dojo/opensrf/JSON_v1.js"></script>
index cbaa379..738ca7f 100644 (file)
@@ -1 +1 @@
-<eg-embed-frame save-space="150" url="rurl"></eg-embed-frame>
+<eg-embed-frame autoresize save-space="150" url="rurl"></eg-embed-frame>
index 0562f66..0c9d72d 100644 (file)
@@ -1,8 +1,11 @@
 <div class="eg-embed-frame">
+  <button type="button" class="btn btn-default btn-xs" ng-show="allowEscape &&  showIframe" ng-click="escapeEmbed()">[% l('Open in New Window') %]</button>
+  <button type="button" class="btn btn-default btn-xs" ng-show="allowEscape && !showIframe" ng-click="restoreEmbed()">[% l('Re-embed') %]</button>
   <!-- height is calculated at render time -->
   <iframe 
-    src="{{url}}" 
-    style="height:{{height}}px">
+    ng-if="showIframe"
+    ng-attr-style="{{ autoresize ? undefined : 'height:' + height + 'px' }}"
+    src="{{url}}">
   </iframe>
 </div>
 
index 4bfb433..2d982c4 100644 (file)
@@ -32,7 +32,10 @@ module.exports = function(grunt) {
             'bower_components/ngtoast/dist/ngToast.min.js',
             'bower_components/jquery/dist/jquery.min.js',
             'bower_components/angular-cookies/angular-cookies.min.js',
-            'bower_components/angular-cookies/angular-cookies.min.js.map'
+            'bower_components/angular-cookies/angular-cookies.min.js.map',
+            'bower_components/iframe-resizer/js/iframeResizer.min.js',
+            'bower_components/iframe-resizer/js/iframeResizer.map',
+            'bower_components/iframe-resizer/js/iframeResizer.contentWindow.min.js'
           ]
         }]
       },
index 20b9647..afceb4d 100644 (file)
@@ -9,7 +9,7 @@ angular.module('egLocalAdmin',
     var resolver = {delay : function(egStartup) {return egStartup.go()}};
 
     var eframe_template = 
-        '<eg-embed-frame url="local_admin_url" handlers="funcs"></eg-embed-frame>';
+        '<eg-embed-frame allow-escape="true" min-height="min_height" url="local_admin_url" handlers="funcs"></eg-embed-frame>';
 
     // non-conify routes come first
     $routeProvider.when('/admin/local/money/cash_reports', {
@@ -76,6 +76,8 @@ function($scope , $routeParams , $location , egCore) {
     var conify_path = '/eg/conify/global/' + 
         $routeParams.schema + '/' + $routeParams.page;
 
+    $scope.min_height = 800;
+
     // embed URL must include protocol/domain or it will be loaded via
     // push-state, resulting in an infinitely nested pages.
     $scope.local_admin_url = 
index a28987a..962f0e5 100644 (file)
@@ -9,7 +9,7 @@ angular.module('egServerAdmin',
     var resolver = {delay : function(egStartup) {return egStartup.go()}};
 
     var eframe_template = 
-        '<eg-embed-frame url="server_admin_url" handlers="funcs"></eg-embed-frame>';
+        '<eg-embed-frame allow-escape="true" min-height="min_height" url="server_admin_url" handlers="funcs"></eg-embed-frame>';
 
     // old-style Confiy
     $routeProvider.when('/admin/server/legacy/:schema/:page', {
@@ -51,6 +51,8 @@ function($scope , $routeParams , $location , egCore) {
         (angular.isDefined($routeParams.module) ? ($routeParams.module + '/') : '') +
         $routeParams.schema + '/' + $routeParams.page;
 
+    $scope.min_height = 800;
+
     // embed URL must include protocol/domain or it will be loaded via
     // push-state, resulting in an infinitely nested pages.
     $scope.server_admin_url = 
index f332f3b..59fa196 100644 (file)
@@ -33,6 +33,7 @@
     "angular-cookies": "^1.5.8"
   },
   "resolutions": {
-    "angular": "~1.5.5"
+    "angular": "~1.5.5",
+    "iframe-resizer": "^3.5.5"
   }
 }
index aa87c7b..9bd6e3d 100644 (file)
@@ -18,12 +18,21 @@ angular.module('egCoreMod')
 
             // called after onload of each new iframe page
             onchange : '=?',
+
+            // for tweaking height
             saveSpace : '@',
+            minHeight : '=?',
+
+            // to display button for displaying embedded page
+            // in a new tab
+            allowEscape : '=?'
         },
 
         templateUrl : './share/t_eframe',
 
         link: function (scope, element, attrs) {
+            scope.autoresize = 'autoresize' in attrs;
+            scope.showIframe = true;
             element.find('iframe').on(
                 'load',
                 function() {scope.egEmbedFrameLoader(this)}
@@ -38,6 +47,9 @@ angular.module('egCoreMod')
             // Set the initial iframe height to just under the window height.
             // leave room for the navbar, padding, margins, etc.
             $scope.height = $window.outerHeight - $scope.save_space;
+            if ($scope.minHeight && $scope.height < $scope.minHeight) {
+                $scope.height = $scope.minHeight;
+            }
 
             // browser client doesn't use cookies, so we don't load the
             // (at the time of writing, quite limited) angular.cookies
@@ -78,9 +90,13 @@ angular.module('egCoreMod')
                 $scope.frame = {dom:iframe};
                 $scope.iframe = iframe;
 
-                // Reset the iframe height to the final content height.
-                if ($scope.height < $scope.iframe.contentWindow.document.body.scrollHeight)
-                    $scope.height = $scope.iframe.contentWindow.document.body.scrollHeight;
+                if ($scope.autoresize) {
+                    iFrameResize({}, $scope.iframe);
+                } else {
+                    // Reset the iframe height to the final content height.
+                    if ($scope.height < $scope.iframe.contentWindow.document.body.scrollHeight)
+                        $scope.height = $scope.iframe.contentWindow.document.body.scrollHeight;
+                }
 
                 var page = $scope.iframe.contentWindow.location.href;
                 console.debug('egEmbedFrameLoader(): ' + page);
@@ -91,6 +107,10 @@ angular.module('egCoreMod')
                         $scope.iframe.contentWindow.location);
                 }
 
+                $scope.style = function() {
+                    return 'height:' + $scope.height + 'px';
+                }
+
                 // tell the iframe'd window its inside the staff client
                 $scope.iframe.contentWindow.IAMXUL = true;
 
@@ -106,6 +126,7 @@ angular.module('egCoreMod')
 
                 // Adjust the height again if the iframe loads the openils.Util Dojo module
                 $timeout(function () {
+                    if ($scope.autoresize) return; // let iframe-resizer handle it
                     if ($scope.iframe.contentWindow.openils && $scope.iframe.contentWindow.openils.Util) {
 
                         // HACK! for patron reg page
@@ -251,6 +272,15 @@ angular.module('egCoreMod')
 
                 if ($scope.onchange) $scope.onchange(page);
             }
+
+            // open a new tab with the embedded URL
+            $scope.escapeEmbed = function() {
+                $scope.showIframe = false;
+                $window.open($scope.url, '_blank').focus();
+            }
+            $scope.restoreEmbed = function() {
+                $scope.showIframe = true;
+            }
         }]
     }
 })
index c1aad54..fbbae6b 100644 (file)
@@ -10,6 +10,7 @@
                parseOnLoad: true
        }
 </script>
+<script type="text/javascript" src="/js/ui/default/staff/build/js/iframeResizer.contentWindow.min.js"></script>
 <script type="text/javascript" src="/js/dojo/dojo/dojo.js"></script>
 <script type="text/javascript">
        dojo.require('dojo.parser');