1
0
mirror of https://github.com/jhillyerd/inbucket.git synced 2025-12-17 09:37:02 +00:00

Remove legacy theme 'integral'

This commit is contained in:
James Hillyerd
2016-12-31 01:41:13 +00:00
parent ff481c56c6
commit 493efb04cd
24 changed files with 4 additions and 1529 deletions

View File

@@ -195,8 +195,8 @@ func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
// Have to reset default mux to prevent duplicate routes
http.DefaultServeMux = http.NewServeMux()
cfg := config.WebConfig{
TemplateDir: "../themes/integral/templates",
PublicDir: "../themes/integral/public",
TemplateDir: "../themes/bootstrap/templates",
PublicDir: "../themes/bootstrap/public",
}
shutdownChan := make(chan bool)
httpd.Initialize(cfg, ds, shutdownChan)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 565 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 109 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 B

File diff suppressed because one or more lines are too long

View File

@@ -1,665 +0,0 @@
/*!
* jQuery Color Animations v@VERSION
* https://github.com/jquery/jquery-color
*
* Copyright 2012 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* Date: @DATE
*/
(function( jQuery, undefined ) {
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
// plusequals test for += 100 -= 100
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
// a set of RE's that can match strings and generate color tuples.
stringParsers = [{
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ],
execResult[ 3 ],
execResult[ 4 ]
];
}
}, {
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ] * 2.55,
execResult[ 2 ] * 2.55,
execResult[ 3 ] * 2.55,
execResult[ 4 ]
];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ], 16 )
];
}
}, {
// this regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
];
}
}, {
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
space: "hsla",
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ] / 100,
execResult[ 3 ] / 100,
execResult[ 4 ]
];
}
}],
// jQuery.Color( )
color = jQuery.Color = function( color, green, blue, alpha ) {
return new jQuery.Color.fn.parse( color, green, blue, alpha );
},
spaces = {
rgba: {
props: {
red: {
idx: 0,
type: "byte"
},
green: {
idx: 1,
type: "byte"
},
blue: {
idx: 2,
type: "byte"
}
}
},
hsla: {
props: {
hue: {
idx: 0,
type: "degrees"
},
saturation: {
idx: 1,
type: "percent"
},
lightness: {
idx: 2,
type: "percent"
}
}
}
},
propTypes = {
"byte": {
floor: true,
max: 255
},
"percent": {
max: 1
},
"degrees": {
mod: 360,
floor: true
}
},
support = color.support = {},
// element for support tests
supportElem = jQuery( "<p>" )[ 0 ],
// colors = jQuery.Color.names
colors,
// local aliases of functions called often
each = jQuery.each;
// determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
// define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
space.cache = "_" + spaceName;
space.props.alpha = {
idx: 3,
type: "percent",
def: 1
};
});
function clamp( value, prop, allowEmpty ) {
var type = propTypes[ prop.type ] || {};
if ( value == null ) {
return (allowEmpty || !prop.def) ? null : prop.def;
}
// ~~ is an short way of doing floor for positive numbers
value = type.floor ? ~~value : parseFloat( value );
// IE will pass in empty strings as value for alpha,
// which will hit this case
if ( isNaN( value ) ) {
return prop.def;
}
if ( type.mod ) {
// we add mod before modding to make sure that negatives values
// get converted properly: -10 -> 350
return (value + type.mod) % type.mod;
}
// for now all property types without mod have min and max
return 0 > value ? 0 : type.max < value ? type.max : value;
}
function stringParse( string ) {
var inst = color(),
rgba = inst._rgba = [];
string = string.toLowerCase();
each( stringParsers, function( i, parser ) {
var parsed,
match = parser.re.exec( string ),
values = match && parser.parse( match ),
spaceName = parser.space || "rgba";
if ( values ) {
parsed = inst[ spaceName ]( values );
// if this was an rgba parse the assignment might happen twice
// oh well....
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
rgba = inst._rgba = parsed._rgba;
// exit each( stringParsers ) here because we matched
return false;
}
});
// Found a stringParser that handled it
if ( rgba.length ) {
// if this came from a parsed string, force "transparent" when alpha is 0
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
if ( rgba.join() === "0,0,0,0" ) {
jQuery.extend( rgba, colors.transparent );
}
return inst;
}
// named colors
return colors[ string ];
}
color.fn = jQuery.extend( color.prototype, {
parse: function( red, green, blue, alpha ) {
if ( red === undefined ) {
this._rgba = [ null, null, null, null ];
return this;
}
if ( red.jquery || red.nodeType ) {
red = jQuery( red ).css( green );
green = undefined;
}
var inst = this,
type = jQuery.type( red ),
rgba = this._rgba = [],
source;
// more than 1 argument specified - assume ( red, green, blue, alpha )
if ( green !== undefined ) {
red = [ red, green, blue, alpha ];
type = "array";
}
if ( type === "string" ) {
return this.parse( stringParse( red ) || colors._default );
}
if ( type === "array" ) {
each( spaces.rgba.props, function( key, prop ) {
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
});
return this;
}
if ( type === "object" ) {
if ( red instanceof color ) {
each( spaces, function( spaceName, space ) {
if ( red[ space.cache ] ) {
inst[ space.cache ] = red[ space.cache ].slice();
}
});
} else {
each( spaces, function( spaceName, space ) {
var cache = space.cache;
each( space.props, function( key, prop ) {
// if the cache doesn't exist, and we know how to convert
if ( !inst[ cache ] && space.to ) {
// if the value was null, we don't need to copy it
// if the key was alpha, we don't need to copy it either
if ( key === "alpha" || red[ key ] == null ) {
return;
}
inst[ cache ] = space.to( inst._rgba );
}
// this is the only case where we allow nulls for ALL properties.
// call clamp with alwaysAllowEmpty
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
});
// everything defined but alpha?
if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
// use the default of 1
inst[ cache ][ 3 ] = 1;
if ( space.from ) {
inst._rgba = space.from( inst[ cache ] );
}
}
});
}
return this;
}
},
is: function( compare ) {
var is = color( compare ),
same = true,
inst = this;
each( spaces, function( _, space ) {
var localCache,
isCache = is[ space.cache ];
if (isCache) {
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
each( space.props, function( _, prop ) {
if ( isCache[ prop.idx ] != null ) {
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
return same;
}
});
}
return same;
});
return same;
},
_space: function() {
var used = [],
inst = this;
each( spaces, function( spaceName, space ) {
if ( inst[ space.cache ] ) {
used.push( spaceName );
}
});
return used.pop();
},
transition: function( other, distance ) {
var end = color( other ),
spaceName = end._space(),
space = spaces[ spaceName ],
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
start = startColor[ space.cache ] || space.to( startColor._rgba ),
result = start.slice();
end = end[ space.cache ];
each( space.props, function( key, prop ) {
var index = prop.idx,
startValue = start[ index ],
endValue = end[ index ],
type = propTypes[ prop.type ] || {};
// if null, don't override start value
if ( endValue === null ) {
return;
}
// if null - use end
if ( startValue === null ) {
result[ index ] = endValue;
} else {
if ( type.mod ) {
if ( endValue - startValue > type.mod / 2 ) {
startValue += type.mod;
} else if ( startValue - endValue > type.mod / 2 ) {
startValue -= type.mod;
}
}
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
}
});
return this[ spaceName ]( result );
},
blend: function( opaque ) {
// if we are already opaque - return ourself
if ( this._rgba[ 3 ] === 1 ) {
return this;
}
var rgb = this._rgba.slice(),
a = rgb.pop(),
blend = color( opaque )._rgba;
return color( jQuery.map( rgb, function( v, i ) {
return ( 1 - a ) * blend[ i ] + a * v;
}));
},
toRgbaString: function() {
var prefix = "rgba(",
rgba = jQuery.map( this._rgba, function( v, i ) {
return v == null ? ( i > 2 ? 1 : 0 ) : v;
});
if ( rgba[ 3 ] === 1 ) {
rgba.pop();
prefix = "rgb(";
}
return prefix + rgba.join() + ")";
},
toHslaString: function() {
var prefix = "hsla(",
hsla = jQuery.map( this.hsla(), function( v, i ) {
if ( v == null ) {
v = i > 2 ? 1 : 0;
}
// catch 1 and 2
if ( i && i < 3 ) {
v = Math.round( v * 100 ) + "%";
}
return v;
});
if ( hsla[ 3 ] === 1 ) {
hsla.pop();
prefix = "hsl(";
}
return prefix + hsla.join() + ")";
},
toHexString: function( includeAlpha ) {
var rgba = this._rgba.slice(),
alpha = rgba.pop();
if ( includeAlpha ) {
rgba.push( ~~( alpha * 255 ) );
}
return "#" + jQuery.map( rgba, function( v, i ) {
// default to 0 when nulls exist
v = ( v || 0 ).toString( 16 );
return v.length === 1 ? "0" + v : v;
}).join("");
},
toString: function() {
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
}
});
color.fn.parse.prototype = color.fn;
// hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
function hue2rgb( p, q, h ) {
h = ( h + 1 ) % 1;
if ( h * 6 < 1 ) {
return p + (q - p) * h * 6;
}
if ( h * 2 < 1) {
return q;
}
if ( h * 3 < 2 ) {
return p + (q - p) * ((2/3) - h) * 6;
}
return p;
}
spaces.hsla.to = function ( rgba ) {
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
return [ null, null, null, rgba[ 3 ] ];
}
var r = rgba[ 0 ] / 255,
g = rgba[ 1 ] / 255,
b = rgba[ 2 ] / 255,
a = rgba[ 3 ],
max = Math.max( r, g, b ),
min = Math.min( r, g, b ),
diff = max - min,
add = max + min,
l = add * 0.5,
h, s;
if ( min === max ) {
h = 0;
} else if ( r === max ) {
h = ( 60 * ( g - b ) / diff ) + 360;
} else if ( g === max ) {
h = ( 60 * ( b - r ) / diff ) + 120;
} else {
h = ( 60 * ( r - g ) / diff ) + 240;
}
// chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
if ( diff === 0 ) {
s = 0;
} else if ( l <= 0.5 ) {
s = diff / add;
} else {
s = diff / ( 2 - add );
}
return [ Math.round(h) % 360, s, l, a == null ? 1 : a ];
};
spaces.hsla.from = function ( hsla ) {
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
return [ null, null, null, hsla[ 3 ] ];
}
var h = hsla[ 0 ] / 360,
s = hsla[ 1 ],
l = hsla[ 2 ],
a = hsla[ 3 ],
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
p = 2 * l - q,
r, g, b;
return [
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Math.round( hue2rgb( p, q, h ) * 255 ),
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
a
];
};
each( spaces, function( spaceName, space ) {
var props = space.props,
cache = space.cache,
to = space.to,
from = space.from;
// makes rgba() and hsla()
color.fn[ spaceName ] = function( value ) {
// generate a cache for this space if it doesn't exist
if ( to && !this[ cache ] ) {
this[ cache ] = to( this._rgba );
}
if ( value === undefined ) {
return this[ cache ].slice();
}
var ret,
type = jQuery.type( value ),
arr = ( type === "array" || type === "object" ) ? value : arguments,
local = this[ cache ].slice();
each( props, function( key, prop ) {
var val = arr[ type === "object" ? key : prop.idx ];
if ( val == null ) {
val = local[ prop.idx ];
}
local[ prop.idx ] = clamp( val, prop );
});
if ( from ) {
ret = color( from( local ) );
ret[ cache ] = local;
return ret;
} else {
return color( local );
}
};
// makes red() green() blue() alpha() hue() saturation() lightness()
each( props, function( key, prop ) {
// alpha is included in more than one space
if ( color.fn[ key ] ) {
return;
}
color.fn[ key ] = function( value ) {
var vtype = jQuery.type( value ),
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
local = this[ fn ](),
cur = local[ prop.idx ],
match;
if ( vtype === "undefined" ) {
return cur;
}
if ( vtype === "function" ) {
value = value.call( this, cur );
vtype = jQuery.type( value );
}
if ( value == null && prop.empty ) {
return this;
}
if ( vtype === "string" ) {
match = rplusequals.exec( value );
if ( match ) {
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
}
}
local[ prop.idx ] = value;
return this[ fn ]( local );
};
});
});
// add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
var hooks = hook.split( " " );
each( hooks, function( i, hook ) {
jQuery.cssHooks[ hook ] = {
set: function( elem, value ) {
var parsed, curElem,
backgroundColor = "";
if ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) {
value = color( parsed || value );
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
while (
(backgroundColor === "" || backgroundColor === "transparent") &&
curElem && curElem.style
) {
try {
backgroundColor = jQuery.css( curElem, "backgroundColor" );
curElem = curElem.parentNode;
} catch ( e ) {
}
}
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
backgroundColor :
"_default" );
}
value = value.toRgbaString();
}
try {
elem.style[ hook ] = value;
} catch( value ) {
// wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit'
}
}
};
jQuery.fx.step[ hook ] = function( fx ) {
if ( !fx.colorInit ) {
fx.start = color( fx.elem, hook );
fx.end = color( fx.end );
fx.colorInit = true;
}
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
};
});
};
color.hook( stepHooks );
jQuery.cssHooks.borderColor = {
expand: function( value ) {
var expanded = {};
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
expanded[ "border" + part + "Color" ] = value;
});
return expanded;
}
};
// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {
// 4.1. Basic color keywords
aqua: "#00ffff",
black: "#000000",
blue: "#0000ff",
fuchsia: "#ff00ff",
gray: "#808080",
green: "#008000",
lime: "#00ff00",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
purple: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
teal: "#008080",
white: "#ffffff",
yellow: "#ffff00",
// 4.2.3. transparent color keyword
transparent: [ null, null, null, 0 ],
_default: "#ffffff"
};
})( jQuery );

