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>
Tue, 12 Jun 2018 19:38:41 +0000 (15:38 -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>
Signed-off-by: Remington Steed <rjs7@calvin.edu>
Conflicts:
Open-ILS/src/templates/opac/parts/record/contents.tt2

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 b5f2e0f..3cbd754 100644 (file)
@@ -234,7 +234,7 @@ sub init_ro_object_cache {
             $rest = substr $string, $loc;
         }
 
-        return ($short, $rest);
+        return ($short, $rest, $string);
     };
 
 
index 79a10a7..e7f18f4 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,94 +3368,6 @@ 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);
-  }
 }
 
 .oils_SH {
index b0ad747..6b0627c 100644 (file)
@@ -246,7 +246,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 103394a..5770ceb 100644 (file)
 [%-
+#provide a default value in case truncation length is unset in config.tt2
+
+default_contents_length = contents_truncate_length || 100;
+
 contents =  [
     {
         display_field => 'general_note',
         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"]'
     }, {
         display_field => 'thesis',
         label => l('Dissertation Note: '),
+        trunc_length => default_contents_length,
+        noteid => l('dissertationnote'),
         xpath => '//*[@tag="502"]'
     }, {
         display_field => 'bibliography',
         label => l('Bibliography, etc. Note: '),
-        trunc_length => 25,
+        trunc_length => default_contents_length,
+        noteid => l('bibnote'),
         xpath => '//*[@tag="504"]'
     }, {
         display_field => 'toc',
         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"]'
     }, {
         display_field => 'production_credits',
         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"]'
     }, {
         display_field => 'performers',
         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"]'
     }, {
         display_field => 'abstract',
         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"]'
     } 
 ];
@@ -180,11 +282,11 @@ BLOCK render_contents;
         END;
         total_contents = all_content.join(" ").replace('\s+$', '');
         %] [% "<div class='content_field'>"; total_contents | html ; "</div>";
-            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;
         FOREACH link880 IN graphics;
             '<div class="graphic880"' _ link880.dir _ '>';
@@ -208,12 +310,17 @@ BLOCK render_all_contents;
 <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; %]