Rev Author Line No. Line
4988 kaklik 1 var tableRows = document.getElementsByTagName('tr');
2  
3 function toggleGroup(groupName)
4 {
5 for (var i = 0; i < tableRows.length; i++)
6 {
7 if (tableRows[i].title == groupName)
8 {
9 if (tableRows[i].style.display == 'none')
10 {
11 tableRows[i].style.display = 'table-row';
12 }
13 else
14 {
15 tableRows[i].style.display = 'none';
16 }
17 }
18 }
19 }
20  
21 function collapseAllGroups()
22 {
23 for (var i = 0; i < tableRows.length; i++)
24 {
25 if (tableRows[i].title != '')
26 {
27 tableRows[i].style.display = 'none';
28 }
29 }
30 }
31  
32 $("table.collapsible thead").find("th").on("click", function()
33 {
34 let oldClass = $(this).get(0).className;
35 let newClass = (oldClass == 'open') ? 'closed' : 'open';
36  
37 $(this).get(0).className = newClass;
38 $(this).closest("table").find("tbody").toggle();
39 });
40  
41 /**
42 * Hide all non-root entries currently visible.
43 * <p>
44 * Depending on the config, the site is able to load ALL files and directories of the current repo
45 * recursively to prevent additional requests. The use case is to hide all of the root-dirs and let
46 * users simply toggle the next level of interest without additional waiting. This is implemented by
47 * using the {@code title}-attribute and the {@code /}-character to represent some path and ONLY the
48 * root-dirs themself to show DON'T contain such. All other entries have some, either because they
49 * belong to a subdir or file within some parent dir.
50 * </p>
51 * <p>
52 * There's currently no additional config necessary to apply this JS or not, because the rows worked
53 * on are only generated in case recursive loading is enabled already!
54 * </p>
55 */
56 $('table#listing > tbody > tr[title*="/"]').each(function()
57 {
58 // "visibility: collapse" leaves some space at the bottom of the whole list, resulting in not
59 // wanted scrollbars being shown by default.
60 $(this).hide();
61 });
62  
63 /**
64 * Select all direct children for the given parent.
65 * <p>
66 * The markup doesn't model parent-child relationships currently, but instead all directories,
67 * files etc. are maintained as individual rows one after each other. In theory not even the order
68 * of those rows needs to be alphabetically or fit the parent-child-order in the repo or else, all
69 * can be mixed-up. So this function searches all rows of the given {@code body} for DIRECT children
70 * of the given parent row, which can be identified by their paths maintained in the {@code title}-
71 * attribute. Such filtering is non-trivial and one can't use CSS-selectors only, because those
72 * paths need to fulfill certain conditions.
73 * </p>
74 * @param[in] body
75 * @param[in] rowParent
76 * @return Array with direct children of the given parent.
77 */
78 function recursiveLoadDirectChildrenSelect(body, rowParent)
79 {
80 // The parent title is used in some reg exp, so properly escape/quote it. Sadly "\Q...\E" does
81 // not work and JS doesn't seem to provide anythign else on its own as well.
82 // https://stackoverflow.com/a/3561711/2055163
83 let titleParent = rowParent.attr('title') || '';
84 titleParent = titleParent.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
85 let selector = 'tr[title^="' + titleParent + '/"]';
86 let directChildren = [];
87  
88 // Selectors don't support regular expressions, but direct children not only start with the
89 // parent, but don't contain additional children in their title as well. One can't select
90 // that condition easily, so find ALL children and filter later to direct ones only.
91 body.children(selector).each(function()
92 {
93 let rowChild = $(this);
94 let titleChild = rowChild.attr('title') || '';
95  
96 let ptChildDirs = titleParent + '/$';
97 let ptChildFiles = titleParent + '/[^/]+$';
98 let pattern = ptChildDirs + '|' + ptChildFiles;
99  
100 if (titleChild.match(pattern))
101 {
102 directChildren.push(rowChild);
103 }
104 });
105  
106 return directChildren;
107 }
108  
109 /**
110 * Click-handler for some parent directory.
111 * <p>
112 * What needs to happen depends on the visibility of the direct children associated with some parent
113 * and therefore given: If children are NOT visible, simply show them and ONLY those, as showing
114 * should not be recursive currently. If children are visible OTOH, ALL of those need to be hidden
115 * or otherwise some lower level children would still be shown. This is because of the currently
116 * used markup, which doesn't model parent-child-relationships properly, but places everything at
117 * one level. Someone needs to take care of hiding children of children of children, when hiding
118 * associated markup itself only hides some of those. To hide recursively, a custom event named
119 * {@code hide_children} seems the easiest approach currently, which is then simply handled by the
120 * parent directory again.
121 * </p>
122 * @param[in] directChildren
123 * @return {@code false} to stop propagation of the current event.
124 */
125 function recursiveLoadRowParentOnClick(directChildren)
126 {
127 $.each(directChildren, function()
128 {
129 let self = $(this);
130 let isVisible = self.is(':visible');
131  
132 if (!isVisible)
133 {
134 self.show();
135 return true;
136 }
137  
138 self.trigger('hide_children');
139 self.hide();
140 });
141  
142 return false;
143 }
144  
145 /**
146 * Handler to hide direct children.
147 * <p>
148 * While showing only the next level of children is wanted, when hiding ALL levels need to be hidden
149 * instead. This can not easily be achieved with the current markup placing ALL directories, files
150 * etc. regardless of their depth on the same level. So a special event is registered on each dir
151 * to simply hide ALL of it's own children and that event is triggered on ALL children of some dir
152 * as necessary.
153 * </p>
154 * @param[in] directChildren
155 * @return {@code false} to stop propagation of the current event.
156 */
157 function recursiveLoadRowParentOnHideChildren(directChildren)
158 {
159 $.each(directChildren, function()
160 {
161 let self = $(this);
162  
163 self.trigger('hide_children');
164 self.hide();
165 });
166  
167 return false;
168 }
169  
170 /**
171 * Process one row when loading all directories and files of some repo recursively.
172 * <p>
173 * Markup currently doesn't proiperly model parent-child-relationships, so the current approach is
174 * to iterated all rows of some rendered table to find direct children on our own. Those children
175 * are the once to show or hide in the end any by iterating all rows and search the whole body for
176 * children, all of those can be found easily to register necessary event handlers.
177 * </p>
178 * @param[in] body
179 * @param[in] rowParent
180 */
181 function recursiveLoadRowProc(body, rowParent)
182 {
183 let directChildren = recursiveLoadDirectChildrenSelect(body, rowParent);
184  
185 rowParent.find('td.path a[href^="listing.php?"]').on('click', function()
186 {
187 return recursiveLoadRowParentOnClick(directChildren);
188 });
189  
190 rowParent.on('hide_children', function()
191 {
192 return recursiveLoadRowParentOnHideChildren(directChildren);
193 });
194 }
195  
196 /**
197 * Register event handlers to hide and show children of root-directories.
198 */
199 $('table#listing > tbody').each(function()
200 {
201 let body = $(this);
202  
203 // Each row needs to be checked for its direct children, so that only those can be toggled. The
204 // "tbody" is necessary so that one can find direct children per row as well, because all those
205 // are maintained on the same level and only distinguished by their textual path. So we either
206 // need to search the "tbody" per row for all children or implement some other approach mapping
207 // things by only iterating rows once. The current approach seems easier for now.
208 body.children('tr').each(function() { recursiveLoadRowProc(body, $(this)); });
209 });