File diff suppressed because one or more lines are too long

View File

@@ -1,354 +0,0 @@
/*
Design by Free CSS Templates
http://www.freecsstemplates.org
Released for free under a Creative Commons Attribution 2.5 License
*/
/* Elements */
body {
margin: 20px 0;
font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
font-size: 12px;
color: #808080;
}
h1 {
}
h2, h3, h4, h5, h6 {
color: #2582A4;
}
p, ol, ul {
text-align: justify;
}
strong {
font-weight: bold;
color: #808080;
}
a {
color: #87A019;
}
a:hover {
text-decoration: none;
color: #2582A4;
}
.box {
margin-bottom: 0;
padding-bottom: 0;
background: url(/public/images/img07.gif) repeat-x left bottom;
}
.bottom {
display: block;
margin-bottom: 0;
padding-bottom: 10px;
background: url(/public/images/img08.gif) no-repeat left bottom;
}
.image {
float: left;
margin: 3px 0 0 0;
padding: 0;
}
.indent {
margin-left: 125px;
}
/* Header */
#header {
width: 928px;
height: 37px;
margin: 0 auto;
background: #BECF74 url(/public/images/img01.gif) repeat-x;
border-bottom: 3px solid #FFFFFF;
}
/* Menu */
#menu {
float: left;
width: 600px;
height: 37px;
margin: 0;
padding: 0 0 0 10px;
list-style: none;
background: url(/public/images/img02.gif) no-repeat;
}
#menu li {
display: inline;
}
#menu a {
display: block;
float: left;
height: 27px;
padding: 10px 15px 0px 15px;
text-transform: lowercase;
text-decoration: none;
font-size: 12px;
font-weight: bold;
color: #FFFFFF;
}
#menu a:hover {
background: #A4B74C url(/public/images/img04.gif) repeat-x;
}
/* Search */
#search {
float: right;
height: 28px;
margin: 0;
padding: 9px 25px 0 0;
background: url(/public/images/img03.gif) no-repeat right top;
}
#search fieldset {
display: inline;
margin: 0;
padding: 0;
border: none;
}
#input1 {
width: 164px;
padding: 2px 5px;
background: #FFFFFF;
border: none;
}
#input2 {
height: 20px;
background: #87C4DB;
border: none;
text-transform: lowercase;
font-size: 10px;
font-weight: bold;
color: #FFFFFF;
}
/* Content */
#content {
width: 928px;
min-height: 300px;
margin: 0 auto;
}
#colOne {
float: left;
width: 238px;
background: url(/public/images/img05.gif) repeat-x;
}
#colOne h3 {
padding: 0 20px;
}
#colOne ul {
margin-left: 0;
padding-left: 20px;
padding-right: 20px;
list-style: none;
}
#colOne li {
padding: 5px 0;
border-top: 1px solid #EFEFEF;
}
#colOne li.first {
border: none;
}
#colTwo {
float: right;
width: 617px;
padding: 30px 40px 0 30px;
background: url(/public/images/img09.gif) repeat-x;
}
#colTwo h2 {
margin-top: 0;
font-size: 26px;
}
#colTwo h3 {
margin-bottom: 0;
font-size: 18px;
}
#colTwo h4 {
margin-top: 0;
font-size: 11px;
font-weight: normal;
}
#colTwo .box {
margin: 0 -30px 30px -20px;
padding: 0 30px 0 20px;
}
#colTwo .bottom {
margin: 0 0 20px -20px;
padding: 0 0 20px 20px;
}
/* Logo */
#logo {
height: 150px;
background: url(/public/images/img06.gif) no-repeat;
}
#logo h1, #logo h2, #logo a {
margin: 0;
padding: 0;
text-decoration: none;
text-transform: lowercase;
text-align: center;
color: #FFFFFF;
}
#logo h1 {
padding-top: 25px;
font-size: 34px;
}
#logo h2 {
margin-top: -5px;
font-size: 12px;
}
/* Footer */
#footer {
clear: both;
width: 928px;
margin: 0 auto;
padding-top: 40px;
background: url(/public/images/img11.gif) repeat-x;
}
#footer p {
margin: 0;
text-align: center;
}
.listEntry {
color: #909090;
padding: 5px;
}
.listEntry > .subject {
color: #2582A4;
font-weight: bold;
}
.listEntrySelected {
background: #becf74;
color: #666;
}
.listEntryHover {
background: #8ac6dc;
color: #666;
}
#emailContent {
padding-bottom: 20px;
}
#emailHeader {
border-collapse: collapse;
}
#emailHeader th, #emailHeader td {
text-align: left;
padding: 0 3px 3px 0;
}
#emailSubject {
border-bottom: 1px #606060 solid;
margin: 0;
width: 617px;
}
#emailBody {
color: #555;
margin-top: 15px;
}
#emailActions {
padding: 5px 0;
margin: 0 0 10px 0;
}
#emailActions a {
background: #8ac6dc;
color: #fff;
text-decoration: none;
font-weight: bold;
padding: 5px;
}
#emailActions a:hover {
background: #becf74;
}
.errors {
background-color: #ffa0a0;
color: #333;
padding: 5px 10px;
}
table.metrics {
}
.metrics th {
text-align: left;
width: 15em;
}
.metrics td.number {
width: 10em;
}
.metrics td.sparkline {
width: 200px;
}
#emailAttachments {
border-collapse: collapse;
}
#emailAttachments th, #emailAttachments td {
text-align: left;
padding: 0 3px 3px 0;
}
#emailAttachments .fileName:before {
content: '\203A\00A0';
}
#emailAttachments a {
background: #8ac6dc;
color: #fff;
text-decoration: none;
padding: 0 5px;
}
#emailAttachments a:hover {
background: #becf74;
}

