LP#1424815: jQuery implmentation of See More for notes
authorKathy Lussier <klussier@masslnc.org>
Thu, 31 Aug 2017 15:49:38 +0000 (11:49 -0400)
committerKathy Lussier <klussier@masslnc.org>
Fri, 3 Nov 2017 14:34:25 +0000 (10:34 -0400)
Because the anchor approach was a little clunky, this approach uses jQuery to
provide a "Read More" button for long contents on the record details page. We
still use jlitrell's perl work to generate the strings and then use jQuery to
change the div class when the button is clicked.

A new setting will allow Evergreen sites to truncate the display of long note
fields in the public catalog. When truncated, a _Read More..._ link will
appear at the end of the field, allowing the user to click to view the entire
field contents.

Since jQuery is turned off by default, I also turned off this feature by default
since both settings need to be enabled for this feature to work. To enable it:

  * Enable the ctx.want_jquery setting in the config.tt2 file.
  * Enable the truncate_contents setting in the config.tt2 file.
  * In config.tt2, adjust the contents_truncate_length setting to set the
number of characters that should display before the field is truncated (default
is 100).

A fallback is provided for browsers that have disabled javascript.

Signed-off-by: Kathy Lussier <klussier@masslnc.org>
LP#1424815: Make the button pretty and add options

Make the button look like a link and add options for use of this feature in
config.tt2. Also adds a fallback for browsers that don't have javascript
enabled.

Signed-off-by: Kathy Lussier <klussier@masslnc.org>
Open-ILS/src/perlmods/lib/OpenILS/WWW/EGCatLoader/Util.pm
Open-ILS/src/templates/opac/css/style.css.tt2
Open-ILS/src/templates/opac/parts/config.tt2
Open-ILS/src/templates/opac/parts/js.tt2
Open-ILS/src/templates/opac/parts/record/contents.tt2

index 95ae2fd..99273bf 100644 (file)
@@ -234,7 +234,7 @@ sub init_ro_object_cache {
             $rest = substr $string, $loc;
         }
 
-        return ($short, $rest);
+        return ($short, $rest, $string);
     };
 
 
index 248ea43..cf75b3e 100644 (file)
@@ -1989,7 +1989,40 @@ a.opac-button-header:hover, #dash_wrapper a.opac-button:hover {
 .rdetail_content_type, .rdetail_subject_type {
     vertical-align: top;
     font-weight: bold;
+    white-space: nowrap;
+    [% IF rtl == 't' -%]
+    padding-left: .5em;
+    [% ELSE -%]
+    padding-right:.5em;
+    [% END -%]
+}
+
+.show_truncated .cont_short {
+     display:inline-block;
+}
+
+.show_more .cont_short {
+     display:none;
+}
+
+.show_truncated .cont_long {
+     display:none;
+}
+
+.show_more .cont_long {
+     display:inline-block;
+}
+
+button.readmore, button.readless {
+     background:none!important;
+     color:[% css_colors.primary %];
+     border:none; 
+     padding:0!important;
+     font: inherit;
+     border-bottom:1px solid [% css_colors.primary %]; 
+     cursor: pointer;
 }
+     
 
 .bookbag-item-row td { vertical-align: top; }
 
