site/js/dev/ponymail_email_tools.js (153 lines of code) (raw):

/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // findEml: Finds and returns an email object based on message ID function findEml(id) { // for each email we currently have in the saved JSON array for (var i in current_flat_json) { // Does MID match? if (current_flat_json[i].id == id) { return current_flat_json[i] } } } // countSubs: counts the number of replies to an email function countSubs(eml, state) { var n = 0; // If first call, start with -1, as the main email will increment this by one if (!state) { n = -1 } // construct a duplicate guard hash state = state ? state : {} // get email ID - either TID or MID, depends.. var x = eml.tid ? eml.tid : eml.mid // If we haven't seen this email before in the count, increment by one if (!state[x]) { n++; state[x] = true } // Also count each child in the thread (and possibly their children) for (var i in eml.children) { n += countSubs(eml.children[i], state); } return n } // countNewest: finds the newest email in a thread function countNewest(eml) { var n = eml.epoch; // for each child, find the oldest and keep that epoch val for (var i in eml.children) { n = Math.max(n, countNewest(eml.children[i])); } return n } // countParts: counts the number of unique participants in a thread function countParts(eml, kv) { var n = 0; var email = findEml(eml.tid) // kv keeps tracks of duplicate entries, only count each email once kv = kv ? kv : {} if (!email) { return n } // have we seen any email from this sender before? If not, increment! if (!kv[email.from]) { kv[email.from] = true n++; } // Run the counter for each child in the thread.. for (var i in eml.children) { n += countParts(eml.children[i], kv); } return n } // sortIt: sort function for emails: sorts by age function sortIt(json) { for (var i in json) { json[i].latest = countNewest(json[i]) } if (json && json != undefined && json.sort) { json.sort(function(a, b) { return b.latest - a.latest }) } return (json && json.sort) ? json : [] } // getChildren: fetch all replies to a topic from ES function getChildren(main, email, level, pnode) { // nesting level level = level ? level : 1 var pchild = null // if email is a valid thread struct and can be sorted (is array)... if (email && email.children && email.children.sort) { // Sort child emails ascending by epoch email.children.sort(function(a, b) { return a.epoch - b.epoch }) var pchildo = null // for each child in the thread for (var i in email.children) { var child = email.children[i] // If it's not the parent (don't want a loop!), then.. if (child.tid != email.mid) { // see if we have a saved copy of the email already var eml = saved_emails[child.tid] // Placeholder for the email, so we don't lose our sorting if (pnode) { var node = document.createElement('div') node.setAttribute("id", "thread_" + (child.mid ? child.mid : child.tid).toString().replace(/@<.+>/, "")) pnode.appendChild(node) } // No saved copy? Let's fetch from the backend then! if (!eml || !eml.from) { GetAsync("/api/email.lua?id=" + child.tid, { main: main, before: email.tid, pchild: pchild, child: child, level: level+1 }, displayEmailThreaded) // Saved copy here? Just show it then! } else { displayEmailThreaded(eml, { main: main, before: email.tid, pchild: pchild, child: child, level: level+1 }) } } // set pchild (for proper DOM placement) pchild = child.tid } } } // permaLink: redirect to an email permalink function permaLink(id, type) { var t = 'thread' if (prefs.groupBy == 'date') { t = 'permalink' } var eml = findEml(id) if (eml) { // This is so, in case you move to another list software, you'll keep back compat id = eml['message-id'] } window.open("/" + t + ".html/" + id, "_new") } // getSingleEmail: fetch an email from ES and go to callback // invoked by onload in permalink.html function getSingleEmail(id, object) { GetAsync("/api/email.lua?id=" + id, {object: object} , displaySingleEmail) } // seedGetSingleThread: pre-caller for the above. // invoked by onload in thread.html function seedGetSingleThread(id) { GetAsync("/api/preferences.lua", {docall:["/api/thread.lua?id=" + id, displaySingleThread]}, seedPrefs) } // Padding prototype, akin to %0[size]u in printf Number.prototype.pad = function(size) { var str = String(this); while (str.length < size) { str = "0" + str; } return str; } // formatEpoch: Return an epoch value (seconds) as YYYY-MM-DD HH:mm using UTC function formatEpochUTC(epoch){ var date = new Date(epoch*1000) return (date.getUTCFullYear() + "-" + (date.getUTCMonth()+1).pad(2) + "-" + date.getUTCDate().pad(2) + " " + date.getUTCHours().pad(2) + ":" + date.getUTCMinutes().pad(2)) } // hex -> base 36 conversion for creating shorter permalinks function shortenID(mid) { var id1 = parseInt(mid.substr(0,9), 16).toString(36) if (isNaN(id1)) { // conversion failed return mid; // return unchanged } // add padding if < 7 chars long while (id1.length < 7) id1 = '-' + id1 var id2 = parseInt(mid.substr(9,9), 16).toString(36) if (isNaN(id2)) { // conversion failed return mid; // return unchanged } while (id2.length < 7) id2 = '-' + id2 // add 'Z' which is the short link denoter return 'Z' + id1 + id2 } // hex <- base 36 conversion, reverses short links function unshortenID(mid) { // all short links begin with 'Z'. If not, it's not a short link // so let's just pass it through unaltered if so. // Some old shortlinks begin with 'B', so let's be backwards compatible for now. if (mid[0] == 'Z' || mid[0] == 'B') { // remove padding var id1 = parseInt(mid.substr(1, 7).replace(/-/g, ""), 36) var id2 = parseInt(mid.substr(8, 7).replace(/-/g, ""), 36) id1 = id1.toString(16) id2 = id2.toString(16) // add 0-padding while (id1.length < 9) id1 = '0' + id1 while (id2.length < 9) id2 = '0' + id2 return id1+id2 } return mid }