View File

@@ -1,54 +0,0 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
Design by Free CSS Templates
http://www.freecsstemplates.org
Released for free under a Creative Commons Attribution 2.5 License
-->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>{{template "title" .}}</title>
<link href="/public/main.css" rel="stylesheet" type="text/css" />
<link rel="shortcut icon" type="image/png" href="/public/images/favicon.png">
<script src="/public/jquery-1.8.2.min.js" type="text/javascript" charset="utf-8"></script>
<script src="/public/jquery.color.js" type="text/javascript" charset="utf-8"></script>
{{template "script" .}}
</head>
<body>
<div id="header">
<ul id="menu">
<li><a href="/" accesskey="1" title="">Home</a></li>
<li><a href="/status" accesskey="2" title="">Status</a></li>
</ul>
<form id="search" action="{{reverse "MailboxIndex"}}" method="GET">
<fieldset>
<input name="name" type="text" id="input1" />
<input name="submit" type="submit" id="input2" value="Go" />
</fieldset>
</form>
</div>
<div id="content">
<div id="colOne">
{{template "menu" .}}
</div>
<div id="colTwo">
{{with .ctx.Session.Flashes "errors"}}
<div class="errors">
<p>Please fix the following errors and resubmit:<p>
<ul>
{{range .}}
<li>{{.}}</li>
{{end}}
</ul>
</div>
{{end}}
{{template "content" .}}
</div>
</div>
<div id="footer">
<p><a href="http://www.inbucket.org/">Inbucket</a> is an open source project hosted at
<a href="http://github.com/jhillyerd/inbucket">github</a>.
Design by <a href="http://www.freecsstemplates.org/">FCT</a>.</p>
</div>
</body>
</html>

