You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ponymail.apache.org by hu...@apache.org on 2021/12/13 22:43:59 UTC

[incubator-ponymail-foal] branch master updated (c5c9899 -> 3348f21)

This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ponymail-foal.git.


    from c5c9899  tweak height/margin of email elements
     new 6612556  Make sidebar stats optional, expand calendar if hidden.
     new eb07643  Add sidebar stats checkbox to prefs
     new 3348f21  regen JS

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 webui/admin.html                    |  8 ++--
 webui/css/scaffolding.css           |  7 ++-
 webui/index.html                    |  6 +--
 webui/js/ponymail.js                | 92 ++++++++++++++++++++++++++-----------
 webui/js/source/aavariables.js      |  1 +
 webui/js/source/preferences.js      | 23 +++++++++-
 webui/js/source/primer.js           | 16 ++++++-
 webui/js/source/sidebar-calendar.js | 44 ++++++++++--------
 webui/js/source/sidebar-stats.js    |  8 +++-
 webui/list.html                     | 15 ++++--
 webui/oauth.html                    |  8 ++--
 webui/thread.html                   |  8 ++--
 12 files changed, 164 insertions(+), 72 deletions(-)

[incubator-ponymail-foal] 01/03: Make sidebar stats optional, expand calendar if hidden.

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ponymail-foal.git

commit 6612556a5bc8c0a9274d4ed36b6f14594de75ab5
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Mon Dec 13 23:43:16 2021 +0100

    Make sidebar stats optional, expand calendar if hidden.
---
 webui/css/scaffolding.css           |  7 +++++-
 webui/js/source/aavariables.js      |  1 +
 webui/js/source/preferences.js      | 23 ++++++++++++++++++-
 webui/js/source/primer.js           | 16 ++++++++++++--
 webui/js/source/sidebar-calendar.js | 44 ++++++++++++++++++++-----------------
 webui/js/source/sidebar-stats.js    |  8 +++++--
 6 files changed, 73 insertions(+), 26 deletions(-)

diff --git a/webui/css/scaffolding.css b/webui/css/scaffolding.css
index a7ea6f0..a435ab8 100644
--- a/webui/css/scaffolding.css
+++ b/webui/css/scaffolding.css
@@ -696,12 +696,17 @@ a.dropdown-toggle {
 }
 
 #display_options_dropdown > div {
+    width: 100%;
+    overflow-y: auto;
+}
+
+#display_options_dropdown > div > div {
     width: 45%;
     float: left;
     margin: 2%;
 }
 
-#display_options_dropdown > div:first-child {
+#display_options_dropdown > div > div:first-child {
     border-right: 2px solid #3333;
 }
 
diff --git a/webui/js/source/aavariables.js b/webui/js/source/aavariables.js
index b3e3420..4fcaf74 100644
--- a/webui/js/source/aavariables.js
+++ b/webui/js/source/aavariables.js
@@ -53,6 +53,7 @@ let G_current_per_page = 0;
 // sidebar calendar
 const MONTHS_SHORTENED = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
 const CALENDAR_YEARS_SHOWN = 4; // TODO: should this be configurable?
+let G_show_stats_sidebar = true; // Whether to show author stats or not
 
 // datepicker
 const DAYS_SHORTENED = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
diff --git a/webui/js/source/preferences.js b/webui/js/source/preferences.js
index 0789b44..3ca036a 100644
--- a/webui/js/source/preferences.js
+++ b/webui/js/source/preferences.js
@@ -37,6 +37,9 @@ function init_preferences(state, json) {
             if (ljson.G_current_listmode_compact !== undefined) {
                 G_current_listmode_compact = ljson.G_current_listmode_compact;
             }
+            if (ljson.G_show_stats_sidebar !== undefined) {
+                G_show_stats_sidebar = ljson.G_show_stats_sidebar;
+            }
         }
     }
 
