Remove legacy theme 'integral'
@@ -195,8 +195,8 @@ func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
|
|||||||
// Have to reset default mux to prevent duplicate routes
|
// Have to reset default mux to prevent duplicate routes
|
||||||
http.DefaultServeMux = http.NewServeMux()
|
http.DefaultServeMux = http.NewServeMux()
|
||||||
cfg := config.WebConfig{
|
cfg := config.WebConfig{
|
||||||
TemplateDir: "../themes/integral/templates",
|
TemplateDir: "../themes/bootstrap/templates",
|
||||||
PublicDir: "../themes/integral/public",
|
PublicDir: "../themes/bootstrap/public",
|
||||||
}
|
}
|
||||||
shutdownChan := make(chan bool)
|
shutdownChan := make(chan bool)
|
||||||
httpd.Initialize(cfg, ds, shutdownChan)
|
httpd.Initialize(cfg, ds, shutdownChan)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 161 B |
|
Before Width: | Height: | Size: 379 B |
|
Before Width: | Height: | Size: 407 B |
|
Before Width: | Height: | Size: 161 B |
|
Before Width: | Height: | Size: 565 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 109 B |
|
Before Width: | Height: | Size: 365 B |
|
Before Width: | Height: | Size: 108 B |
|
Before Width: | Height: | Size: 276 B |
2
themes/integral/public/jquery-1.8.2.min.js
vendored
@@ -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 );
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -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>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{{.body}}
|
|
||||||
@@ -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}}
|
|
||||||
@@ -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>
|
|
||||||
|
|
||||||
@@ -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}}
|
|
||||||
|
|
||||||
@@ -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}}
|
|
||||||
@@ -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"> </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"> </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"> </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"> </p>
|
|
||||||
</div>
|
|
||||||
{{end}}
|
|
||||||
|
|
||||||
@@ -408,8 +408,8 @@ func setupWebServer(ds smtpd.DataStore) *bytes.Buffer {
|
|||||||
// Have to reset default mux to prevent duplicate routes
|
// Have to reset default mux to prevent duplicate routes
|
||||||
http.DefaultServeMux = http.NewServeMux()
|
http.DefaultServeMux = http.NewServeMux()
|
||||||
cfg := config.WebConfig{
|
cfg := config.WebConfig{
|
||||||
TemplateDir: "../themes/integral/templates",
|
TemplateDir: "../themes/bootstrap/templates",
|
||||||
PublicDir: "../themes/integral/public",
|
PublicDir: "../themes/bootstrap/public",
|
||||||
}
|
}
|
||||||
shutdownChan := make(chan bool)
|
shutdownChan := make(chan bool)
|
||||||
httpd.Initialize(cfg, ds, shutdownChan)
|
httpd.Initialize(cfg, ds, shutdownChan)
|
||||||
|
|||||||