View File

@@ -1 +0,0 @@
{{.body}}

View File

@@ -1,12 +0,0 @@
{{$name := .name}}
{{range .messages}}
<div class="box listEntry" id="{{.ID}}">
<div class="subject">{{.Subject}}</div>
<div class="from">{{.From}}</div>
<div class="date">{{friendlyTime .Date}}</div>
</div>
{{else}}
<div class="box">
<p style="height: 30px; padding-left: 10px;">No messages!</p>
</div>
{{end}}

View File

@@ -1,43 +0,0 @@
{{$name := .name}}
{{$id := .message.ID}}
<div id="emailActions">
<a href="/link/{{$name}}/{{$id}}">Link</a>
<a href="javascript:deleteMessage('{{.message.ID}}');">Delete</a>
<a href="javascript:messageSource('{{.message.ID}}');">Source</a>
{{if .htmlAvailable}}
<a href="javascript:htmlView('{{.message.ID}}');">HTML</a>
{{end}}
</div>
<table id="emailHeader">
<tr>
<th>From:</th>
<td>{{.message.From}}</td>
</tr>
<tr>
<th>To:</th>
<td>{{.message.To}}</td>
</tr>
<tr>
<th>Date:</th>
<td>{{.message.Date}}</td>
</tr>
<table>
{{with .attachments}}
<table id="emailAttachments">
<tr><th colspan="4">Attachments:</th></tr>
{{range $i, $e := .}}
<tr>
<td class="fileName">{{$e.FileName}}</td>
<td>({{$e.ContentType}})</td>
<td><a href="/mailbox/vattach/{{$name}}/{{$id}}/{{$i}}/{{$e.FileName}}" target="_blank">View</a></td>
<td><a href="/mailbox/dattach/{{$name}}/{{$id}}/{{$i}}/{{$e.FileName}}">Download</a></td>
</tr>
{{end}}
</table>
{{end}}
<div id="emailSubject"><h3>{{.message.Subject}}</h3></div>
<div id="emailBody">{{.body}}</div>

