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/09/15 23:18:26 UTC
[incubator-ponymail-foal] 01/02: auto-lint code
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 7cf5999862b3b2fabda3b8ffbdaff5c441b1ee1e
Author: Daniel Gruno <hu...@apache.org>
AuthorDate: Wed Sep 15 18:18:08 2021 -0500
auto-lint code
---
webui/js/source/base-http-extensions.js | 26 ++-
webui/js/source/base-js-extensions.js | 130 ++++++------
webui/js/source/body-fixups.js | 342 ++++++++++++++++----------------
webui/js/source/composer.js | 105 ++++++----
webui/js/source/construct-thread.js | 43 ++--
webui/js/source/datepicker.js | 268 +++++++++++++------------
webui/js/source/init.js | 38 ++--
webui/js/source/key-commands.js | 80 +++++---
webui/js/source/list-index.js | 16 +-
webui/js/source/listview-flat.js | 92 ++++++---
webui/js/source/listview-header.js | 2 +-
webui/js/source/listview-threaded.js | 132 +++++++-----
webui/js/source/mgmt.js | 172 ++++++++++++----
webui/js/source/preferences.js | 119 +++++------
webui/js/source/primer.js | 198 +++++++++---------
webui/js/source/render-email.js | 261 +++++++++++++++++-------
webui/js/source/scaffolding-html.js | 162 +++++++--------
webui/js/source/search.js | 15 +-
webui/js/source/sidebar-calendar.js | 95 ++++++---
webui/js/source/sidebar-stats.js | 31 ++-
20 files changed, 1389 insertions(+), 938 deletions(-)
diff --git a/webui/js/source/base-http-extensions.js b/webui/js/source/base-http-extensions.js
index 8994dbe..8691207 100644
--- a/webui/js/source/base-http-extensions.js
+++ b/webui/js/source/base-http-extensions.js
@@ -27,7 +27,7 @@ async function escrow_check() {
let now = new Date();
let show_spinner = false;
for (var k in async_escrow) {
- if ( (now - async_escrow[k]) > async_maxwait ) {
+ if ((now - async_escrow[k]) > async_maxwait) {
show_spinner = true;
break;
}
@@ -35,8 +35,14 @@ async function escrow_check() {
// Fetch or create the spinner
let spinner = document.getElementById('spinner');
if (!spinner) {
- spinner = new HTML('div', { id: 'spinner', class: 'spinner'});
- spinwheel = new HTML('div', {id: 'spinwheel', class: 'spinwheel'});
+ spinner = new HTML('div', {
+ id: 'spinner',
+ class: 'spinner'
+ });
+ spinwheel = new HTML('div', {
+ id: 'spinwheel',
+ class: 'spinwheel'
+ });
spinner.inject(spinwheel);
spinner.inject(new HTML('h2', {}, "Loading, please wait.."));
document.body.appendChild(spinner);
@@ -78,21 +84,21 @@ async function GET(url, callback, state) {
if (state && state.cached === true && async_cache[url]) {
console.log("Fetching %s from cache".format(url));
res_json = async_cache[url];
- }
- else {
+ } else {
try {
console.log("putting %s in escrow...".format(url));
async_escrow[pkey] = new Date(); // Log start of request in escrow dict
- const rv = await fetch(url, {credentials: 'same-origin'}); // Wait for resource...
-
+ const rv = await fetch(url, {
+ credentials: 'same-origin'
+ }); // Wait for resource...
+
// Since this is an async request, the request may have been canceled
// by the time we get a response. Only do callback if not.
if (async_escrow[pkey] !== undefined) {
delete async_escrow[pkey]; // move out of escrow when fetched
res = rv;
}
- }
- catch (e) {
+ } catch (e) {
delete async_escrow[pkey]; // move out of escrow if failed
console.log("The URL %s could not be fetched: %s".format(url, e));
modal("An error occured", "An error occured while trying to fetch %s:\n%s".format(url, e), "error");
@@ -118,4 +124,4 @@ async function GET(url, callback, state) {
async_snap(res);
}
}
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/base-js-extensions.js b/webui/js/source/base-js-extensions.js
index e8292e7..ea0fb48 100644
--- a/webui/js/source/base-js-extensions.js
+++ b/webui/js/source/base-js-extensions.js
@@ -21,34 +21,34 @@
*/
String.prototype.format = function() {
- let args = arguments;
- let n = 0;
- let t = this;
- let rtn = this.replace(/(?!%)?%([-+]*)([0-9.]*)([a-zA-Z])/g, function(m, pm, len, fmt) {
- len = parseInt(len || '1');
- // We need the correct number of args, balk otherwise, using ourselves to format the error!
- if (args.length <= n) {
- let err = "Error interpolating string '%s': Expected at least %u argments, only got %u!".format(t, n+1, args.length);
- console.log(err);
- throw err;
- }
- let varg = args[n];
- n++;
- switch (fmt) {
- case 's':
- if (typeof(varg) == 'function') {
- varg = '(function)';
- }
- return varg;
- // For now, let u, d and i do the same thing
- case 'd':
- case 'i':
- case 'u':
- varg = parseInt(varg).pad(len); // truncate to Integer, pad if needed
- return varg;
- }
+ let args = arguments;
+ let n = 0;
+ let t = this;
+ let rtn = this.replace(/(?!%)?%([-+]*)([0-9.]*)([a-zA-Z])/g, function(m, pm, len, fmt) {
+ len = parseInt(len || '1');
+ // We need the correct number of args, balk otherwise, using ourselves to format the error!
+ if (args.length <= n) {
+ let err = "Error interpolating string '%s': Expected at least %u argments, only got %u!".format(t, n + 1, args.length);
+ console.log(err);
+ throw err;
+ }
+ let varg = args[n];
+ n++;
+ switch (fmt) {
+ case 's':
+ if (typeof(varg) == 'function') {
+ varg = '(function)';
+ }
+ return varg;
+ // For now, let u, d and i do the same thing
+ case 'd':
+ case 'i':
+ case 'u':
+ varg = parseInt(varg).pad(len); // truncate to Integer, pad if needed
+ return varg;
+ }
});
- return rtn;
+ return rtn;
}
@@ -58,10 +58,10 @@ String.prototype.format = function() {
*/
Number.prototype.pretty = function(fix) {
- if (fix) {
- return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
- }
- return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
+ if (fix) {
+ return String(this.toFixed(fix)).replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
+ }
+ return String(this.toFixed(0)).replace(/(\d)(?=(\d{3})+$)/g, '$1,');
};
@@ -71,69 +71,67 @@ Number.prototype.pretty = function(fix) {
*/
Number.prototype.pad = function(n) {
- var str;
- str = String(this);
-
- /* Do we need to pad? if so, do it using String.repeat */
- if (str.length < n) {
- str = "0".repeat(n - str.length) + str;
- }
- return str;
+ var str;
+ str = String(this);
+
+ /* Do we need to pad? if so, do it using String.repeat */
+ if (str.length < n) {
+ str = "0".repeat(n - str.length) + str;
+ }
+ return str;
};
/* Func for converting a date to YYYY-MM-DD HH:MM */
Date.prototype.ISOBare = function() {
- var M, d, h, m, y;
- y = this.getFullYear();
- m = (this.getMonth() + 1).pad(2);
- d = this.getDate().pad(2);
- h = this.getHours().pad(2);
- M = this.getMinutes().pad(2);
- return y + "-" + m + "-" + d + " " + h + ":" + M;
+ var M, d, h, m, y;
+ y = this.getFullYear();
+ m = (this.getMonth() + 1).pad(2);
+ d = this.getDate().pad(2);
+ h = this.getHours().pad(2);
+ M = this.getMinutes().pad(2);
+ return y + "-" + m + "-" + d + " " + h + ":" + M;
};
/* isArray: function to detect if an object is an array */
isArray = function(value) {
- return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length'));
+ return value && typeof value === 'object' && value instanceof Array && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length'));
};
/* isHash: function to detect if an object is a hash */
isHash = function(value) {
- return value && typeof value === 'object' && !isArray(value);
+ return value && typeof value === 'object' && !isArray(value);
};
/* Remove an array element by value */
Array.prototype.remove = function(val) {
- var i, item, j, len;
- for (i = j = 0, len = this.length; j < len; i = ++j) {
- item = this[i];
- if (item === val) {
- this.splice(i, 1);
- return this;
+ var i, item, j, len;
+ for (i = j = 0, len = this.length; j < len; i = ++j) {
+ item = this[i];
+ if (item === val) {
+ this.splice(i, 1);
+ return this;
+ }
}
- }
- return this;
+ return this;
};
/* Check if array has value */
Array.prototype.has = function(val) {
- var i, item, j, len;
- for (i = j = 0, len = this.length; j < len; i = ++j) {
- item = this[i];
- if (item === val) {
- return true;
+ var i, item, j, len;
+ for (i = j = 0, len = this.length; j < len; i = ++j) {
+ item = this[i];
+ if (item === val) {
+ return true;
+ }
}
- }
- return false;
-};
-
-
+ return false;
+};
\ No newline at end of file
diff --git a/webui/js/source/body-fixups.js b/webui/js/source/body-fixups.js
index 3e990b4..a9a2b3d 100644
--- a/webui/js/source/body-fixups.js
+++ b/webui/js/source/body-fixups.js
@@ -23,55 +23,55 @@ ponymail_url_regex = new RegExp("(" + "(?:(?:[a-z]+)://)" + "(?:\\S+(?::\\S*)?@)
// - inline quoting
// - top posting with original email following
ponymail_quote_regex = new RegExp("(" +
- // Typical encapsulation of context by ticketing systems and/or bug trackers
- "(---\\r?\\n([^\\r\\n]*?\\r?\\n)*?---$)|" +
- "(" +
- "(?:\\r?\\n|^)" + // start of line or after a colon
+ // Typical encapsulation of context by ticketing systems and/or bug trackers
+ "(---\\r?\\n([^\\r\\n]*?\\r?\\n)*?---$)|" +
+ "(" +
+ "(?:\\r?\\n|^)" + // start of line or after a colon
// Classic method; a signal line and the quote with '>' starting each line quoted
"(" +
- "(" + // Initial line signalling a quote
- "((\\d+-\\d+-\\d+)\\s+.+<\\S+@\\S+>:[ \t\r\n]+)|" + // "01-02-1982 Foo Bar <fo...@bar.baz>:" OR
- "(on\\s+(.+|.+\\n.+)\\s+wrote:[\r?\n]+)|" + // "On $somedate, $someone wrote:", OR...
- "(le\\s+(.+|.+\\n.+)\\s+écrit:[\r?\n]+)|" + // French version of the above, OR...
- "(.?am .+? schrieb\\s+.+:[\r?\n]+)|" + // German version of the above, OR...
- "(envoy[ée] de mon .+|sent from my .+|von meinem .+ gesendet)[ \t\r\n]+" + // "sent from my iphone/ipad/android phone/whatever", usually means the next part is a quote.
- ")" + // End initial signal line
- "(^$)*" + // Accept blank newlines following it...
- "(((^(?!>)[\\s\\S]+$)*)|(^\\s*>[\\s\\S]+$)*)" + // Either text that follows immediately after with no '>' first, OR text with '>' first, but NOT both...
+ "(" + // Initial line signalling a quote
+ "((\\d+-\\d+-\\d+)\\s+.+<\\S+@\\S+>:[ \t\r\n]+)|" + // "01-02-1982 Foo Bar <fo...@bar.baz>:" OR
+ "(on\\s+(.+|.+\\n.+)\\s+wrote:[\r?\n]+)|" + // "On $somedate, $someone wrote:", OR...
+ "(le\\s+(.+|.+\\n.+)\\s+écrit:[\r?\n]+)|" + // French version of the above, OR...
+ "(.?am .+? schrieb\\s+.+:[\r?\n]+)|" + // German version of the above, OR...
+ "(envoy[ée] de mon .+|sent from my .+|von meinem .+ gesendet)[ \t\r\n]+" + // "sent from my iphone/ipad/android phone/whatever", usually means the next part is a quote.
+ ")" + // End initial signal line
+ "(^$)*" + // Accept blank newlines following it...
+ "(((^(?!>)[\\s\\S]+$)*)|(^\\s*>[\\s\\S]+$)*)" + // Either text that follows immediately after with no '>' first, OR text with '>' first, but NOT both...
")|" +
- "(" +
- // Lines after the signal line; comes in one shape, generally speaking...
- "(^\\s*>+[ \\t]*[^\r\n]*\r*\n+)+" + // Lines beginning with one or more '>' after the initial signal line
- ")" +
+ "(" +
+ // Lines after the signal line; comes in one shape, generally speaking...
+ "(^\\s*>+[ \\t]*[^\r\n]*\r*\n+)+" + // Lines beginning with one or more '>' after the initial signal line
+ ")" +
")+|" + //OR...
"(" +
- "^(-{5,10}).+?\\1[\r\n]+" + // ----- Forwarded Message -----
- "(^\\w+:\\s+.+[\r\n]+){3,10}[\r\n]+" + // Between three and ten header fields (we ask for at least 3, so as to not quote PGP blocks)
- "[\\S\\s]+" + // Whatever comes next...
+ "^(-{5,10}).+?\\1[\r\n]+" + // ----- Forwarded Message -----
+ "(^\\w+:\\s+.+[\r\n]+){3,10}[\r\n]+" + // Between three and ten header fields (we ask for at least 3, so as to not quote PGP blocks)
+ "[\\S\\s]+" + // Whatever comes next...
")+" +
")", "mi");
// Somewhat simplified method for catching email footers/trailers that we don't need
-ponymail_trailer_regex = new RegExp("^--[\r\n]+.*", "mi");//(--\r?\n([^\r\n]*?\r?\n){1,6}$)|[\r\n.]+^((--+ \r?\n|--+\r?\n|__+\r?\n|--+\\s*[^\r\n]+\\s*--+\r?\n)(.*\r?\n)+)+$", "m");
+ponymail_trailer_regex = new RegExp("^--[\r\n]+.*", "mi"); //(--\r?\n([^\r\n]*?\r?\n){1,6}$)|[\r\n.]+^((--+ \r?\n|--+\r?\n|__+\r?\n|--+\\s*[^\r\n]+\\s*--+\r?\n)(.*\r?\n)+)+$", "m");
// This is a regex for capturing code diff blocks in an email
ponymail_diff_regex = new RegExp(
- "(" +
- "^-{3} .+?[\r\n]+" + // Starts with a "--- /foo/bar/baz"
- "^\\+{3} .+?[\r\n]+" + // Then a "+++ /foo/bar/baz"
- "(" + // Then one or more of...
+ "(" +
+ "^-{3} .+?[\r\n]+" + // Starts with a "--- /foo/bar/baz"
+ "^\\+{3} .+?[\r\n]+" + // Then a "+++ /foo/bar/baz"
+ "(" + // Then one or more of...
"^@@@? .+[\r\n]+" + // positioning
"(^ .*[\r\n]*$){0,3}" + // diff header
"(^[-+ ].*[\r\n]*)+" + // actual diff
"(^ .*[\r\n]*$){0,3}" + // diff trailer
- ")+" +
- ")", "mi");
+ ")+" +
+ ")", "mi");
// Function for turning URLs into <a> tags
function fixup_urls(splicer) {
-
+
if (typeof splicer == 'object') {
- return splicer;
+ return splicer;
//splicer = splicer.innerText;
}
/* Array holding text and links */
@@ -84,34 +84,34 @@ function fixup_urls(splicer) {
/* While we have more links, ... */
while (i !== -1) {
- urls++;
-
- /* Only parse the first 250 URLs... srsly */
- if (urls > 250) {
- break;
- }
-
- /* Text preceding the link? add it to textbits frst */
- if (i > 0) {
- t = splicer.substr(0, i);
- textbits.push(t);
- splicer = splicer.substr(i);
- }
-
- /* Find the URL and cut it out as a link */
- m = splicer.match(ponymail_url_regex);
- if (m) {
- url = m[1];
- i = url.length;
- t = splicer.substr(0, i);
- textbits.push(new HTML('a', {
- href: url
- }, url));
- splicer = splicer.substr(i);
- }
-
- /* Find the next link */
- i = splicer.search(ponymail_url_regex);
+ urls++;
+
+ /* Only parse the first 250 URLs... srsly */
+ if (urls > 250) {
+ break;
+ }
+
+ /* Text preceding the link? add it to textbits frst */
+ if (i > 0) {
+ t = splicer.substr(0, i);
+ textbits.push(t);
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the URL and cut it out as a link */
+ m = splicer.match(ponymail_url_regex);
+ if (m) {
+ url = m[1];
+ i = url.length;
+ t = splicer.substr(0, i);
+ textbits.push(new HTML('a', {
+ href: url
+ }, url));
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the next link */
+ i = splicer.search(ponymail_url_regex);
}
/* push the remaining text into textbits */
@@ -123,25 +123,25 @@ function fixup_urls(splicer) {
// Simple check to (attempt to) assess whether a trailer should
// remain or get cut out.
function legit_trailer(a) {
- let lines = a.split(/\s*\r?\n/);
- let first_line = lines.shift();
- while (first_line.length == 0 && lines.length) first_line = lines.shift(); // get first meaningful line
- if (!lines.length || first_line == '--') return ''; // likely a simple trailer
- let last_line = lines.pop();
- while (last_line.length == 0 && lines.length) last_line = lines.pop(); // get last meaningful line
-
- // Check if first and last line are similar, which is usually indictive of a ticket system
- if (last_line == first_line) {
- return a;
- }
- // Otherwise, check if first line has two or more dashes, and it occurs again later (also tix)
- if (first_line.match(/^---+/) && lines.has(first_line)) {
- return "|||" + a + "|||";
- }
-
- // Lastly, if there is "sufficient" length to the dashes, allow (JIRA etc)
- if (first_line.match(/^-{6,72}$/)) return a;
- return '';
+ let lines = a.split(/\s*\r?\n/);
+ let first_line = lines.shift();
+ while (first_line.length == 0 && lines.length) first_line = lines.shift(); // get first meaningful line
+ if (!lines.length || first_line == '--') return ''; // likely a simple trailer
+ let last_line = lines.pop();
+ while (last_line.length == 0 && lines.length) last_line = lines.pop(); // get last meaningful line
+
+ // Check if first and last line are similar, which is usually indictive of a ticket system
+ if (last_line == first_line) {
+ return a;
+ }
+ // Otherwise, check if first line has two or more dashes, and it occurs again later (also tix)
+ if (first_line.match(/^---+/) && lines.has(first_line)) {
+ return "|||" + a + "|||";
+ }
+
+ // Lastly, if there is "sufficient" length to the dashes, allow (JIRA etc)
+ if (first_line.match(/^-{6,72}$/)) return a;
+ return '';
}
// Function for cutting away trailers
@@ -157,20 +157,24 @@ function cut_trailer(splicer) {
}
function color_diff_lines(diff) {
- let lines = diff.split(/[\r\n]+/);
- let ret = [];
- for (var z = 0; z < lines.length;z++) {
- let line = lines[z];
- let color = 'grey';
- if (line[0] == '@') color = 'blue';
- if (line[0] == '-') color = 'red';
- if (line[0] == '+') color = 'green';
- if (line[0] == ' ') color = 'black';
- let el = new HTML('span', {style: {color: color}}, line);
- ret.push(el);
- ret.push(new HTML('br'));
- }
- return ret;
+ let lines = diff.split(/[\r\n]+/);
+ let ret = [];
+ for (var z = 0; z < lines.length; z++) {
+ let line = lines[z];
+ let color = 'grey';
+ if (line[0] == '@') color = 'blue';
+ if (line[0] == '-') color = 'red';
+ if (line[0] == '+') color = 'green';
+ if (line[0] == ' ') color = 'black';
+ let el = new HTML('span', {
+ style: {
+ color: color
+ }
+ }, line);
+ ret.push(el);
+ ret.push(new HTML('br'));
+ }
+ return ret;
}
// Function for coloring diffs
@@ -189,32 +193,34 @@ function fixup_diffs(splicer) {
/* While we have more links, ... */
while (i !== -1) {
- diffs++;
-
- /* Only parse the first 20 diffs... srsly */
- if (diffs > 25) {
- break;
- }
- console.log(i);
- /* Text preceding the diff? add it to textbits frst */
- if (i > 0) {
- t = splicer.substr(0, i);
- textbits.push(t);
- splicer = splicer.substr(i);
- }
-
- /* Find the URL and cut it out as a link */
- m = splicer.match(ponymail_diff_regex);
- if (m) {
- diff = m[1];
- i = diff.length;
- t = splicer.substr(0, i);
- textbits.push(new HTML('pre', {class: 'diff'}, color_diff_lines(diff)));
- splicer = splicer.substr(i);
- }
-
- /* Find the next link */
- i = splicer.search(ponymail_diff_regex);
+ diffs++;
+
+ /* Only parse the first 20 diffs... srsly */
+ if (diffs > 25) {
+ break;
+ }
+ console.log(i);
+ /* Text preceding the diff? add it to textbits frst */
+ if (i > 0) {
+ t = splicer.substr(0, i);
+ textbits.push(t);
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the URL and cut it out as a link */
+ m = splicer.match(ponymail_diff_regex);
+ if (m) {
+ diff = m[1];
+ i = diff.length;
+ t = splicer.substr(0, i);
+ textbits.push(new HTML('pre', {
+ class: 'diff'
+ }, color_diff_lines(diff)));
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the next link */
+ i = splicer.search(ponymail_diff_regex);
}
/* push the remaining text into textbits */
@@ -224,11 +230,11 @@ function fixup_diffs(splicer) {
// Function for turning quotes into quote segments
function fixup_quotes(splicer) {
- if (splicer[splicer.length-1] !== "\n") splicer += "\n"; //tweak to make quotes match the last line if no newline on it.
+ if (splicer[splicer.length - 1] !== "\n") splicer += "\n"; //tweak to make quotes match the last line if no newline on it.
var hideQuotes, i, m, qdiv, quote, quotes, t, textbits;
hideQuotes = true;
if (prefs.compactQuotes === false && !chatty_layout) {
- hideQuotes = false;
+ hideQuotes = false;
}
if (!hideQuotes) return splicer; // We'll bail here for now. Dunno why not.
@@ -241,59 +247,63 @@ function fixup_quotes(splicer) {
/* While we have more quotes, ... */
while (i !== -1) {
- quotes++;
-
- /* Only parse the first 50 quotes... srsly */
- if (quotes > 50) {
- break;
- }
-
- /* Text preceding the quote? add it to textbits first */
- if (i > 0) {
- t = splicer.substr(0, i);
- let diffed = fixup_diffs(cut_trailer(t));
- if (isArray(diffed)) { for(var z = 0; z < diffed.length; z++) textbits.push(fixup_urls(diffed[z]));}
- else textbits.push(fixup_urls(diffed));
- splicer = splicer.substr(i);
- }
-
- /* Find the quote and cut it out as a div */
- m = splicer.match(ponymail_quote_regex);
- if (m) {
- quote = m[0];
- i = quote.length;
- t = splicer.substr(0, i);
- quote = quote.replace(/(>*\s*\r?\n)+$/g, "");
- qdiv = new HTML('div', {
- "class": "email_quote_parent"
- }, [
- new HTML('button', {
- title: "Toggle quote",
- onclick: "toggle_quote(this)"
- }, new HTML('span', {class:'glyphicon glyphicon-comment'}, " ")), new HTML('br'), new HTML('blockquote', {
- "class": "email_quote",
- style: {
- display: hideQuotes ? 'none' : 'block'
- }
- }, fixup_urls(quote))
- ]);
- textbits.push(qdiv);
- splicer = splicer.substr(i);
- }
-
- /* Find the next quotes */
- i = splicer.search(ponymail_quote_regex);
+ quotes++;
+
+ /* Only parse the first 50 quotes... srsly */
+ if (quotes > 50) {
+ break;
+ }
+
+ /* Text preceding the quote? add it to textbits first */
+ if (i > 0) {
+ t = splicer.substr(0, i);
+ let diffed = fixup_diffs(cut_trailer(t));
+ if (isArray(diffed)) {
+ for (var z = 0; z < diffed.length; z++) textbits.push(fixup_urls(diffed[z]));
+ } else textbits.push(fixup_urls(diffed));
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the quote and cut it out as a div */
+ m = splicer.match(ponymail_quote_regex);
+ if (m) {
+ quote = m[0];
+ i = quote.length;
+ t = splicer.substr(0, i);
+ quote = quote.replace(/(>*\s*\r?\n)+$/g, "");
+ qdiv = new HTML('div', {
+ "class": "email_quote_parent"
+ }, [
+ new HTML('button', {
+ title: "Toggle quote",
+ onclick: "toggle_quote(this)"
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-comment'
+ }, " ")), new HTML('br'), new HTML('blockquote', {
+ "class": "email_quote",
+ style: {
+ display: hideQuotes ? 'none' : 'block'
+ }
+ }, fixup_urls(quote))
+ ]);
+ textbits.push(qdiv);
+ splicer = splicer.substr(i);
+ }
+
+ /* Find the next quotes */
+ i = splicer.search(ponymail_quote_regex);
}
/* push the remaining text into textbits */
let diffed = fixup_diffs(cut_trailer(splicer));
- if (isArray(diffed)) { for(var z = 0; z < diffed.length; z++) diffed[z] = fixup_urls(diffed[z]);}
- else diffed = fixup_urls(diffed);
+ if (isArray(diffed)) {
+ for (var z = 0; z < diffed.length; z++) diffed[z] = fixup_urls(diffed[z]);
+ } else diffed = fixup_urls(diffed);
textbits.push(new HTML('span', {}, diffed));
-
+
return textbits;
- }
-
+}
+
function toggle_quote(el) {
let quote = el.parentNode.childNodes[2];
if (quote.style.display != 'block') {
@@ -301,4 +311,4 @@ function toggle_quote(el) {
} else {
quote.style.display = 'none';
}
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/composer.js b/webui/js/source/composer.js
index 32983bc..5b88ef6 100644
--- a/webui/js/source/composer.js
+++ b/webui/js/source/composer.js
@@ -6,20 +6,19 @@ let mua_headers = {};
function compose_send() {
let of = [];
for (let k in mua_headers) {
- of.push(k + "=" + encodeURIComponent(mua_headers[k]));
+ of .push(k + "=" + encodeURIComponent(mua_headers[k]));
}
// Push the subject and email body into the form data
- of.push("subject=" + encodeURIComponent(document.getElementById('composer_subject').value));
- of.push("body=" + encodeURIComponent(document.getElementById('composer_body').value));
+ of .push("subject=" + encodeURIComponent(document.getElementById('composer_subject').value)); of .push("body=" + encodeURIComponent(document.getElementById('composer_body').value));
if (ponymail_preferences.login && ponymail_preferences.login.alternates && document.getElementById('composer_alt')) {
- of.push("alt=" + encodeURIComponent(document.getElementById('composer_alt').options[document.getElementById('composer_alt').selectedIndex].value));
+ of .push("alt=" + encodeURIComponent(document.getElementById('composer_alt').options[document.getElementById('composer_alt').selectedIndex].value));
}
-
+
let request = new XMLHttpRequest();
request.open("POST", "/api/compose.lua");
request.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
- request.send(of.join("&")); // send email as a POST string
-
+ request.send( of .join("&")); // send email as a POST string
+
document.getElementById('composer_modal').style.display = 'none';
modal("Message dispatched!", "Your email has been sent. Depending on moderation rules, it may take a while before it shows up in the archives.", "help");
}
@@ -27,7 +26,7 @@ function compose_send() {
function compose_email(replyto, list) {
let email = null;
let loggedIn = (ponymail_preferences.login && ponymail_preferences.login.credentials) ? true : false;
- if (replyto) email = full_emails[replyto||''];
+ if (replyto) email = full_emails[replyto || ''];
let listname = list;
mua_headers = {};
if (email) {
@@ -42,23 +41,26 @@ function compose_email(replyto, list) {
mua_list = listname;
mua_headers.to = listname;
mua_mid = email ? email['message-id'] : null;
-
+
// Not logged in? MUA it is, then!
if (!loggedIn) {
if (email) {
- let a = new HTML('a', {href: mua_trigger}, "Reply via your own email client");
+ let a = new HTML('a', {
+ href: mua_trigger
+ }, "Reply via your own email client");
let p = new HTML('p', {}, [
- "In order to reply to emails using the web interface, you need to be ",
- new HTML('a', {href: '/oauth.html'}, "logged in first"),
- ". You can however still reply to this email using your own email client: ",
- a
- ]
- );
+ "In order to reply to emails using the web interface, you need to be ",
+ new HTML('a', {
+ href: '/oauth.html'
+ }, "logged in first"),
+ ". You can however still reply to this email using your own email client: ",
+ a
+ ]);
composer("Reply to thread:", p);
return;
}
}
-
+
// Replying to an email and logged in?
let eml_subject = "";
let eml_body = "";
@@ -70,7 +72,9 @@ function compose_email(replyto, list) {
}
let form = [];
form.push(new HTML('b', {}, "Sending as:"));
- let s = new HTML('select', { id: 'composer_alt' });
+ let s = new HTML('select', {
+ id: 'composer_alt'
+ });
s.inject(new HTML('option', {}, ponymail_preferences.login.credentials.email));
if (ponymail_preferences.login && ponymail_preferences.login.alternates) {
for (let z = 0; z < ponymail_preferences.login.alternates.length; z++) {
@@ -82,18 +86,38 @@ function compose_email(replyto, list) {
form.push(new HTML('br'));
form.push(new HTML('b', {}, "Subject:"));
form.push(new HTML('br'));
- form.push(new HTML('input', {style: { width: '90%'}, id: 'composer_subject', type: 'text', value: eml_subject}));
+ form.push(new HTML('input', {
+ style: {
+ width: '90%'
+ },
+ id: 'composer_subject',
+ type: 'text',
+ value: eml_subject
+ }));
form.push(new HTML('br'));
form.push(new HTML('b', {}, "Reply:"));
form.push(new HTML('br'));
- let body = new HTML('textarea', {style: { width: '90%', minHeight: '400px'}, id: 'composer_body'}, eml_body);
+ let body = new HTML('textarea', {
+ style: {
+ width: '90%',
+ minHeight: '400px'
+ },
+ id: 'composer_body'
+ }, eml_body);
form.push(body);
-
- let btn = new HTML('button', { onclick: 'compose_send();'}, "Send reply");
+
+ let btn = new HTML('button', {
+ onclick: 'compose_send();'
+ }, "Send reply");
form.push(btn);
form.push(" ");
- form.push(new HTML('a', {href: mua_trigger, style: { marginLeft: '10px'}}, "Or compose via your own email client"));
-
+ form.push(new HTML('a', {
+ href: mua_trigger,
+ style: {
+ marginLeft: '10px'
+ }
+ }, "Or compose via your own email client"));
+
composer(eml_title, form);
if (email) document.getElementById('composer_body').focus();
@@ -105,19 +129,30 @@ function compose_email(replyto, list) {
function composer(title, contents) {
let modal = document.getElementById('composer_modal');
if (modal == undefined) {
- modal = new HTML('div', { id: 'composer_modal'}, [
- new HTML('div', {id: 'composer_modal_content'}, [
- new HTML('span', {id: 'composer_modal_close', onclick: 'document.getElementById("composer_modal").style.display = "none";'}, 'X'),
- new HTML('h2', {id: 'composer_modal_title'}, title),
- new HTML('div', {id: 'composer_modal_contents'}, contents)
- ])
- ]);
+ modal = new HTML('div', {
+ id: 'composer_modal'
+ }, [
+ new HTML('div', {
+ id: 'composer_modal_content'
+ }, [
+ new HTML('span', {
+ id: 'composer_modal_close',
+ onclick: 'document.getElementById("composer_modal").style.display = "none";'
+ }, 'X'),
+ new HTML('h2', {
+ id: 'composer_modal_title'
+ }, title),
+ new HTML('div', {
+ id: 'composer_modal_contents'
+ }, contents)
+ ])
+ ]);
document.body.appendChild(modal);
-
+
} else {
document.getElementById('composer_modal_title').innerText = title;
document.getElementById('composer_modal_contents').innerHTML = '';
- document.getElementById('composer_modal_contents').inject(contents||'');
+ document.getElementById('composer_modal_contents').inject(contents || '');
}
modal.style.display = 'block';
}
@@ -139,7 +174,7 @@ function mua_link(email, xlist) {
return `mailto:${xlist}?subject=Subject+goes+here`;
}
let eml_raw_short = composer_re(email);
- let subject = "RE: " + email.subject||'';
+ let subject = "RE: " + email.subject || '';
let truncated = false;
let N = 16000; // Anything above 16K can cause namespace issues with links.
if (eml_raw_short.length > N) {
@@ -148,5 +183,5 @@ function mua_link(email, xlist) {
}
let listname = email.list_raw.replace(/[<>]/g, '').replace('.', '@', 1);
let xlink = 'mailto:' + listname + "?subject=" + encodeURIComponent(subject) + "&In-Reply-To=" + encodeURIComponent(email['message-id']) + "&body=" + encodeURIComponent(eml_raw_short);
- return xlink;
+ return xlink;
}
\ No newline at end of file
diff --git a/webui/js/source/construct-thread.js b/webui/js/source/construct-thread.js
index d675aff..aae213c 100644
--- a/webui/js/source/construct-thread.js
+++ b/webui/js/source/construct-thread.js
@@ -55,31 +55,40 @@ function construct_thread(thread, cid, nestlevel, included) {
if (cid === undefined) {
doScroll = true;
}
- included = included||[];
+ included = included || [];
cid = (cid || 0) + 1;
- nestlevel = (nestlevel||0) + 1;
+ nestlevel = (nestlevel || 0) + 1;
let mw = calc_email_width();
let max_nesting = ponymail_max_nesting;
if (mw < 700) {
- max_nesting = Math.floor(mw/250);
+ max_nesting = Math.floor(mw / 250);
}
cid %= 5;
let color = ['286090', 'ccab0a', 'c04331', '169e4e', '6d4ca5'][cid];
let email = undefined;
if (nestlevel < max_nesting) {
- email = new HTML('div', { class: 'email_wrapper', id: 'email_%s'.format(thread.tid||thread.id)});
+ email = new HTML('div', {
+ class: 'email_wrapper',
+ id: 'email_%s'.format(thread.tid || thread.id)
+ });
if (chatty_layout) {
email.style.border = "none !important";
} else {
email.style.borderLeft = '3px solid #%s'.format(color);
}
} else {
- email = new HTML('div', { class: 'email_wrapper_nonest', id: 'email_%s'.format(thread.tid||thread.id)});
+ email = new HTML('div', {
+ class: 'email_wrapper_nonest',
+ id: 'email_%s'.format(thread.tid || thread.id)
+ });
}
- let wrapper = new HTML('div', { class: 'email_inner_wrapper', id: 'email_contents_%s'.format(thread.tid||thread.id)});
+ let wrapper = new HTML('div', {
+ class: 'email_inner_wrapper',
+ id: 'email_contents_%s'.format(thread.tid || thread.id)
+ });
email.inject(wrapper);
if (isArray(thread.children)) {
- thread.children.sort((a,b) => a.epoch - b.epoch);
+ thread.children.sort((a, b) => a.epoch - b.epoch);
for (var i = 0; i < thread.children.length; i++) {
let reply = construct_thread(thread.children[i], cid, nestlevel, included);
cid++;
@@ -88,11 +97,16 @@ function construct_thread(thread, cid, nestlevel, included) {
}
}
}
- let tid = thread.tid||thread.id;
+ let tid = thread.tid || thread.id;
if (!included.includes(tid)) {
included.push(tid);
console.log("Loading email %s".format(tid));
- GET("%sapi/email.lua?id=%s".format(apiURL, tid), render_email, {cached: true, scroll: doScroll, id: tid, div: wrapper});
+ GET("%sapi/email.lua?id=%s".format(apiURL, tid), render_email, {
+ cached: true,
+ scroll: doScroll,
+ id: tid,
+ div: wrapper
+ });
}
return email;
}
@@ -113,8 +127,13 @@ function construct_single_thread(state, json) {
if (chatty_layout) {
let listname = json.thread.list_raw.replace(/[<>]/g, '').replace('.', '@', 1);
div.setAttribute("class", "email_placeholder_chatty");
- div.inject(new HTML('h4', {class: 'chatty_title'}, json.emails[0].subject));
- div.inject(new HTML('a', {href: 'list.html?%s'.format(listname), class: 'chatty_title'}, 'Posted to %s'.format(listname)));
+ div.inject(new HTML('h4', {
+ class: 'chatty_title'
+ }, json.emails[0].subject));
+ div.inject(new HTML('a', {
+ href: 'list.html?%s'.format(listname),
+ class: 'chatty_title'
+ }, 'Posted to %s'.format(listname)));
} else {
div.setAttribute("class", "email_placeholder");
}
@@ -122,4 +141,4 @@ function construct_single_thread(state, json) {
let thread = json.thread;
let email = construct_thread(thread);
div.inject(email);
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/datepicker.js b/webui/js/source/datepicker.js
index d828335..958b8fc 100644
--- a/webui/js/source/datepicker.js
+++ b/webui/js/source/datepicker.js
@@ -26,24 +26,24 @@ var units = {
}
function fixupPicker(obj) {
- obj.addEventListener("focus", function(event){
- $('html').on('hide.bs.dropdown', function (e) {
+ obj.addEventListener("focus", function(event) {
+ $('html').on('hide.bs.dropdown', function(e) {
return false;
});
});
- obj.addEventListener("blur", function(event){
+ obj.addEventListener("blur", function(event) {
$('html').unbind('hide.bs.dropdown')
});
}
// makeSelect: Creates a <select> object with options
function makeSelect(options, id, selval) {
var sel = document.createElement('select')
- sel.addEventListener("focus", function(event){
- $('html').on('hide.bs.dropdown', function (e) {
+ sel.addEventListener("focus", function(event) {
+ $('html').on('hide.bs.dropdown', function(e) {
return false;
});
});
- sel.addEventListener("blur", function(event){
+ sel.addEventListener("blur", function(event) {
$('html').unbind('hide.bs.dropdown')
});
sel.setAttribute("name", id)
@@ -81,24 +81,24 @@ function splitDiv(id, name, div2) {
radio.setAttribute("name", "datepicker_radio")
radio.setAttribute("value", name)
radio.setAttribute("id", "datepicker_radio_" + id)
- radio.setAttribute("onclick", "calcTimespan('"+ id + "')")
+ radio.setAttribute("onclick", "calcTimespan('" + id + "')")
var label = document.createElement('label')
label.innerHTML = " " + name + ": "
label.setAttribute("for", "datepicker_radio_" + id)
-
-
+
+
subdiv.appendChild(radio)
subdiv.appendChild(label)
-
-
+
+
subdiv.style.float = "left"
div2.style.float = "left"
-
+
subdiv.style.width = "120px"
subdiv.style.height = "48px"
div2.style.height = "48px"
div2.style.width = "250px"
-
+
div.appendChild(subdiv)
div.appendChild(div2)
return div
@@ -110,7 +110,7 @@ function splitDiv(id, name, div2) {
function calcTimespan(what) {
var wat = ""
var tval = ""
-
+
// Less than N units ago?
if (what == 'lt') {
// Get unit and how many units
@@ -120,7 +120,7 @@ function calcTimespan(what) {
if (parseInt(N) != 1) {
unitt += "s"
}
-
+
// If this makes sense, construct a humanly readable and a computer version
// of the timespan
if (N.length > 0) {
@@ -128,7 +128,7 @@ function calcTimespan(what) {
tval = "lte=" + N + unit
}
}
-
+
// More than N units ago?
if (what == 'mt') {
// As above, get unit and no of units.
@@ -138,14 +138,14 @@ function calcTimespan(what) {
if (parseInt(N) != 1) {
unitt += "s"
}
-
+
// construct timespan val + description
if (N.length > 0) {
wat = "More than " + N + " " + unitt + " ago"
tval = "gte=" + N + unit
}
}
-
+
// Date range?
if (what == 'cd') {
// Get From and To values
@@ -157,7 +157,7 @@ function calcTimespan(what) {
tval = "dfr=" + f + "|dto=" + t
}
}
-
+
// If we calc'ed a value and spawner exists, update its key/val
if (datepicker_spawner && what && wat.length > 0) {
document.getElementById('datepicker_radio_' + what).checked = true
@@ -168,7 +168,7 @@ function calcTimespan(what) {
datepicker_spawner.value = wat
datepicker_spawner.setAttribute("data", tval)
}
-
+
}
}
@@ -177,7 +177,7 @@ function calcTimespan(what) {
function datePicker(parent, seedPeriod) {
datepicker_spawner = parent
var div = document.getElementById('datepicker_popup')
-
+
// If the datepicker object doesn't exist, spawn it
if (!div) {
div = document.createElement('div')
@@ -185,17 +185,17 @@ function datePicker(parent, seedPeriod) {
div.setAttribute("id", "datepicker_popup")
div.setAttribute("class", "datepicker")
}
-
+
// Reset the contents of the datepicker object
div.innerHTML = ""
div.style.display = "block"
-
+
// Position the datepicker next to whatever called it
var bb = parent.getBoundingClientRect()
div.style.top = (bb.bottom + 8) + "px"
div.style.left = (bb.left + 32) + "px"
-
-
+
+
// -- Less than N $units ago
var ltdiv = document.createElement('div')
var lti = document.createElement('input')
@@ -204,7 +204,7 @@ function datePicker(parent, seedPeriod) {
lti.setAttribute("onkeyup", "calcTimespan('lt')")
lti.setAttribute("onblur", "calcTimespan('lt')")
ltdiv.appendChild(lti)
-
+
var lts = makeSelect({
'd': "Day(s)",
'w': 'Week(s)',
@@ -214,21 +214,21 @@ function datePicker(parent, seedPeriod) {
lts.setAttribute("onchange", "calcTimespan('lt')")
ltdiv.appendChild(lts)
ltdiv.appendChild(document.createTextNode(' ago'))
-
+
div.appendChild(splitDiv('lt', 'Less than', ltdiv))
-
-
+
+
// -- More than N $units ago
var mtdiv = document.createElement('div')
-
+
var mti = document.createElement('input')
mti.style.width = "48px"
mti.setAttribute("id", "datepicker_mti")
mti.setAttribute("onkeyup", "calcTimespan('mt')")
mti.setAttribute("onblur", "calcTimespan('mt')")
mtdiv.appendChild(mti)
-
-
+
+
var mts = makeSelect({
'd': "Day(s)",
'w': 'Week(s)',
@@ -239,13 +239,13 @@ function datePicker(parent, seedPeriod) {
mts.setAttribute("onchange", "calcTimespan('mt')")
mtdiv.appendChild(document.createTextNode(' ago'))
div.appendChild(splitDiv('mt', 'More than', mtdiv))
-
-
-
+
+
+
// -- Calendar timespan
// This is just two text fields, the calendarPicker sub-plugin populates them
var cdiv = document.createElement('div')
-
+
var cfrom = document.createElement('input')
cfrom.style.width = "90px"
cfrom.setAttribute("id", "datepicker_cfrom")
@@ -253,7 +253,7 @@ function datePicker(parent, seedPeriod) {
cfrom.setAttribute("onchange", "calcTimespan('cd')")
cdiv.appendChild(document.createTextNode('From: '))
cdiv.appendChild(cfrom)
-
+
var cto = document.createElement('input')
cto.style.width = "90px"
cto.setAttribute("id", "datepicker_cto")
@@ -261,11 +261,11 @@ function datePicker(parent, seedPeriod) {
cto.setAttribute("onchange", "calcTimespan('cd')")
cdiv.appendChild(document.createTextNode('To: '))
cdiv.appendChild(cto)
-
+
div.appendChild(splitDiv('cd', 'Date range', cdiv))
-
-
-
+
+
+
// -- Magic button that sends the timespan back to the caller
var okay = document.createElement('input')
okay.setAttribute("type", "button")
@@ -274,16 +274,18 @@ function datePicker(parent, seedPeriod) {
div.appendChild(okay)
parent.parentNode.appendChild(div)
document.body.setAttribute("onclick", "")
- window.setTimeout(function() { document.body.setAttribute("onclick", "blurDatePicker(event)") }, 200)
+ window.setTimeout(function() {
+ document.body.setAttribute("onclick", "blurDatePicker(event)")
+ }, 200)
lti.focus()
-
+
// This is for recalcing the set options if spawned from a
// select/input box with an existing value derived from an
// earlier call to datePicker
var ptype = ""
var pvalue = parent.hasAttribute("data") ? parent.getAttribute("data") : parent.value
if (pvalue.search(/=|-/) != -1) {
-
+
// Less than N units ago?
if (pvalue.match(/lte/)) {
var m = pvalue.match(/lte=(\d+)([dMyw])/)
@@ -301,9 +303,9 @@ function datePicker(parent, seedPeriod) {
}
}
}
-
+
}
-
+
// More than N units ago?
if (pvalue.match(/gte/)) {
ptype = 'mt'
@@ -323,7 +325,7 @@ function datePicker(parent, seedPeriod) {
}
}
}
-
+
// Date range?
if (pvalue.match(/dfr/)) {
ptype = 'cd'
@@ -343,8 +345,8 @@ function datePicker(parent, seedPeriod) {
var m = pvalue.match(/(\d{4})-(\d+)/)
if (m.length == 3) {
// easy peasy, just set two text fields!
- var dfrom = new Date(parseInt(m[1]),parseInt(m[2])-1,1, 0, 0, 0)
- var dto = new Date(parseInt(m[1]),parseInt(m[2]),0, 23, 59, 59)
+ var dfrom = new Date(parseInt(m[1]), parseInt(m[2]) - 1, 1, 0, 0, 0)
+ var dto = new Date(parseInt(m[1]), parseInt(m[2]), 0, 23, 59, 59)
document.getElementById('datepicker_cfrom').value = m[0] + "-" + dfrom.getDate()
document.getElementById('datepicker_cto').value = m[0] + "-" + dto.getDate()
}
@@ -361,7 +363,7 @@ function datePickerValue(seedPeriod) {
var ptype = ""
var rv = seedPeriod
if (seedPeriod && seedPeriod.search && seedPeriod.search(/=|-/) != -1) {
-
+
// Less than N units ago?
if (seedPeriod.match(/lte/)) {
var m = seedPeriod.match(/lte=(\d+)([dMyw])/)
@@ -372,7 +374,7 @@ function datePickerValue(seedPeriod) {
}
rv = "Less than " + m[1] + " " + unitt + " ago"
}
-
+
// More than N units ago?
if (seedPeriod.match(/gte/)) {
ptype = 'mt'
@@ -383,7 +385,7 @@ function datePickerValue(seedPeriod) {
}
rv = "More than " + m[1] + " " + unitt + " ago"
}
-
+
// Date range?
if (seedPeriod.match(/dfr/)) {
ptype = 'cd'
@@ -393,17 +395,17 @@ function datePickerValue(seedPeriod) {
rv = "From " + mf[1] + " to " + mt[1]
}
}
-
+
// Month??
if (seedPeriod.match(/^(\d+)-(\d+)$/)) {
ptype = 'mr' // just a made up thing...(month range)
var mr = seedPeriod.match(/(\d+)-(\d+)/)
if (mr) {
- dfrom = new Date(parseInt(mr[1]),parseInt(mr[2])-1,1, 0, 0, 0)
+ dfrom = new Date(parseInt(mr[1]), parseInt(mr[2]) - 1, 1, 0, 0, 0)
rv = months[dfrom.getMonth()] + ', ' + mr[1]
}
}
-
+
}
return rv
}
@@ -418,75 +420,75 @@ function datePickerDouble(seedPeriod) {
var tspan = 1
var dfrom = new Date()
var dto = new Date()
-
+
// datepicker range?
if (seedPeriod && seedPeriod.search && seedPeriod.search(/=/) != -1) {
-
+
// Less than N units ago?
if (seedPeriod.match(/lte/)) {
var m = seedPeriod.match(/lte=(\d+)([dMyw])/)
ptype = 'lt'
rv = "<" + m[1] + m[2] + " ago"
- dbl = "lte=" + (parseInt(m[1])*2) + m[2]
-
+ dbl = "lte=" + (parseInt(m[1]) * 2) + m[2]
+
// N months ago
if (m[2] == "M") {
- dfrom.setMonth(dfrom.getMonth()-parseInt(m[1]), dfrom.getDate())
+ dfrom.setMonth(dfrom.getMonth() - parseInt(m[1]), dfrom.getDate())
}
-
+
// N days ago
if (m[2] == "d") {
- dfrom.setDate(dfrom.getDate()-parseInt(m[1]))
+ dfrom.setDate(dfrom.getDate() - parseInt(m[1]))
}
-
+
// N years ago
if (m[2] == "y") {
- dfrom.setYear(dfrom.getFullYear()-parseInt(m[1]))
+ dfrom.setYear(dfrom.getFullYear() - parseInt(m[1]))
}
-
+
// N weeks ago
if (m[2] == "w") {
- dfrom.setDate(dfrom.getDate()-(parseInt(m[1])*7))
+ dfrom.setDate(dfrom.getDate() - (parseInt(m[1]) * 7))
}
-
+
// Calc total duration in days for this time span
- tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
+ tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000 * 86400))
}
-
+
// More than N units ago?
if (seedPeriod.match(/gte/)) {
ptype = 'mt'
var m = seedPeriod.match(/gte=(\d+)([dMyw])/)
rv = ">" + m[1] + m[2] + " ago"
- dbl = "gte=" + (parseInt(m[1])*2) + m[2]
+ dbl = "gte=" + (parseInt(m[1]) * 2) + m[2]
tspan = parseInt(parseInt(m[1]) * 30.4)
dfrom = null
-
+
// Months
if (m[2] == "M") {
- dto.setMonth(dto.getMonth()-parseInt(m[1]), dto.getDate())
+ dto.setMonth(dto.getMonth() - parseInt(m[1]), dto.getDate())
}
-
+
// Days
if (m[2] == "d") {
- dto.setDate(dto.getDate()-parseInt(m[1]))
+ dto.setDate(dto.getDate() - parseInt(m[1]))
}
-
+
// Years
if (m[2] == "y") {
- dto.setYear(dto.getFullYear()-parseInt(m[1]))
+ dto.setYear(dto.getFullYear() - parseInt(m[1]))
}
-
+
// Weeks
if (m[2] == "w") {
- dto.setDate(dto.getDate()-(parseInt(m[1])*7))
+ dto.setDate(dto.getDate() - (parseInt(m[1]) * 7))
}
-
+
// Can't really figure out a timespan for this, so...null!
// This also sort of invalidates use on the trend page, but meh..
tspan = null
}
-
+
// Date range?
if (seedPeriod.match(/dfr/)) {
ptype = 'cd'
@@ -496,55 +498,55 @@ function datePickerDouble(seedPeriod) {
if (mf && mt) {
rv = "from " + mf[1] + " to " + mt[1]
// Starts at 00:00:00 on from date
- dfrom = new Date(parseInt(mf[1]),parseInt(mf[2])-1,parseInt(mf[3]), 0, 0, 0)
-
+ dfrom = new Date(parseInt(mf[1]), parseInt(mf[2]) - 1, parseInt(mf[3]), 0, 0, 0)
+
// Ends at 23:59:59 on to date
- dto = new Date(parseInt(mt[1]),parseInt(mt[2])-1,parseInt(mt[3]), 23, 59, 59)
-
+ dto = new Date(parseInt(mt[1]), parseInt(mt[2]) - 1, parseInt(mt[3]), 23, 59, 59)
+
// Get duration in days, add 5 seconds to we can floor the value and get an integer
- tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
-
+ tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000 * 86400))
+
// double the distance
var dpast = new Date(dfrom)
dpast.setDate(dpast.getDate() - tspan)
- dbl = seedPeriod.replace(/dfr=[^|]+/, "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth()+1) + '-' + dpast.getDate())
+ dbl = seedPeriod.replace(/dfr=[^|]+/, "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth() + 1) + '-' + dpast.getDate())
} else {
tspan = 0
}
}
}
-
+
// just N days?
else if (parseInt(seedPeriod).toString() == seedPeriod.toString()) {
tspan = parseInt(seedPeriod)
dfrom.setDate(dfrom.getDate() - tspan)
- dbl = "lte=" + (tspan*2) + "d"
+ dbl = "lte=" + (tspan * 2) + "d"
}
-
+
// Specific month?
else if (seedPeriod.match(/^(\d+)-(\d+)$/)) {
// just a made up thing...(month range)
- ptype = 'mr'
+ ptype = 'mr'
var mr = seedPeriod.match(/(\d+)-(\d+)/)
if (mr) {
rv = seedPeriod
// Same as before, start at 00:00:00
- dfrom = new Date(parseInt(mr[1]),parseInt(mr[2])-1,1, 0, 0, 0)
+ dfrom = new Date(parseInt(mr[1]), parseInt(mr[2]) - 1, 1, 0, 0, 0)
// end at 23:59:59
- dto = new Date(parseInt(mr[1]),parseInt(mr[2]),0, 23, 59, 59)
-
+ dto = new Date(parseInt(mr[1]), parseInt(mr[2]), 0, 23, 59, 59)
+
// B-A, add 5 seconds so we can floor the no. of days into an integer neatly
- tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000*86400))
-
+ tspan = parseInt((dto.getTime() - dfrom.getTime() + 5000) / (1000 * 86400))
+
// Double timespan
var dpast = new Date(dfrom)
dpast.setDate(dpast.getDate() - tspan)
- dbl = "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth()+1) + '-' + dpast.getDate() + "|dto=" + (dto.getFullYear()) + '-' + (dto.getMonth()+1) + '-' + dto.getDate()
+ dbl = "dfr=" + (dpast.getFullYear()) + '-' + (dpast.getMonth() + 1) + '-' + dpast.getDate() + "|dto=" + (dto.getFullYear()) + '-' + (dto.getMonth() + 1) + '-' + dto.getDate()
} else {
tspan = 0
}
}
-
+
return [dbl, dfrom, dto, tspan]
}
@@ -583,39 +585,39 @@ function blurDatePicker(evt) {
// draws the actual calendar inside a calendarPicker object
function drawCalendarPicker(obj, date) {
-
-
+
+
obj.focus()
-
+
// Default to NOW for calendar.
var now = new Date()
-
+
// if called with an existing date (YYYY-MM-DD),
// convert it to a JS date object and use that for
// rendering the calendar
if (date) {
var ar = date.split(/-/)
- now = new Date(ar[0],parseInt(ar[1])-1,ar[2])
+ now = new Date(ar[0], parseInt(ar[1]) - 1, ar[2])
}
- var days = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun']
+ var days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
var mat = now
-
+
// Go to first day of the month
mat.setDate(1)
-
+
obj.innerHTML = "<h3>" + months[mat.getMonth()] + ", " + mat.getFullYear() + ":</h3>"
var tm = mat.getMonth()
-
+
// -- Nav buttons --
-
+
// back-a-year button
var a = document.createElement('a')
fixupPicker(a)
- a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear()-1) + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
+ a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear() - 1) + '-' + (mat.getMonth() + 1) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "≪"
obj.appendChild(a)
-
+
// back-a-month button
a = document.createElement('a')
fixupPicker(a)
@@ -623,31 +625,31 @@ function drawCalendarPicker(obj, date) {
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "<"
obj.appendChild(a)
-
+
// forward-a-month button
a = document.createElement('a')
fixupPicker(a)
- a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + mat.getFullYear() + '-' + (mat.getMonth()+2) + '-' + mat.getDate() + "');")
+ a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + mat.getFullYear() + '-' + (mat.getMonth() + 2) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = ">"
obj.appendChild(a)
-
+
// forward-a-year button
a = document.createElement('a')
fixupPicker(a)
- a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear()+1) + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
+ a.setAttribute("onclick", "drawCalendarPicker(this.parentNode, '" + (mat.getFullYear() + 1) + '-' + (mat.getMonth() + 1) + '-' + mat.getDate() + "');")
a.setAttribute("href", "javascript:void(0);")
a.innerHTML = "≫"
obj.appendChild(a)
obj.appendChild(document.createElement('br'))
-
-
+
+
// Table containing the dates of the selected month
var table = document.createElement('table')
-
+
table.setAttribute("border", "1")
table.style.margin = "0 auto"
-
+
// Add header day names
var tr = document.createElement('tr');
for (var m = 0; m < 7; m++) {
@@ -656,7 +658,7 @@ function drawCalendarPicker(obj, date) {
tr.appendChild(td)
}
table.appendChild(tr)
-
+
// Until we hit the first day in a month, add blank days
tr = document.createElement('tr');
var weekday = mat.getDay()
@@ -668,7 +670,7 @@ function drawCalendarPicker(obj, date) {
var td = document.createElement('td')
tr.appendChild(td)
}
-
+
// While still in this month, add day then increment date by 1 day.
while (mat.getMonth() == tm) {
weekday = mat.getDay()
@@ -682,24 +684,26 @@ function drawCalendarPicker(obj, date) {
}
td = document.createElement('td')
// onclick for setting the calendarPicker's parent to this val.
- td.setAttribute("onclick", "setCalendarDate('" + mat.getFullYear() + '-' + (mat.getMonth()+1) + '-' + mat.getDate() + "');")
+ td.setAttribute("onclick", "setCalendarDate('" + mat.getFullYear() + '-' + (mat.getMonth() + 1) + '-' + mat.getDate() + "');")
td.innerHTML = mat.getDate()
- mat.setDate(mat.getDate()+1)
+ mat.setDate(mat.getDate() + 1)
tr.appendChild(td)
}
-
+
table.appendChild(tr)
obj.appendChild(table)
}
// callback for datePicker; sets the cd value to what date was picked
function setCalendarDate(what) {
- $('html').on('hide.bs.dropdown', function (e) {
+ $('html').on('hide.bs.dropdown', function(e) {
return false;
});
- setTimeout(function() { $('html').unbind('hide.bs.dropdown');}, 250);
-
-
+ setTimeout(function() {
+ $('html').unbind('hide.bs.dropdown');
+ }, 250);
+
+
calendarpicker_spawner.value = what
var div = document.getElementById('calendarpicker_popup')
div.parentNode.focus()
@@ -710,7 +714,7 @@ function setCalendarDate(what) {
// caller for when someone clicks on a calendarPicker enabled field
function showCalendarPicker(parent, seedDate) {
calendarpicker_spawner = parent
-
+
// If supplied with a YYYY-MM-DD date, use this to seed the calendar
if (!seedDate) {
var m = parent.value.match(/(\d+-\d+(-\d+)?)/)
@@ -718,7 +722,7 @@ function showCalendarPicker(parent, seedDate) {
seedDate = m[1]
}
}
-
+
// Show or create the calendar object
var div = document.getElementById('calendarpicker_popup')
if (!div) {
@@ -730,10 +734,10 @@ function showCalendarPicker(parent, seedDate) {
}
div.style.display = "block"
var bb = parent.getBoundingClientRect()
-
+
// Align with the calling object, slightly below
div.style.top = (bb.bottom + 8) + "px"
div.style.left = (bb.right - 32) + "px"
-
- drawCalendarPicker(div, seedDate)
+
+ drawCalendarPicker(div, seedDate)
}
\ No newline at end of file
diff --git a/webui/js/source/init.js b/webui/js/source/init.js
index 43d529f..4648efb 100644
--- a/webui/js/source/init.js
+++ b/webui/js/source/init.js
@@ -15,7 +15,7 @@
limitations under the License.
*/
-var ponymail_version = "1.0.1-Foal" // Current version of Pony Mail
+var ponymail_version = "1.0.1-Foal" // Current version of Pony Mail
var ponymail_name = "Pony Mail" // name of archive (set to "Foo's mail archive" or whatever)
var hits_per_page = 10;
@@ -39,7 +39,12 @@ var ponymail_max_nesting = 10; // max nesting level before unthreading to save s
// thread state
var current_email_idx = undefined;
var chatty_layout = true;
-var ponymail_date_format = { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric'};
+var ponymail_date_format = {
+ weekday: 'long',
+ year: 'numeric',
+ month: 'long',
+ day: 'numeric'
+};
var virtual_inbox_loading = false;
var collated_json = {};
@@ -81,18 +86,23 @@ if (pm_config && pm_config.apiURL) {
console.log("Setting API URL to %s".format(apiURL));
}
-window.addEventListener('load',function() {
- document.body.appendChild(new HTML('footer', {class: 'footer'}, [
- new HTML('div', { class: 'container'}, [
- new HTML('p', {class: 'muted'}, "Powered by Apache Pony Mail (Foal v/%s)".format(ponymail_version))
- ]
- )
- ])
- );
- }
- );
+window.addEventListener('load', function() {
+ document.body.appendChild(new HTML('footer', {
+ class: 'footer'
+ }, [
+ new HTML('div', {
+ class: 'container'
+ }, [
+ new HTML('p', {
+ class: 'muted'
+ }, "Powered by Apache Pony Mail (Foal v/%s)".format(ponymail_version))
+ ])
+ ]));
+});
console.log("initializing pop state checker");
window.onpopstate = function(event) {
console.log("Popping state");
- return parseURL({cached: true});
-};
+ return parseURL({
+ cached: true
+ });
+};
\ No newline at end of file
diff --git a/webui/js/source/key-commands.js b/webui/js/source/key-commands.js
index 19ed423..23fd1b2 100644
--- a/webui/js/source/key-commands.js
+++ b/webui/js/source/key-commands.js
@@ -21,16 +21,27 @@ function modal(title, msg, type, isHTML) {
let modal = document.getElementById('modal');
let text = document.getElementById('modal_text');
if (modal == undefined) {
- text = new HTML('p', {id: 'modal_text'}, "");
- modal = new HTML('div', { id: 'modal'}, [
- new HTML('div', {id: 'modal_content'}, [
- new HTML('span', {id: 'modal_close', onclick: 'document.getElementById("modal").style.display = "none";'}, 'X'),
- new HTML('h2', {id: 'modal_title'}, title),
- new HTML('div', {}, text)
- ])
- ]);
+ text = new HTML('p', {
+ id: 'modal_text'
+ }, "");
+ modal = new HTML('div', {
+ id: 'modal'
+ }, [
+ new HTML('div', {
+ id: 'modal_content'
+ }, [
+ new HTML('span', {
+ id: 'modal_close',
+ onclick: 'document.getElementById("modal").style.display = "none";'
+ }, 'X'),
+ new HTML('h2', {
+ id: 'modal_title'
+ }, title),
+ new HTML('div', {}, text)
+ ])
+ ]);
document.body.appendChild(modal);
-
+
}
if (type) {
modal.setAttribute("class", "modal_" + type);
@@ -50,7 +61,7 @@ function modal(title, msg, type, isHTML) {
// Helper for determining if an email is open or not...
function anyOpen() {
- let open = (current_email_idx !== undefined) ? true: false;
+ let open = (current_email_idx !== undefined) ? true : false;
console.log("Emails open? " + open);
return open;
}
@@ -58,28 +69,28 @@ function anyOpen() {
// Helper function for hiding windows and open tabs
// Hide previous action on first escape, hide everything on second escape
function hideWindows(force_all) {
-
+
// First, check if we want to hide a modal
let modal = document.getElementById('modal');
if (modal && modal.style.display == 'block') {
modal.style.display = 'none';
if (force_all !== true) return;
}
-
+
// RThen, check if we want to hide a composer modal
let cmodal = document.getElementById('composer_modal');
if (cmodal && cmodal.style.display == 'block') {
cmodal.style.display = 'none';
if (force_all !== true) return;
}
-
+
// Check Advanced Search
let as = document.getElementById('advanced_search');
if (as && as.style.display == 'block') {
as.style.display = 'none';
if (force_all !== true) return;
}
-
+
// Check for individually opened email
if (current_email_idx !== undefined) {
console.log("Hiding placeholder at index %u".format(current_email_idx));
@@ -90,10 +101,10 @@ function hideWindows(force_all) {
current_email_idx = undefined; // undef this even if we can't find the email
if (force_all !== true) return;
}
-
+
// if viewing a single thread, disregard the collapses below - the won't make sense!
if (location.href.match(/thread(?:\.html)?/)) return;
-
+
// Finally, check for other opened emails, close 'em all
let placeholders = document.getElementsByClassName('email_placeholder');
for (var i = 0; i < placeholders.length; i++) {
@@ -101,20 +112,24 @@ function hideWindows(force_all) {
console.log("Hiding placeholder %s".format(placeholders[i].getAttribute('id')));
placeholders[i].style.display = 'none';
// Reset scroll cache
- try { window.scrollTo(0,0);} catch (e) {}
+ try {
+ window.scrollTo(0, 0);
+ } catch (e) {}
}
}
-
+
placeholders = document.getElementsByClassName('email_placeholder_chatty');
for (var i = 0; i < placeholders.length; i++) {
if (placeholders[i].style.display == 'block') {
console.log("Hiding placeholder %s".format(placeholders[i].getAttribute('id')));
placeholders[i].style.display = 'none';
// Reset scroll cache
- try { window.scrollTo(0,0);} catch (e) {}
+ try {
+ window.scrollTo(0, 0);
+ } catch (e) {}
}
}
-
+
}
// Show keyboard commands
@@ -158,7 +173,9 @@ function keyCommands(e) {
if (current_listmode == 'threaded') blobs = current_json.thread_struct;
let no_emails = blobs.length;
if (current_email_idx == undefined && current_json && (current_index_pos + current_per_page) < no_emails) {
- listview_header({pos: current_index_pos + current_per_page}, current_json);
+ listview_header({
+ pos: current_index_pos + current_per_page
+ }, current_json);
}
}
return;
@@ -168,20 +185,22 @@ function keyCommands(e) {
if (current_listmode == 'threaded') blobs = current_json.thread_struct;
let no_emails = blobs.length;
if (current_email_idx == undefined && current_json && (current_index_pos - current_per_page) >= 0) {
- listview_header({pos: current_index_pos - current_per_page}, current_json);
+ listview_header({
+ pos: current_index_pos - current_per_page
+ }, current_json);
}
}
return;
}
-
+
}
}
// swipe left/right for next/previous page on mobile
function ponymail_swipe(event) {
// Only accept "big" swipes
- let len = Math.abs(event.swipestart.coords[0] - event.swipestop.coords[ 0 ]);
- let direction = event.swipestart.coords[0] > event.swipestop.coords[ 0 ] ? 'left' : 'right';
+ let len = Math.abs(event.swipestart.coords[0] - event.swipestop.coords[0]);
+ let direction = event.swipestart.coords[0] > event.swipestop.coords[0] ? 'left' : 'right';
console.log("swipe %s of %u pixels detected".format(direction, len));
if (len < 20) return false;
if (direction == 'right') {
@@ -190,17 +209,20 @@ function ponymail_swipe(event) {
if (current_listmode == 'threaded') blobs = current_json.thread_struct;
let no_emails = blobs.length;
if (current_email_idx == undefined && current_json && (current_index_pos - current_per_page) >= 0) {
- listview_header({pos: current_index_pos - current_per_page}, current_json);
+ listview_header({
+ pos: current_index_pos - current_per_page
+ }, current_json);
}
}
- }
- else if (direction == 'left') {
+ } else if (direction == 'left') {
if (current_json) { // IF list view...
let blobs = current_json.emails;
if (current_listmode == 'threaded') blobs = current_json.thread_struct;
let no_emails = blobs.length;
if (current_email_idx == undefined && current_json && (current_index_pos + current_per_page) < no_emails) {
- listview_header({pos: current_index_pos + current_per_page}, current_json);
+ listview_header({
+ pos: current_index_pos + current_per_page
+ }, current_json);
}
}
}
diff --git a/webui/js/source/list-index.js b/webui/js/source/list-index.js
index 18c32f4..d2e36b6 100644
--- a/webui/js/source/list-index.js
+++ b/webui/js/source/list-index.js
@@ -33,15 +33,17 @@ function list_index(state, json) {
} else {
xtab.setAttribute("class", "");
}
-
+
}
return;
- }
- else {
+ } else {
let letters = 'abcdefghijklmnopqrstuvwxyz*';
for (var i = 0; i < letters.length; i++) {
let letter = letters[i].toUpperCase();
- let li = new HTML('li', {onclick: 'switch_index({letter: "%s"});'.format(letter), class: (letter == 'A') ? 'active' :null}, letter);
+ let li = new HTML('li', {
+ onclick: 'switch_index({letter: "%s"});'.format(letter),
+ class: (letter == 'A') ? 'active' : null
+ }, letter);
lists.inject(li);
}
}
@@ -78,7 +80,9 @@ function list_index_onepage(state, json) {
let lhtml = new HTML('h2', {}, l.toUpperCase());
obj.inject(lhtml);
}
- let a = new HTML('a', {href: 'list.html?%s@%s'.format(best_list(json.lists[domain]), domain)}, domain);
+ let a = new HTML('a', {
+ href: 'list.html?%s@%s'.format(best_list(json.lists[domain]), domain)
+ }, domain);
obj.inject(['- ', a]);
obj.inject(new HTML('br'));
}
@@ -86,4 +90,4 @@ function list_index_onepage(state, json) {
function prime_list_index() {
GET('%sapi/preferences.lua'.format(apiURL), list_index_onepage, {});
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/listview-flat.js b/webui/js/source/listview-flat.js
index 000d81a..b7f442d 100644
--- a/webui/js/source/listview-flat.js
+++ b/webui/js/source/listview-flat.js
@@ -19,13 +19,16 @@ function calc_per_page() {
// Figure out how many emails per page
let body = document.body;
let html = document.documentElement;
- let height = Math.max( body.scrollHeight,
- html.clientHeight, html.scrollHeight);
- let width = Math.max( body.scrollWidth,
- html.clientWidth, html.scrollWidth);
+ let height = Math.max(body.scrollHeight,
+ html.clientHeight, html.scrollHeight);
+ let width = Math.max(body.scrollWidth,
+ html.clientWidth, html.scrollWidth);
let email_h = 40;
console.log("window area: %ux%u".format(width, height));
- if (width < 600) { console.log("Using narrow view, halving emails per page..."); email_h = 80;}
+ if (width < 600) {
+ console.log("Using narrow view, halving emails per page...");
+ email_h = 80;
+ }
height -= 180;
let per_page = Math.max(5, Math.floor(height / email_h));
per_page -= per_page % 5;
@@ -36,17 +39,20 @@ function listview_flat(json, start) {
let list = document.getElementById('emails');
list.innerHTML = "";
let per_page = calc_per_page();
-
+
let s = start || 0;
if (json.emails && json.emails.length) {
- for (n = s; n < (s+per_page); n++ ) {
+ for (n = s; n < (s + per_page); n++) {
let z = json.emails.length - n - 1; // reverse order by default
if (json.emails[z]) {
let item = listview_flat_element(json.emails[z], z);
list.inject(item);
-
+
// Hidden placeholder for expanding email(s)
- let placeholder = new HTML('div', {class: chatty_layout ? 'email_placeholder_chatty' : 'email_placeholder', id: 'email_%u'.format(z)});
+ let placeholder = new HTML('div', {
+ class: chatty_layout ? 'email_placeholder_chatty' : 'email_placeholder',
+ id: 'email_%u'.format(z)
+ });
list.inject(placeholder);
}
}
@@ -56,48 +62,68 @@ function listview_flat(json, start) {
}
function listview_flat_element(eml, idx) {
-
- let link_wrapper = new HTML('a', {href:'thread/%s'.format(eml.id), onclick:'return(expand_email_threaded(%u, true));'.format(idx)});
-
- let element = new HTML('div', { class: "listview_email_flat"}, " ");
- let date = new Date(eml.epoch*1000.0);
+
+ let link_wrapper = new HTML('a', {
+ href: 'thread/%s'.format(eml.id),
+ onclick: 'return(expand_email_threaded(%u, true));'.format(idx)
+ });
+
+ let element = new HTML('div', {
+ class: "listview_email_flat"
+ }, " ");
+ let date = new Date(eml.epoch * 1000.0);
let now = new Date();
-
+
// Add gravatar
- let gravatar = new HTML('img', { class:"gravatar", src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(eml.gravatar)});
+ let gravatar = new HTML('img', {
+ class: "gravatar",
+ src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(eml.gravatar)
+ });
element.inject(gravatar);
-
-
+
+
// Add author
let authorName = eml.from.replace(/\s*<.+>/, "").replace(/"/g, '');
let authorEmail = eml.from.match(/\s*<(.+@.+)>\s*/);
if (authorName.length == 0) authorName = authorEmail ? authorEmail[1] : "(No author?)";
- let author = new HTML('span', { class: "listview_email_author"}, authorName);
+ let author = new HTML('span', {
+ class: "listview_email_author"
+ }, authorName);
element.inject(author);
-
-
+
+
// Combined space for subject + body teaser
- let as = new HTML('div', {class: 'listview_email_as'});
-
+ let as = new HTML('div', {
+ class: 'listview_email_as'
+ });
+
let suba = new HTML('a', {}, eml.subject === '' ? '(No subject)' : eml.subject);
- let subject = new HTML('div', {class: 'listview_email_subject email_unread'}, suba);
+ let subject = new HTML('div', {
+ class: 'listview_email_subject email_unread'
+ }, suba);
as.inject(subject);
-
- let body = new HTML('div', {class: 'listview_email_body'}, eml.body);
+
+ let body = new HTML('div', {
+ class: 'listview_email_body'
+ }, eml.body);
as.inject(body);
-
+
element.inject(as);
-
+
// Labels
- let labels = new HTML('div', {class: 'listview_email_labels'});
- let dl = new HTML('span', { class: 'label label-default'}, date.ISOBare());
+ let labels = new HTML('div', {
+ class: 'listview_email_labels'
+ });
+ let dl = new HTML('span', {
+ class: 'label label-default'
+ }, date.ISOBare());
if (now - date < 86400000) {
dl.setAttribute("class", "label label-primary");
}
labels.inject(dl);
-
+
element.inject(labels);
link_wrapper.inject(element);
-
+
return link_wrapper;
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/listview-header.js b/webui/js/source/listview-header.js
index 6abe423..ee9a09c 100644
--- a/webui/js/source/listview-header.js
+++ b/webui/js/source/listview-header.js
@@ -341,4 +341,4 @@ window.addEventListener('orientationchange', function() {
listview_header(prev_listview_state, prev_listview_json);
}
}, 100);
-}, false);
+}, false);
\ No newline at end of file
diff --git a/webui/js/source/listview-threaded.js b/webui/js/source/listview-threaded.js
index 417a73a..364aef8 100644
--- a/webui/js/source/listview-threaded.js
+++ b/webui/js/source/listview-threaded.js
@@ -19,8 +19,8 @@ function calc_email_width() {
// Figure out how many emails per page
let body = document.body;
let html = document.documentElement;
- let width = Math.max( body.scrollWidth, body.offsetWidth,
- html.clientWidth, html.scrollWidth, html.offsetWidth );
+ let width = Math.max(body.scrollWidth, body.offsetWidth,
+ html.clientWidth, html.scrollWidth, html.offsetWidth);
return width;
}
@@ -28,16 +28,19 @@ function listview_threaded(json, start) {
let list = document.getElementById('emails');
list.innerHTML = "";
let per_page = calc_per_page();
-
+
let s = start || 0;
if (json.thread_struct && json.thread_struct.length) {
- for (n = s; n < (s+per_page); n++ ) {
+ for (n = s; n < (s + per_page); n++) {
let z = json.thread_struct.length - n - 1; // reverse order by default
if (json.thread_struct[z]) {
let item = listview_threaded_element(json.thread_struct[z], z);
list.inject(item);
// Hidden placeholder for expanding email(s)
- let placeholder = new HTML('div', {class: chatty_layout ? 'email_placeholder_chatty' : 'email_placeholder', id: 'email_%u'.format(z)});
+ let placeholder = new HTML('div', {
+ class: chatty_layout ? 'email_placeholder_chatty' : 'email_placeholder',
+ id: 'email_%u'.format(z)
+ });
list.inject(placeholder);
}
}
@@ -71,7 +74,7 @@ function count_replies(thread) {
function count_people(thread, hash) {
let ppl = hash || {};
let eml = find_email(thread.tid);
- if (eml) ppl[eml.from] = true;
+ if (eml) ppl[eml.from] = true;
if (isArray(thread.children)) {
for (let i = 0; i < thread.children.length; i++) {
if (true) {
@@ -99,83 +102,120 @@ function last_email(thread) {
function listview_threaded_element(thread, idx) {
let eml = find_email(thread.tid);
- if (!eml) { return; }
-
- let link_wrapper = new HTML('a', {href:'thread/%s'.format(eml.id), onclick:'return(expand_email_threaded(%u));'.format(idx)});
-
- let element = new HTML('div', { class: "listview_email_flat"}, " ");
- let date = new Date(eml.epoch*1000.0);
+ if (!eml) {
+ return;
+ }
+
+ let link_wrapper = new HTML('a', {
+ href: 'thread/%s'.format(eml.id),
+ onclick: 'return(expand_email_threaded(%u));'.format(idx)
+ });
+
+ let element = new HTML('div', {
+ class: "listview_email_flat"
+ }, " ");
+ let date = new Date(eml.epoch * 1000.0);
let now = new Date();
-
+
// Add gravatar
- let gravatar = new HTML('img', { class:"gravatar", src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(eml.gravatar)});
+ let gravatar = new HTML('img', {
+ class: "gravatar",
+ src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(eml.gravatar)
+ });
element.inject(gravatar);
-
-
+
+
// Add author
let authorName = eml.from.replace(/\s*<.+>/, "").replace(/"/g, '');
let authorEmail = eml.from.match(/\s*<(.+@.+)>\s*/);
if (authorName.length == 0) authorName = authorEmail ? authorEmail[1] : "(No author?)";
- let author = new HTML('span', { class: "listview_email_author"}, authorName);
+ let author = new HTML('span', {
+ class: "listview_email_author"
+ }, authorName);
element.inject(author);
-
+
// If needed, inject ML name
if (current_domain == 'inbox' || current_list == '*') {
author.style.lineHeight = '16px';
author.inject(new HTML('br'));
- author.inject(new HTML('span', { class: "label label-primary", style: "font-style: italic; font-size: 1rem;"}, eml.list_raw.replace(/[<>]/g, '').replace('.','@',1)));
+ author.inject(new HTML('span', {
+ class: "label label-primary",
+ style: "font-style: italic; font-size: 1rem;"
+ }, eml.list_raw.replace(/[<>]/g, '').replace('.', '@', 1)));
}
-
-
-
+
+
+
// Combined space for subject + body teaser
- let as = new HTML('div', {class: 'listview_email_as'});
-
- let suba = new HTML('a', {}, eml.subject === '' ? '(No subject)' : eml.subject);
+ let as = new HTML('div', {
+ class: 'listview_email_as'
+ });
+
+ let suba = new HTML('a', {}, eml.subject === '' ? '(No subject)' : eml.subject);
if (current_json.list.match(/\*/) || current_json.domain == '*') {
- let kbd = new HTML('kbd', {class: 'listview_kbd'}, eml.list_raw.replace(/[<>]/g, '').replace('.','@',1))
+ let kbd = new HTML('kbd', {
+ class: 'listview_kbd'
+ }, eml.list_raw.replace(/[<>]/g, '').replace('.', '@', 1))
suba = [kbd, suba];
}
- let subject = new HTML('div', {class: 'listview_email_subject email_unread'}, suba);
+ let subject = new HTML('div', {
+ class: 'listview_email_subject email_unread'
+ }, suba);
as.inject(subject);
-
- let body = new HTML('div', {class: 'listview_email_body'}, eml.body);
+
+ let body = new HTML('div', {
+ class: 'listview_email_body'
+ }, eml.body);
as.inject(body);
-
+
element.inject(as);
-
+
// Labels
- let labels = new HTML('div', {class: 'listview_email_labels'});
-
-
+ let labels = new HTML('div', {
+ class: 'listview_email_labels'
+ });
+
+
// Participants
let ppl = count_people(thread);
let ptitle = (ppl == 1) ? "one participant" : "%u participants".format(ppl);
- let people = new HTML('span', { class: 'label label-default', title: ptitle}, [
- new HTML('span', { class: 'glyphicon glyphicon-user'}, ' '),
+ let people = new HTML('span', {
+ class: 'label label-default',
+ title: ptitle
+ }, [
+ new HTML('span', {
+ class: 'glyphicon glyphicon-user'
+ }, ' '),
" %u".format(ppl)
- ]);
+ ]);
labels.inject(people);
-
+
// Replies
let reps = count_replies(thread);
let rtitle = (reps == 1) ? "one reply" : "%u replies".format(reps);
- let repl = new HTML('span', { class: 'label label-default', title: rtitle}, [
- new HTML('span', { class: 'glyphicon glyphicon-envelope'}, ' '),
+ let repl = new HTML('span', {
+ class: 'label label-default',
+ title: rtitle
+ }, [
+ new HTML('span', {
+ class: 'glyphicon glyphicon-envelope'
+ }, ' '),
" %u".format(reps)
- ]);
+ ]);
labels.inject(repl);
-
+
// Date
date = new Date(last_email(thread) * 1000.0);
- let dl = new HTML('span', { class: 'label label-default'}, date.ISOBare());
+ let dl = new HTML('span', {
+ class: 'label label-default'
+ }, date.ISOBare());
if (now - date < 86400000) {
dl.setAttribute("class", "label label-primary");
}
labels.inject(dl);
-
+
element.inject(labels);
link_wrapper.inject(element);
-
+
return link_wrapper;
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/mgmt.js b/webui/js/source/mgmt.js
index 7f725f4..971e175 100644
--- a/webui/js/source/mgmt.js
+++ b/webui/js/source/mgmt.js
@@ -8,7 +8,9 @@ async function POST(url, formdata, state) {
credentials: "same-origin",
mode: "same-origin",
method: "post",
- headers: { "Content-Type": "application/json" },
+ headers: {
+ "Content-Type": "application/json"
+ },
body: formdata
});
return resp
@@ -60,75 +62,156 @@ async function admin_save_email() {
function admin_email_preview(stats, json) {
admin_current_email = json.mid;
let cp = document.getElementById("panel");
- let div = new HTML('div', { style: { margin: '5px'}});
+ let div = new HTML('div', {
+ style: {
+ margin: '5px'
+ }
+ });
cp.inject(div);
div.inject(new HTML('h1', {}, "Editing email " + json.mid + ":"));
// Author
- let author_field = new HTML('div', {class: 'email_kv_edit'});
- let author_key = new HTML('div', {class: 'email_key'}, "From: ");
- let author_value = new HTML('input', {id: 'email_from', style: {width: "480px"}, value: json.from});
+ let author_field = new HTML('div', {
+ class: 'email_kv_edit'
+ });
+ let author_key = new HTML('div', {
+ class: 'email_key'
+ }, "From: ");
+ let author_value = new HTML('input', {
+ id: 'email_from',
+ style: {
+ width: "480px"
+ },
+ value: json.from
+ });
author_field.inject([author_key, author_value]);
div.inject(author_field);
// Subject
- let subject_field = new HTML('div', {class: 'email_kv_edit'});
- let subject_key = new HTML('div', {class: 'email_key'}, "Subject: ");
- let subject_value = new HTML('input', {id: 'email_subject', style: {width: "480px"}, value: json.subject});
+ let subject_field = new HTML('div', {
+ class: 'email_kv_edit'
+ });
+ let subject_key = new HTML('div', {
+ class: 'email_key'
+ }, "Subject: ");
+ let subject_value = new HTML('input', {
+ id: 'email_subject',
+ style: {
+ width: "480px"
+ },
+ value: json.subject
+ });
subject_field.inject([subject_key, subject_value]);
div.inject(subject_field);
// Date
- let date_field = new HTML('div', {class: 'email_kv_edit'});
- let date_key = new HTML('div', {class: 'email_key'}, "Date: ");
- let date_value = new HTML('div', {class: 'email_value'}, new Date(json.epoch * 1000.0).ISOBare());
+ let date_field = new HTML('div', {
+ class: 'email_kv_edit'
+ });
+ let date_key = new HTML('div', {
+ class: 'email_key'
+ }, "Date: ");
+ let date_value = new HTML('div', {
+ class: 'email_value'
+ }, new Date(json.epoch * 1000.0).ISOBare());
date_field.inject([date_key, date_value]);
div.inject(date_field);
// List
let listname = json.list_raw.replace(".", "@", 1).replace(/[<>]/g, "");
- let list_field = new HTML('div', {class: 'email_kv_edit'});
- let list_key = new HTML('div', {class: 'email_key'}, "List: ");
- let list_value = new HTML('input', {id: 'email_listname', style: {width: "480px"}, value: listname});
+ let list_field = new HTML('div', {
+ class: 'email_kv_edit'
+ });
+ let list_key = new HTML('div', {
+ class: 'email_key'
+ }, "List: ");
+ let list_value = new HTML('input', {
+ id: 'email_listname',
+ style: {
+ width: "480px"
+ },
+ value: listname
+ });
list_field.inject([list_key, list_value]);
div.inject(list_field);
// Private email?
- let priv_field = new HTML('div', {class: 'email_kv_edit'});
- let priv_key = new HTML('div', {class: 'email_key'}, "Visibility: ");
- let priv_value = new HTML('select', {id:'email_private'});
- priv_value.inject(new HTML('option', {value: 'no', style: {color: 'green'}, selected: json.private ? null : "selected"}, "Public"));
- priv_value.inject(new HTML('option', {value: 'yes', style: {color: 'red'}, selected: json.private ? "selected" : null}, "Private"));
+ let priv_field = new HTML('div', {
+ class: 'email_kv_edit'
+ });
+ let priv_key = new HTML('div', {
+ class: 'email_key'
+ }, "Visibility: ");
+ let priv_value = new HTML('select', {
+ id: 'email_private'
+ });
+ priv_value.inject(new HTML('option', {
+ value: 'no',
+ style: {
+ color: 'green'
+ },
+ selected: json.private ? null : "selected"
+ }, "Public"));
+ priv_value.inject(new HTML('option', {
+ value: 'yes',
+ style: {
+ color: 'red'
+ },
+ selected: json.private ? "selected" : null
+ }, "Private"));
priv_field.inject([priv_key, priv_value]);
div.inject(priv_field);
// Attachments?
if (json.attachments && json.attachments.length > 0) {
- let attach_field = new HTML('div', {class: 'email_kv'});
- let attach_key = new HTML('div', {class: 'email_key'}, "Attachment(s): ");
+ let attach_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let attach_key = new HTML('div', {
+ class: 'email_key'
+ }, "Attachment(s): ");
let alinks = [];
for (let n = 0; n < json.attachments.length; n++) {
let attachment = json.attachments[n];
let link = `${pm_config.apiURL}api/email.lua?attachment=true&id=${json.mid}&file=${attachment.hash}`;
- let a = new HTML('a', {href: link, target: '_blank'}, attachment.filename);
+ let a = new HTML('a', {
+ href: link,
+ target: '_blank'
+ }, attachment.filename);
alinks.push(a);
let fs = ` ${attachment.size} bytes`;
if (attachment.size >= 1024) fs = ` ${Math.floor(attachment.size/1024)} KB`;
- if (attachment.size >= 1024*1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
- alinks.push (fs);
+ if (attachment.size >= 1024 * 1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
+ alinks.push(fs);
alinks.push(new HTML('br'));
}
- let attach_value = new HTML('div', {class: 'email_value'}, alinks);
+ let attach_value = new HTML('div', {
+ class: 'email_value'
+ }, alinks);
attach_field.inject([attach_key, attach_value]);
div.inject(attach_field);
}
- let text = new HTML('textarea', {id: 'email_body', style: {width: "100%", height: "480px"}}, json.body);
+ let text = new HTML('textarea', {
+ id: 'email_body',
+ style: {
+ width: "100%",
+ height: "480px"
+ }
+ }, json.body);
div.inject(text);
- let btn_edit = new HTML('button', {onclick: "admin_save_email();"}, "Save changes to archive");
- let btn_hide = new HTML('button', {onclick: "admin_hide_email();", style: {marginLeft: "36px", color: 'red'}}, "Remove email from archives");
+ let btn_edit = new HTML('button', {
+ onclick: "admin_save_email();"
+ }, "Save changes to archive");
+ let btn_hide = new HTML('button', {
+ onclick: "admin_hide_email();",
+ style: {
+ marginLeft: "36px",
+ color: 'red'
+ }
+ }, "Remove email from archives");
div.inject(new HTML('br'));
div.inject(btn_edit);
div.inject(btn_hide);
@@ -139,18 +222,27 @@ function admin_email_preview(stats, json) {
}
function admin_audit_view(state, json) {
- let headers = ['Date', 'Author','Remote','Action','Target', 'Log'];
+ let headers = ['Date', 'Author', 'Remote', 'Action', 'Target', 'Log'];
let cp = document.getElementById("panel");
let div = document.getElementById('auditlog_entries');
if (!div) {
- div = new HTML('div', { id: "auditlog", style: { margin: '5px'}});
+ div = new HTML('div', {
+ id: "auditlog",
+ style: {
+ margin: '5px'
+ }
+ });
cp.inject(div);
div.inject(new HTML('h1', {}, "Audit log:"));
}
let table = document.getElementById('auditlog_entries');
if (json.entries && json.entries.length > 0 || table) {
if (!table) {
- table = new HTML('table', {border: "1", id: "auditlog_entries", class:"auditlog_entries"});
+ table = new HTML('table', {
+ border: "1",
+ id: "auditlog_entries",
+ class: "auditlog_entries"
+ });
let trh = new HTML('tr');
for (let i = 0; i < headers.length; i++) {
let th = new HTML('th', {}, headers[i] + ":");
@@ -158,17 +250,23 @@ function admin_audit_view(state, json) {
}
table.inject(trh)
div.inject(table);
- let btn = new HTML('button', {onclick: "admin_audit_next();"}, "Load more entries");
+ let btn = new HTML('button', {
+ onclick: "admin_audit_next();"
+ }, "Load more entries");
div.inject(btn);
}
for (let i = 0; i < json.entries.length; i++) {
let entry = json.entries[i];
- let tr = new HTML('tr', {class: "auditlog_entry"});
+ let tr = new HTML('tr', {
+ class: "auditlog_entry"
+ });
for (let i = 0; i < headers.length; i++) {
let key = headers[i].toLowerCase();
let value = entry[key];
if (key == 'target') {
- value = new HTML('a', {href: "/admin/" +value}, value);
+ value = new HTML('a', {
+ href: "/admin/" + value
+ }, value);
}
if (key == 'action') {
let action_colors = {
@@ -176,7 +274,11 @@ function admin_audit_view(state, json) {
delete: 'red',
default: 'black'
};
- value = new HTML('spam', {style: {color: action_colors[value] ? action_colors[value] : action_colors['default']}}, value);
+ value = new HTML('spam', {
+ style: {
+ color: action_colors[value] ? action_colors[value] : action_colors['default']
+ }
+ }, value);
}
let th = new HTML('td', {}, value);
tr.inject(th);
diff --git a/webui/js/source/preferences.js b/webui/js/source/preferences.js
index 8445379..ee13a4d 100644
--- a/webui/js/source/preferences.js
+++ b/webui/js/source/preferences.js
@@ -33,56 +33,63 @@ function init_preferences(state, json) {
}
}
}
-
+
// color some links
let cl = document.getElementById('chatty_link');
if (cl) {
- cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
+ cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
}
-
+
if (ponymail_preferences.login && ponymail_preferences.login.credentials) {
- let prefsmenu = document.getElementById('prefs_dropdown');
- let uimg = document.getElementById('uimg');
- uimg.setAttribute("src", "images/user.png");
- uimg.setAttribute("title", "Logged in as %s".format(ponymail_preferences.login.credentials.fullname));
-
- // Generate user menu
- prefsmenu.innerHTML = "";
-
-
- let logout = new HTML('a', { href: "javascript:void(logout());"}, "Log out");
- let li = new HTML('li', {}, logout)
- prefsmenu.inject(li);
-
- } else {
- let prefsmenu = document.getElementById('prefs_dropdown');
- if (prefsmenu) {
+ let prefsmenu = document.getElementById('prefs_dropdown');
+ let uimg = document.getElementById('uimg');
+ uimg.setAttribute("src", "images/user.png");
+ uimg.setAttribute("title", "Logged in as %s".format(ponymail_preferences.login.credentials.fullname));
+
+ // Generate user menu
prefsmenu.innerHTML = "";
- let login = new HTML('a', { href: "javascript:location.href='oauth.html';"}, "Log In");
- let li = new HTML('li', {}, login)
+
+
+ let logout = new HTML('a', {
+ href: "javascript:void(logout());"
+ }, "Log out");
+ let li = new HTML('li', {}, logout)
prefsmenu.inject(li);
- }
+
+ } else {
+ let prefsmenu = document.getElementById('prefs_dropdown');
+ if (prefsmenu) {
+ prefsmenu.innerHTML = "";
+ let login = new HTML('a', {
+ href: "javascript:location.href='oauth.html';"
+ }, "Log In");
+ let li = new HTML('li', {}, login)
+ prefsmenu.inject(li);
+ }
}
-
+
if (json) {
- listview_list_lists(state, json);
- if (state && state.prime) {
- // If lists is accessible, show it
- if (json.lists[current_domain] && json.lists[current_domain][current_list] != undefined) {
- post_prime(state);
- } else {// otherwise, bork
- if (current_list.length > 0 && (!json.lists[current_domain] || Object.keys(json.lists[current_domain]).length > 0)) {
- let eml = document.getElementById('emails');
- eml.innerText = "We couldn't find this list. It may not exist or require you to be logged in with specific credentials.";
- eml.inject(new HTML('br'));
- eml.inject(new HTML('a', {href: 'oauth.html', onclick:'location.href="oauth.html";'}, "Click here to log in via OAuth"));
- } else {
- console.log(current_domain);
- let first_list = Object.keys(json.lists[current_domain])[0];
- location.href = `?${first_list}@${current_domain}`;
- }
+ listview_list_lists(state, json);
+ if (state && state.prime) {
+ // If lists is accessible, show it
+ if (json.lists[current_domain] && json.lists[current_domain][current_list] != undefined) {
+ post_prime(state);
+ } else { // otherwise, bork
+ if (current_list.length > 0 && (!json.lists[current_domain] || Object.keys(json.lists[current_domain]).length > 0)) {
+ let eml = document.getElementById('emails');
+ eml.innerText = "We couldn't find this list. It may not exist or require you to be logged in with specific credentials.";
+ eml.inject(new HTML('br'));
+ eml.inject(new HTML('a', {
+ href: 'oauth.html',
+ onclick: 'location.href="oauth.html";'
+ }, "Click here to log in via OAuth"));
+ } else {
+ console.log(current_domain);
+ let first_list = Object.keys(json.lists[current_domain])[0];
+ location.href = `?${first_list}@${current_domain}`;
+ }
+ }
}
- }
}
}
@@ -105,24 +112,24 @@ function set_theme(theme) {
}
function set_skin(skin) {
- chatty_layout = !chatty_layout;
- let cl = document.getElementById('chatty_link');
- if (cl) {
- cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
- }
- hideWindows(true);
- renderListView(current_state, current_json);
- save_preferences();
+ chatty_layout = !chatty_layout;
+ let cl = document.getElementById('chatty_link');
+ if (cl) {
+ cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
+ }
+ hideWindows(true);
+ renderListView(current_state, current_json);
+ save_preferences();
}
// set_skin, but for permalinks
function set_skin_permalink(skin) {
- chatty_layout = !chatty_layout;
- let cl = document.getElementById('chatty_link');
- if (cl) {
- cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
- }
- hideWindows(true);
- save_preferences();
- parse_permalink();
+ chatty_layout = !chatty_layout;
+ let cl = document.getElementById('chatty_link');
+ if (cl) {
+ cl.setAttribute("class", chatty_layout ? "enabled" : "disabled");
+ }
+ hideWindows(true);
+ save_preferences();
+ parse_permalink();
}
\ No newline at end of file
diff --git a/webui/js/source/primer.js b/webui/js/source/primer.js
index 4451dfe..46b6b8d 100644
--- a/webui/js/source/primer.js
+++ b/webui/js/source/primer.js
@@ -24,21 +24,24 @@ function renderListView(state, json) {
current_state = state;
async_escrow['rendering'] = new Date();
if (!state || state.update_calendar !== false) {
- renderCalendar(json.firstYear,json.firstMonth,json.lastYear, json.lastMonth);
+ renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth);
}
// sort threads by date
if (isArray(json.thread_struct)) {
- current_json.thread_struct.sort((a,b) => last_email(a) - last_email(b));
+ current_json.thread_struct.sort((a, b) => last_email(a) - last_email(b));
}
listview_header(state, json);
- if (current_listmode == 'threaded') { listview_threaded(json, 0); }
- else { listview_flat(json, 0);}
-
+ if (current_listmode == 'threaded') {
+ listview_threaded(json, 0);
+ } else {
+ listview_flat(json, 0);
+ }
+
sidebar_stats(json); // This comes last, takes the longest with WC enabled.
delete async_escrow['rendering'];
-
+
if (state && state.to) {
- listview_list_lists(state);
+ listview_list_lists(state);
}
}
@@ -58,90 +61,92 @@ function primeListView(state) {
// callback from when prefs have loaded
function post_prime(state) {
- let sURL = '%sapi/stats.lua?list=%s&domain=%s'.format(apiURL, current_list, current_domain);
+ let sURL = '%sapi/stats.lua?list=%s&domain=%s'.format(apiURL, current_list, current_domain);
if (current_year && current_month) {
sURL += "&d=%u-%u".format(current_year, current_month);
}
- if (! (state && state.search)) {
- if (state && state.array) {
- collated_json = {};
- virtual_inbox_loading = true;
- for (var i = 0; i < state.array.length; i++) {
- let list = state.array[i].split('@');
- sURL = '%sapi/stats.lua?list=%s&domain=%s'.format(apiURL, list[0], list[1]);
- GET(sURL, render_virtual_inbox, state);
+ if (!(state && state.search)) {
+ if (state && state.array) {
+ collated_json = {};
+ virtual_inbox_loading = true;
+ for (var i = 0; i < state.array.length; i++) {
+ let list = state.array[i].split('@');
+ sURL = '%sapi/stats.lua?list=%s&domain=%s'.format(apiURL, list[0], list[1]);
+ GET(sURL, render_virtual_inbox, state);
+ }
+ } else {
+ GET(sURL, renderListView, state);
}
- } else {
- GET(sURL, renderListView, state);
- }
} else {
- search(state.query, state.date);
+ search(state.query, state.date);
}
}
function parseURL(state) {
- let bits = window.location.search.substr(1).split(":", 3);
- let list = bits[0];
- let month = bits[1];
- let query = bits[2];
- let list_array = null;
- state = state || {};
- current_query = query || "";
- current_month = 0;
- current_year = 0;
-
- // If "month" (year-month) is specified,
- // we should set the current vars
- if (month) {
- try {
- let dbits = month.split("-");
- current_year = dbits[0];
- current_month = dbits[1];
- } catch (e) {}
- }
- // Is this a valid list?
- if (list !== '') {
- // multi-list??
- if (list.match(/,/)) {
- state.array = list.split(',');
- current_domain = 'inbox';
- current_list = 'virtual';
+ let bits = window.location.search.substr(1).split(":", 3);
+ let list = bits[0];
+ let month = bits[1];
+ let query = bits[2];
+ let list_array = null;
+ state = state || {};
+ current_query = query || "";
+ current_month = 0;
+ current_year = 0;
+
+ // If "month" (year-month) is specified,
+ // we should set the current vars
+ if (month) {
+ try {
+ let dbits = month.split("-");
+ current_year = dbits[0];
+ current_month = dbits[1];
+ } catch (e) {}
+ }
+ // Is this a valid list?
+ if (list !== '') {
+ // multi-list??
+ if (list.match(/,/)) {
+ state.array = list.split(',');
+ current_domain = 'inbox';
+ current_list = 'virtual';
+ } else {
+ let lbits = list.split("@");
+ if (lbits.length > 1) {
+ current_list = lbits[0];
+ current_domain = lbits[1];
+ } else {
+ current_domain = lbits;
+ current_list = '';
+ }
+ }
+ }
+ // Are we initiating a search?
+ if (query) {
+ state.search = true;
+ state.query = query;
+ state.date = month;
+ }
+ // If hitting the refresh button, don't refresh preferences, just do the search.
+ if (state.noprefs) {
+ post_prime(state);
} else {
- let lbits = list.split("@");
- if (lbits.length > 1) {
- current_list = lbits[0];
- current_domain = lbits[1];
- } else {
- current_domain = lbits;
- current_list = '';
- }
+ primeListView(state);
}
- }
- // Are we initiating a search?
- if (query) {
- state.search = true;
- state.query = query;
- state.date = month;
- }
- // If hitting the refresh button, don't refresh preferences, just do the search.
- if (state.noprefs) {
- post_prime(state);
- } else {
- primeListView(state);
- }
};
// Parse a permalink and fetch the thread
function parse_permalink() {
- // message id is the bit after the last /
- let mid = location.href.split('/').pop();
- init_preferences(); // blank call to load defaults like social rendering
- GET('%sapi/preferences.lua'.format(apiURL), init_preferences, null);
- // Fetch the thread data and pass to build_single_thread
- GET('%sapi/thread.lua?id=%s'.format(apiURL, mid), construct_single_thread, {cached: true});
+ // message id is the bit after the last /
+ let mid = location.href.split('/').pop();
+ init_preferences(); // blank call to load defaults like social rendering
+ GET('%sapi/preferences.lua'.format(apiURL), init_preferences, null);
+ // Fetch the thread data and pass to build_single_thread
+ GET('%sapi/thread.lua?id=%s'.format(apiURL, mid), construct_single_thread, {
+ cached: true
+ });
}
@@ -151,35 +156,38 @@ function render_virtual_inbox(state, json) {
collated_json.emails = collated_json.emails || [];
collated_json.thread_struct = collated_json.thread_struct || [];
for (var i = 0; i < json.emails.length; i++) {
- collated_json.emails.push(json.emails[i]);
+ collated_json.emails.push(json.emails[i]);
}
for (var i = 0; i < json.thread_struct.length; i++) {
- collated_json.thread_struct.push(json.thread_struct[i]);
+ collated_json.thread_struct.push(json.thread_struct[i]);
}
}
-
+
for (var k in async_escrow) {
return;
}
-
+
if (true) {
- console.log("Rendering multi-list")
- current_json = collated_json;
- current_json.participants = [];
-
- async_escrow['rendering'] = new Date();
- if (!state || state.update_calendar !== false) {
- renderCalendar(json.firstYear,json.firstMonth,json.lastYear, json.lastMonth);
- }
- // sort threads by date
- if (isArray(json.thread_struct)) {
- current_json.thread_struct.sort((a,b) => last_email(a) - last_email(b));
- }
- listview_header(state, current_json);
- if (current_listmode == 'threaded') { listview_threaded(current_json, 0); }
- else { listview_flat(current_json, 0);}
-
- sidebar_stats(current_json); // This comes last, takes the longest with WC enabled.
- delete async_escrow['rendering'];
+ console.log("Rendering multi-list")
+ current_json = collated_json;
+ current_json.participants = [];
+
+ async_escrow['rendering'] = new Date();
+ if (!state || state.update_calendar !== false) {
+ renderCalendar(json.firstYear, json.firstMonth, json.lastYear, json.lastMonth);
+ }
+ // sort threads by date
+ if (isArray(json.thread_struct)) {
+ current_json.thread_struct.sort((a, b) => last_email(a) - last_email(b));
+ }
+ listview_header(state, current_json);
+ if (current_listmode == 'threaded') {
+ listview_threaded(current_json, 0);
+ } else {
+ listview_flat(current_json, 0);
+ }
+
+ sidebar_stats(current_json); // This comes last, takes the longest with WC enabled.
+ delete async_escrow['rendering'];
}
}
\ No newline at end of file
diff --git a/webui/js/source/render-email.js b/webui/js/source/render-email.js
index 7086bf0..f7cb2c6 100644
--- a/webui/js/source/render-email.js
+++ b/webui/js/source/render-email.js
@@ -6,99 +6,162 @@ async function render_email(state, json) {
if (state.scroll) {
let rect = div.getBoundingClientRect();
try {
- window.setTimeout(function() { window.scrollTo(0, rect.top - 48);}, 200);
+ window.setTimeout(function() {
+ window.scrollTo(0, rect.top - 48);
+ }, 200);
console.log("Scrolled to %u".format(rect.top - 48));
} catch (e) {}
}
if (chatty_layout) {
return render_email_chatty(state, json);
}
-
+
// Author
- let author_field = new HTML('div', {class: 'email_kv'});
- let author_key = new HTML('div', {class: 'email_key'}, "From: ");
- let author_value = new HTML('div', {class: 'email_value'}, json.from);
+ let author_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let author_key = new HTML('div', {
+ class: 'email_key'
+ }, "From: ");
+ let author_value = new HTML('div', {
+ class: 'email_value'
+ }, json.from);
author_field.inject([author_key, author_value]);
div.inject(author_field);
-
+
// Subject
- let subject_field = new HTML('div', {class: 'email_kv'});
- let subject_key = new HTML('div', {class: 'email_key'}, "Subject: ");
- let subject_value = new HTML('div', {class: 'email_value'}, json.subject == '' ? '(No subject)' : json.subject);
+ let subject_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let subject_key = new HTML('div', {
+ class: 'email_key'
+ }, "Subject: ");
+ let subject_value = new HTML('div', {
+ class: 'email_value'
+ }, json.subject == '' ? '(No subject)' : json.subject);
subject_field.inject([subject_key, subject_value]);
div.inject(subject_field);
-
+
// Date
- let date_field = new HTML('div', {class: 'email_kv'});
- let date_key = new HTML('div', {class: 'email_key'}, "Date: ");
- let date_value = new HTML('div', {class: 'email_value'}, new Date(json.epoch * 1000.0).ISOBare());
+ let date_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let date_key = new HTML('div', {
+ class: 'email_key'
+ }, "Date: ");
+ let date_value = new HTML('div', {
+ class: 'email_value'
+ }, new Date(json.epoch * 1000.0).ISOBare());
date_field.inject([date_key, date_value]);
div.inject(date_field);
-
-
+
+
// List
let listname = json.list_raw.replace(".", "@", 1).replace(/[<>]/g, "");
- let list_field = new HTML('div', {class: 'email_kv'});
- let list_key = new HTML('div', {class: 'email_key'}, "List: ");
- let list_value = new HTML('div', {class: 'email_value'},
- new HTML('a', {href: 'list?%s'.format(listname)}, listname)
- );
+ let list_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let list_key = new HTML('div', {
+ class: 'email_key'
+ }, "List: ");
+ let list_value = new HTML('div', {
+ class: 'email_value'
+ },
+ new HTML('a', {
+ href: 'list?%s'.format(listname)
+ }, listname)
+ );
list_field.inject([list_key, list_value]);
div.inject(list_field);
-
+
// Private email??
if (json.private === true) {
- let priv_field = new HTML('div', {class: 'email_kv'});
- let priv_key = new HTML('div', {class: 'email_key'}, "Private: ");
- let priv_value = new HTML('div', {class: 'email_value_emphasis'}, "YES");
+ let priv_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let priv_key = new HTML('div', {
+ class: 'email_key'
+ }, "Private: ");
+ let priv_value = new HTML('div', {
+ class: 'email_value_emphasis'
+ }, "YES");
priv_field.inject([priv_key, priv_value]);
div.inject(priv_field);
}
-
+
// Attachments?
if (json.attachments && json.attachments.length > 0) {
- let attach_field = new HTML('div', {class: 'email_kv'});
- let attach_key = new HTML('div', {class: 'email_key'}, "Attachment(s): ");
+ let attach_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let attach_key = new HTML('div', {
+ class: 'email_key'
+ }, "Attachment(s): ");
let alinks = [];
for (let n = 0; n < json.attachments.length; n++) {
let attachment = json.attachments[n];
let link = `${pm_config.apiURL}api/email.lua?attachment=true&id=${json.mid}&file=${attachment.hash}`;
- let a = new HTML('a', {href: link, target: '_blank'}, attachment.filename);
+ let a = new HTML('a', {
+ href: link,
+ target: '_blank'
+ }, attachment.filename);
alinks.push(a);
let fs = ` ${attachment.size} bytes`;
if (attachment.size >= 1024) fs = ` ${Math.floor(attachment.size/1024)} KB`;
- if (attachment.size >= 1024*1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
- alinks.push (fs);
+ if (attachment.size >= 1024 * 1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
+ alinks.push(fs);
alinks.push(new HTML('br'));
}
- let attach_value = new HTML('div', {class: 'email_value'}, alinks);
+ let attach_value = new HTML('div', {
+ class: 'email_value'
+ }, alinks);
attach_field.inject([attach_key, attach_value]);
div.inject(attach_field);
}
-
+
let text = new HTML('pre', {}, fixup_quotes(json.body));
div.inject(text);
-
+
// Private text?
if (json.private === true) {
- text.style.backgroundImage = "url(images/private.png)";
+ text.style.backgroundImage = "url(images/private.png)";
}
-
-
- let toolbar = new HTML('div', {class: 'toolbar'});
-
+
+
+ let toolbar = new HTML('div', {
+ class: 'toolbar'
+ });
+
// reply to email button
- let replybutton = new HTML('button', { title: "Reply to this email", onclick: `compose_email('${json.mid}');`, class: 'btn toolbar_btn toolbar_button_reply'}, new HTML('span', { class: 'glyphicon glyphicon-pencil'}, ' '));
+ let replybutton = new HTML('button', {
+ title: "Reply to this email",
+ onclick: `compose_email('${json.mid}');`,
+ class: 'btn toolbar_btn toolbar_button_reply'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-pencil'
+ }, ' '));
toolbar.inject(replybutton);
-
+
// permalink button
- let linkbutton = new HTML('a', { href: 'thread/%s'.format(json.mid), title: "Permanent link to this email", class: 'btn toolbar_btn toolbar_button_link'}, new HTML('span', { class: 'glyphicon glyphicon-link'}, ' '));
+ let linkbutton = new HTML('a', {
+ href: 'thread/%s'.format(json.mid),
+ title: "Permanent link to this email",
+ class: 'btn toolbar_btn toolbar_button_link'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-link'
+ }, ' '));
toolbar.inject(linkbutton);
-
+
// Source-view button
- let sourcebutton = new HTML('a', { href: '%sapi/source.lua?id=%s'.format(apiURL, json.mid), title: "View raw source", class: 'btn toolbar_btn toolbar_button_source'}, new HTML('span', { class: 'glyphicon glyphicon-file'}, ' '));
+ let sourcebutton = new HTML('a', {
+ href: '%sapi/source.lua?id=%s'.format(apiURL, json.mid),
+ title: "View raw source",
+ class: 'btn toolbar_btn toolbar_button_source'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-file'
+ }, ' '));
toolbar.inject(sourcebutton);
-
+
text.inject(toolbar);
}
@@ -107,81 +170,129 @@ async function render_email(state, json) {
async function render_email_chatty(state, json) {
let div = state.div;
div.parentNode.style.border = 'none';
-
+
// Author
let when = new Date(json.epoch * 1000.0);
let ldate = when.toISOString();
try {
ldate = "%s %s".format(when.toLocaleDateString('en-US', ponymail_date_format), when.toLocaleTimeString());
} catch (e) {
-
+
}
-
- let author_field = new HTML('div', {class: 'chatty_author'});
- let gravatar = new HTML('img', { class:"chatty_gravatar", src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(json.gravatar)});
+
+ let author_field = new HTML('div', {
+ class: 'chatty_author'
+ });
+ let gravatar = new HTML('img', {
+ class: "chatty_gravatar",
+ src: "https://secure.gravatar.com/avatar/%s.png?s=96&r=g&d=mm".format(json.gravatar)
+ });
let author_name = json.from.replace(/\s*<.+>/, "").replace(/"/g, '');
let author_email = json.from.match(/\s*<(.+@.+)>\s*/);
if (author_name.length == 0) author_name = author_email ? author_email[1] : "(No author?)";
- let author_nametag = new HTML('div', {class: 'chatty_author_name'}, [
- new HTML('b', {}, author_name),
- " - %s".format(ldate)
- ]);
+ let author_nametag = new HTML('div', {
+ class: 'chatty_author_name'
+ }, [
+ new HTML('b', {}, author_name),
+ " - %s".format(ldate)
+ ]);
author_field.inject([gravatar, author_nametag]);
div.inject(author_field);
let chatty_body = fixup_quotes(json.body);
if (json.mid == current_open_email) {
- let header = new HTML('h4', {class: 'chatty_title_inline'}, json.subject);
+ let header = new HTML('h4', {
+ class: 'chatty_title_inline'
+ }, json.subject);
chatty_body.unshift(header);
}
- let text = new HTML('pre', {class: 'chatty_body'}, chatty_body);
+ let text = new HTML('pre', {
+ class: 'chatty_body'
+ }, chatty_body);
div.inject(text);
// Private text?
if (json.private === true) {
- text.style.backgroundImage = "url(images/private.png)";
+ text.style.backgroundImage = "url(images/private.png)";
}
-
+
// Attachments?
if (json.attachments && json.attachments.length > 0) {
- let attach_field = new HTML('div', {class: 'email_kv'});
- let attach_key = new HTML('div', {class: 'email_key'}, "Attachment(s):");
+ let attach_field = new HTML('div', {
+ class: 'email_kv'
+ });
+ let attach_key = new HTML('div', {
+ class: 'email_key'
+ }, "Attachment(s):");
let alinks = [];
for (let n = 0; n < json.attachments.length; n++) {
let attachment = json.attachments[n];
let link = `${pm_config.apiURL}api/email.lua?attachment=true&id=${json.mid}&file=${attachment.hash}`;
- let a = new HTML('a', {href: link, target: '_blank'}, attachment.filename);
+ let a = new HTML('a', {
+ href: link,
+ target: '_blank'
+ }, attachment.filename);
alinks.push(a);
let fs = ` ${attachment.size} bytes`;
if (attachment.size >= 1024) fs = ` ${Math.floor(attachment.size/1024)} KB`;
- if (attachment.size >= 1024*1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
- alinks.push (fs);
+ if (attachment.size >= 1024 * 1024) fs = ` ${Math.floor(attachment.size/(1024*10.24))/100} MB`;
+ alinks.push(fs);
alinks.push(new HTML('br'));
}
- let attach_value = new HTML('div', {class: 'email_value'}, alinks);
+ let attach_value = new HTML('div', {
+ class: 'email_value'
+ }, alinks);
attach_field.inject([attach_key, attach_value]);
text.inject(attach_field);
}
-
- let toolbar = new HTML('div', {class: 'toolbar_chatty'});
-
+
+ let toolbar = new HTML('div', {
+ class: 'toolbar_chatty'
+ });
+
// reply to email button
- let replybutton = new HTML('button', { title: "Reply to this email", onclick: `compose_email('${json.mid}');`, class: 'btn toolbar_btn toolbar_button_reply'}, new HTML('span', { class: 'glyphicon glyphicon-pencil'}, ' '));
+ let replybutton = new HTML('button', {
+ title: "Reply to this email",
+ onclick: `compose_email('${json.mid}');`,
+ class: 'btn toolbar_btn toolbar_button_reply'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-pencil'
+ }, ' '));
toolbar.inject(replybutton);
-
+
// permalink button
- let linkbutton = new HTML('a', { href: 'thread/%s'.format(json.mid), title: "Permanent link to this email", target: '_self', class: 'btn toolbar_btn toolbar_button_link'}, new HTML('span', { class: 'glyphicon glyphicon-link'}, ' '));
+ let linkbutton = new HTML('a', {
+ href: 'thread/%s'.format(json.mid),
+ title: "Permanent link to this email",
+ target: '_self',
+ class: 'btn toolbar_btn toolbar_button_link'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-link'
+ }, ' '));
toolbar.inject(linkbutton);
-
+
// Source-view button
- let sourcebutton = new HTML('a', { href: '%sapi/source.lua?id=%s'.format(apiURL, json.mid), target: '_self', title: "View raw source", class: 'btn toolbar_btn toolbar_button_source'}, new HTML('span', { class: 'glyphicon glyphicon-file'}, ' '));
+ let sourcebutton = new HTML('a', {
+ href: '%sapi/source.lua?id=%s'.format(apiURL, json.mid),
+ target: '_self',
+ title: "View raw source",
+ class: 'btn toolbar_btn toolbar_button_source'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-file'
+ }, ' '));
toolbar.inject(sourcebutton);
// Admin button?
if (ponymail_preferences.login && ponymail_preferences.login.credentials && ponymail_preferences.login.credentials.admin) {
- let adminbutton = new HTML('a', { href: 'admin/%s'.format(json.mid), target: '_self', title: "Modify email", class: 'btn toolbar_btn toolbar_button_admin'}, new HTML('span', { class: 'glyphicon glyphicon-cog'}, ' '));
+ let adminbutton = new HTML('a', {
+ href: 'admin/%s'.format(json.mid),
+ target: '_self',
+ title: "Modify email",
+ class: 'btn toolbar_btn toolbar_button_admin'
+ }, new HTML('span', {
+ class: 'glyphicon glyphicon-cog'
+ }, ' '));
toolbar.inject(adminbutton);
}
-
- text.inject(toolbar);
-}
+ text.inject(toolbar);
+}
\ No newline at end of file
diff --git a/webui/js/source/scaffolding-html.js b/webui/js/source/scaffolding-html.js
index 31a40dd..a2e792d 100644
--- a/webui/js/source/scaffolding-html.js
+++ b/webui/js/source/scaffolding-html.js
@@ -34,75 +34,75 @@
var txt = (msg) => document.createTextNode(msg);
var HTML = (function() {
- function HTML(type, params, children) {
+ function HTML(type, params, children) {
- /* create the raw element, or clone if passed an existing element */
- var child, j, len, val;
- if (typeof type === 'object') {
- this.element = type.cloneNode();
- } else {
- this.element = document.createElement(type);
- }
+ /* create the raw element, or clone if passed an existing element */
+ var child, j, len, val;
+ if (typeof type === 'object') {
+ this.element = type.cloneNode();
+ } else {
+ this.element = document.createElement(type);
+ }
- /* If params have been passed, set them */
- if (isHash(params)) {
- for (var key in params) {
- val = params[key];
-
- /* Standard string value? */
- if (typeof val === "string" || typeof val === 'number') {
- this.element.setAttribute(key, val);
- } else if (isArray(val)) {
-
- /* Are we passing a list of data to set? concatenate then */
- this.element.setAttribute(key, val.join(" "));
- } else if (isHash(val)) {
-
- /* Are we trying to set multiple sub elements, like a style? */
- for (var subkey in val) {
- let subval = val[subkey];
- if (!this.element[key]) {
- throw "No such attribute, " + key + "!";
+ /* If params have been passed, set them */
+ if (isHash(params)) {
+ for (var key in params) {
+ val = params[key];
+
+ /* Standard string value? */
+ if (typeof val === "string" || typeof val === 'number') {
+ this.element.setAttribute(key, val);
+ } else if (isArray(val)) {
+
+ /* Are we passing a list of data to set? concatenate then */
+ this.element.setAttribute(key, val.join(" "));
+ } else if (isHash(val)) {
+
+ /* Are we trying to set multiple sub elements, like a style? */
+ for (var subkey in val) {
+ let subval = val[subkey];
+ if (!this.element[key]) {
+ throw "No such attribute, " + key + "!";
+ }
+ this.element[key][subkey] = subval;
+ }
+ }
}
- this.element[key][subkey] = subval;
- }
}
- }
- }
-
- /* If any children have been passed, add them to the element */
- if (children) {
- /* If string, convert to textNode using txt() */
- if (typeof children === "string") {
- this.element.inject(txt(children));
- } else {
+ /* If any children have been passed, add them to the element */
+ if (children) {
- /* If children is an array of elems, iterate and add */
- if (isArray(children)) {
- for (j = 0, len = children.length; j < len; j++) {
- child = children[j];
-
- /* String? Convert via txt() then */
- if (typeof child === "string") {
- this.element.inject(txt(child));
+ /* If string, convert to textNode using txt() */
+ if (typeof children === "string") {
+ this.element.inject(txt(children));
} else {
- /* Plain element, add normally */
- this.element.inject(child);
+ /* If children is an array of elems, iterate and add */
+ if (isArray(children)) {
+ for (j = 0, len = children.length; j < len; j++) {
+ child = children[j];
+
+ /* String? Convert via txt() then */
+ if (typeof child === "string") {
+ this.element.inject(txt(child));
+ } else {
+
+ /* Plain element, add normally */
+ this.element.inject(child);
+ }
+ }
+ } else {
+
+ /* Just a single element, add it */
+ this.element.inject(children);
+ }
}
- }
- } else {
-
- /* Just a single element, add it */
- this.element.inject(children);
}
- }
+ return this.element;
}
- return this.element;
- }
- return HTML;
+ return HTML;
})();
@@ -112,22 +112,22 @@ var HTML = (function() {
*/
HTMLElement.prototype.inject = function(child) {
- var item, j, len;
- if (isArray(child)) {
- for (j = 0, len = child.length; j < len; j++) {
- item = child[j];
- if (typeof item === 'string') {
- item = txt(item);
- }
- this.appendChild(item);
- }
- } else {
- if (typeof child === 'string') {
- child = txt(child);
+ var item, j, len;
+ if (isArray(child)) {
+ for (j = 0, len = child.length; j < len; j++) {
+ item = child[j];
+ if (typeof item === 'string') {
+ item = txt(item);
+ }
+ this.appendChild(item);
+ }
+ } else {
+ if (typeof child === 'string') {
+ child = txt(child);
+ }
+ this.appendChild(child);
}
- this.appendChild(child);
- }
- return child;
+ return child;
};
@@ -137,15 +137,15 @@ HTMLElement.prototype.inject = function(child) {
*/
HTMLElement.prototype.empty = function() {
- var ndiv;
- ndiv = this.cloneNode();
- this.parentNode.replaceChild(ndiv, this);
- return ndiv;
+ var ndiv;
+ ndiv = this.cloneNode();
+ this.parentNode.replaceChild(ndiv, this);
+ return ndiv;
};
function toggleView(id) {
- let obj = document.getElementById(id);
- if (obj) {
- obj.style.display = (obj.style.display == 'block') ? 'none' : 'block';
- }
-}
+ let obj = document.getElementById(id);
+ if (obj) {
+ obj.style.display = (obj.style.display == 'block') ? 'none' : 'block';
+ }
+}
\ No newline at end of file
diff --git a/webui/js/source/search.js b/webui/js/source/search.js
index 411a95b..3d95d36 100644
--- a/webui/js/source/search.js
+++ b/webui/js/source/search.js
@@ -29,14 +29,21 @@ function search(query, date) {
global = true;
}
let sURL = '%sapi/stats.lua?d=%s&list=%s&domain=%s&q=%s'.format(apiURL, date, list, domain, query);
- GET(sURL, renderListView, {search: true, global: global});
+ GET(sURL, renderListView, {
+ search: true,
+ global: global
+ });
let listid = '%s@%s'.format(list, domain);
let newhref = "list?%s:%s:%s".format(listid, date, query);
if (location.href !== newhref) {
- window.history.pushState({}, null, newhref);
+ window.history.pushState({}, null, newhref);
}
- listview_list_lists({url: sURL, search: true, query: query});
+ listview_list_lists({
+ url: sURL,
+ search: true,
+ query: query
+ });
hideWindows(true);
document.getElementById('q').value = query;
return false;
@@ -57,4 +64,4 @@ function search_set_list(what) {
}
}
document.getElementById('q').setAttribute("placeholder", "Search %s...".format(whatxt));
-}
+}
\ No newline at end of file
diff --git a/webui/js/source/sidebar-calendar.js b/webui/js/source/sidebar-calendar.js
index 2bb356c..7dbde37 100644
--- a/webui/js/source/sidebar-calendar.js
+++ b/webui/js/source/sidebar-calendar.js
@@ -23,11 +23,13 @@ var calendar_years_shown = 4;
function renderCalendar(FY, FM, LY, LM) {
calendar_index = 0;
-
+
// Only render if calendar div is present
let cal = document.getElementById('sidebar_calendar');
- if (!cal) {return;}
-
+ if (!cal) {
+ return;
+ }
+
let now = new Date();
let CY = now.getFullYear();
let CM = now.getMonth() + 1;
@@ -37,47 +39,75 @@ function renderCalendar(FY, FM, LY, LM) {
LM = CM;
}
- let cdiv = new HTML('div', { class: 'sidebar_calendar' })
+ let cdiv = new HTML('div', {
+ class: 'sidebar_calendar'
+ })
let N = 0;
-
+
// Chevron for moving to later years
- let chevron = new HTML('div', { class: 'sidebar_calendar_chevron'});
- chevron.inject(new HTML('span', { onclick: 'calendar_scroll(this, -4);', style: {display: 'none'}, id: 'sidebar_calendar_up' , class: 'glyphicon glyphicon-collapse-up', title: "Show later years"}, " "));
- cdiv.inject(chevron);
-
+ let chevron = new HTML('div', {
+ class: 'sidebar_calendar_chevron'
+ });
+ chevron.inject(new HTML('span', {
+ onclick: 'calendar_scroll(this, -4);',
+ style: {
+ display: 'none'
+ },
+ id: 'sidebar_calendar_up',
+ class: 'glyphicon glyphicon-collapse-up',
+ title: "Show later years"
+ }, " "));
+ cdiv.inject(chevron);
+
// Create divs for each year, assign all visible
for (var Y = SY; Y >= FY; Y--) {
- let ydiv = new HTML('div', { class: 'sidebar_calendar_year', id: 'sidebar_calendar_'+N++ });
+ let ydiv = new HTML('div', {
+ class: 'sidebar_calendar_year',
+ id: 'sidebar_calendar_' + N++
+ });
ydiv.inject(txt(Y));
ydiv.inject(new HTML('br'));
for (var i = 0; i < months_shortened.length; i++) {
let mon = months_shortened[i];
- let mdiv = new HTML('div', { onclick: 'calendar_click(%u, %u);'.format(Y, i+1), class: 'sidebar_calendar_month'}, mon);
-
+ let mdiv = new HTML('div', {
+ onclick: 'calendar_click(%u, %u);'.format(Y, i + 1),
+ class: 'sidebar_calendar_month'
+ }, mon);
+
// Mark out-of-bounds segments
- if ( (Y == SY && i >= LM) || (Y == CY && i > CM) ) {
+ if ((Y == SY && i >= LM) || (Y == CY && i > CM)) {
mdiv.setAttribute("class", "sidebar_calendar_month_nothing");
}
- if (Y == FY && ((i+1) < FM)) {
+ if (Y == FY && ((i + 1) < FM)) {
mdiv.setAttribute("class", "sidebar_calendar_month_nothing");
}
ydiv.inject(mdiv);
}
cdiv.inject(ydiv);
}
-
+
cal.innerHTML = "<p style='text-align: center;'>Archives (%u - %u):</p>".format(FY, SY);
cal.inject(cdiv);
-
-
- chevron = new HTML('div', { class: 'sidebar_calendar_chevron'});
- chevron.inject(new HTML('span', { onclick: 'calendar_scroll(this, 4);', style: {display: 'none'}, id: 'sidebar_calendar_down', class: 'glyphicon glyphicon-collapse-down', title: "Show earlier years"}, " "));
+
+
+ chevron = new HTML('div', {
+ class: 'sidebar_calendar_chevron'
+ });
+ chevron.inject(new HTML('span', {
+ onclick: 'calendar_scroll(this, 4);',
+ style: {
+ display: 'none'
+ },
+ id: 'sidebar_calendar_down',
+ class: 'glyphicon glyphicon-collapse-down',
+ title: "Show earlier years"
+ }, " "));
cdiv.inject(chevron);
-
+
// If we have > 4 years, hide the rest
if (N > calendar_years_shown) {
for (var i = calendar_years_shown; i < N; i++) {
- let obj = document.getElementById('sidebar_calendar_'+i);
+ let obj = document.getElementById('sidebar_calendar_' + i);
if (obj) {
obj.style.display = "none";
}
@@ -88,30 +118,30 @@ function renderCalendar(FY, FM, LY, LM) {
function calendar_scroll(me, x) {
let years = document.getElementsByClassName('sidebar_calendar_year');
- calendar_index = Math.max(Math.min(years.length-x, calendar_index + x), 0);
+ calendar_index = Math.max(Math.min(years.length - x, calendar_index + x), 0);
if (calendar_index > 0) {
document.getElementById('sidebar_calendar_up').style.display = 'block';
} else {
document.getElementById('sidebar_calendar_up').style.display = 'none';
}
- if (calendar_index < (years.length-x)) {
+ if (calendar_index < (years.length - x)) {
document.getElementById('sidebar_calendar_down').style.display = 'block';
} else {
document.getElementById('sidebar_calendar_down').style.display = 'none';
}
-
-
+
+
for (var i = 0; i < years.length; i++) {
let year = years[i];
if (typeof(year) == 'object') {
- if (i >= calendar_index && i < (calendar_index+Math.abs(x))) {
+ if (i >= calendar_index && i < (calendar_index + Math.abs(x))) {
year.style.display = "block";
} else {
year.style.display = "none";
}
- }
+ }
}
-
+
}
function calendar_click(year, month) {
@@ -120,7 +150,10 @@ function calendar_click(year, month) {
searching = false;
let newhref = "list.html?%s@%s:%u-%u".format(current_list, current_domain, year, month);
if (location.href !== newhref) {
- window.history.pushState({}, null, newhref);
+ window.history.pushState({}, null, newhref);
}
- GET('%sapi/stats.lua?list=%s&domain=%s&d=%u-%u'.format(apiURL, current_list, current_domain, year, month), renderListView, {to: '%s@%s'.format(current_list, current_domain), update_calendar: false});
-}
+ GET('%sapi/stats.lua?list=%s&domain=%s&d=%u-%u'.format(apiURL, current_list, current_domain, year, month), renderListView, {
+ to: '%s@%s'.format(current_list, current_domain),
+ update_calendar: false
+ });
+}
\ No newline at end of file
diff --git a/webui/js/source/sidebar-stats.js b/webui/js/source/sidebar-stats.js
index 217eb4a..89fb945 100644
--- a/webui/js/source/sidebar-stats.js
+++ b/webui/js/source/sidebar-stats.js
@@ -17,19 +17,21 @@
async function sidebar_stats(json) {
let obj = document.getElementById('sidebar_stats');
- if (!obj) { return; }
-
+ if (!obj) {
+ return;
+ }
+
obj.innerHTML = ""; // clear stats bar
-
+
if (!json.emails || isHash(json.emails) || json.emails.length == 0) {
obj.innerText = "No emails found...";
return;
}
-
+
// 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:"));
- for (var i=0; i < json.participants.length; i++) {
+ for (var i = 0; i < json.participants.length; i++) {
if (i >= 5) {
break;
}
@@ -40,15 +42,20 @@ async function sidebar_stats(json) {
if (par.name.length == 0) {
par.name = par.email;
}
- pdiv = new HTML('div', {class:"sidebar_stats_participant"});
- pimg = new HTML('img', { class:"gravatar_sm", src: "https://secure.gravatar.com/avatar/%s.jpg?s=64&r=g&d=mm".format(par.gravatar)})
+ pdiv = new HTML('div', {
+ class: "sidebar_stats_participant"
+ });
+ pimg = new HTML('img', {
+ class: "gravatar_sm",
+ src: "https://secure.gravatar.com/avatar/%s.jpg?s=64&r=g&d=mm".format(par.gravatar)
+ })
pdiv.inject(pimg);
- pdiv.inject(new HTML('b', {}, par.name+": "));
+ pdiv.inject(new HTML('b', {}, par.name + ": "));
pdiv.inject(new HTML('br'));
pdiv.inject("%u emails sent".format(par.count));
obj.inject(pdiv);
}
-
+
// Word cloud, if applicable
let wc = document.getElementById('sidebar_wordcloud');
if (wc && json.cloud) {
@@ -56,6 +63,8 @@ async function sidebar_stats(json) {
wc.inject(new HTML('h5', {}, "Popular topics:"));
// word cloud is delayed by 50ms to let the rest render first
// this is a chrome-specific slowdown we're addressing.
- window.setTimeout(function() {wordCloud(json.cloud, 220, 100, wc);}, 50);
+ window.setTimeout(function() {
+ wordCloud(json.cloud, 220, 100, wc);
+ }, 50);
}
-}
+}
\ No newline at end of file