mails_viewer 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +20 -0
- data/LICENSE +20 -0
- data/README.md +37 -0
- data/Rakefile +15 -0
- data/app/assets/images/colorbox/border.png +0 -0
- data/app/assets/images/colorbox/controls.png +0 -0
- data/app/assets/images/colorbox/loading.gif +0 -0
- data/app/assets/images/colorbox/loading_background.png +0 -0
- data/app/assets/images/colorbox/overlay.png +0 -0
- data/app/assets/images/tablesorter/asc.gif +0 -0
- data/app/assets/images/tablesorter/bg.gif +0 -0
- data/app/assets/images/tablesorter/desc.gif +0 -0
- data/app/assets/images/tablesorter/first.png +0 -0
- data/app/assets/images/tablesorter/last.png +0 -0
- data/app/assets/images/tablesorter/next.png +0 -0
- data/app/assets/images/tablesorter/prev.png +0 -0
- data/app/assets/javascripts/jquery.colorbox-min.js +4 -0
- data/app/assets/javascripts/jquery.livequery.js +226 -0
- data/app/assets/javascripts/jquery.tablesorter.min.js +4 -0
- data/app/assets/javascripts/jquery.tablesorter.pager.js +184 -0
- data/app/assets/javascripts/mails_viewer.js +25 -0
- data/app/assets/stylesheets/colorbox.css +82 -0
- data/app/assets/stylesheets/jquery.tablesorter.pager.css +25 -0
- data/app/assets/stylesheets/mails_viewer.css +24 -0
- data/app/assets/stylesheets/table.css +40 -0
- data/app/controllers/mails_viewer/home_controller.rb +79 -0
- data/app/helper/mails_viewer/home_helper.rb +11 -0
- data/app/views/mails_viewer/home/index.html.erb +63 -0
- data/app/views/mails_viewer/home/plain.html.erb +1 -0
- data/config/routes.rb +10 -0
- data/lib/mails_viewer.rb +6 -0
- data/lib/mails_viewer/engine.rb +16 -0
- data/lib/mails_viewer/file_delivery.rb +15 -0
- data/lib/mails_viewer/mail.rb +15 -0
- data/lib/mails_viewer/version.rb +3 -0
- data/lib/tasks/mails_viewer_tasks.rake +4 -0
- metadata +133 -0
data/Gemfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
# Declare your gem's dependencies in mails_viewer.gemspec.
|
4
|
+
# Bundler will treat runtime dependencies like base dependencies, and
|
5
|
+
# development dependencies will be added by default to the :development group.
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :test, :development do
|
9
|
+
gem 'rspec-rails'
|
10
|
+
gem "rspec-instafail", "~> 0.1.8"
|
11
|
+
|
12
|
+
gem 'guard'
|
13
|
+
gem 'guard-bundler'
|
14
|
+
gem 'guard-rspec'
|
15
|
+
|
16
|
+
gem 'capybara'
|
17
|
+
gem "growl"
|
18
|
+
|
19
|
+
gem 'sqlite3'
|
20
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 Dingding Ye, Pragmatic.ly
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#### MailsViewer ####
|
2
|
+
|
3
|
+
MailsViewer is a mails preview Engine which provides a table view for all mails under tmp/mails. So you can easily preview the mails
|
4
|
+
in non-production mode and no longer need to worry about accidentally sending a test email to someone else’s address.
|
5
|
+
|
6
|
+
MailsViewer is a fork of tomlion's [original code](https://github.com/tomlion/mails_viewer) and I'm glad to be
|
7
|
+
the maintainer; thanks go to him for getting this thing started!
|
8
|
+
|
9
|
+
#### REQUIREMENT ####
|
10
|
+
|
11
|
+
* MailsViewer should be used with Rails >= 3.1
|
12
|
+
|
13
|
+
* In your config file, You should `require "sprockets/railtie" `if you don't `require 'rails/all'`
|
14
|
+
and enable assets pipeline by adding `config.assets.enabled = true` to config file
|
15
|
+
|
16
|
+
#### Usage ####
|
17
|
+
|
18
|
+
Add the gem to your Gemfile :
|
19
|
+
|
20
|
+
gem "mails_viewer"
|
21
|
+
|
22
|
+
put this in your routes.rb:
|
23
|
+
|
24
|
+
mount MailsViewer::Engine => '/delivered_mails'
|
25
|
+
|
26
|
+
Now just load upt http://localhost:3000/delivered_mails
|
27
|
+
|
28
|
+
Credits
|
29
|
+
-------
|
30
|
+
|
31
|
+