View File

@@ -1,92 +0,0 @@
{{define "title"}}{{printf "Inbucket for %v" .name}}{{end}}
{{$name := .name}}
{{define "script"}}
<script>
var selected = "{{.selected}}"
function messageLoaded(responseText, textStatus, XMLHttpRequest) {
if (textStatus == "error") {
alert("Failed to load message, server said:\n" + responseText)
} else {
window.scrollTo(0,0)
}
}
function listLoaded() {
$('.listEntry').hover(
function() {
$(this).addClass("listEntryHover")
},
function() {
$(this).removeClass("listEntryHover")
}
).click(
function() {
$('.listEntry').removeClass("listEntrySelected")
$(this).addClass("listEntrySelected")
$('#emailContent').load('/mailbox/{{.name}}/' + this.id, messageLoaded)
}
)
$("#messageList").slideDown()
if (selected != "") {
$("#" + selected).click()
selected = ""
}
}
function loadList() {
$('#messageList').load("/mailbox/{{.name}}", listLoaded)
}
function reloadList() {
$('#messageList').hide()
loadList()
}
function listInit() {
$("#messageList").hide()
loadList()
}
function deleteMessage(id) {
$('#emailContent').empty()
$.ajax({
type: 'DELETE',
url: '/mailbox/{{.name}}/' + id,
success: reloadList
})
}
function htmlView(id) {
window.open('/mailbox/{{.name}}/' + id + "/html", '_blank',
'width=800,height=600,' +
'menubar=yes,resizable=yes,scrollbars=yes,status=yes,toolbar=yes')
}
function messageSource(id) {
window.open('/mailbox/{{.name}}/' + id + "/source", '_blank',
'width=800,height=600,' +
'menubar=no,resizable=yes,scrollbars=yes,status=no,toolbar=no')
}
$(document).ready(listInit)
</script>
{{end}}
{{define "menu"}}
<div id="logo">
<h1><a href="#">inbucket</a></h1>
<h2>mail for {{.name}}</h2>
</div>
<div class="box" style="text-align:center; padding-bottom:10px;">
<a href="javascript:reloadList()">Refresh List</a>
</div>
<div id="messageList"></div>
{{end}}
{{define "content"}}
<div id="emailContent">
<p>Select a message at left, or enter a different username into the box on upper right.</p>
</div>
{{end}}

