Backup of db before drupal security update
[yaffs-website] / web / core / misc / tableresponsive.js
1 /**
2  * @file
3  * Responsive table functionality.
4  */
5
6 (function ($, Drupal, window) {
7
8   'use strict';
9
10   /**
11    * Attach the tableResponsive function to {@link Drupal.behaviors}.
12    *
13    * @type {Drupal~behavior}
14    *
15    * @prop {Drupal~behaviorAttach} attach
16    *   Attaches tableResponsive functionality.
17    */
18   Drupal.behaviors.tableResponsive = {
19     attach: function (context, settings) {
20       var $tables = $(context).find('table.responsive-enabled').once('tableresponsive');
21       if ($tables.length) {
22         var il = $tables.length;
23         for (var i = 0; i < il; i++) {
24           TableResponsive.tables.push(new TableResponsive($tables[i]));
25         }
26       }
27     }
28   };
29
30   /**
31    * The TableResponsive object optimizes table presentation for screen size.
32    *
33    * A responsive table hides columns at small screen sizes, leaving the most
34    * important columns visible to the end user. Users should not be prevented
35    * from accessing all columns, however. This class adds a toggle to a table
36    * with hidden columns that exposes the columns. Exposing the columns will
37    * likely break layouts, but it provides the user with a means to access
38    * data, which is a guiding principle of responsive design.
39    *
40    * @constructor Drupal.TableResponsive
41    *
42    * @param {HTMLElement} table
43    *   The table element to initialize the responsive table on.
44    */
45   function TableResponsive(table) {
46     this.table = table;
47     this.$table = $(table);
48     this.showText = Drupal.t('Show all columns');
49     this.hideText = Drupal.t('Hide lower priority columns');
50     // Store a reference to the header elements of the table so that the DOM is
51     // traversed only once to find them.
52     this.$headers = this.$table.find('th');
53     // Add a link before the table for users to show or hide weight columns.
54     this.$link = $('<button type="button" class="link tableresponsive-toggle"></button>')
55       .attr('title', Drupal.t('Show table cells that were hidden to make the table fit within a small screen.'))
56       .on('click', $.proxy(this, 'eventhandlerToggleColumns'));
57
58     this.$table.before($('<div class="tableresponsive-toggle-columns"></div>').append(this.$link));
59
60     // Attach a resize handler to the window.
61     $(window)
62       .on('resize.tableresponsive', $.proxy(this, 'eventhandlerEvaluateColumnVisibility'))
63       .trigger('resize.tableresponsive');
64   }
65
66   /**
67    * Extend the TableResponsive function with a list of managed tables.
68    */
69   $.extend(TableResponsive, /** @lends Drupal.TableResponsive */{
70
71     /**
72      * Store all created instances.
73      *
74      * @type {Array.<Drupal.TableResponsive>}
75      */
76     tables: []
77   });
78
79   /**
80    * Associates an action link with the table that will show hidden columns.
81    *
82    * Columns are assumed to be hidden if their header has the class priority-low
83    * or priority-medium.
84    */
85   $.extend(TableResponsive.prototype, /** @lends Drupal.TableResponsive# */{
86
87     /**
88      * @param {jQuery.Event} e
89      *   The event triggered.
90      */
91     eventhandlerEvaluateColumnVisibility: function (e) {
92       var pegged = parseInt(this.$link.data('pegged'), 10);
93       var hiddenLength = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden').length;
94       // If the table has hidden columns, associate an action link with the
95       // table to show the columns.
96       if (hiddenLength > 0) {
97         this.$link.show().text(this.showText);
98       }
99       // When the toggle is pegged, its presence is maintained because the user
100       // has interacted with it. This is necessary to keep the link visible if
101       // the user adjusts screen size and changes the visibility of columns.
102       if (!pegged && hiddenLength === 0) {
103         this.$link.hide().text(this.hideText);
104       }
105     },
106
107     /**
108      * Toggle the visibility of columns based on their priority.
109      *
110      * Columns are classed with either 'priority-low' or 'priority-medium'.
111      *
112      * @param {jQuery.Event} e
113      *   The event triggered.
114      */
115     eventhandlerToggleColumns: function (e) {
116       e.preventDefault();
117       var self = this;
118       var $hiddenHeaders = this.$headers.filter('.priority-medium:hidden, .priority-low:hidden');
119       this.$revealedCells = this.$revealedCells || $();
120       // Reveal hidden columns.
121       if ($hiddenHeaders.length > 0) {
122         $hiddenHeaders.each(function (index, element) {
123           var $header = $(this);
124           var position = $header.prevAll('th').length;
125           self.$table.find('tbody tr').each(function () {
126             var $cells = $(this).find('td').eq(position);
127             $cells.show();
128             // Keep track of the revealed cells, so they can be hidden later.
129             self.$revealedCells = $().add(self.$revealedCells).add($cells);
130           });
131           $header.show();
132           // Keep track of the revealed headers, so they can be hidden later.
133           self.$revealedCells = $().add(self.$revealedCells).add($header);
134         });
135         this.$link.text(this.hideText).data('pegged', 1);
136       }
137       // Hide revealed columns.
138       else {
139         this.$revealedCells.hide();
140         // Strip the 'display:none' declaration from the style attributes of
141         // the table cells that .hide() added.
142         this.$revealedCells.each(function (index, element) {
143           var $cell = $(this);
144           var properties = $cell.attr('style').split(';');
145           var newProps = [];
146           // The hide method adds display none to the element. The element
147           // should be returned to the same state it was in before the columns
148           // were revealed, so it is necessary to remove the display none value
149           // from the style attribute.
150           var match = /^display\s*\:\s*none$/;
151           for (var i = 0; i < properties.length; i++) {
152             var prop = properties[i];
153             prop.trim();
154             // Find the display:none property and remove it.
155             var isDisplayNone = match.exec(prop);
156             if (isDisplayNone) {
157               continue;
158             }
159             newProps.push(prop);
160           }
161           // Return the rest of the style attribute values to the element.
162           $cell.attr('style', newProps.join(';'));
163         });
164         this.$link.text(this.showText).data('pegged', 0);
165         // Refresh the toggle link.
166         $(window).trigger('resize.tableresponsive');
167       }
168     }
169   });
170
171   // Make the TableResponsive object available in the Drupal namespace.
172   Drupal.TableResponsive = TableResponsive;
173
174 })(jQuery, Drupal, window);