@@ -53,6 +56,10 @@ function init_preferences(state, json) {
     if (cld) {
         cld.checked = !G_chatty_layout;
     }
+    let cla = document.getElementById('G_show_stats_sidebar');
+    if (cla) {
+        cla.checked = G_show_stats_sidebar;
+    }
 
     // Set list display mode:
     let dmt = document.getElementById('display_mode_threaded');
@@ -134,7 +141,8 @@ function save_preferences() {
         let ljson = {
             G_chatty_layout: G_chatty_layout,
             G_current_listmode: G_current_listmode,
-            G_current_listmode_compact: G_current_listmode_compact
+            G_current_listmode_compact: G_current_listmode_compact,
+            G_show_stats_sidebar: G_show_stats_sidebar
         };
         let lstring = JSON.stringify(ljson);
         window.localStorage.setItem('G_ponymail_preferences', lstring);
@@ -182,3 +190,16 @@ function set_skin_permalink(enable_chatty) {
     save_preferences();
     parse_permalink();
 }
+
+function set_show_stats(display) {
+    G_show_stats_sidebar = display;
+    if (display === false) {
+        document.getElementById('sidebar_stats').style.display = "none";
+        document.getElementById('sidebar_wordcloud').style.display = "none";
+    } else {
+        document.getElementById('sidebar_stats').style.display = "block";
+        document.getElementById('sidebar_wordcloud').style.display = "block";
+    }
+    save_preferences();
+    renderCalendar();
+}
\ No newline at end of file
diff --git a/webui/js/source/primer.js b/webui/js/source/primer.js
index f83bd56..cbec6fc 100644
--- a/webui/js/source/primer.js
+++ b/webui/js/source/primer.js
@@ -24,7 +24,13 @@ function renderListView(state, json) {
     G_current_state = state;
     async_escrow['rendering'] = new Date();
     if (!state || state.update_calendar !== false) {
-        renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth, json.active_months);
+        renderCalendar({
+            FY: json.firstYear,
+            FM: json.firstMonth,
+            LY: json.lastYear,
+            LM: json.lastMonth,
+            activity: json.active_months
+        });
     }
     // sort threads by date
     if (isArray(json.thread_struct)) {
@@ -182,7 +188,13 @@ function render_virtual_inbox(state, json) {
 
         async_escrow['rendering'] = new Date();
         if (!state || state.update_calendar !== false) {
-            renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth, json.active_months);
+            renderCalendar({
+                FY: json.firstYear,
+                FM: json.firstMonth,
+                LY: json.lastYear,
+                LM: json.lastMonth,
+                activity: json.active_months
+            });
         }
         // sort threads by date
         if (isArray(json.thread_struct)) {
diff --git a/webui/js/source/sidebar-calendar.js b/webui/js/source/sidebar-calendar.js
index 8a9ea2d..3e1ed41 100644
--- a/webui/js/source/sidebar-calendar.js
+++ b/webui/js/source/sidebar-calendar.js
@@ -16,10 +16,13 @@
 */
 
 let calendar_index = 0;
+let current_calendar_size = CALENDAR_YEARS_SHOWN;
+let calendar_state = {}
 
-function renderCalendar(FY, FM, LY, LM, activity = null) {
+function renderCalendar(state) {
+    calendar_state = state ? state : calendar_state;
     calendar_index = 0;
-
+    current_calendar_size = G_show_stats_sidebar ? CALENDAR_YEARS_SHOWN : CALENDAR_YEARS_SHOWN * 3;
     // Only render if calendar div is present
     let cal = document.getElementById('sidebar_calendar');
     if (!cal) {
@@ -29,10 +32,11 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     let now = new Date();
     let CY = now.getFullYear();
     let CM = now.getMonth() + 1;
-    let SY = Math.min(LY, CY); // last year in calendar, considering current date
+    let SY = Math.min(calendar_state.LY, CY); // last year in calendar, considering current date
+
     // If Last Year is into the future, set Last Month to this one.
-    if (LY > CY) {
-        LM = CM;
+    if (calendar_state.LY > CY) {
+        calendar_state.LM = CM;
     }
 
     let cdiv = new HTML('div', {
@@ -45,7 +49,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
         class: 'sidebar_calendar_chevron'
     });
     chevron.inject(new HTML('span', {
-        onclick: 'calendar_scroll(this, -4);',
+        onclick: 'calendar_scroll(this, -1);',
         style: {
             display: 'none'
         },
@@ -56,7 +60,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     cdiv.inject(chevron);
 
     // Create divs for each year, assign all visible
-    for (let Y = SY; Y >= FY; Y--) {
+    for (let Y = SY; Y >= calendar_state.FY; Y--) {
         let ydiv = new HTML('div', {
             class: 'sidebar_calendar_year',
             id: 'sidebar_calendar_' + N++
@@ -73,34 +77,34 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
             // Mark out-of-bounds segments
             let ym = '%04u-%02u'.format(Y, i+1);
             let c_active = true;
-            if (activity && !activity[ym]) {
+            if (calendar_state.activity && !calendar_state.activity[ym]) {
                 c_active = false;
             }
-            if ((Y == SY && i >= LM) || (Y == CY && i > CM)) {
+            if ((Y == SY && i >= calendar_state.LM) || (Y == CY && i > CM)) {
                 c_active = false;
             }
-            if (Y == FY && ((i + 1) < FM)) {
+            if (Y == calendar_state.FY && ((i + 1) < calendar_state.FM)) {
                 c_active = false;
             }
             if (!c_active) {
                 mdiv.setAttribute("class", "sidebar_calendar_month_nothing");
                 mdiv.setAttribute("onclick", "javascript:void(0);");
-            } else if (activity && activity[ym]) {
-                let count = activity[ym];
+            } else if (calendar_state.activity && calendar_state.activity[ym]) {
+                let count = calendar_state.activity[ym];
                 if (count >= 1000) {
                     count = Math.round(count/100.0); // nearest century
                     count = Math.floor(count/10) + "k" + (count % 10); // thousands and remainder
                 } else {
                     count = count.toString();
                 }
-                mdiv.inject(new HTML('span', {title: `${activity[ym].pretty()} emails this month`, class: 'calendar_count'}, count));
+                mdiv.inject(new HTML('span', {title: `${calendar_state.activity[ym].pretty()} emails this month`, class: 'calendar_count'}, count));
             }
             ydiv.inject(mdiv);
         }
         cdiv.inject(ydiv);
     }
 
-    cal.innerHTML = "<p style='text-align: center;'>Archives (%u - %u):</p>".format(FY, SY);
+    cal.innerHTML = "<p style='text-align: center;'>Archives (%u - %u):</p>".format(calendar_state.FY, SY);
     cal.inject(cdiv);
 
 
@@ -108,7 +112,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
         class: 'sidebar_calendar_chevron'
     });
     chevron.inject(new HTML('span', {
-        onclick: 'calendar_scroll(this, 4);',
+        onclick: 'calendar_scroll(this, 1);',
         style: {
             display: 'none'
         },
@@ -118,9 +122,9 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     }, " "));
     cdiv.inject(chevron);
 
-    // If we have > 4 years, hide the rest
-    if (N > CALENDAR_YEARS_SHOWN) {
-        for (let i = CALENDAR_YEARS_SHOWN; i < N; i++) {
+    // If we have > N years, hide the rest
+    if (N > current_calendar_size) {
+        for (let i = current_calendar_size; i < N; i++) {
             let obj = document.getElementById('sidebar_calendar_' + i);
             if (obj) {
                 obj.style.display = "none";
@@ -130,8 +134,8 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     }
 }
 
-function calendar_scroll(me, x) {
-    console.log(me)
+function calendar_scroll(me, direction) {
+    let x = direction * current_calendar_size;
     let years = document.getElementsByClassName('sidebar_calendar_year');
     calendar_index = Math.max(Math.min(years.length - x, calendar_index + x), 0);
     if (calendar_index > 0) {
diff --git a/webui/js/source/sidebar-stats.js b/webui/js/source/sidebar-stats.js
index d323bca..a75a4b5 100644
--- a/webui/js/source/sidebar-stats.js
+++ b/webui/js/source/sidebar-stats.js
@@ -15,6 +15,7 @@
  limitations under the License.
 */
 
+
 async function sidebar_stats(json) {
     let obj = document.getElementById('sidebar_stats');
     if (!obj) {
@@ -46,7 +47,7 @@ async function sidebar_stats(json) {
 
     // Top 10 participants
     obj.inject("Found %u emails by %u authors, divided into %u topics.".format(json.emails.length, json.numparts, json.no_threads));
-    obj.inject(new HTML('h5', {}, "Most active authors:"));
+    obj.inject(new HTML('h5', {}, "Most active authors: "));
     for (let i = 0; i < json.participants.length; i++) {
         if (i >= 5) {
             break;
@@ -82,5 +83,8 @@ async function sidebar_stats(json) {
             wordCloud(json.cloud, 220, 100, wc);
         }, 50);
     }
-
+    if (G_show_stats_sidebar === false) {
+        obj.style.display = "none";
+        wc.style.display = "none";
+    }
 }

[incubator-ponymail-foal] 02/03: Add sidebar stats checkbox to prefs

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ponymail-foal.git

commit eb07643b7001247cb394fcd4194c80e780bd83c6
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Mon Dec 13 23:43:31 2021 +0100

    Add sidebar stats checkbox to prefs
---
 webui/list.html | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/webui/list.html b/webui/list.html
index 867771c..1153688 100644
--- a/webui/list.html
+++ b/webui/list.html
@@ -94,6 +94,7 @@ the License. -->
             <span class="caret"></span>
           </a>
             <div class="dropdown-menu" id="display_options_dropdown">
+              <div style="display: block; width: 100%;">
               <div>
                 <b>List display mode:</b><br/><br/>
               <input type="radio" id="display_mode_threaded" name="ui_threading" value="threaded" onchange="set_theme('threaded');"> <label for="display_mode_threaded">Threaded view</label><br/>
@@ -108,7 +109,11 @@ the License. -->
                 <input type="radio" id="email_mode_plain" name="ui_emailmode" value="plain" onchange="set_skin(false);"> <label for="email_mode_plain">Legacy rendering</label><br/>
 
               </div>
-
+              </div>
+              <hr/>
+              <div style="display: block; width: 100%; text-align: center;">
+                <input type="checkbox" id="G_show_stats_sidebar" name="ui_stats_sidebar" value="compact" onchange="set_show_stats(this.checked);"> <label for="G_show_stats_sidebar">Show side-bar stats</label><br/>
+              </div>
             </div>
         </li>
 

[incubator-ponymail-foal] 03/03: regen JS

Posted by hu...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

humbedooh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-ponymail-foal.git

commit 3348f21560fa48f18603437274eedf6d3de12355
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Mon Dec 13 23:43:49 2021 +0100

    regen JS
---
 webui/admin.html     |  8 ++---
 webui/index.html     |  6 ++--
 webui/js/ponymail.js | 92 +++++++++++++++++++++++++++++++++++++---------------
 webui/list.html      |  8 ++---
 webui/oauth.html     |  8 ++---
 webui/thread.html    |  8 ++---
 6 files changed, 85 insertions(+), 45 deletions(-)

diff --git a/webui/admin.html b/webui/admin.html
index d11a6de..9f92858 100644
--- a/webui/admin.html
+++ b/webui/admin.html
@@ -25,7 +25,7 @@ the License. -->
     <!-- Bootstrap -->
 
     <link href="css/bootstrap.min.css" rel="stylesheet" media="all">
-    <link href="css/scaffolding.css?revision=1ac956d" rel="stylesheet" media="all">
+    <link href="css/scaffolding.css?revision=6612556" rel="stylesheet" media="all">
     <link href="css/modal.css" rel="stylesheet" media="all">
     <link href="css/spinner.css" rel="stylesheet" media="all">
     <link rel="alternate" href="/api/static.lua"/>
@@ -79,9 +79,9 @@ the License. -->
     <script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
     <!-- Include all compiled plugins (below), or include individual files as needed -->
     <script src="js/bootstrap.min.js"></script>
-    <script src="js/config.js?revision=1ac956d"></script>
-    <script src="js/wordcloud.js?revision=1ac956d"></script>
-    <script src="js/ponymail.js?revision=1ac956d"></script>
+    <script src="js/config.js?revision=6612556"></script>
+    <script src="js/wordcloud.js?revision=6612556"></script>
+    <script src="js/ponymail.js?revision=6612556"></script>
     <div id="splash" class="splash fade-in"> &nbsp; </div>
     <div style="clear: both;"></div>
   </body>
diff --git a/webui/index.html b/webui/index.html
index 5d66375..986140b 100644
--- a/webui/index.html
+++ b/webui/index.html
@@ -24,7 +24,7 @@ the License. -->
     <!-- Bootstrap -->
     
     <link href="css/bootstrap.min.css" rel="stylesheet" media="all">
-    <link href="css/scaffolding.css?revision=1ac956d" rel="stylesheet" media="all">
+    <link href="css/scaffolding.css?revision=6612556" rel="stylesheet" media="all">
     <link href="css/modal.css" rel="stylesheet" media="all">
     <link href="css/spinner.css" rel="stylesheet" media="all">
     <link rel="alternate" href="/api/static.lua"/>
@@ -60,8 +60,8 @@ the License. -->
     <script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
     <!-- Include all compiled plugins (below), or include individual files as needed -->
     <script src="js/bootstrap.min.js"></script>
-    <script src="js/config.js?revision=1ac956d"></script>
-    <script src="js/ponymail.js?revision=1ac956d"></script>
+    <script src="js/config.js?revision=6612556"></script>
+    <script src="js/ponymail.js?revision=6612556"></script>
     <div id="splash" class="splash fade-in"> &nbsp; </div>
     <div style="clear: both;"></div>
     
diff --git a/webui/js/ponymail.js b/webui/js/ponymail.js
index 9b14fac..9392e43 100644
--- a/webui/js/ponymail.js
+++ b/webui/js/ponymail.js
@@ -16,7 +16,7 @@
 */
 // THIS IS AN AUTOMATICALLY COMBINED FILE. PLEASE EDIT THE source/ FILES!
 
-const PONYMAIL_REVISION = '1ac956d';
+const PONYMAIL_REVISION = '6612556';
 
 
 /******************************************
@@ -61,6 +61,7 @@ let G_current_per_page = 0;
 // sidebar calendar
 const MONTHS_SHORTENED = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
 const CALENDAR_YEARS_SHOWN = 4; // TODO: should this be configurable?
+let G_show_stats_sidebar = true; // Whether to show author stats or not
 
 // datepicker
 const DAYS_SHORTENED = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
@@ -3274,6 +3275,9 @@ function init_preferences(state, json) {
             if (ljson.G_current_listmode_compact !== undefined) {
                 G_current_listmode_compact = ljson.G_current_listmode_compact;
             }
+            if (ljson.G_show_stats_sidebar !== undefined) {
+                G_show_stats_sidebar = ljson.G_show_stats_sidebar;
+            }
         }
     }
 
@@ -3290,6 +3294,10 @@ function init_preferences(state, json) {
     if (cld) {
         cld.checked = !G_chatty_layout;
     }
+    let cla = document.getElementById('G_show_stats_sidebar');
+    if (cla) {
+        cla.checked = G_show_stats_sidebar;
+    }
 
     // Set list display mode:
     let dmt = document.getElementById('display_mode_threaded');
@@ -3371,7 +3379,8 @@ function save_preferences() {
         let ljson = {
             G_chatty_layout: G_chatty_layout,
             G_current_listmode: G_current_listmode,
-            G_current_listmode_compact: G_current_listmode_compact
+            G_current_listmode_compact: G_current_listmode_compact,
+            G_show_stats_sidebar: G_show_stats_sidebar
         };
         let lstring = JSON.stringify(ljson);
         window.localStorage.setItem('G_ponymail_preferences', lstring);
@@ -3420,6 +3429,18 @@ function set_skin_permalink(enable_chatty) {
     parse_permalink();
 }
 
+function set_show_stats(display) {
+    G_show_stats_sidebar = display;
+    if (display === false) {
+        document.getElementById('sidebar_stats').style.display = "none";
+        document.getElementById('sidebar_wordcloud').style.display = "none";
+    } else {
+        document.getElementById('sidebar_stats').style.display = "block";
+        document.getElementById('sidebar_wordcloud').style.display = "block";
+    }
+    save_preferences();
+    renderCalendar();
+}
 
 /******************************************
  Fetched from source/primer.js
@@ -3433,7 +3454,13 @@ function renderListView(state, json) {
     G_current_state = state;
     async_escrow['rendering'] = new Date();
     if (!state || state.update_calendar !== false) {
-        renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth, json.active_months);
+        renderCalendar({
+            FY: json.firstYear,
+            FM: json.firstMonth,
+            LY: json.lastYear,
+            LM: json.lastMonth,
+            activity: json.active_months
+        });
     }
     // sort threads by date
     if (isArray(json.thread_struct)) {
@@ -3591,7 +3618,13 @@ function render_virtual_inbox(state, json) {
 
         async_escrow['rendering'] = new Date();
         if (!state || state.update_calendar !== false) {
-            renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth, json.active_months);
+            renderCalendar({
+                FY: json.firstYear,
+                FM: json.firstMonth,
+                LY: json.lastYear,
+                LM: json.lastMonth,
+                activity: json.active_months
+            });
         }
         // sort threads by date
         if (isArray(json.thread_struct)) {
@@ -4203,10 +4236,13 @@ function search_set_list(what) {
 ******************************************/
 
 let calendar_index = 0;
+let current_calendar_size = CALENDAR_YEARS_SHOWN;
+let calendar_state = {}
 
-function renderCalendar(FY, FM, LY, LM, activity = null) {
+function renderCalendar(state) {
+    calendar_state = state ? state : calendar_state;
     calendar_index = 0;
-
+    current_calendar_size = G_show_stats_sidebar ? CALENDAR_YEARS_SHOWN : CALENDAR_YEARS_SHOWN * 3;
     // Only render if calendar div is present
     let cal = document.getElementById('sidebar_calendar');
     if (!cal) {
@@ -4216,10 +4252,11 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     let now = new Date();
     let CY = now.getFullYear();
     let CM = now.getMonth() + 1;
-    let SY = Math.min(LY, CY); // last year in calendar, considering current date
+    let SY = Math.min(calendar_state.LY, CY); // last year in calendar, considering current date
+
     // If Last Year is into the future, set Last Month to this one.
-    if (LY > CY) {
-        LM = CM;
+    if (calendar_state.LY > CY) {
+        calendar_state.LM = CM;
     }
 
     let cdiv = new HTML('div', {
@@ -4232,7 +4269,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
         class: 'sidebar_calendar_chevron'
     });
     chevron.inject(new HTML('span', {
-        onclick: 'calendar_scroll(this, -4);',
+        onclick: 'calendar_scroll(this, -1);',
         style: {
             display: 'none'
         },
@@ -4243,7 +4280,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     cdiv.inject(chevron);
 
     // Create divs for each year, assign all visible
-    for (let Y = SY; Y >= FY; Y--) {
+    for (let Y = SY; Y >= calendar_state.FY; Y--) {
         let ydiv = new HTML('div', {
             class: 'sidebar_calendar_year',
             id: 'sidebar_calendar_' + N++
@@ -4260,34 +4297,34 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
             // Mark out-of-bounds segments
             let ym = '%04u-%02u'.format(Y, i+1);
             let c_active = true;
-            if (activity && !activity[ym]) {
+            if (calendar_state.activity && !calendar_state.activity[ym]) {
                 c_active = false;
             }
-            if ((Y == SY && i >= LM) || (Y == CY && i > CM)) {
+            if ((Y == SY && i >= calendar_state.LM) || (Y == CY && i > CM)) {
                 c_active = false;
             }
-            if (Y == FY && ((i + 1) < FM)) {
+            if (Y == calendar_state.FY && ((i + 1) < calendar_state.FM)) {
                 c_active = false;
             }
             if (!c_active) {
                 mdiv.setAttribute("class", "sidebar_calendar_month_nothing");
                 mdiv.setAttribute("onclick", "javascript:void(0);");
-            } else if (activity && activity[ym]) {
-                let count = activity[ym];
+            } else if (calendar_state.activity && calendar_state.activity[ym]) {
+                let count = calendar_state.activity[ym];
                 if (count >= 1000) {
                     count = Math.round(count/100.0); // nearest century
                     count = Math.floor(count/10) + "k" + (count % 10); // thousands and remainder
                 } else {
                     count = count.toString();
                 }
-                mdiv.inject(new HTML('span', {title: `${activity[ym].pretty()} emails this month`, class: 'calendar_count'}, count));
+                mdiv.inject(new HTML('span', {title: `${calendar_state.activity[ym].pretty()} emails this month`, class: 'calendar_count'}, count));
             }
             ydiv.inject(mdiv);
         }
         cdiv.inject(ydiv);
     }
 
-    cal.innerHTML = "<p style='text-align: center;'>Archives (%u - %u):</p>".format(FY, SY);
+    cal.innerHTML = "<p style='text-align: center;'>Archives (%u - %u):</p>".format(calendar_state.FY, SY);
     cal.inject(cdiv);
 
 
@@ -4295,7 +4332,7 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
         class: 'sidebar_calendar_chevron'
     });
     chevron.inject(new HTML('span', {
-        onclick: 'calendar_scroll(this, 4);',
+        onclick: 'calendar_scroll(this, 1);',
         style: {
             display: 'none'
         },
@@ -4305,9 +4342,9 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     }, " "));
     cdiv.inject(chevron);
 
-    // If we have > 4 years, hide the rest
-    if (N > CALENDAR_YEARS_SHOWN) {
-        for (let i = CALENDAR_YEARS_SHOWN; i < N; i++) {
+    // If we have > N years, hide the rest
+    if (N > current_calendar_size) {
+        for (let i = current_calendar_size; i < N; i++) {
             let obj = document.getElementById('sidebar_calendar_' + i);
             if (obj) {
                 obj.style.display = "none";
@@ -4317,8 +4354,8 @@ function renderCalendar(FY, FM, LY, LM, activity = null) {
     }
 }
 
-function calendar_scroll(me, x) {
-    console.log(me)
+function calendar_scroll(me, direction) {
+    let x = direction * current_calendar_size;
     let years = document.getElementsByClassName('sidebar_calendar_year');
     calendar_index = Math.max(Math.min(years.length - x, calendar_index + x), 0);
     if (calendar_index > 0) {
@@ -4415,7 +4452,7 @@ async function sidebar_stats(json) {
 
     // Top 10 participants
     obj.inject("Found %u emails by %u authors, divided into %u topics.".format(json.emails.length, json.numparts, json.no_threads));
-    obj.inject(new HTML('h5', {}, "Most active authors:"));
+    obj.inject(new HTML('h5', {}, "Most active authors: "));
     for (let i = 0; i < json.participants.length; i++) {
         if (i >= 5) {
             break;
@@ -4451,7 +4488,10 @@ async function sidebar_stats(json) {
             wordCloud(json.cloud, 220, 100, wc);
         }, 50);
     }
-
+    if (G_show_stats_sidebar === false) {
+        obj.style.display = "none";
+        wc.style.display = "none";
+    }
 }
 
 
diff --git a/webui/list.html b/webui/list.html
index 1153688..3ac9785 100644
--- a/webui/list.html
+++ b/webui/list.html
@@ -24,7 +24,7 @@ the License. -->
     <!-- Bootstrap -->
     
     <link href="css/bootstrap.min.css" rel="stylesheet" media="all">
-    <link href="css/scaffolding.css?revision=1ac956d" rel="stylesheet" media="all">
+    <link href="css/scaffolding.css?revision=6612556" rel="stylesheet" media="all">
     <link href="css/modal.css" rel="stylesheet" media="all">
     <link href="css/spinner.css" rel="stylesheet" media="all">
     <link rel="alternate" href="/api/static.lua"/>
@@ -178,9 +178,9 @@ the License. -->
     </script>
     <!-- Include all compiled plugins (below), or include individual files as needed -->
     <script src="js/bootstrap.min.js"></script>
-    <script src="js/config.js?revision=1ac956d"></script>
-    <script src="js/wordcloud.js?revision=1ac956d"></script>
-    <script src="js/ponymail.js?revision=1ac956d"></script>
+    <script src="js/config.js?revision=6612556"></script>
+    <script src="js/wordcloud.js?revision=6612556"></script>
+    <script src="js/ponymail.js?revision=6612556"></script>
     <div id="splash" class="splash fade-in"> &nbsp; </div>
     <div style="clear: both;"></div>
     <script type="text/javascript">
diff --git a/webui/oauth.html b/webui/oauth.html
index 85c88ad..644d730 100644
--- a/webui/oauth.html
+++ b/webui/oauth.html
@@ -21,7 +21,7 @@ the License. -->
 
     <!-- CSS -->
     <link href="css/bootstrap.min.css" rel="stylesheet" media="all">
-    <link href="css/scaffolding.css?revision=1ac956d" rel="stylesheet" media="all">
+    <link href="css/scaffolding.css?revision=6612556" rel="stylesheet" media="all">
     <link href="css/modal.css" rel="stylesheet" media="all">
     <link href="css/spinner.css" rel="stylesheet" media="all">
 
@@ -54,8 +54,8 @@ the License. -->
     <script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
     <!-- Include all compiled plugins (below), or include individual files as needed -->
     <script src="js/bootstrap.min.js"></script>
-    <script src="js/config.js?revision=1ac956d"></script>
-    <script src="js/ponymail.js?revision=1ac956d"></script>
-    <script src="js/oauth.js?revision=1ac956d"></script>
+    <script src="js/config.js?revision=6612556"></script>
+    <script src="js/ponymail.js?revision=6612556"></script>
+    <script src="js/oauth.js?revision=6612556"></script>
   </body>
 </html>
diff --git a/webui/thread.html b/webui/thread.html
index d707e2f..8a2d073 100644
--- a/webui/thread.html
+++ b/webui/thread.html
@@ -25,7 +25,7 @@ the License. -->
     <!-- Bootstrap -->
     
     <link href="css/bootstrap.min.css" rel="stylesheet" media="all">
-    <link href="css/scaffolding.css?revision=1ac956d" rel="stylesheet" media="all">
+    <link href="css/scaffolding.css?revision=6612556" rel="stylesheet" media="all">
     <link href="css/modal.css" rel="stylesheet" media="all">
     <link href="css/spinner.css" rel="stylesheet" media="all">
     <link rel="alternate" href="/api/static.lua"/>
@@ -97,9 +97,9 @@ the License. -->
     <script src="js/jquery-1.12.4.min.js" integrity="sha256-ZosEbRLbNQzLpnKIkEdrPv7lOy9C27hHQ+Xp8a4MxAQ="></script>
     <!-- Include all compiled plugins (below), or include individual files as needed -->
     <script src="js/bootstrap.min.js"></script>
-    <script src="js/config.js?revision=1ac956d"></script>
-    <script src="js/wordcloud.js?revision=1ac956d"></script>
-    <script src="js/ponymail.js?revision=1ac956d"></script>
+    <script src="js/config.js?revision=6612556"></script>
+    <script src="js/wordcloud.js?revision=6612556"></script>
+    <script src="js/ponymail.js?revision=6612556"></script>
     <div id="splash" class="splash fade-in"> &nbsp; </div>
     <div style="clear: both;"></div>
   </body>