UNPKG

foam-framework

Version:
324 lines (274 loc) 10.5 kB
<html> <head> <link rel="stylesheet" type="text/css" href="../../core/foam.css" /> <link rel="stylesheet" type="text/css" href="mreader.css" /> <script>var FOAM_BOOT_DIR="../../core/";</script> <script language="javascript" src="../../core/bootFOAM.js"></script> <title>Mail Reader</title> </head> <body style="overflow:hidden;margin-top:5px;"> <table> <tr> <td> </td> <td> <div class="title"></div> <div class="subtitle"> &nbsp;MBOX Reader</div> </td> <td width=90%></td> <td valign="top"> <div class="titleBar"> <span style="float:right; margin-top: 23px;color:#666">MBOX File:<input type="file" onchange="loadmbox(event);"></span> </div> </td> </tr> </table> <hr color="#9BC0FA"> <div id="search" style="position:absolute;background-color:#fff;"> <div id="subjectSearch" class="searchTitle"></div> <div id="toSearch" class="searchTitle"></div> <div id="fromSearch" class="searchTitle"></div> <div id="labelSearch" class="searchTitle"></div> <div onClick="resetSearch()" style="float:right" class="searchTitle"><u>Clear All</u></div> <div id="viewMode" class="searchTitle"></div> </div> <div id="browse" style="position:absolute;background-color:#FFF;float:left;"></div> <div id="edit" style="position:absolute;margin-top:10px;margin-right:15px;border-width:1px;border-style:solid;border-color:black;position:absolute;background-color:#FFF;"> </div> <div id="footer" style="position:absolute;text-align:left;padding-top:3px;"> <!-- <hr color="#9BC0FA"> --> <font size=-1 face="catull" style="padding-left:10px;text-shadow:rgba(64,64,64,0.3) 3px 3px 4px;"> <font color="#3333FF">F</font><font color="#FF0000">O</font><font color="#ddaa00">A</font><font color="#33CC00">M</font> <font color2="#555555"> POWERED</font> <div onClick="switchHands()" style="float:right;padding-right:10px;" class="searchTitle"><u>switch hands</u></div> </div> <script> var GROUP_PROPERTY = EMail.CONV_ID; var expanded = {}; var ThreadedEMail = EMail.deepClone(); ThreadedEMail.properties.push(Property.create({ name: 'count', tableWidth: 45, label: 'Count', type: 'int', tableFormatter: function(c, email, table) { if ( c ) { if ( c == 1 ) return "&nbsp;&nbsp;&nbsp;&nbsp;1"; var isExpanded = expanded[GROUP_PROPERTY.f(email)]; var icon = isExpanded ? "&nbsp;-" : "+"; var id = table.on('click', (function(isExpanded) { return function() { if ( isExpanded ) { delete expanded[GROUP_PROPERTY.f(email)]; } else { expanded[GROUP_PROPERTY.f(email)] = true; } updateQuery(); }})(isExpanded)); return '<span id=' + id + '>' + icon + '</span>' + "&nbsp;&nbsp;" + c; } return ""; }, })); ThreadedEMail.tableProperties.unshift('count'); EMail.ATTACHMENTS.compare = function(o1, o2) { return this.f(o1).length - this.f(o2).length; }; // var header = $('header'); var footer = $('footer'); var search = $('search'); var browse = $('browse'); var edit = $('edit'); var reversed = false; function pos(e, top, left, width, height) { var s = e.style; left = left || 0; if ( reversed ) left = (window.innerWidth - 15) - left - (width || toNum(e.style.width)); top != null && (e.style.top = toNum(top) + 'px'); left != null && (e.style.left = toNum(left) + 'px'); width != null && (e.style.width = toNum(width) + 'px'); height != null && (e.style.height = toNum(height) + 'px'); } var MIN_THREE_COLUMN_W = 1600; var table; function layout() { var W = window.innerWidth - 15; var H = window.innerHeight-5; var HEADER_H = 85; var FOOTER_H = 20; var SEARCH_W = 400; var SEARCH_H = H - HEADER_H - FOOTER_H; var RIGHT_W = W - SEARCH_W - 5; // pos(header,null,null,W,HEADER_H-10); pos(search, HEADER_H, null, SEARCH_W, SEARCH_H); if ( W > MIN_THREE_COLUMN_W ) { pos(browse, HEADER_H, SEARCH_W + 10, RIGHT_W * 0.6, SEARCH_H+70); // ??? Why is the 70 needed pos(edit, HEADER_H, SEARCH_W + 10 + RIGHT_W * 0.6, RIGHT_W * 0.4-10, SEARCH_H-15); } else { pos(browse, HEADER_H, SEARCH_W + 10, RIGHT_W, SEARCH_H/2); pos(edit, toNum(browse.style.top) + toNum(browse.style.height) + 5, SEARCH_W + 10, RIGHT_W-10, SEARCH_H / 2 -20); } pos(footer, H-FOOTER_H, null, W, FOOTER_H); table && table.layout(); } window.onresize = layout; layout(); emails = IDBDAO.create({model: EMail}); var dao = MDAO.create({model: EMail}); dao.addIndex(EMail.TIMESTAMP); // dao.addIndex(EMail.CONV_ID); dao.addIndex(EMail.TO); dao.addIndex(EMail.FROM); dao.addIndex(EMail.SUBJECT); // var dao = []; /* dao = PartitionDAO.create({ partitions: [ WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }), WorkerDAO.create({ model: EMail }) ] }); */ /* dao.index = AltIndex.create( TreeIndex.create(EMail.TIMESTAMP, ValueIndex), TreeIndex.create(EMail.TO, AltIndex.create( TreeIndex.create(EMail.FROM, TreeIndex.create(EMail.TIMESTAMP, ValueIndex)), TreeIndex.create(EMail.TIMESTAMP, ValueIndex) )), TreeIndex.create(EMail.FROM, TreeIndex.create(EMail.TIMESTAMP, ValueIndex)), TreeIndex.create(EMail.SUBJECT, TreeIndex.create(EMail.TIMESTAMP, ValueIndex)) ); */ // dao2.bulkLoad(dao2); var d1 = dao; var d2 = emails; var lock = {}; var idbPerf; dao = { __proto__: dao, find: function(query, sink) { console.log('find:', query); d1.find(query, sink); }, select2: function(sink, options) { var future = afuture(); var s = CountExpr.isInstance(sink) ? COUNT() : { put: function() { } }; asynchronized(aseq( // alog('select ', sink, options && options.query && options.query.toSQL() || 'TRUE', options && options.skip, options && options.limit), // atime('indexedDB', arepeat(1, function(ret) { d2.select(s, options)(ret); }), function(p) { idbPerf = p; }), // alog('indexedDB to MDAO'), // atime('idao', arepeat(100, function(ret) { d1.select(s, options)(ret); }), function(p) { console.log(idbPerf + ',' + (p/1000)); }), function(ret) { d1.select(sink, options)(function(v) { future.set(sink); ret(); }); } ),lock)(anop); return future.get; } }; // Quick hack to make search work on each keystroke // TODO: make option of TextSearchView DomValue.DEFAULT_EVENT = 'keyup'; table = ScrollBorder.create({ view: TableView.create({ model: EMail, dao: dao, rows: 20 }), dao: dao }); var searchSubject = TextSearchView.create({width:57, label: 'Search', property: CONCAT(EMail.SUBJECT, EMail.BODY)}); var byTo = GroupBySearchView.create({size: 9, dao: dao, property: EMail.TO}); var byFrom = GroupBySearchView.create({size: 11, dao: dao, property: EMail.FROM}); var byLabel = GroupBySearchView.create({size: 6, dao: dao, property: EMail.LABELS}); var viewMode = RadioBoxView.create({value:SimpleValue.create('Message'), choices: ['Message', 'Conversation']}); browse.innerHTML = table.toHTML(); searchSubject.insertInElement('subjectSearch'); viewMode.insertInElement('viewMode'); byTo.insertInElement('toSearch'); byFrom.insertInElement('fromSearch'); byLabel.insertInElement('labelSearch'); table.initHTML(); table.view.selection.addListener(function (src, property, oldValue, newValue) { if ( ! newValue ) return; var editView = SummaryView.create({value: table.view.selection}); editView.model = EMail; edit.innerHTML = editView.toHTML(); editView.initHTML(); }); table.view.selection.set(table.view.objs[0]); layout(); function updateQuery() { var predicate = AND( searchSubject.predicate, byFrom.predicate, byTo.predicate, byLabel.predicate).partialEval(); // console.log('query: ', predicate.toSQL()); table.scrollbar.value = 0; if ( viewMode.value.get() === 'Message' ) { table.view.model = EMail; table.dao = dao.where(predicate); } else { table.view.model = ThreadedEMail; dao.where(predicate).select(ExpandableGroupByExpr.create({ arg1: GROUP_PROPERTY, arg2: EMail.TIMESTAMP, expanded: expanded }))(function(groups) { table.dao = groups;// .values; }); } byFrom.filter = AND(searchSubject.predicate, byTo.predicate, byLabel.predicate).partialEval(); byTo.filter = AND(searchSubject.predicate, byFrom.predicate, byLabel.predicate).partialEval(); byLabel.filter = AND(searchSubject.predicate, byTo.predicate, byFrom.predicate).partialEval(); } viewMode.value.addListener(updateQuery); Events.dynamic(function() { searchSubject.predicate; byFrom.predicate; byTo.predicate; byLabel.predicate; }, updateQuery); function resetSearch() { byFrom.view.value.set(''); byTo.view.value.set(''); byLabel.view.value.set(''); byFrom.filter = byTo.filter = byLabel.filter = TRUE; table.dao = dao; } function switchHands() { reversed = ! reversed; layout(); } function loadmbox(event) { emails.removeAll(); // this only works with storagedao because its synchronous var file = event.target.files[0]; MBOXLoader.dao = emails; SourceBlob(file, BlobToText(TextToLines(MBOXLoader))); } var a = []; emails.select(a)(function() { console.log('********************************************** loaded'); // Copy values from the array into the dao in an order // which will cause a balanced tree to be created. function bcopy(s,e) { if ( s == e ) dao.put(a[s]); if ( e <= s ) return; var m = Math.floor((s+e)/2); dao.put(a[m]); bcopy(s,m-1); bcopy(m+1,e); } bcopy(0, a.length-1); a = undefined; console.log('********************************************** inserted'); layout(); byTo.dao = byTo.dao; byFrom.dao = byFrom.dao; byLabel.dao = byLabel.dao; resetSearch(); }); TemplateUtil = undefined; </script> </body> </html>