View File

@@ -1,12 +0,0 @@
{{define "title"}}Inbucket{{end}}
{{define "script"}}{{end}}
{{define "menu"}}
<div id="logo">
<h1><a href="/">inbucket</a></h1>
<h2>email testing service</h2>
</div>
{{end}}
{{define "content"}}{{.greeting}}{{end}}

View File

@@ -1,285 +0,0 @@
{{define "title"}}Inbucket Status{{end}}
{{define "script"}}
<script src="/public/jquery.sparkline.min.js" type="text/javascript" charset="utf-8"></script>
<script>
jQuery.ajaxSetup({ cache: false })
flashOn = jQuery.Color("rgba(255,255,0,1)")
flashOff = jQuery.Color("rgba(255,255,0,0)")
dataHist = new Object()
function timeFilter(seconds) {
if (seconds < 60) {
return seconds + " seconds"
} else if (seconds < 3600) {
return (seconds/60).toFixed(0) + " minute(s)"
} else if (seconds < 86400) {
return (seconds/3600).toFixed(1) + " hour(s)"
}
return (seconds/86400).toFixed(0) + " day(s)"
}
function sizeFilter(bytes) {
if (bytes < 1024) {
return bytes + " bytes"
} else if (bytes < 1048576) {
return (bytes/1024).toFixed(0) + " KB"
} else if (bytes < 1073741824) {
return (bytes/1048576).toFixed(2) + " MB"
}
return (bytes/1073741824).toFixed(2) + " GB"
}
function numberFilter(x) {
var parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
return parts.join(".");
}
function appendHistory(name, value) {
var h = dataHist[name]
if (! h) {
h = new Array(0)
}
// Prevent array from growing
if (h.length >= 60) {
h = h.slice(1,60)
}
h.push(parseInt(value))
dataHist[name] = h
el = $('#s-' + name)
if (el) {
el.sparkline(dataHist[name])
}
}
// Show spikes for numbers that only increase
function setHistoryOfActivity(name, value) {
var h = value.split(",")
var prev = parseInt(h[0])
for (i=0; i<h.length; i++) {
var t = parseInt(h[i])
h[i] = t-prev
prev = t
}
// First value will always be zero
if (h.length > 0) {
h = h.slice(1)
}
el = $('#s-' + name)
if (el) {
el.sparkline(h)
}
}
// Show up/down for numbers that can decrease
function setHistoryOfCount(name, value) {
var h = value.split(",")
el = $('#s-' + name)
if (el) {
el.sparkline(h)
}
}
function metric(name, value, filter, chartable) {
if (chartable) {
appendHistory(name, value)
}
if (filter) {
value = filter(value)
}
var el = $('#m-' + name)
if (el.text() != value) {
el.text(value)
el.css('background-color', flashOn)
el.animate({ backgroundColor: flashOff }, 1500)
}
}
function displayMetrics(data, textStatus, jqXHR) {
// Non graphing
metric('uptime', data.uptime, timeFilter, false)
metric('retentionScanCompleted', data.retention.SecondsSinceScanCompleted, timeFilter, false)
metric('retentionPeriod', data.retention.Period, timeFilter, false)
// JavaScript history
metric('memstatsSys', data.memstats.Sys, sizeFilter, true)
metric('memstatsHeapAlloc', data.memstats.HeapAlloc, sizeFilter, true)
metric('memstatsHeapSys', data.memstats.HeapSys, sizeFilter, true)
metric('memstatsHeapObjects', data.memstats.HeapObjects, numberFilter, true)
metric('smtpConnectsCurrent', data.smtp.ConnectsCurrent, numberFilter, true)
// Server-side history
metric('smtpReceivedTotal', data.smtp.ReceivedTotal, numberFilter, false)
setHistoryOfActivity('smtpReceivedTotal', data.smtp.ReceivedHist)
metric('smtpConnectsTotal', data.smtp.ConnectsTotal, numberFilter, false)
setHistoryOfActivity('smtpConnectsTotal', data.smtp.ConnectsHist)
metric('smtpWarnsTotal', data.smtp.WarnsTotal, numberFilter, false)
setHistoryOfActivity('smtpWarnsTotal', data.smtp.WarnsHist)
metric('smtpErrorsTotal', data.smtp.ErrorsTotal, numberFilter, false)
setHistoryOfActivity('smtpErrorsTotal', data.smtp.ErrorsHist)
metric('retentionDeletesTotal', data.retention.DeletesTotal, numberFilter, false)
setHistoryOfActivity('retentionDeletesTotal', data.retention.DeletesHist)
metric('retainedCurrent', data.retention.RetainedCurrent, numberFilter, false)
setHistoryOfCount('retainedCurrent', data.retention.RetainedHist)
}
function loadMetrics() {
// jQuery.getJSON( url [, data] [, success(data, textStatus, jqXHR)] )
jQuery.getJSON('/debug/vars', null, displayMetrics)
}
function aboutInit() {
loadMetrics()
setInterval(loadMetrics, 10000)
}
$(document).ready(aboutInit)
</script>
{{end}}
{{define "menu"}}
<div id="logo">
<h1><a href="/">inbucket</a></h1>
<h2>email testing service</h2>
</div>
{{end}}
{{define "content"}}
<h2>Inbucket Status</h2>
<p>Metrics are polled every 10 seconds. Inbucket does not keep history for the
10 minute graphs, but your web browser will accumulate the data over time.</p>
<div class="box">
<h3>Configuration</h3>
<table class="metrics">
<tr>
<th>Version:</th>
<td><span>{{.version}}, built on {{.buildDate}}</span></td>
</tr>
<tr>
<th>SMTP Listener:</th>
<td><span>{{.smtpListener}}</span></td>
</tr>
<tr>
<th>POP3 Listener:</th>
<td><span>{{.pop3Listener}}</span></td>
</tr>
<tr>
<th>HTTP Listener:</th>
<td><span>{{.webListener}}</span></td>
</tr>
</table>
<p class="last">&nbsp;</p>
</div>
<div class="box">
<h3>General Metrics</h3>
<table class="metrics">
<tr>
<th>Uptime:</th>
<td class="number"><span id="m-uptime">.</span></td>
</tr>
<tr>
<th>System Memory:</th>
<td class="number"><span id="m-memstatsSys">.</span></td>
<td class="sparkline"><span id="s-memstatsSys">.</span></td>
<td>(10min)</td>
</tr>
<tr>
<th>Heap Size:</th>
<td class="number"><span id="m-memstatsHeapSys">.</span></td>
<td class="sparkline"><span id="s-memstatsHeapSys">.</span></td>
<td>(10min)</td>
</tr>
<tr>
<th>Heap In-Use:</th>
<td class="number"><span id="m-memstatsHeapAlloc">.</span></td>
<td class="sparkline"><span id="s-memstatsHeapAlloc">.</span></td>
<td>(10min)</td>
</tr>
<tr>
<th>Heap # Objects:</th>
<td class="number"><span id="m-memstatsHeapObjects">.</span></td>
<td class="sparkline"><span id="s-memstatsHeapObjects">.</span></td>
<td>(10min)</td>
</tr>
</table>
<p class="last">&nbsp;</p>
</div>
<div class="box">
<h3>SMTP Metrics</h3>
<table class="metrics">
<tr>
<th>Current Connections:</th>
<td class="number"><span id="m-smtpConnectsCurrent">.</span></td>
<td class="sparkline"><span id="s-smtpConnectsCurrent">.</span></td>
<td>(10min)</td>
</tr>
<tr>
<th>Total Connections:</th>
<td class="number"><span id="m-smtpConnectsTotal">.</span></td>
<td class="sparkline"><span id="s-smtpConnectsTotal">.</span></td>
<td>(60min)</td>
</tr>
<tr>
<th>Messages Received:</th>
<td class="number"><span id="m-smtpReceivedTotal">.</span></td>
<td class="sparkline"><span id="s-smtpReceivedTotal">.</span></td>
<td>(60min)</td>
</tr>
<tr>
<th>Errors Logged:</th>
<td class="number"><span id="m-smtpErrorsTotal">.</span></td>
<td class="sparkline"><span id="s-smtpErrorsTotal"></span></td>
<td>(60min)</td>
</tr>
<tr>
<th>Warnings Logged:</th>
<td class="number"><span id="m-smtpWarnsTotal">.</span></td>
<td class="sparkline"><span id="s-smtpWarnsTotal"></span></td>
<td>(60min)</td>
</tr>
</table>
<p class="last">&nbsp;</p>
</div>
<div class="box">
<h3>Data Store Metrics</h3>
<table class="metrics">
<tr>
<th>Retention Period:</th>
<td colspan="3">
{{if .retentionMinutes}}
<span id="m-retentionPeriod">.</span>
{{else}}
Disabled
{{end}}
</td>
</tr>
<tr>
<th>Retention Scan:</th>
<td colspan="3">
{{if .retentionMinutes}}
Completed <span id="m-retentionScanCompleted">.</span> ago
{{else}}
Disabled
{{end}}
</td>
</tr>
<tr>
<th>Retention Deletes:</th>
<td class="number"><span id="m-retentionDeletesTotal">.</span></td>
<td class="sparkline"><span id="s-retentionDeletesTotal"></span></td>
<td>(60min)</td>
</tr>
<tr>
<th>Currently Retained:</th>
<td class="number"><span id="m-retainedCurrent">.</span></td>
<td class="sparkline"><span id="s-retainedCurrent"></span></td>
<td>(60min)</td>
</tr>
</table>
<p class="last">&nbsp;</p>
</div>
{{end}}

View File

@@ -408,8 +408,8 @@ func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
// Have to reset default mux to prevent duplicate routes
http.DefaultServeMux = http.NewServeMux()
cfg := config.WebConfig{
TemplateDir: "../themes/integral/templates",
PublicDir: "../themes/integral/public",
TemplateDir: "../themes/bootstrap/templates",
PublicDir: "../themes/bootstrap/public",
}
shutdownChan := make(chan bool)
httpd.Initialize(cfg, ds, shutdownChan)