@@ -3005,6 +3038,9 @@ a.preflib_change {
     h2.rdetail_uris {
         clear: both;
     }
+    .rdetail_content_type, .rdetail_subject_type {
+        white-space: normal;
+    }
     #metarecord_population {
         overflow: hidden;
         width: 100%;
@@ -3332,92 +3368,4 @@ label[for*=expert_]
 }
 [id^="toggled-inline-"]:target{
     display: inline;
-ul {
-  list-style: none;
-  perspective: 900;
-  padding: 0;
-  margin: 0;
-}
-ul li {
-  position: relative;
-  padding: 0;
-  margin: 0;
-  padding-bottom: 4px;
-  padding-top: 18px;
-  border-top: 1px dotted #dce7eb;
-}
-ul li:nth-of-type(1) {
-  animation-delay: 0.5s;
-}
-ul li:nth-of-type(2) {
-  animation-delay: 0.75s;
-}
-ul li:nth-of-type(3) {
-  animation-delay: 1s;
-}
-ul li:last-of-type {
-  padding-bottom: 0;
-}
-ul li i {
-  position: absolute;
-  transform: translate(-6px, 0);
-  margin-top: 16px;
-  right: 0;
-}
-ul li i:before, ul li i:after {
-  content: "";
-  position: absolute;
-  background-color: #ff6873;
-  width: 3px;
-  height: 9px;
-}
-ul li i:before {
-  transform: translate(-2px, 0) rotate(45deg);
-}
-ul li i:after {
-  transform: translate(2px, 0) rotate(-45deg);
-}
-ul li input[type=checkbox] {
-  position: absolute;
-  cursor: pointer;
-  width: 10%;
-  height: 100%;
-  z-index: 1;
-  opacity: 0;
-}
-ul li input[type=checkbox]:checked ~ p {
-  margin-top: 0;
-  max-height: 0;
-  opacity: 0;
-  transform: translate(0, 50%);
-}
-ul li input[type=checkbox]:checked ~ i:before {
-  transform: translate(2px, 0) rotate(45deg);
-}
-ul li input[type=checkbox]:checked ~ i:after {
-  transform: translate(-2px, 0) rotate(-45deg);
-}
-
-@keyframes flipdown {
-  0% {
-    opacity: 0;
-    transform-origin: top center;
-    transform: rotateX(-90deg);
-  }
-  5% {
-    opacity: 1;
-  }
-  80% {
-    transform: rotateX(8deg);
-  }
-  83% {
-    transform: rotateX(6deg);
-  }
-  92% {
-    transform: rotateX(-3deg);
-  }
-  100% {
-    transform-origin: top center;
-    transform: rotateX(0deg);
-  }
 }
index 28f730c..3437fad 100644 (file)
@@ -243,7 +243,21 @@ ctx.exclude_electronic_checkbox = 0;
 # Include JQuery in the TPAC?
 # Set to a true value to enable
 ##############################################################################
-# ctx.want_jquery = 1;
+#ctx.want_jquery = 1;
+
+##############################################################################
+# Truncate fields in catalog
+##############################################################################
+# Truncates long fields in the catalog and displays a Show More link that the
+# user can click to display the field's full contents. Set to 1 to enable
+# field truncation. Set the number of characters that should display before the
+# field is truncated. jQuery should also be enabled to use this feature.
+##############################################################################
+#truncate_contents = 1;
+#contents_truncate_length = 100; 
+
+# Edit parts/record/contents.tt2 to designate character length on a field-by-
+# field basis.
 
 ##############################################################################
 # Browser cache-busting key
index 01fb9f9..9ed8c05 100644 (file)
@@ -143,3 +143,14 @@ var aou_hash = {
 
 <script type="text/javascript">if ($('client_tz_id')) { $('client_tz_id').value = OpenSRF.tz }</script>
 [%- END; # want_dojo -%]
+
+<!-- Add Read More / Read Less Functionality -->
+<script type="text/javascript">
+$('.readmore').click(function() {
+        $('div#'+$(this).attr('data-id')).removeClass('show_truncated').addClass('show_more');
+    });
+$('.readless').click(function() {
+        $('div#'+$(this).attr('data-id')).removeClass('show_more').addClass('show_truncated');
+    });
+</script>
+
index ca85773..ba88b7b 100644 (file)
 [%-
+#provide a default value in case truncation length is unset in config.tt2
+
+default_contents_length = contents_truncate_length || 100;
+
 contents =  [
     {
         label => l('General Note: '),
-trunc_length => 20,
+        trunc_length => default_contents_length,
+        noteid => l('generalnote'),
         xpath => '//*[@tag="500"]'
     }, {
         label => l('With Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('withnote'),
         xpath => '//*[@tag="501"]'
     }, {
         label => l('Dissertation Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('dissertationnote'),
         xpath => '//*[@tag="502"]'
     }, {
         label => l('Bibliography, etc. Note: '),
-trunc_length => 25,
+        trunc_length => default_contents_length,
+        noteid => l('bibnote'),
         xpath => '//*[@tag="504"]'
     }, {
         label => l('Formatted Contents Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('contentsnote'),
         xpath => '//*[@tag="505"]'
     }, {
         label => l('Restrictions on Access Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('accessnote'),
         xpath => '//*[@tag="506"]'
     }, {
         label => l('Scale Note for Graphic Material: '),
+        trunc_length => default_contents_length,
+        noteid => l('scalenote'),
         xpath => '//*[@tag="507"]'
     }, {
         label => l('Creation/Production Credits Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('creationnote'),
         xpath => '//*[@tag="508"]'
     }, {
         label => l('Citation/References Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('citationnote'),
         xpath => '//*[@tag="510"]'
     }, {
         label => l('Participant or Performer Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('performernote'),
         xpath => '//*[@tag="511"]'
     }, {
         label => l('Type of Report and Period Covered Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('reporttypenote'),
         xpath => '//*[@tag="513"]'
     }, {
         label => l('Data Quality Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('dataqualitynote'),
         xpath => '//*[@tag="514"]'
     }, {
         label => l('Numbering Peculiarities Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('numberingnote'),
         xpath => '//*[@tag="515"]'
     }, {
         label => l('Type of Computer File or Data Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('filetypenote'),
         xpath => '//*[@tag="516"]'
     }, {
         label => l('Date/Time and Place of an Event Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('eventnote'),
         xpath => '//*[@tag="518"]'
     }, {
         label => l('Summary, etc.: '),
+        trunc_length => default_contents_length,
+        noteid => 'summarynote',
         xpath => '//*[@tag="520"]'
     }, {
         label => l('Target Audience Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('audiencenote'),
         xpath => '//*[@tag="521"]'
     }, {
         label => l('Geographic Coverage Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('geographicnote'),
         xpath => '//*[@tag="522"]'
     }, {
         label => l('Preferred Citation of Described Materials Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('prefcitationnote'),
         xpath => '//*[@tag="524"]'
     }, {
         label => l('Supplement Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('suppnote'),
         xpath => '//*[@tag="525"]'
     }, {
         label => l('Study Program Information Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('studynote'),
         xpath => '//*[@tag="526"]'
     }, {
         label => l('Additional Physical Form available Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('physformnote'),
         xpath => '//*[@tag="530"]'
     }, {
         label => l('Reproduction Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('repronote'),
         xpath => '//*[@tag="533"]'
     }, {
         label => l('Original Version Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('origvernote'),
         xpath => '//*[@tag="534"]'
     }, {
         label => l('Location of Originals/Duplicates Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('originalsnote'),
         xpath => '//*[@tag="535"]'
     }, {
         label => l('Funding Information Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('fundingnote'),
         xpath => '//*[@tag="536"]'
     }, {
         label => l('System Details Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('sysdetailsnote'),
         xpath => '//*[@tag="538"]'
     }, {
         label => l('Terms Governing Use and Reproduction Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('termsofusenote'),
         xpath => '//*[@tag="540"]'
     }, {
         label => l('Immediate Source of Acquisition Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('acqnote'),
         xpath => '//*[@tag="541"]'
     }, {
         label => l('Information Relating to Copyright Status: '),
+        trunc_length => default_contents_length,
+        noteid => l('copyrightnote'),
         xpath => '//*[@tag="542"]'
     }, {
         label => l('Location of Other Archival Materials Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('archivalnote'),
         xpath => '//*[@tag="544"]'
     }, {
         label => l('Biographical or Historical Data: '),
+        trunc_length => default_contents_length,
+        noteid => l('bionote'),
         xpath => '//*[@tag="545"]'
     }, {
         label => l('Language Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('langnote'),
         xpath => '//*[@tag="546"]'
     }, {
         label => l('Former Title Complexity Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('formertitlenote'),
         xpath => '//*[@tag="547"]'
     }, {
         label => l('Issuing Body Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('issuingbodynote'),
         xpath => '//*[@tag="550"]'
     }, {
         label => l('Entity and Attribute Information Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('entitynote'),
         xpath => '//*[@tag="552"]'
     }, {
         label => l('Cumulative Index/Finding Aids Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('indexnote'),
         xpath => '//*[@tag="555"]'
     }, {
         label => l('Information About Documentation Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('documentationnote'),
         xpath => '//*[@tag="556"]'
     }, {
         label => l('Ownership and Custodial History: '),
+        trunc_length => default_contents_length,
+        noteid => l('ownershipnote'),
         xpath => '//*[@tag="561"]'
     }, {
         label => l('Copy and Version Identification Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('copyvernote'),
         xpath => '//*[@tag="562"]'
     }, {
         label => l('Binding Information: '),
+        trunc_length => default_contents_length,
+        noteid => l('bindingnote'),
         xpath => '//*[@tag="563"]'
     }, {
         label => l('Case File Characteristics Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('casefilenote'),
         xpath => '//*[@tag="565"]'
     }, {
         label => l('Methodology Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('methodologynote'),
         xpath => '//*[@tag="567"]'
     }, {
         label => l('Linking Entry Complexity Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('linkingnote'),
         xpath => '//*[@tag="580"]'
     }, {
         label => l('Publications About Described Materials Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('publicationsnote'),
         xpath => '//*[@tag="581"]'
     }, {
         label => l('Action Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('actionnote'),
         xpath => '//*[@tag="583"]'
     }, {
         label => l('Accumulation and Frequency of Use Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('accumulationnote'),
         xpath => '//*[@tag="584"]'
     }, {
         label => l('Exhibitions Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('exhibitionsnote'),
         xpath => '//*[@tag="585"]'
     }, {
         label => l('Awards Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('awardsnote'),
         xpath => '//*[@tag="586"]'
     }, {
         label => l('Source of Description Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('descsourcenote'),
         xpath => '//*[@tag="588"]'
     }
 ];
@@ -174,11 +276,11 @@ BLOCK render_contents;
         total_contents = all_content.join(" ").replace('\s+$', '');
         %] [% total_contents;
         IF total_contents.size;
-            IF total_contents.length > cont.trunc_length; # should be ok on undefined... I think.  Just skips it.
+            IF total_contents.length > cont.trunc_length; 
               # need to chop!
               blah = ctx.split_for_accordion(total_contents, cont.trunc_length);
               cont.short = blah.0;
-              cont.long  = blah.1;
+              cont.long  = blah.2;
             END;
             '<br/>';
         END;
@@ -198,12 +300,17 @@ END
 <tr>
     <td class='rdetail_content_type'>[% cont.label %]</td>
     <td class='rdetail_content_value' property='keywords'>
-[% IF cont.short.length %]
-<ul>
-<li>
-    [% cont.short %]... <input type="checkbox" checked>[% l('(click for more)') %] <p>[% cont.long%]</p>
-</li>
-</ul>
+[% IF truncate_contents AND ctx.want_jquery AND cont.short.length AND cont.trunc_length %]
+<noscript>
+   <style type="text/css">
+      .show_truncated {display:none;}
+   </style>
+   [% content %] 
+</noscript>
+  <div id ='[% cont.noteid %]' class='show_truncated'>
+   <span class='cont_short'>[% cont.short %]...<button class="readmore" data-id='[% cont.noteid %]'>[% l('(Read more)') %]</button></span>
+   <span class='cont_long'>[% cont.long %] <button class="readless" data-id='[% cont.noteid %]'>[% l('(Read less)') %]</button></span>
+  </div>
 [% ELSE %]
     [% content %]
 [% END; %]
@@ -217,9 +324,10 @@ END
     IF content_html.length > 0;
 %]
 <h2 class='rdetail_contents'>[% l('Content descriptions') %]</h2>
-<table class='rdetail_content'>
+<table id='rdetail_content_table' class='rdetail_content'>
     <tbody>
 [%- content_html %]
     </tbody>
 </table>
-[%- END %]
\ No newline at end of file
+[%- END %]
+