|
32
|
+
|
33
|
+
MailsViewer is maintained by [Pragmatic.ly](https://pragmatic.ly/ "Pragmatic.ly").
|
34
|
+
|
35
|
+
Special thanks to [tomlion](https://github.com/tomlion) for starting the project.
|
36
|
+
|
37
|
+
Copyright (c) 2012 Dingding Ye, Pragmatic.ly (dingding@pragmatic.ly, https://pragmatic.ly/)
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
3
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
4
|
+
|
5
|
+
Dir['lib/tasks/*.rake'].each { |rake| load rake }
|
6
|
+
|
7
|
+
require 'bundler'
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
|
+
|
10
|
+
require 'rspec/core/rake_task'
|
11
|
+
RSpec::Core::RakeTask.new(:spec)
|
12
|
+
|
13
|
+
task :default => :spec
|
14
|
+
task :test => :spec
|
15
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,4 @@
|
|
1
|
+
// ColorBox v1.3.17.2 - a full featured, light-weight, customizable lightbox based on jQuery 1.3+
|
2
|
+
// Copyright (c) 2011 Jack Moore - jack@colorpowered.com
|
3
|
+
// Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
|
4
|
+
(function(a,b,c){function bc(b){if(!U){P=b,_(),y=a(P),Q=0,K.rel!=="nofollow"&&(y=a("."+g).filter(function(){var b=a.data(this,e).rel||this.rel;return b===K.rel}),Q=y.index(P),Q===-1&&(y=y.add(P),Q=y.length-1));if(!S){S=T=!0,r.show();if(K.returnFocus)try{P.blur(),a(P).one(l,function(){try{this.focus()}catch(a){}})}catch(c){}q.css({opacity:+K.opacity,cursor:K.overlayClose?"pointer":"auto"}).show(),K.w=Z(K.initialWidth,"x"),K.h=Z(K.initialHeight,"y"),X.position(),o&&z.bind("resize."+p+" scroll."+p,function(){q.css({width:z.width(),height:z.height(),top:z.scrollTop(),left:z.scrollLeft()})}).trigger("resize."+p),ba(h,K.onOpen),J.add(D).hide(),I.html(K.close).show()}X.load(!0)}}function bb(){var a,b=f+"Slideshow_",c="click."+f,d,e,g;K.slideshow&&y[1]?(d=function(){F.text(K.slideshowStop).unbind(c).bind(j,function(){if(Q<y.length-1||K.loop)a=setTimeout(X.next,K.slideshowSpeed)}).bind(i,function(){clearTimeout(a)}).one(c+" "+k,e),r.removeClass(b+"off").addClass(b+"on"),a=setTimeout(X.next,K.slideshowSpeed)},e=function(){clearTimeout(a),F.text(K.slideshowStart).unbind([j,i,k,c].join(" ")).one(c,d),r.removeClass(b+"on").addClass(b+"off")},K.slideshowAuto?d():e()):r.removeClass(b+"off "+b+"on")}function ba(b,c){c&&c.call(P),a.event.trigger(b)}function _(b){K=a.extend({},a.data(P,e));for(b in K)a.isFunction(K[b])&&b.substring(0,2)!=="on"&&(K[b]=K[b].call(P));K.rel=K.rel||P.rel||"nofollow",K.href=K.href||a(P).attr("href"),K.title=K.title||P.title,typeof K.href=="string"&&(K.href=a.trim(K.href))}function $(a){return K.photo||/\.(gif|png|jpg|jpeg|bmp)(?:\?([^#]*))?(?:#(\.*))?$/i.test(a)}function Z(a,b){return Math.round((/%/.test(a)?(b==="x"?z.width():z.height())/100:1)*parseInt(a,10))}function Y(c,d,e){e=b.createElement("div"),c&&(e.id=f+c),e.style.cssText=d||"";return a(e)}var d={transition:"elastic",speed:300,width:!1,initialWidth:"600",innerWidth:!1,maxWidth:!1,height:!1,initialHeight:"450",innerHeight:!1,maxHeight:!1,scalePhotos:!0,scrolling:!0,inline:!1,html:!1,iframe:!1,fastIframe:!0,photo:!1,href:!1,title:!1,rel:!1,opacity:.9,preloading:!0,current:"image {current} of {total}",previous:"previous",next:"next",close:"close",open:!1,returnFocus:!0,loop:!0,slideshow:!1,slideshowAuto:!0,slideshowSpeed:2500,slideshowStart:"start slideshow",slideshowStop:"stop slideshow",onOpen:!1,onLoad:!1,onComplete:!1,onCleanup:!1,onClosed:!1,overlayClose:!0,escKey:!0,arrowKey:!0,top:!1,bottom:!1,left:!1,right:!1,fixed:!1,data:!1},e="colorbox",f="cbox",g=f+"Element",h=f+"_open",i=f+"_load",j=f+"_complete",k=f+"_cleanup",l=f+"_closed",m=f+"_purge",n=a.browser.msie&&!a.support.opacity,o=n&&a.browser.version<7,p=f+"_IE6",q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X;X=a.fn[e]=a[e]=function(b,c){var f=this;b=b||{};if(!f[0]){if(f.selector)return f;f=a("<a/>"),b.open=!0}c&&(b.onComplete=c),f.each(function(){a.data(this,e,a.extend({},a.data(this,e)||d,b)),a(this).addClass(g)}),(a.isFunction(b.open)&&b.open.call(f)||b.open)&&bc(f[0]);return f},X.init=function(){z=a(c),r=Y().attr({id:e,"class":n?f+(o?"IE6":"IE"):""}),q=Y("Overlay",o?"position:absolute":"").hide(),s=Y("Wrapper"),t=Y("Content").append(A=Y("LoadedContent","width:0; height:0; overflow:hidden"),C=Y("LoadingOverlay").add(Y("LoadingGraphic")),D=Y("Title"),E=Y("Current"),G=Y("Next"),H=Y("Previous"),F=Y("Slideshow").bind(h,bb),I=Y("Close")),s.append(Y().append(Y("TopLeft"),u=Y("TopCenter"),Y("TopRight")),Y(!1,"clear:left").append(v=Y("MiddleLeft"),t,w=Y("MiddleRight")),Y(!1,"clear:left").append(Y("BottomLeft"),x=Y("BottomCenter"),Y("BottomRight"))).children().children().css({"float":"left"}),B=Y(!1,"position:absolute; width:9999px; visibility:hidden; display:none"),a("body").prepend(q,r.append(s,B)),t.children().hover(function(){a(this).addClass("hover")},function(){a(this).removeClass("hover")}).addClass("hover"),L=u.height()+x.height()+t.outerHeight(!0)-t.height(),M=v.width()+w.width()+t.outerWidth(!0)-t.width(),N=A.outerHeight(!0),O=A.outerWidth(!0),r.css({"padding-bottom":L,"padding-right":M}).hide(),G.click(function(){X.next()}),H.click(function(){X.prev()}),I.click(function(){X.close()}),J=G.add(H).add(E).add(F),t.children().removeClass("hover"),q.click(function(){K.overlayClose&&X.close()}),a(b).bind("keydown."+f,function(a){var b=a.keyCode;S&&K.escKey&&b===27&&(a.preventDefault(),X.close()),S&&K.arrowKey&&y[1]&&(b===37?(a.preventDefault(),H.click()):b===39&&(a.preventDefault(),G.click()))})},X.remove=function(){r.add(q).remove(),a("."+g).removeData(e).removeClass(g)},X.position=function(a,c){function g(a){u[0].style.width=x[0].style.width=t[0].style.width=a.style.width,C[0].style.height=C[1].style.height=t[0].style.height=v[0].style.height=w[0].style.height=a.style.height}var d=0,e=0;z.unbind("resize."+f),r.hide(),K.fixed&&!o?r.css({position:"fixed"}):(d=z.scrollTop(),e=z.scrollLeft(),r.css({position:"absolute"})),K.right!==!1?e+=Math.max(z.width()-K.w-O-M-Z(K.right,"x"),0):K.left!==!1?e+=Z(K.left,"x"):e+=Math.round(Math.max(z.width()-K.w-O-M,0)/2),K.bottom!==!1?d+=Math.max(b.documentElement.clientHeight-K.h-N-L-Z(K.bottom,"y"),0):K.top!==!1?d+=Z(K.top,"y"):d+=Math.round(Math.max(b.documentElement.clientHeight-K.h-N-L,0)/2),r.show(),a=r.width()===K.w+O&&r.height()===K.h+N?0:a||0,s[0].style.width=s[0].style.height="9999px",r.dequeue().animate({width:K.w+O,height:K.h+N,top:d,left:e},{duration:a,complete:function(){g(this),T=!1,s[0].style.width=K.w+O+M+"px",s[0].style.height=K.h+N+L+"px",c&&c(),setTimeout(function(){z.bind("resize."+f,X.position)},1)},step:function(){g(this)}})},X.resize=function(a){if(S){a=a||{},a.width&&(K.w=Z(a.width,"x")-O-M),a.innerWidth&&(K.w=Z(a.innerWidth,"x")),A.css({width:K.w}),a.height&&(K.h=Z(a.height,"y")-N-L),a.innerHeight&&(K.h=Z(a.innerHeight,"y"));if(!a.innerHeight&&!a.height){var b=A.wrapInner("<div style='overflow:auto'></div>").children();K.h=b.height(),b.replaceWith(b.children())}A.css({height:K.h}),X.position(K.transition==="none"?0:K.speed)}},X.prep=function(b){function h(){K.h=K.h||A.height(),K.h=K.mh&&K.mh<K.h?K.mh:K.h;return K.h}function g(){K.w=K.w||A.width(),K.w=K.mw&&K.mw<K.w?K.mw:K.w;return K.w}if(!!S){var c,d=K.transition==="none"?0:K.speed;A.remove(),A=Y("LoadedContent").append(b),A.hide().appendTo(B.show()).css({width:g(),overflow:K.scrolling?"auto":"hidden"}).css({height:h()}).prependTo(t),B.hide(),a(R).css({"float":"none"}),o&&a("select").not(r.find("select")).filter(function(){return this.style.visibility!=="hidden"}).css({visibility:"hidden"}).one(k,function(){this.style.visibility="inherit"}),c=function(){function o(){n&&r[0].style.removeAttribute("filter")}var b,c,g,h,i=y.length,k,l;!S||(l=function(){clearTimeout(W),C.hide(),ba(j,K.onComplete)},n&&R&&A.fadeIn(100),D.html(K.title).add(A).show(),i>1?(typeof K.current=="string"&&E.html(K.current.replace("{current}",Q+1).replace("{total}",i)).show(),G[K.loop||Q<i-1?"show":"hide"]().html(K.next),H[K.loop||Q?"show":"hide"]().html(K.previous),b=Q?y[Q-1]:y[i-1],g=Q<i-1?y[Q+1]:y[0],K.slideshow&&F.show(),K.preloading&&(h=a.data(g,e).href||g.href,c=a.data(b,e).href||b.href,h=a.isFunction(h)?h.call(g):h,c=a.isFunction(c)?c.call(b):c,$(h)&&(a("<img/>")[0].src=h),$(c)&&(a("<img/>")[0].src=c))):J.hide(),K.iframe?(k=a("<iframe/>").addClass(f+"Iframe")[0],K.fastIframe?l():a(k).one("load",l),k.name=f+ +(new Date),k.src=K.href,K.scrolling||(k.scrolling="no"),n&&(k.frameBorder=0,k.allowTransparency="true"),a(k).appendTo(A).one(m,function(){k.src="//about:blank"})):l(),K.transition==="fade"?r.fadeTo(d,1,o):o())},K.transition==="fade"?r.fadeTo(d,0,function(){X.position(0,c)}):X.position(d,c)}},X.load=function(b){var c,d,e=X.prep;T=!0,R=!1,P=y[Q],b||_(),ba(m),ba(i,K.onLoad),K.h=K.height?Z(K.height,"y")-N-L:K.innerHeight&&Z(K.innerHeight,"y"),K.w=K.width?Z(K.width,"x")-O-M:K.innerWidth&&Z(K.innerWidth,"x"),K.mw=K.w,K.mh=K.h,K.maxWidth&&(K.mw=Z(K.maxWidth,"x")-O-M,K.mw=K.w&&K.w<K.mw?K.w:K.mw),K.maxHeight&&(K.mh=Z(K.maxHeight,"y")-N-L,K.mh=K.h&&K.h<K.mh?K.h:K.mh),c=K.href,W=setTimeout(function(){C.show()},100),K.inline?(Y().hide().insertBefore(a(c)[0]).one(m,function(){a(this).replaceWith(A.children())}),e(a(c))):K.iframe?e(" "):K.html?e(K.html):$(c)?(a(R=new Image).addClass(f+"Photo").error(function(){K.title=!1,e(Y("Error").text("This image could not be loaded"))}).load(function(){var a;R.onload=null,K.scalePhotos&&(d=function(){R.height-=R.height*a,R.width-=R.width*a},K.mw&&R.width>K.mw&&(a=(R.width-K.mw)/R.width,d()),K.mh&&R.height>K.mh&&(a=(R.height-K.mh)/R.height,d())),K.h&&(R.style.marginTop=Math.max(K.h-R.height,0)/2+"px"),y[1]&&(Q<y.length-1||K.loop)&&(R.style.cursor="pointer",R.onclick=function(){X.next()}),n&&(R.style.msInterpolationMode="bicubic"),setTimeout(function(){e(R)},1)}),setTimeout(function(){R.src=c},1)):c&&B.load(c,K.data,function(b,c,d){e(c==="error"?Y("Error").text("Request unsuccessful: "+d.statusText):a(this).contents())})},X.next=function(){!T&&y[1]&&(Q<y.length-1||K.loop)&&(Q=Q<y.length-1?Q+1:0,X.load())},X.prev=function(){!T&&y[1]&&(Q||K.loop)&&(Q=Q?Q-1:y.length-1,X.load())},X.close=function(){S&&!U&&(U=!0,S=!1,ba(k,K.onCleanup),z.unbind("."+f+" ."+p),q.fadeTo(200,0),r.stop().fadeTo(300,0,function(){r.add(q).css({opacity:1,cursor:"auto"}).hide(),ba(m),A.remove(),setTimeout(function(){U=!1,ba(l,K.onClosed)},1)}))},X.element=function(){return a(P)},X.settings=d,V=function(a){a.button!==0&&typeof a.button!="undefined"||a.ctrlKey||a.shiftKey||a.altKey||(a.preventDefault(),bc(this))},a.fn.delegate?a(b).delegate("."+g,"click",V):a("."+g).live("click",V),a(X.init)})(jQuery,document,this);
|
@@ -0,0 +1,226 @@
|
|
1
|
+
/*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net)
|
2
|
+
* Dual licensed under the MIT (MIT_LICENSE.txt)
|
3
|
+
* and GPL Version 2 (GPL_LICENSE.txt) licenses.
|
4
|
+
*
|
5
|
+
* Version: 1.1.1
|
6
|
+
* Requires jQuery 1.3+
|
7
|
+
* Docs: http://docs.jquery.com/Plugins/livequery
|
8
|
+
*/
|
9
|
+
|
10
|
+
(function($) {
|
11
|
+
|
12
|
+
$.extend($.fn, {
|
13
|
+
livequery: function(type, fn, fn2) {
|
14
|
+
var self = this, q;
|
15
|
+
|
16
|
+
// Handle different call patterns
|
17
|
+
if ($.isFunction(type))
|
18
|
+
fn2 = fn, fn = type, type = undefined;
|
19
|
+
|
20
|
+
// See if Live Query already exists
|
21
|
+
$.each( $.livequery.queries, function(i, query) {
|
22
|
+
if ( self.selector == query.selector && self.context == query.context &&
|
23
|
+
type == query.type && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) )
|
24
|
+
// Found the query, exit the each loop
|
25
|
+
return (q = query) && false;
|
26
|
+
});
|
27
|
+
|
28
|
+
// Create new Live Query if it wasn't found
|
29
|
+
q = q || new $.livequery(this.selector, this.context, type, fn, fn2);
|
30
|
+
|
31
|
+
// Make sure it is running
|
32
|
+
q.stopped = false;
|
33
|
+
|
34
|
+
// Run it immediately for the first time
|
35
|
+
q.run();
|
36
|
+
|
37
|
+
// Contnue the chain
|
38
|
+
return this;
|
39
|
+
},
|
40
|
+
|
41
|
+
expire: function(type, fn, fn2) {
|
42
|
+
var self = this;
|
43
|
+
|
44
|
+
// Handle different call patterns
|
45
|
+
if ($.isFunction(type))
|
46
|
+
fn2 = fn, fn = type, type = undefined;
|
47
|
+
|
48
|
+
// Find the Live Query based on arguments and stop it
|
49
|
+
$.each( $.livequery.queries, function(i, query) {
|
50
|
+
if ( self.selector == query.selector && self.context == query.context &&
|
51
|
+
(!type || type == query.type) && (!fn || fn.$lqguid == query.fn.$lqguid) && (!fn2 || fn2.$lqguid == query.fn2.$lqguid) && !this.stopped )
|
52
|
+
$.livequery.stop(query.id);
|
53
|
+
});
|
54
|
+
|
55
|
+
// Continue the chain
|
56
|
+
return this;
|
57
|
+
}
|
58
|
+
});
|
59
|
+
|
60
|
+
$.livequery = function(selector, context, type, fn, fn2) {
|
61
|
+
this.selector = selector;
|
62
|
+
this.context = context;
|
63
|
+
this.type = type;
|
64
|
+
this.fn = fn;
|
65
|
+
this.fn2 = fn2;
|
66
|
+
this.elements = [];
|
67
|
+
this.stopped = false;
|
68
|
+
|
69
|
+
// The id is the index of the Live Query in $.livequery.queries
|
70
|
+
this.id = $.livequery.queries.push(this)-1;
|
71
|
+
|
72
|
+
// Mark the functions for matching later on
|
73
|
+
fn.$lqguid = fn.$lqguid || $.livequery.guid++;
|
74
|
+
if (fn2) fn2.$lqguid = fn2.$lqguid || $.livequery.guid++;
|
75
|
+
|
76
|
+
// Return the Live Query
|
77
|
+
return this;
|
78
|
+
};
|
79
|
+
|
80
|
+
$.livequery.prototype = {
|
81
|
+
stop: function() {
|
82
|
+
var query = this;
|
83
|
+
|
84
|
+
if ( this.type )
|
85
|
+
// Unbind all bound events
|
86
|
+
this.elements.unbind(this.type, this.fn);
|
87
|
+
else if (this.fn2)
|
88
|
+
// Call the second function for all matched elements
|
89
|
+
this.elements.each(function(i, el) {
|
90
|
+
query.fn2.apply(el);
|
91
|
+
});
|
92
|
+
|
93
|
+
// Clear out matched elements
|
94
|
+
this.elements = [];
|
95
|
+
|
96
|
+
// Stop the Live Query from running until restarted
|
97
|
+
this.stopped = true;
|
98
|
+
},
|
99
|
+
|
100
|
+
run: function() {
|
101
|
+
// Short-circuit if stopped
|
102
|
+
if ( this.stopped ) return;
|
103
|
+
var query = this;
|
104
|
+
|
105
|
+
var oEls = this.elements,
|
106
|
+
els = $(this.selector, this.context),
|
107
|
+
nEls = els.not(oEls);
|
108
|
+
|
109
|
+
// Set elements to the latest set of matched elements
|
110
|
+
this.elements = els;
|
111
|
+
|
112
|
+
if (this.type) {
|
113
|
+
// Bind events to newly matched elements
|
114
|
+
nEls.bind(this.type, this.fn);
|
115
|
+
|
116
|
+
// Unbind events to elements no longer matched
|
117
|
+
if (oEls.length > 0)
|
118
|
+
$.each(oEls, function(i, el) {
|
119
|
+
if ( $.inArray(el, els) < 0 )
|
120
|
+
$.event.remove(el, query.type, query.fn);
|
121
|
+
});
|
122
|
+
}
|
123
|
+
else {
|
124
|
+
// Call the first function for newly matched elements
|
125
|
+
nEls.each(function() {
|
126
|
+
query.fn.apply(this);
|
127
|
+
});
|
128
|
+
|
129
|
+
// Call the second function for elements no longer matched
|
130
|
+
if ( this.fn2 && oEls.length > 0 )
|
131
|
+
$.each(oEls, function(i, el) {
|
132
|
+
if ( $.inArray(el, els) < 0 )
|
133
|
+
query.fn2.apply(el);
|
134
|
+
});
|
135
|
+
}
|
136
|
+
}
|
137
|
+
};
|
138
|
+
|
139
|
+
$.extend($.livequery, {
|
140
|
+
guid: 0,
|
141
|
+
queries: [],
|
142
|
+
queue: [],
|
143
|
+
running: false,
|
144
|
+
timeout: null,
|
145
|
+
|
146
|
+
checkQueue: function() {
|
147
|
+
if ( $.livequery.running && $.livequery.queue.length ) {
|
148
|
+
var length = $.livequery.queue.length;
|
149
|
+
// Run each Live Query currently in the queue
|
150
|
+
while ( length-- )
|
151
|
+
$.livequery.queries[ $.livequery.queue.shift() ].run();
|
152
|
+
}
|
153
|
+
},
|
154
|
+
|
155
|
+
pause: function() {
|
156
|
+
// Don't run anymore Live Queries until restarted
|
157
|
+
$.livequery.running = false;
|
158
|
+
},
|
159
|
+
|
160
|
+
play: function() {
|
161
|
+
// Restart Live Queries
|
162
|
+
$.livequery.running = true;
|
163
|
+
// Request a run of the Live Queries
|
164
|
+
$.livequery.run();
|
165
|
+
},
|
166
|
+
|
167
|
+
registerPlugin: function() {
|
168
|
+
$.each( arguments, function(i,n) {
|
169
|
+
// Short-circuit if the method doesn't exist
|
170
|
+
if (!$.fn[n]) return;
|
171
|
+
|
172
|
+
// Save a reference to the original method
|
173
|
+
var old = $.fn[n];
|
174
|
+
|
175
|
+
// Create a new method
|
176
|
+
$.fn[n] = function() {
|
177
|
+
// Call the original method
|
178
|
+
var r = old.apply(this, arguments);
|
179
|
+
|
180
|
+
// Request a run of the Live Queries
|
181
|
+
$.livequery.run();
|
182
|
+
|
183
|
+
// Return the original methods result
|
184
|
+
return r;
|
185
|
+
}
|
186
|
+
});
|
187
|
+
},
|
188
|
+
|
189
|
+
run: function(id) {
|
190
|
+
if (id != undefined) {
|
191
|
+
// Put the particular Live Query in the queue if it doesn't already exist
|
192
|
+
if ( $.inArray(id, $.livequery.queue) < 0 )
|
193
|
+
$.livequery.queue.push( id );
|
194
|
+
}
|
195
|
+
else
|
196
|
+
// Put each Live Query in the queue if it doesn't already exist
|
197
|
+
$.each( $.livequery.queries, function(id) {
|
198
|
+
if ( $.inArray(id, $.livequery.queue) < 0 )
|
199
|
+
$.livequery.queue.push( id );
|
200
|
+
});
|
201
|
+
|
202
|
+
// Clear timeout if it already exists
|
203
|
+
if ($.livequery.timeout) clearTimeout($.livequery.timeout);
|
204
|
+
// Create a timeout to check the queue and actually run the Live Queries
|
205
|
+
$.livequery.timeout = setTimeout($.livequery.checkQueue, 20);
|
206
|
+
},
|
207
|
+
|
208
|
+
stop: function(id) {
|
209
|
+
if (id != undefined)
|
210
|
+
// Stop are particular Live Query
|
211
|
+
$.livequery.queries[ id ].stop();
|
212
|
+
else
|
213
|
+
// Stop all Live Queries
|
214
|
+
$.each( $.livequery.queries, function(id) {
|
215
|
+
$.livequery.queries[ id ].stop();
|
216
|
+
});
|
217
|
+
}
|
218
|
+
});
|
219
|
+
|
220
|
+
// Register core DOM manipulation methods
|
221
|
+
$.livequery.registerPlugin('append', 'prepend', 'after', 'before', 'wrap', 'attr', 'removeAttr', 'addClass', 'removeClass', 'toggleClass', 'empty', 'remove', 'html');
|
222
|
+
|
223
|
+
// Run Live Queries when the Document is ready
|
224
|
+
$(function() { $.livequery.play(); });
|
225
|
+
|
226
|
+
})(jQuery);
|
@@ -0,0 +1,4 @@
|
|
1
|
+
|
2
|
+
(function($){$.extend({tablesorter:new
|
3
|
+
function(){var parsers=[],widgets=[];this.defaults={cssHeader:"header",cssAsc:"headerSortUp",cssDesc:"headerSortDown",cssChildRow:"expand-child",sortInitialOrder:"asc",sortMultiSortKey:"shiftKey",sortForce:null,sortAppend:null,sortLocaleCompare:true,textExtraction:"simple",parsers:{},widgets:[],widgetZebra:{css:["even","odd"]},headers:{},widthFixed:false,cancelSelection:true,sortList:[],headerList:[],dateFormat:"us",decimal:'/\.|\,/g',onRenderHeader:null,selectorHeaders:'thead th',debug:false};function benchmark(s,d){log(s+","+(new Date().getTime()-d.getTime())+"ms");}this.benchmark=benchmark;function log(s){if(typeof console!="undefined"&&typeof console.debug!="undefined"){console.log(s);}else{alert(s);}}function buildParserCache(table,$headers){if(table.config.debug){var parsersDebug="";}if(table.tBodies.length==0)return;var rows=table.tBodies[0].rows;if(rows[0]){var list=[],cells=rows[0].cells,l=cells.length;for(var i=0;i<l;i++){var p=false;if($.metadata&&($($headers[i]).metadata()&&$($headers[i]).metadata().sorter)){p=getParserById($($headers[i]).metadata().sorter);}else if((table.config.headers[i]&&table.config.headers[i].sorter)){p=getParserById(table.config.headers[i].sorter);}if(!p){p=detectParserForColumn(table,rows,-1,i);}if(table.config.debug){parsersDebug+="column:"+i+" parser:"+p.id+"\n";}list.push(p);}}if(table.config.debug){log(parsersDebug);}return list;};function detectParserForColumn(table,rows,rowIndex,cellIndex){var l=parsers.length,node=false,nodeValue=false,keepLooking=true;while(nodeValue==''&&keepLooking){rowIndex++;if(rows[rowIndex]){node=getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex);nodeValue=trimAndGetNodeText(table.config,node);if(table.config.debug){log('Checking if value was empty on row:'+rowIndex);}}else{keepLooking=false;}}for(var i=1;i<l;i++){if(parsers[i].is(nodeValue,table,node)){return parsers[i];}}return parsers[0];}function getNodeFromRowAndCellIndex(rows,rowIndex,cellIndex){return rows[rowIndex].cells[cellIndex];}function trimAndGetNodeText(config,node){return $.trim(getElementText(config,node));}function getParserById(name){var l=parsers.length;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==name.toLowerCase()){return parsers[i];}}return false;}function buildCache(table){if(table.config.debug){var cacheTime=new Date();}var totalRows=(table.tBodies[0]&&table.tBodies[0].rows.length)||0,totalCells=(table.tBodies[0].rows[0]&&table.tBodies[0].rows[0].cells.length)||0,parsers=table.config.parsers,cache={row:[],normalized:[]};for(var i=0;i<totalRows;++i){var c=$(table.tBodies[0].rows[i]),cols=[];if(c.hasClass(table.config.cssChildRow)){cache.row[cache.row.length-1]=cache.row[cache.row.length-1].add(c);continue;}cache.row.push(c);for(var j=0;j<totalCells;++j){cols.push(parsers[j].format(getElementText(table.config,c[0].cells[j]),table,c[0].cells[j]));}cols.push(cache.normalized.length);cache.normalized.push(cols);cols=null;};if(table.config.debug){benchmark("Building cache for "+totalRows+" rows:",cacheTime);}return cache;};function getElementText(config,node){var text="";if(!node)return"";if(!config.supportsTextContent)config.supportsTextContent=node.textContent||false;if(config.textExtraction=="simple"){if(config.supportsTextContent){text=node.textContent;}else{if(node.childNodes[0]&&node.childNodes[0].hasChildNodes()){text=node.childNodes[0].innerHTML;}else{text=node.innerHTML;}}}else{if(typeof(config.textExtraction)=="function"){text=config.textExtraction(node);}else{text=$(node).text();}}return text;}function appendToTable(table,cache){if(table.config.debug){var appendTime=new Date()}var c=cache,r=c.row,n=c.normalized,totalRows=n.length,checkCell=(n[0].length-1),tableBody=$(table.tBodies[0]),rows=[];for(var i=0;i<totalRows;i++){var pos=n[i][checkCell];rows.push(r[pos]);if(!table.config.appender){var l=r[pos].length;for(var j=0;j<l;j++){tableBody[0].appendChild(r[pos][j]);}}}if(table.config.appender){table.config.appender(table,rows);}rows=null;if(table.config.debug){benchmark("Rebuilt table:",appendTime);}applyWidget(table);setTimeout(function(){$(table).trigger("sortEnd");},0);};function buildHeaders(table){if(table.config.debug){var time=new Date();}var meta=($.metadata)?true:false;var header_index=computeTableHeaderCellIndexes(table);$tableHeaders=$(table.config.selectorHeaders,table).each(function(index){this.column=header_index[this.parentNode.rowIndex+"-"+this.cellIndex];this.order=formatSortingOrder(table.config.sortInitialOrder);this.count=this.order;if(checkHeaderMetadata(this)||checkHeaderOptions(table,index))this.sortDisabled=true;if(checkHeaderOptionsSortingLocked(table,index))this.order=this.lockedOrder=checkHeaderOptionsSortingLocked(table,index);if(!this.sortDisabled){var $th=$(this).addClass(table.config.cssHeader);if(table.config.onRenderHeader)table.config.onRenderHeader.apply($th);}table.config.headerList[index]=this;});if(table.config.debug){benchmark("Built headers:",time);log($tableHeaders);}return $tableHeaders;};function computeTableHeaderCellIndexes(t){var matrix=[];var lookup={};var thead=t.getElementsByTagName('THEAD')[0];var trs=thead.getElementsByTagName('TR');for(var i=0;i<trs.length;i++){var cells=trs[i].cells;for(var j=0;j<cells.length;j++){var c=cells[j];var rowIndex=c.parentNode.rowIndex;var cellId=rowIndex+"-"+c.cellIndex;var rowSpan=c.rowSpan||1;var colSpan=c.colSpan||1
|
4
|
+
var firstAvailCol;if(typeof(matrix[rowIndex])=="undefined"){matrix[rowIndex]=[];}for(var k=0;k<matrix[rowIndex].length+1;k++){if(typeof(matrix[rowIndex][k])=="undefined"){firstAvailCol=k;break;}}lookup[cellId]=firstAvailCol;for(var k=rowIndex;k<rowIndex+rowSpan;k++){if(typeof(matrix[k])=="undefined"){matrix[k]=[];}var matrixrow=matrix[k];for(var l=firstAvailCol;l<firstAvailCol+colSpan;l++){matrixrow[l]="x";}}}}return lookup;}function checkCellColSpan(table,rows,row){var arr=[],r=table.tHead.rows,c=r[row].cells;for(var i=0;i<c.length;i++){var cell=c[i];if(cell.colSpan>1){arr=arr.concat(checkCellColSpan(table,headerArr,row++));}else{if(table.tHead.length==1||(cell.rowSpan>1||!r[row+1])){arr.push(cell);}}}return arr;};function checkHeaderMetadata(cell){if(($.metadata)&&($(cell).metadata().sorter===false)){return true;};return false;}function checkHeaderOptions(table,i){if((table.config.headers[i])&&(table.config.headers[i].sorter===false)){return true;};return false;}function checkHeaderOptionsSortingLocked(table,i){if((table.config.headers[i])&&(table.config.headers[i].lockedOrder))return table.config.headers[i].lockedOrder;return false;}function applyWidget(table){var c=table.config.widgets;var l=c.length;for(var i=0;i<l;i++){getWidgetById(c[i]).format(table);}}function getWidgetById(name){var l=widgets.length;for(var i=0;i<l;i++){if(widgets[i].id.toLowerCase()==name.toLowerCase()){return widgets[i];}}};function formatSortingOrder(v){if(typeof(v)!="Number"){return(v.toLowerCase()=="desc")?1:0;}else{return(v==1)?1:0;}}function isValueInArray(v,a){var l=a.length;for(var i=0;i<l;i++){if(a[i][0]==v){return true;}}return false;}function setHeadersCss(table,$headers,list,css){$headers.removeClass(css[0]).removeClass(css[1]);var h=[];$headers.each(function(offset){if(!this.sortDisabled){h[this.column]=$(this);}});var l=list.length;for(var i=0;i<l;i++){h[list[i][0]].addClass(css[list[i][1]]);}}function fixColumnWidth(table,$headers){var c=table.config;if(c.widthFixed){var colgroup=$('<colgroup>');$("tr:first td",table.tBodies[0]).each(function(){colgroup.append($('<col>').css('width',$(this).width()));});$(table).prepend(colgroup);};}function updateHeaderSortCount(table,sortList){var c=table.config,l=sortList.length;for(var i=0;i<l;i++){var s=sortList[i],o=c.headerList[s[0]];o.count=s[1];o.count++;}}function multisort(table,sortList,cache){if(table.config.debug){var sortTime=new Date();}var dynamicExp="var sortWrapper = function(a,b) {",l=sortList.length;for(var i=0;i<l;i++){var c=sortList[i][0];var order=sortList[i][1];var s=(table.config.parsers[c].type=="text")?((order==0)?makeSortFunction("text","asc",c):makeSortFunction("text","desc",c)):((order==0)?makeSortFunction("numeric","asc",c):makeSortFunction("numeric","desc",c));var e="e"+i;dynamicExp+="var "+e+" = "+s;dynamicExp+="if("+e+") { return "+e+"; } ";dynamicExp+="else { ";}var orgOrderCol=cache.normalized[0].length-1;dynamicExp+="return a["+orgOrderCol+"]-b["+orgOrderCol+"];";for(var i=0;i<l;i++){dynamicExp+="}; ";}dynamicExp+="return 0; ";dynamicExp+="}; ";if(table.config.debug){benchmark("Evaling expression:"+dynamicExp,new Date());}eval(dynamicExp);cache.normalized.sort(sortWrapper);if(table.config.debug){benchmark("Sorting on "+sortList.toString()+" and dir "+order+" time:",sortTime);}return cache;};function makeSortFunction(type,direction,index){var a="a["+index+"]",b="b["+index+"]";if(type=='text'&&direction=='asc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+a+" < "+b+") ? -1 : 1 )));";}else if(type=='text'&&direction=='desc'){return"("+a+" == "+b+" ? 0 : ("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : ("+b+" < "+a+") ? -1 : 1 )));";}else if(type=='numeric'&&direction=='asc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+a+" - "+b+"));";}else if(type=='numeric'&&direction=='desc'){return"("+a+" === null && "+b+" === null) ? 0 :("+a+" === null ? Number.POSITIVE_INFINITY : ("+b+" === null ? Number.NEGATIVE_INFINITY : "+b+" - "+a+"));";}};function makeSortText(i){return"((a["+i+"] < b["+i+"]) ? -1 : ((a["+i+"] > b["+i+"]) ? 1 : 0));";};function makeSortTextDesc(i){return"((b["+i+"] < a["+i+"]) ? -1 : ((b["+i+"] > a["+i+"]) ? 1 : 0));";};function makeSortNumeric(i){return"a["+i+"]-b["+i+"];";};function makeSortNumericDesc(i){return"b["+i+"]-a["+i+"];";};function sortText(a,b){if(table.config.sortLocaleCompare)return a.localeCompare(b);return((a<b)?-1:((a>b)?1:0));};function sortTextDesc(a,b){if(table.config.sortLocaleCompare)return b.localeCompare(a);return((b<a)?-1:((b>a)?1:0));};function sortNumeric(a,b){return a-b;};function sortNumericDesc(a,b){return b-a;};function getCachedSortType(parsers,i){return parsers[i].type;};this.construct=function(settings){return this.each(function(){if(!this.tHead||!this.tBodies)return;var $this,$document,$headers,cache,config,shiftDown=0,sortOrder;this.config={};config=$.extend(this.config,$.tablesorter.defaults,settings);$this=$(this);$.data(this,"tablesorter",config);$headers=buildHeaders(this);this.config.parsers=buildParserCache(this,$headers);cache=buildCache(this);var sortCSS=[config.cssDesc,config.cssAsc];fixColumnWidth(this);$headers.click(function(e){var totalRows=($this[0].tBodies[0]&&$this[0].tBodies[0].rows.length)||0;if(!this.sortDisabled&&totalRows>0){$this.trigger("sortStart");var $cell=$(this);var i=this.column;this.order=this.count++%2;if(this.lockedOrder)this.order=this.lockedOrder;if(!e[config.sortMultiSortKey]){config.sortList=[];if(config.sortForce!=null){var a=config.sortForce;for(var j=0;j<a.length;j++){if(a[j][0]!=i){config.sortList.push(a[j]);}}}config.sortList.push([i,this.order]);}else{if(isValueInArray(i,config.sortList)){for(var j=0;j<config.sortList.length;j++){var s=config.sortList[j],o=config.headerList[s[0]];if(s[0]==i){o.count=s[1];o.count++;s[1]=o.count%2;}}}else{config.sortList.push([i,this.order]);}};setTimeout(function(){setHeadersCss($this[0],$headers,config.sortList,sortCSS);appendToTable($this[0],multisort($this[0],config.sortList,cache));},1);return false;}}).mousedown(function(){if(config.cancelSelection){this.onselectstart=function(){return false};return false;}});$this.bind("update",function(){var me=this;setTimeout(function(){me.config.parsers=buildParserCache(me,$headers);cache=buildCache(me);},1);}).bind("updateCell",function(e,cell){var config=this.config;var pos=[(cell.parentNode.rowIndex-1),cell.cellIndex];cache.normalized[pos[0]][pos[1]]=config.parsers[pos[1]].format(getElementText(config,cell),cell);}).bind("sorton",function(e,list){$(this).trigger("sortStart");config.sortList=list;var sortList=config.sortList;updateHeaderSortCount(this,sortList);setHeadersCss(this,$headers,sortList,sortCSS);appendToTable(this,multisort(this,sortList,cache));}).bind("appendCache",function(){appendToTable(this,cache);}).bind("applyWidgetId",function(e,id){getWidgetById(id).format(this);}).bind("applyWidgets",function(){applyWidget(this);});if($.metadata&&($(this).metadata()&&$(this).metadata().sortlist)){config.sortList=$(this).metadata().sortlist;}if(config.sortList.length>0){$this.trigger("sorton",[config.sortList]);}applyWidget(this);});};this.addParser=function(parser){var l=parsers.length,a=true;for(var i=0;i<l;i++){if(parsers[i].id.toLowerCase()==parser.id.toLowerCase()){a=false;}}if(a){parsers.push(parser);};};this.addWidget=function(widget){widgets.push(widget);};this.formatFloat=function(s){var i=parseFloat(s);return(isNaN(i))?0:i;};this.formatInt=function(s){var i=parseInt(s);return(isNaN(i))?0:i;};this.isDigit=function(s,config){return/^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g,'')));};this.clearTableBody=function(table){if($.browser.msie){function empty(){while(this.firstChild)this.removeChild(this.firstChild);}empty.apply(table.tBodies[0]);}else{table.tBodies[0].innerHTML="";}};}});$.fn.extend({tablesorter:$.tablesorter.construct});var ts=$.tablesorter;ts.addParser({id:"text",is:function(s){return true;},format:function(s){return $.trim(s.toLocaleLowerCase());},type:"text"});ts.addParser({id:"digit",is:function(s,table){var c=table.config;return $.tablesorter.isDigit(s,c);},format:function(s){return $.tablesorter.formatFloat(s);},type:"numeric"});ts.addParser({id:"currency",is:function(s){return/^[£$€?.]/.test(s);},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g),""));},type:"numeric"});ts.addParser({id:"ipAddress",is:function(s){return/^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s);},format:function(s){var a=s.split("."),r="",l=a.length;for(var i=0;i<l;i++){var item=a[i];if(item.length==2){r+="0"+item;}else{r+=item;}}return $.tablesorter.formatFloat(r);},type:"numeric"});ts.addParser({id:"url",is:function(s){return/^(https?|ftp|file):\/\/$/.test(s);},format:function(s){return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//),''));},type:"text"});ts.addParser({id:"isoDate",is:function(s){return/^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s);},format:function(s){return $.tablesorter.formatFloat((s!="")?new Date(s.replace(new RegExp(/-/g),"/")).getTime():"0");},type:"numeric"});ts.addParser({id:"percent",is:function(s){return/\%$/.test($.trim(s));},format:function(s){return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g),""));},type:"numeric"});ts.addParser({id:"usLongDate",is:function(s){return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/));},format:function(s){return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"shortDate",is:function(s){return/\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s);},format:function(s,table){var c=table.config;s=s.replace(/\-/g,"/");if(c.dateFormat=="us"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$1/$2");}else if(c.dateFormat=="uk"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/,"$3/$2/$1");}else if(c.dateFormat=="dd/mm/yy"||c.dateFormat=="dd-mm-yy"){s=s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/,"$1/$2/$3");}return $.tablesorter.formatFloat(new Date(s).getTime());},type:"numeric"});ts.addParser({id:"time",is:function(s){return/^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s);},format:function(s){return $.tablesorter.formatFloat(new Date("2000/01/01 "+s).getTime());},type:"numeric"});ts.addParser({id:"metadata",is:function(s){return false;},format:function(s,table,cell){var c=table.config,p=(!c.parserMetadataName)?'sortValue':c.parserMetadataName;return $(cell).metadata()[p];},type:"numeric"});ts.addWidget({id:"zebra",format:function(table){if(table.config.debug){var time=new Date();}var $tr,row=-1,odd;$("tr:visible",table.tBodies[0]).each(function(i){$tr=$(this);if(!$tr.hasClass(table.config.cssChildRow))row++;odd=(row%2==0);$tr.removeClass(table.config.widgetZebra.css[odd?0:1]).addClass(table.config.widgetZebra.css[odd?1:0])});if(table.config.debug){$.tablesorter.benchmark("Applying Zebra widget",time);}}});})(jQuery);
|
@@ -0,0 +1,184 @@
|
|
1
|
+
(function($) {
|
2
|
+
$.extend({
|
3
|
+
tablesorterPager: new function() {
|
4
|
+
|
5
|
+
function updatePageDisplay(c) {
|
6
|
+
var s = $(c.cssPageDisplay,c.container).val((c.page+1) + c.seperator + c.totalPages);
|
7
|
+
}
|
8
|
+
|
9
|
+
function setPageSize(table,size) {
|
10
|
+
var c = table.config;
|
11
|
+
c.size = size;
|
12
|
+
c.totalPages = Math.ceil(c.totalRows / c.size);
|
13
|
+
c.pagerPositionSet = false;
|
14
|
+
moveToPage(table);
|
15
|
+
fixPosition(table);
|
16
|
+
}
|
17
|
+
|
18
|
+
function fixPosition(table) {
|
19
|
+
var c = table.config;
|
20
|
+
if(!c.pagerPositionSet && c.positionFixed) {
|
21
|
+
var c = table.config, o = $(table);
|
22
|
+
if(o.offset) {
|
23
|
+
c.container.css({
|
24
|
+
top: o.offset().top + o.height() + 'px',
|
25
|
+
position: 'absolute'
|
26
|
+
});
|
27
|
+
}
|
28
|
+
c.pagerPositionSet = true;
|
29
|
+
}
|
30
|
+
}
|
31
|
+
|
32
|
+
function moveToFirstPage(table) {
|
33
|
+
var c = table.config;
|
34
|
+
c.page = 0;
|
35
|
+
moveToPage(table);
|
36
|
+
}
|
37
|
+
|
38
|
+
function moveToLastPage(table) {
|
39
|
+
var c = table.config;
|
40
|
+
c.page = (c.totalPages-1);
|
41
|
+
moveToPage(table);
|
42
|
+
}
|
43
|
+
|
44
|
+
function moveToNextPage(table) {
|
45
|
+
var c = table.config;
|
46
|
+
c.page++;
|
47
|
+
if(c.page >= (c.totalPages-1)) {
|
48
|
+
c.page = (c.totalPages-1);
|
49
|
+
}
|
50
|
+
moveToPage(table);
|
51
|
+
}
|
52
|
+
|
53
|
+
function moveToPrevPage(table) {
|
54
|
+
var c = table.config;
|
55
|
+
c.page--;
|
56
|
+
if(c.page <= 0) {
|
57
|
+
c.page = 0;
|
58
|
+
}
|
59
|
+
moveToPage(table);
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
function moveToPage(table) {
|
64
|
+
var c = table.config;
|
65
|
+
if(c.page < 0 || c.page > (c.totalPages-1)) {
|
66
|
+
c.page = 0;
|
67
|
+
}
|
68
|
+
|
69
|
+
renderTable(table,c.rowsCopy);
|
70
|
+
}
|
71
|
+
|
72
|
+
function renderTable(table,rows) {
|
73
|
+
|
74
|
+
var c = table.config;
|
75
|
+
var l = rows.length;
|
76
|
+
var s = (c.page * c.size);
|
77
|
+
var e = (s + c.size);
|
78
|
+
if(e > rows.length ) {
|
79
|
+
e = rows.length;
|
80
|
+
}
|
81
|
+
|
82
|
+
|
83
|
+
var tableBody = $(table.tBodies[0]);
|
84
|
+
|
85
|
+
// clear the table body
|
86
|
+
|
87
|
+
$.tablesorter.clearTableBody(table);
|
88
|
+
|
89
|
+
for(var i = s; i < e; i++) {
|
90
|
+
|
91
|
+
//tableBody.append(rows[i]);
|
92
|
+
|
93
|
+
var o = rows[i];
|
94
|
+
var l = o.length;
|
95
|
+
for(var j=0; j < l; j++) {
|
96
|
+
|
97
|
+
tableBody[0].appendChild(o[j]);
|
98
|
+
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
fixPosition(table,tableBody);
|
103
|
+
|
104
|
+
$(table).trigger("applyWidgets");
|
105
|
+
|
106
|
+
if( c.page >= c.totalPages ) {
|
107
|
+
moveToLastPage(table);
|
108
|
+
}
|
109
|
+
|
110
|
+
updatePageDisplay(c);
|
111
|
+
}
|
112
|
+
|
113
|
+
this.appender = function(table,rows) {
|
114
|
+
|
115
|
+
var c = table.config;
|
116
|
+
|
117
|
+
c.rowsCopy = rows;
|
118
|
+
c.totalRows = rows.length;
|
119
|
+
c.totalPages = Math.ceil(c.totalRows / c.size);
|
120
|
+
|
121
|
+
renderTable(table,rows);
|
122
|
+
};
|
123
|
+
|
124
|
+
this.defaults = {
|
125
|
+
size: 10,
|
126
|
+
offset: 0,
|
127
|
+
page: 0,
|
128
|
+
totalRows: 0,
|
129
|
+
totalPages: 0,
|
130
|
+
container: null,
|
131
|
+
cssNext: '.next',
|
132
|
+
cssPrev: '.prev',
|
133
|
+
cssFirst: '.first',
|
134
|
+
cssLast: '.last',
|
135
|
+
cssPageDisplay: '.pagedisplay',
|
136
|
+
cssPageSize: '.pagesize',
|
137
|
+
seperator: "/",
|
138
|
+
positionFixed: true,
|
139
|
+
appender: this.appender
|
140
|
+
};
|
141
|
+
|
142
|
+
this.construct = function(settings) {
|
143
|
+
|
144
|
+
return this.each(function() {
|
145
|
+
|
146
|
+
config = $.extend(this.config, $.tablesorterPager.defaults, settings);
|
147
|
+
|
148
|
+
var table = this, pager = config.container;
|
149
|
+
|
150
|
+
$(this).trigger("appendCache");
|
151
|
+
|
152
|
+
config.size = parseInt($(".pagesize",pager).val());
|
153
|
+
|
154
|
+
$(config.cssFirst,pager).click(function() {
|
155
|
+
moveToFirstPage(table);
|
156
|
+
return false;
|
157
|
+
});
|
158
|
+
$(config.cssNext,pager).click(function() {
|
159
|
+
moveToNextPage(table);
|
160
|
+
return false;
|
161
|
+
});
|
162
|
+
$(config.cssPrev,pager).click(function() {
|
163
|
+
moveToPrevPage(table);
|
164
|
+
return false;
|
165
|
+
});
|
166
|
+
$(config.cssLast,pager).click(function() {
|
167
|
+
moveToLastPage(table);
|
168
|
+
return false;
|
169
|
+
});
|
170
|
+
$(config.cssPageSize,pager).change(function() {
|
171
|
+
setPageSize(table,parseInt($(this).val()));
|
172
|
+
return false;
|
173
|
+
});
|
174
|
+
});
|
175
|
+
};
|
176
|
+
|
177
|
+
}
|
178
|
+
});
|
179
|
+
// extend plugin scope
|
180
|
+
$.fn.extend({
|
181
|
+
tablesorterPager: $.tablesorterPager.construct
|
182
|
+
});
|
183
|
+
|
184
|
+
})(jQuery);
|
@@ -0,0 +1,25 @@
|
|
1
|
+
//= require jquery
|
2
|
+
//= require_tree .
|
3
|
+
|
4
|
+
$(function() {
|
5
|
+
$.livequery.registerPlugin("tablesorter", "tablesorterPager");
|
6
|
+
|
7
|
+
$('.mail a.preview').livequery(function() {
|
8
|
+
console.log(this);
|
9
|
+
$(this).colorbox({width:"80%", height:"80%", iframe:true});
|
10
|
+
});
|
11
|
+
|
12
|
+
$('.mail a.raw').live('click', function(){
|
13
|
+
$.get($(this).attr('href'), function(data){
|
14
|
+
$('#raw div').text(data);
|
15
|
+
});
|
16
|
+
return false;
|
17
|
+
});
|
18
|
+
|
19
|
+
$("table").tablesorter({
|
20
|
+
widthFixed: true,
|
21
|
+
sortList: [[3, 1]]
|
22
|
+
}).tablesorterPager({
|
23
|
+
container: $("#pager")
|
24
|
+
});
|
25
|
+
});
|
@@ -0,0 +1,82 @@
|
|
1
|
+
/*
|
2
|
+
ColorBox Core Style:
|
3
|
+
The following CSS is consistent between example themes and should not be altered.
|
4
|
+
*/
|
5
|
+
#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:9999; overflow:hidden;}
|
6
|
+
#cboxOverlay{position:fixed; width:100%; height:100%;}
|
7
|
+
#cboxMiddleLeft, #cboxBottomLeft{clear:left;}
|
8
|
+
#cboxContent{position:relative;}
|
9
|
+
#cboxLoadedContent{overflow:auto;}
|
10
|
+
#cboxTitle{margin:0;}
|
11
|
+
#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%;}
|
12
|
+
#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;}
|
13
|
+
.cboxPhoto{float:left; margin:auto; border:0; display:block;}
|
14
|
+
.cboxIframe{width:100%; height:100%; display:block; border:0;}
|
15
|
+
|
16
|
+
/*
|
17
|
+
User Style:
|
18
|
+
Change the following styles to modify the appearance of ColorBox. They are
|
19
|
+
ordered & tabbed in a way that represents the nesting of the generated HTML.
|
20
|
+
*/
|
21
|
+
#cboxOverlay{background:url(colorbox/overlay.png) repeat 0 0;}
|
22
|
+
#colorbox{}
|
23
|
+
#cboxTopLeft{width:21px; height:21px; background:url(colorbox/controls.png) no-repeat -100px 0;}
|
24
|
+
#cboxTopRight{width:21px; height:21px; background:url(colorbox/controls.png) no-repeat -129px 0;}
|
25
|
+
#cboxBottomLeft{width:21px; height:21px; background:url(colorbox/controls.png) no-repeat -100px -29px;}
|
26
|
+
#cboxBottomRight{width:21px; height:21px; background:url(colorbox/controls.png) no-repeat -129px -29px;}
|
27
|
+
#cboxMiddleLeft{width:21px; background:url(colorbox/controls.png) left top repeat-y;}
|
28
|
+
#cboxMiddleRight{width:21px; background:url(colorbox/controls.png) right top repeat-y;}
|
29
|
+
#cboxTopCenter{height:21px; background:url(colorbox/border.png) 0 0 repeat-x;}
|
30
|
+
#cboxBottomCenter{height:21px; background:url(colorbox/border.png) 0 -29px repeat-x;}
|
31
|
+
#cboxContent{background:#fff; overflow:hidden;}
|
32
|
+
#cboxError{padding:50px; border:1px solid #ccc;}
|
33
|
+
#cboxLoadedContent{margin-bottom:28px;}
|
34
|
+
#cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;}
|
35
|
+
#cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;}
|
36
|
+
#cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;}
|
37
|
+
#cboxPrevious{position:absolute; bottom:0; left:0; background:url(colorbox/controls.png) no-repeat -75px 0; width:25px; height:25px; text-indent:-9999px;}
|
38
|
+
#cboxPrevious.hover{background-position:-75px -25px;}
|
39
|
+
#cboxNext{position:absolute; bottom:0; left:27px; background:url(colorbox/controls.png) no-repeat -50px 0; width:25px; height:25px; text-indent:-9999px;}
|
40
|
+
#cboxNext.hover{background-position:-50px -25px;}
|
41
|
+
#cboxLoadingOverlay{background:url(colorbox/loading_background.png) no-repeat center center;}
|
42
|
+
#cboxLoadingGraphic{background:url(colorbox/loading.gif) no-repeat center center;}
|
43
|
+
#cboxClose{position:absolute; bottom:0; right:0; background:url(colorbox/controls.png) no-repeat -25px 0; width:25px; height:25px; text-indent:-9999px;}
|
44
|
+
#cboxClose.hover{background-position:-25px -25px;}
|
45
|
+
|
46
|
+
/*
|
47
|
+
The following fixes a problem where IE7 and IE8 replace a PNG's alpha transparency with a black fill
|
48
|
+
when an alpha filter (opacity change) is set on the element or ancestor element. This style is not applied to IE9.
|
49
|
+
*/
|
50
|
+
.cboxIE #cboxTopLeft,
|
51
|
+
.cboxIE #cboxTopCenter,
|
52
|
+
.cboxIE #cboxTopRight,
|
53
|
+
.cboxIE #cboxBottomLeft,
|
54
|
+
.cboxIE #cboxBottomCenter,
|
55
|
+
.cboxIE #cboxBottomRight,
|
56
|
+
.cboxIE #cboxMiddleLeft,
|
57
|
+
.cboxIE #cboxMiddleRight {
|
58
|
+
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#00FFFFFF,endColorstr=#00FFFFFF);
|
59
|
+
}
|
60
|
+
|
61
|
+
/*
|
62
|
+
The following provides PNG transparency support for IE6
|
63
|
+
*/
|
64
|
+
.cboxIE6 #cboxTopLeft{background:url(colorbox/ie6/borderTopLeft.png);}
|
65
|
+
.cboxIE6 #cboxTopCenter{background:url(colorbox/ie6/borderTopCenter.png);}
|
66
|
+
.cboxIE6 #cboxTopRight{background:url(colorbox/ie6/borderTopRight.png);}
|
67
|
+
.cboxIE6 #cboxBottomLeft{background:url(colorbox/ie6/borderBottomLeft.png);}
|
68
|
+
.cboxIE6 #cboxBottomCenter{background:url(colorbox/ie6/borderBottomCenter.png);}
|
69
|
+
.cboxIE6 #cboxBottomRight{background:url(colorbox/ie6/borderBottomRight.png);}
|
70
|
+
.cboxIE6 #cboxMiddleLeft{background:url(colorbox/ie6/borderMiddleLeft.png);}
|
71
|
+
.cboxIE6 #cboxMiddleRight{background:url(colorbox/ie6/borderMiddleRight.png);}
|
72
|
+
|
73
|
+
.cboxIE6 #cboxTopLeft,
|
74
|
+
.cboxIE6 #cboxTopCenter,
|
75
|
+
.cboxIE6 #cboxTopRight,
|
76
|
+
.cboxIE6 #cboxBottomLeft,
|
77
|
+
.cboxIE6 #cboxBottomCenter,
|
78
|
+
.cboxIE6 #cboxBottomRight,
|
79
|
+
.cboxIE6 #cboxMiddleLeft,
|
80
|
+
.cboxIE6 #cboxMiddleRight {
|
81
|
+
_behavior: expression(this.src = this.src ? this.src : this.currentStyle.backgroundImage.split('"')[1], this.style.background = "none", this.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src=" + this.src + ", sizingMethod='scale')");
|
82
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
div.tablesorterPager {
|
2
|
+
padding: 10px 0 10px 0;
|
3
|
+
background-color: #D6D2C2;
|
4
|
+
text-align: center;
|
5
|
+
}
|
6
|
+
div.tablesorterPager span {
|
7
|
+
padding: 0 5px 0 5px;
|
8
|
+
}
|
9
|
+
div.tablesorterPager input.prev {
|
10
|
+
width: auto;
|
11
|
+
margin-right: 10px;
|
12
|
+
}
|
13
|
+
div.tablesorterPager input.next {
|
14
|
+
width: auto;
|
15
|
+
margin-left: 10px;
|
16
|
+
}
|
17
|
+
div.tablesorterPager input {
|
18
|
+
font-size: 8px;
|
19
|
+
width: 50px;
|
20
|
+
border: 1px solid #330000;
|
21
|
+
text-align: center;
|
22
|
+
}
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*= require_tree .
|
7
|
+
*/
|
8
|
+
|
9
|
+
#pager {
|
10
|
+
margin-top: 10px;
|
11
|
+
}
|
12
|
+
|
13
|
+
.pagedisplay {
|
14
|
+
width: 56px;
|
15
|
+
}
|
16
|
+
|
17
|
+
.pagesize {
|
18
|
+
width: 56px;
|
19
|
+
}
|
20
|
+
|
21
|
+
#raw{
|
22
|
+
width: 906px;
|
23
|
+
margin-top: 40px;
|
24
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
/* tables */
|
2
|
+
table.tablesorter {
|
3
|
+
font-family:arial;
|
4
|
+
background-color: #CDCDCD;
|
5
|
+
margin:10px 0pt 15px;
|
6
|
+
font-size: 12px;
|
7
|
+
width: 100%;
|
8
|
+
text-align: left;
|
9
|
+
}
|
10
|
+
table.tablesorter thead tr th, table.tablesorter tfoot tr th {
|
11
|
+
background-color: #e6EEEE;
|
12
|
+
border: 1px solid #FFF;
|
13
|
+
font-size: 12px;
|
14
|
+
padding: 4px;
|
15
|
+
}
|
16
|
+
table.tablesorter thead tr .header {
|
17
|
+
background-image: url(tablesorter/bg.gif);
|
18
|
+
background-repeat: no-repeat;
|
19
|
+
background-position: center right;
|
20
|
+
cursor: pointer;
|
21
|
+
}
|
22
|
+
table.tablesorter tbody td {
|
23
|
+
color: #3D3D3D;
|
24
|
+
padding: 4px;
|
25
|
+
background-color: #FFF;
|
26
|
+
vertical-align: top;
|
27
|
+
}
|
28
|
+
table.tablesorter tbody tr.odd td {
|
29
|
+
background-color:#F0F0F6;
|
30
|
+
}
|
31
|
+
table.tablesorter thead tr .headerSortUp {
|
32
|
+
background-image: url(tablesorter/asc.gif);
|
33
|
+
}
|
34
|
+
table.tablesorter thead tr .headerSortDown {
|
35
|
+
background-image: url(tablesorter/desc.gif);
|
36
|
+
}
|
37
|
+
table.tablesorter thead tr .headerSortDown, table.tablesorter thead tr .headerSortUp {
|
38
|
+
background-color: #8dbdd8;
|
39
|
+
}
|
40
|
+
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module MailsViewer
|
2
|
+
class HomeController < ActionController::Base
|
3
|
+
layout false
|
4
|
+
before_filter :disabled_on_production
|
5
|
+
before_filter :find_absolute_filename, only: [:raw, :html, :attachment, :plain]
|
6
|
+
|
7
|
+
def index
|
8
|
+
Dir.chdir(mails_path) do
|
9
|
+
@mails = Dir["**/*"]
|
10
|
+
.select{|f| File.file?(f)}
|
11
|
+
.map{|f| [Mail.read(f), f]}
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def raw
|
16
|
+
if @filename
|
17
|
+
render text: File.read(@filename)
|
18
|
+
else
|
19
|
+
head :not_found
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def html
|
24
|
+
if @filename
|
25
|
+
mail = Mail.read(@filename)
|
26
|
+
body = mail.html_part ? mail.html_part.body : mail.body
|
27
|
+
render text: body
|
28
|
+
else
|
29
|
+
head :not_found
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def plain
|
34
|
+
if @filename
|
35
|
+
mail = Mail.read(@filename)
|
36
|
+
@body = mail.text_part ? mail.text_part.body.to_s : mail.body.to_s
|
37
|
+
else
|
38
|
+
head :not_found
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def attachment
|
43
|
+
if @filename
|
44
|
+
mail = Mail.read(@filename)
|
45
|
+
attachment = mail.attachments[params[:attachment]]
|
46
|
+
|
47
|
+
if attachment
|
48
|
+
send_data attachment.body.decoded, filename: params[:attachment], type: attachment.content_type and return
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
head :not_found
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def mails_path
|
57
|
+
@mails_path ||= File.expand_path(Rails.application.config.action_mailer.file_settings.try(:[], :location) || './tmp/mails',
|
58
|
+
Rails.root)
|
59
|
+
end
|
60
|
+
|
61
|
+
def disabled_on_production
|
62
|
+
if Rails.env == 'production' || Rails.application.config.action_mailer.delivery_method.to_sym != :file
|
63
|
+
render text: 'Mails Viewer is disabled' and return false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def find_absolute_filename
|
68
|
+
if params[:filename].present?
|
69
|
+
filename = File.expand_path(params[:filename], mails_path)
|
70
|
+
|
71
|
+
# ensure the file is in mails_path
|
72
|
+
if filename == File.join(mails_path, params[:filename])
|
73
|
+
@filename = filename
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module MailsViewer
|
2
|
+
module HomeHelper
|
3
|
+
def email_path(filename, format = :raw)
|
4
|
+
url_for(controller: "mails_viewer/home", action: format, filename: filename)
|
5
|
+
end
|
6
|
+
|
7
|
+
def attachment_path(filename, attachment_name)
|
8
|
+
url_for(controller: "mails_viewer/home", action: :attachment, filename: filename, attachment: attachment_name)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Mailer</title>
|
5
|
+
<%= stylesheet_link_tag "mails_viewer" %>
|
6
|
+
<%= javascript_include_tag "mails_viewer" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
</head>
|
9
|
+
<body>
|
10
|
+
|
11
|
+
<div class="container">
|
12
|
+
<div id="list">
|
13
|
+
<table class="tablesorter">
|
14
|
+
<thead><tr><th>From</th><th>To</th><th>Subject</th><th>Date</th></thead>
|
15
|
+
<tbody>
|
16
|
+
<% @mails.each do |mail, filename| %>
|
17
|
+
<tr class="mail">
|
18
|
+
<td><%= mail.from.join(', ') %></td>
|
19
|
+
<td><%= mail.to.join(', ') %></td>
|
20
|
+
<td>
|
21
|
+
<%= mail.subject %>
|
22
|
+
<% if mail.html_part || mail.content_type =~ /html/ %>
|
23
|
+
<a href="<%= email_path(filename, :html) %>" class="html preview">html</a>
|
24
|
+
<% end %>
|
25
|
+
<% if mail.text_part || mail.content_type =~ /plain/ %>
|
26
|
+
<a href="<%= email_path(filename, :plain) %>" class="plain preview">plain</a>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<% mail.attachments.each do |attachment| %>
|
30
|
+
<a href="<%= attachment_path(filename, attachment.filename) %>" class="attachment preview"><%= attachment.filename %></a>
|
31
|
+
<% end %>
|
32
|
+
<a href="<%= email_path(filename, :raw) %>" class="raw">raw</a>
|
33
|
+
</td>
|
34
|
+
<td><%= mail.date.to_s(:long) %></td>
|
35
|
+
</tr>
|
36
|
+
<% end %>
|
37
|
+
</tbody>
|
38
|
+
</table>
|
39
|
+
|
40
|
+
<div id="pager" class="pager">
|
41
|
+
<form>
|
42
|
+
<input type="text" class="pagedisplay"/>
|
43
|
+
<select class="pagesize">
|
44
|
+
<option selected="selected" value="10">10</option>
|
45
|
+
<option value="20">20</option>
|
46
|
+
<option value="30">30</option>
|
47
|
+
<option value="40">40</option>
|
48
|
+
</select>
|
49
|
+
<img src="/assets/tablesorter/first.png" class="first"/>
|
50
|
+
<img src="/assets/tablesorter/prev.png" class="prev"/>
|
51
|
+
<img src="/assets/tablesorter/next.png" class="next"/>
|
52
|
+
<img src="/assets/tablesorter/last.png" class="last"/>
|
53
|
+
</form>
|
54
|
+
</div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<pre id='raw'>
|
58
|
+
<h3>Click link above to view original email content here!</h3>
|
59
|
+
<div></div>
|
60
|
+
</pre>
|
61
|
+
</div>
|
62
|
+
</body>
|
63
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
<pre><%= CGI.escapeHTML(@body) %></pre>
|
data/config/routes.rb
ADDED
data/lib/mails_viewer.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'mails_viewer'
|
2
|
+
require 'rails'
|
3
|
+
|
4
|
+
module MailsViewer
|
5
|
+
class Engine < Rails::Engine
|
6
|
+
engine_name = :mails_viewer
|
7
|
+
isolate_namespace MailsViewer
|
8
|
+
|
9
|
+
# Enabling assets precompiling under rails 3.1
|
10
|
+
if Rails.version >= '3.1' && Rails.env != 'production'
|
11
|
+
initializer :assets do |app|
|
12
|
+
app.config.assets.precompile += %w(mails_viewer.js mails_viewer.css)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Mail::FileDelivery.class_eval do
|
2
|
+
# We need to save the mail to seperate files when have several destination addresses
|
3
|
+
# So we generate different file name and save them.
|
4
|
+
def deliver!(mail)
|
5
|
+
if ::File.respond_to?(:makedirs)
|
6
|
+
::File.makedirs settings[:location]
|
7
|
+
else
|
8
|
+
::FileUtils.mkdir_p settings[:location]
|
9
|
+
end
|
10
|
+
|
11
|
+
mail.destinations.uniq.each do |to|
|
12
|
+
::File.open(::File.join(settings[:location], mail.filename_for(to)), 'w') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Mail
|
2
|
+
class Message
|
3
|
+
|
4
|
+
#def html_part
|
5
|
+
#find_first_mime_type('text/html')
|
6
|
+
#end
|
7
|
+
|
8
|
+
# Save the mail to seperate files when have several destination addresses
|
9
|
+
# This function used to return a filename by mail's date and destination address
|
10
|
+
def filename_for(to)
|
11
|
+
"#{date.to_time.to_i}.#{to}.txt"
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mails_viewer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Youcai Qian
|
9
|
+
- Dingding Ye
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2012-09-02 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.1.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 3.1.0
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: mail
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ~>
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: 2.4.0
|
39
|
+
type: :development
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: 2.4.0
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rspec
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 2.11.0
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.11.0
|
63
|
+
description: A mails preview Engine which provides a table view for all mails under
|
64
|
+
tmp/mails.
|
65
|
+
email:
|
66
|
+
- qycpublic@gmail.com
|
67
|
+
- yedingding@gmail.com
|
68
|
+
executables: []
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- app/assets/images/colorbox/border.png
|
73
|
+
- app/assets/images/colorbox/controls.png
|
74
|
+
- app/assets/images/colorbox/loading.gif
|
75
|
+
- app/assets/images/colorbox/loading_background.png
|
76
|
+
- app/assets/images/colorbox/overlay.png
|
77
|
+
- app/assets/images/tablesorter/asc.gif
|
78
|
+
- app/assets/images/tablesorter/bg.gif
|
79
|
+
- app/assets/images/tablesorter/desc.gif
|
80
|
+
- app/assets/images/tablesorter/first.png
|
81
|
+
- app/assets/images/tablesorter/last.png
|
82
|
+
- app/assets/images/tablesorter/next.png
|
83
|
+
- app/assets/images/tablesorter/prev.png
|
84
|
+
- app/assets/javascripts/jquery.colorbox-min.js
|
85
|
+
- app/assets/javascripts/jquery.livequery.js
|
86
|
+
- app/assets/javascripts/jquery.tablesorter.min.js
|
87
|
+
- app/assets/javascripts/jquery.tablesorter.pager.js
|
88
|
+
- app/assets/javascripts/mails_viewer.js
|
89
|
+
- app/assets/stylesheets/colorbox.css
|
90
|
+
- app/assets/stylesheets/jquery.tablesorter.pager.css
|
91
|
+
- app/assets/stylesheets/mails_viewer.css
|
92
|
+
- app/assets/stylesheets/table.css
|
93
|
+
- app/controllers/mails_viewer/home_controller.rb
|
94
|
+
- app/helper/mails_viewer/home_helper.rb
|
95
|
+
- app/views/mails_viewer/home/index.html.erb
|
96
|
+
- app/views/mails_viewer/home/plain.html.erb
|
97
|
+
- config/routes.rb
|
98
|
+
- lib/mails_viewer/engine.rb
|
99
|
+
- lib/mails_viewer/file_delivery.rb
|
100
|
+
- lib/mails_viewer/mail.rb
|
101
|
+
- lib/mails_viewer/version.rb
|
102
|
+
- lib/mails_viewer.rb
|
103
|
+
- lib/tasks/mails_viewer_tasks.rake
|
104
|
+
- LICENSE
|
105
|
+
- Gemfile
|
106
|
+
- Rakefile
|
107
|
+
- README.md
|
108
|
+
homepage: https://github.com/pragmaticly/mails_viewer
|
109
|
+
licenses: []
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ! '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.8.23
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: A mails preview Engine which provides a table view for all mails under tmp/mails.
|
132
|
+
test_files: []
|
133
|
+
has_rdoc:
|