OPiQuotations  v.03.00.00 — April 5, 2019
OPiQuotations.js
Go to the documentation of this file.
1 /* -*- coding: utf-8 -*- */
2 /** \file OPiQuotations.js
3  * (September 11, 2016)
4  *
5  * \brief
6  * JavaScript functions to
7  * - highlight founded words
8  * - init sharing buttons
9  * - open/close about panel
10  * - open/close AJAX lists
11  * - open/close AJAX sharing panel
12  * - open/close control panel.
13  *
14  * Piece of OPiQuotations.
15  * https://bitbucket.org/OPiMedia/opiquotations
16  *
17  * GPLv3 --- Copyright (C) 2014, 2015, 2016 Olivier Pirson
18  * http://www.opimedia.be/
19  */
20 
21 /**
22  * \brief
23  * true if highlight is active,
24  * else false.
25  */
26 var highlightActive = false;
27 
28 
29 /**
30  * \brief
31  * The stylesheet to modify.
32  */
33 var highlightSheet = null;
34 
35 
36 
37 /**
38  * \brief
39  * Close the about panel.
40  */
41 function aboutClose() {
42  "use strict";
43 
44  cssClassRemove(document.getElementById("about"), "opened");
45 }
46 
47 
48 /**
49  * \brief
50  * Open the about panel.
51  */
52 function aboutOpen() {
53  "use strict";
54 
55  cssClassAdd(document.getElementById("about"), "opened");
56 }
57 
58 
59 /**
60  * \brief
61  * AJAX load the list name, if necessary.
62  *
63  * @param String name
64  */
65 function buildList(name) {
66  "use strict";
67 
68  console.assert(typeof name === "string", name);
69 
70  if (document.getElementById("list-" + name + "-list") !== null) { // already loaded
71  return;
72  }
73 
74  var xhr = new XMLHttpRequest();
75 
76  xhr.open("GET", "OPiQuotations-list.php?list=" + name + "s", true);
77  xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
78 
79  xhr.onreadystatechange = function() { // callback
80  if ((xhr.readyState !== 4) || (xhr.status !== 200)) {
81  return;
82  }
83 
84  var list = JSON.parse(xhr.responseText);
85  var containerItem = document.getElementById("list-" + name + "-container");
86 
87  if (!list || (list.length === 0)) {
88  containerItem.innerHTML = ""; // remove loading message
89 
90  return;
91  }
92 
93  // Add number of items
94  document.getElementById("list-" + name + "-nb").innerHTML = list.length;
95 
96  // Calculate min and max of occurrences
97  var nbOccurrence;
98  var min = Number.MAX_VALUE;
99  var max = 0;
100  var i;
101 
102  for (i in list) {
103  nbOccurrence = list[i][1];
104  min = Math.min(min, nbOccurrence);
105  max = Math.max(max, nbOccurrence);
106  }
107 
108  // Build the list
109  var ulItem = document.createElement("ul");
110 
111  ulItem.setAttribute("id", "list-" + name + "-list");
112 
113  var aItem;
114  var value;
115  var percent;
116 
117  for (i in list) {
118  aItem = document.createElement("a");
119 
120  value = list[i][0];
121  nbOccurrence = list[i][1];
122 
123  percent = (nbOccurrence - min)*120/(max - min) + 80; // between 80% and 200%
124 
125  cssClassAdd(aItem, (nbOccurrence === min
126  ? "min"
127  : (nbOccurrence === max
128  ? "max"
129  : "")));
130 
131  aItem.setAttribute("href", encodeURI("?" + name + "=" + value));
132  aItem.setAttribute("title", nbOccurrence + " citation" + (nbOccurrence > 1
133  ? "s"
134  : ""));
135  aItem.style.fontSize = Math.round(percent) + "%";
136 
137  aItem.appendChild(document.createTextNode(value));
138 
139  ulItem.appendChild(document.createElement("li")).appendChild(aItem);
140  }
141 
142  containerItem.innerHTML = ""; // remove loading message
143  containerItem.appendChild(ulItem);
144  };
145 
146  xhr.send(null);
147 }
148 
149 
150 /**
151  * \brief
152  * Close the control panel (in responsive mode),
153  * and eventually the about panel.
154  */
155 function controlPanelClose() {
156  "use strict";
157 
158  cssClassRemove(document.getElementById("control-panel"), "opened");
159  aboutClose();
160 }
161 
162 
163 /**
164  * \brief
165  * Open the control panel (in responsive mode).
166  */
167 function controlPanelOpen() {
168  "use strict";
169 
170  cssClassAdd(document.getElementById("control-panel"), "opened");
171 }
172 
173 
174 /**
175  * \brief
176  * Add a CSS class to item.
177  *
178  * @param DOM item
179  * @param String className
180  */
181 function cssClassAdd(item, className) {
182  "use strict";
183 
184  console.assert(item instanceof HTMLElement, item);
185  console.assert(typeof className === "string", className);
186 
187  if (className !== "") {
188  try {
189  item.classList.add(className);
190  }
191  catch (e) { // some old browsers and IE < 10
192  item.className += " " + className;
193  }
194  }
195 }
196 
197 
198 /**
199  * \brief
200  * Remove a CSS class to item.
201  *
202  * @param DOM item
203  * @param String className
204  */
205 function cssClassRemove(item, className) {
206  "use strict";
207 
208  console.assert(item instanceof HTMLElement, item);
209  console.assert(typeof className === "string", className);
210 
211  if (className !== "") {
212  try {
213  item.classList.remove(className);
214  }
215  catch (e) { // some old browsers and IE < 10
216  var a = item.className.split(" ");
217  var i = a.indexOf(className);
218 
219  if (i >= 0) {
220  a.splice(i, 1);
221  }
222  item.className = a.join(" ");
223  }
224  }
225 }
226 
227 
228 /**
229  * \brief
230  * Switch on/off all highlighted words
231  * and close the control panel (in responsive mode).
232  */
233 function highlightOnOff() {
234  "use strict";
235 
236  if (highlightSheet !== null) {
237  if (highlightActive) {
238  highlightSheet.deleteRule(0);
239  highlightSheet.deleteRule(0);
240  }
241  else {
242  highlightSheet.insertRule("main > section.quotation mark { background-color: yellow !important; }", 0);
243  highlightSheet.insertRule("main > section.maxim mark { background-color: #ffbda0 !important; }", 1);
244  }
245  highlightActive = !highlightActive;
246  }
247 
248  controlPanelClose();
249 }
250 
251 
252 /**
253  * \brief
254  * Close all lists in panel,
255  * open list of name.
256  *
257  * Load the list name, if necessary.
258  *
259  * @param String name
260  */
261 function listOpen(name) {
262  "use strict";
263 
264  console.assert(typeof name === "string", name);
265 
266  listsHide();
267 
268  window.scroll(0, 0);
269  document.getElementById("list-" + name).style.display = "block";
270 
271  buildList(name);
272 }
273 
274 
275 /**
276  * \brief
277  * Close all lists in panel.
278  */
279 function listsHide() {
280  "use strict";
281 
282  var labels = ["author", "nation", "subject", "work"];
283 
284  var i;
285 
286  for (i in labels) {
287  document.getElementById("list-" + labels[i]).style.display = "none";
288  }
289 }
290 
291 
292 /**
293  * \brief
294  * Close this sharing panel.
295  *
296  * @param: DOM liCloseItem
297  */
298 function sharingClose(liCloseItem) {
299  "use strict";
300 
301  console.assert(liCloseItem instanceof HTMLElement, liCloseItem);
302 
303  var ul = liCloseItem.parentNode;
304 
305  ul.parentNode.removeChild(ul);
306 }
307 
308 
309 /**
310  * \brief
311  * Open the sharing panel for the quotation id
312  * in a <ul> sibling of item.
313  *
314  * @param DOM item
315  * @param integer id > 0
316  */
317 function sharingOpen(item, id) {
318  "use strict";
319 
320  console.assert(item instanceof HTMLElement, item);
321  console.assert(Number.isInteger(id), id);
322  console.assert(id > 0, id);
323 
324  if (!item || !id || (id <= 0)) {
325  return;
326  }
327 
328  var parent = item.parentNode;
329 
330  // If panel already open, then remove sibling items of item
331  if (parent.children.length > 1) {
332  while (parent.children.length > 1) {
333  parent.removeChild(parent.children[1]);
334  }
335 
336  return;
337  }
338 
339  // Create <ul> and fill it in AJAX
340  var ul = document.createElement("ul");
341 
342  ul.setAttribute("aria-haspopup", "true");
343 
344  ul.innerHTML = "<li>Chargement&hellip;</li>";
345  parent.appendChild(ul);
346 
347  var xhr = new XMLHttpRequest();
348 
349  xhr.open("GET", "OPiQuotations-sharing.php?id=" + id, true);
350  xhr.setRequestHeader("Content-Type", "text/html;charset=UTF-8");
351 
352  xhr.onreadystatechange = function() { // callback
353  if ((xhr.readyState !== 4) || (xhr.status !== 200 || !xhr.responseText)) {
354  return;
355  }
356  ul.innerHTML = xhr.responseText;
357  };
358 
359  xhr.send(null);
360 }
361 
362 
363 
364 /**
365  * \brief
366  * Initializations.
367  */
368 (function () {
369  "use strict";
370 
371  // Search the good stylesheet
372  var i;
373  for (i = 0; i < document.styleSheets.length; ++i) {
374  highlightSheet = document.styleSheets[i];
375 
376  if (highlightSheet.title === "highlight") {
377  break;
378  }
379  }
380 
381 
382  // Set listener to on/off highlight
383  var item = document.getElementById("highlight-on-off");
384 
385  if (item) {
386  item.addEventListener("click", highlightOnOff, false);
387  }
388 
389  // Set listeners to open/close about panel
390  document.getElementById("about-open").addEventListener("click", aboutOpen, false);
391  document.getElementById("about-close").addEventListener("click", aboutClose, false);
392 
393 
394  // Set listeners to open/close control panel
395  document.getElementById("control-panel-right-border").addEventListener("click", controlPanelOpen, false);
396  document.getElementById("control-panel-close").addEventListener("click", controlPanelClose, false);
397 
398 
399  // Set listeners to open/close lists
400  var buttons = document.getElementById("lists").getElementsByClassName("close");
401 
402  for (i = 0; i < buttons.length; ++i) {
403  buttons[i].addEventListener("click", listsHide, false);
404  }
405 
406  buttons = document.getElementById("menu").getElementsByClassName("list-open");
407  for (i = 0; i < buttons.length; ++i) {
408  (function (name) {
409  buttons[i].addEventListener("click",
410  function () {
411  listOpen(name);
412  }, false);
413  }(buttons[i].parentNode.parentNode.className));
414  }
415 }());