Compare commits

..

39 commits

Author SHA1 Message Date
Wojciech Todryk b63cc2bd14 deps update 2013-02-12 20:06:43 +01:00
Wojciech Todryk 2a6e2a3d85 migrate script fo jquery 2013-02-07 19:48:25 +01:00
Wojciech Todryk 99fc560572 docs updated 2013-02-02 15:10:17 +01:00
Wojciech Todryk 5eb7874d79 favicon size 2013-02-02 15:04:27 +01:00
Wojciech Todryk 298eb0a023 favicon 2013-02-02 14:54:09 +01:00
Wojciech Todryk 362ec3bcbd bump gem versions 2013-02-02 13:58:43 +01:00
Wojciech Todryk 3ddedca1d3 cc & bcc adresses handle fix 2012-07-10 22:10:06 +02:00
Wojciech Todryk 11cd31cdee fixes in draft folder 2012-07-08 14:18:19 +02:00
Wojciech Todryk 0a2bbed2a0 fixes 2012-06-18 21:34:30 +02:00
Wojciech Todryk 0c3e911553 links fix 2012-05-28 21:17:24 +02:00
Wojciech Todryk ccd3636021 Update README.markdown 2012-04-27 23:44:03 +03:00
Wojciech Todryk 193f2fc524 info update 2012-04-27 22:39:08 +02:00
Wojciech Todryk a45506a642 gimnasium status added 2012-04-15 19:55:45 +02:00
Wojciech Todryk 38a7b015da Merge branch 'master' of github.com:musashimm/mailr 2012-04-15 19:54:44 +02:00
Wojciech Todryk a5b6df393c fixes 2012-04-15 19:51:58 +02:00
Wojciech Todryk 2517df1814 Update README.markdown 2012-04-07 00:06:32 +03:00
Wojciech Todryk 05dfa004c8 Update README.markdown 2012-04-07 00:05:05 +03:00
Wojciech Todryk 77c8d3e7d7 devel 2012-03-30 19:31:23 +02:00
Wojciech Todryk b8eddc8e48 devel cont 2012-03-26 20:22:01 +02:00
Wojciech Todryk 0872730d8d view cleanup 2012-03-24 18:09:31 +01:00
Wojciech Todryk 0daf487816 dev cont 2012-03-24 13:23:34 +01:00
Wojciech Todryk 7de07db812 cont 2012-03-10 21:03:56 +01:00
Wojciech Todryk cacd9575d0 rails 3.2.2 added tweeter bootstrap 2012-03-10 18:08:39 +01:00
Wojciech Todryk 74c23fa0d1 start to switch to rails 3.2.2 2012-03-03 18:53:39 +01:00
Wojciech Todryk 244942a78f switching to rails 3.2 2012-03-03 17:37:37 +01:00
Wojciech Todryk 9be6f493a3 fix in selecting messages from current folder 2012-03-02 20:30:11 +01:00
Wojciech Todryk f0dcdc3985 links added and other stuff 2012-02-04 00:45:28 +01:00
Wojciech Todryk eb455e704a new calendar view 2011-10-15 18:31:20 +02:00
Wojciech Todryk b74d28793d contacts_external_path fix 2011-10-04 20:45:44 +02:00
Wojciech Todryk eac30875f3 messages controller fix 2011-10-01 08:30:45 +02:00
Wojciech Todryk e96e11db96 identity,servers view 2011-09-30 01:14:41 +02:00
Wojciech Todryk ef0b894ad8 identity,servers view 2011-09-29 21:16:40 +02:00
Wojciech Todryk 9bb5f3a20f servers view 2011-09-24 22:13:45 +02:00
Wojciech Todryk 9e31ca239d TODO, CHANGES added 2011-09-23 21:37:23 +02:00
Wojciech Todryk 17a85a5916 calendar as separate gem, bluecloth integrated 2011-09-23 21:35:12 +02:00
Wojciech Todryk 66cba6bbc7 view fixes 2011-09-18 21:18:52 +02:00
Wojciech Todryk 1663cd60b5 version info 2011-09-16 22:21:57 +02:00
Wojciech Todryk 6fa55112da file_select fix 2011-09-16 22:19:22 +02:00
Wojciech Todryk bb3289e0d4 fixes for contacts import;flash fixes 2011-09-16 22:08:30 +02:00
297 changed files with 3991 additions and 14900 deletions

20
.gitignore vendored
View file

@ -1,5 +1,15 @@
.bundle
db/*.sqlite3
log/*.log
tmp/
config/database.yml
# See http://help.github.com/ignore-files/ for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile ~/.gitignore_global
# Ignore bundler config
/.bundle
# Ignore the default SQLite database.
/db/*.sqlite3
# Ignore all logfiles and tempfiles.
/log/*.log
/tmp

View file

@ -1,3 +1,5 @@
## Authors
* Luben Manolov <luben.manolov@gmail.com>
* Nick Penkov <nick.penkov@gmail.com>
* Eugene Korbut

47
CHANGES.markdown Executable file
View file

@ -0,0 +1,47 @@
## Changes
#### 0.9.5
* favicon added
#### 0.9.4
* bump gems
#### 0.9.3
* handle Cc & Bcc adresses fix
#### 0.9.2
* fixes in handling draft folder
#### 0.9.1
* nowrap to edit column in contacts & links
* decoded changed in mail gem
* fixes in pl locale
#### 0.9.0
* switch to Rails 3.2.x
* Tweeter Bootstrap as default theme
* many fixes
#### 0.8.6
* new calendar view
#### 0.8.5
* servers view
* identity modification
#### 0.8.4
* calendar view as separate gem
* adding bluecloth for rendering markdown text
#### 0.8.3
* export, imports of contact

51
Gemfile
View file

@ -1,8 +1,47 @@
source 'http://rubygems.org'
source 'https://rubygems.org'
gem 'rails', '~>3.0.7'
gem 'rails', '>= 3.2.11'
gem 'mysql2' , '~>0.2.7'
gem 'will_paginate', '~> 3.0.beta'
gem 'themes_for_rails'
gem "ezcrypto", "~> 0.7.2"
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'mysql2'
gem 'json', '>= 1.7.6'
# Gems used only for assets and not required
# in production environments by default.
group :assets do
gem 'sass-rails'
gem 'coffee-rails'
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
# gem 'therubyracer'
gem 'uglifier'
end
gem 'jquery-rails'
# To use ActiveModel has_secure_password
# gem 'bcrypt-ruby', '~> 3.0.0'
# To use Jbuilder templates for JSON
# gem 'jbuilder'
# Use unicorn as the app server
# gem 'unicorn'
# Deploy with Capistrano
# gem 'capistrano'
# To use debugger
# gem 'ruby-debug'
gem 'will_paginate'
gem "ezcrypto"
gem 'calendar_view'
gem 'bluecloth'
gem 'sass'
gem 'haml'
#gem 'twitter_bootstrap_form_for'

125
Gemfile.lock Normal file
View file

@ -0,0 +1,125 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (3.2.11)
actionpack (= 3.2.11)
mail (~> 2.4.4)
actionpack (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.0)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.11)
activesupport (= 3.2.11)
builder (~> 3.0.0)
activerecord (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
arel (~> 3.0.2)
tzinfo (~> 0.3.29)
activeresource (3.2.11)
activemodel (= 3.2.11)
activesupport (= 3.2.11)
activesupport (3.2.11)
i18n (~> 0.6)
multi_json (~> 1.0)
arel (3.0.2)
bluecloth (2.2.0)
builder (3.0.4)
calendar_view (0.0.7)
rails (>= 3.0.0)
coffee-rails (3.2.2)
coffee-script (>= 2.2.0)
railties (~> 3.2.0)
coffee-script (2.2.0)
coffee-script-source
execjs
coffee-script-source (1.4.0)
erubis (2.7.0)
execjs (1.4.0)
multi_json (~> 1.0)
ezcrypto (0.7.2)
haml (3.1.7)
hike (1.2.1)
i18n (0.6.1)
journey (1.0.4)
jquery-rails (2.2.0)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.7.6)
mail (2.4.4)
i18n (>= 0.4.0)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mime-types (1.19)
multi_json (1.5.0)
mysql2 (0.3.11)
polyglot (0.3.3)
rack (1.4.4)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.3)
rack
rack-test (0.6.2)
rack (>= 1.0)
rails (3.2.11)
actionmailer (= 3.2.11)
actionpack (= 3.2.11)
activerecord (= 3.2.11)
activeresource (= 3.2.11)
activesupport (= 3.2.11)
bundler (~> 1.0)
railties (= 3.2.11)
railties (3.2.11)
actionpack (= 3.2.11)
activesupport (= 3.2.11)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.0.3)
rdoc (3.12)
json (~> 1.4)
sass (3.2.5)
sass-rails (3.2.6)
railties (~> 3.2.0)
sass (>= 3.1.10)
tilt (~> 1.3)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
thor (0.17.0)
tilt (1.3.3)
treetop (1.4.12)
polyglot
polyglot (>= 0.3.1)
tzinfo (0.3.35)
uglifier (1.3.0)
execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2)
will_paginate (3.0.4)
PLATFORMS
ruby
DEPENDENCIES
bluecloth
calendar_view
coffee-rails
ezcrypto
haml
jquery-rails
json (>= 1.7.6)
mysql2
rails (>= 3.2.11)
sass
sass-rails
uglifier
will_paginate

View file

@ -1,34 +1,30 @@
[![Dependency Status](https://gemnasium.com/musashimm/mailr.png)](https://gemnasium.com/musashimm/mailr)
## Introduction
_Mailr_ is a IMAP mail client based on _Ruby on Rails_ platform.
_MailR_ is a IMAP mail client based on _Ruby on Rails_ platform.
**NOTE** All path and filenames are based on _Rails.root_ directory.
### Requirements
## Requirements
In _Rails 3_ all dependencies should be defined in file _Gemfile_. All needed gems can be installed using bundler.
In _Rails 3_ and above all dependencies should be defined in file _Gemfile_. All needed gems can be installed using bundler.
### Installation procedure
## Installation procedure
* Checkout the source code.
* Install all dependiences. Check if proper gems (sqlite3/mysql/postgresql) are defined in _Gemfile_ and installed. Use _bundler_ for that:
```shell
bundle install
```
* Check _config/defaults.yml_ for proper values.
* Check _config/settings.yml_ for proper values. (see _config/settings.yml.example_).
* Prepare config/database.yml file (see _config/database.yml.example_).
* Migrate database (rake db:migrate)
* Start rails server if applicable
* Point your browser to application URL:
For local access: http://localhost:3000
For remote access: http://some_url/mailr
* Using browser do basic setup. If You make a mistake delete all data from DB using rake task:
```shell
@ -37,12 +33,6 @@ rake db:clear_data
* Use it.
### Specific configuration
## Specific configuration
For themes: if server sends files with no content in production mode comment out
```ruby
config.action_dispatch.x_sendfile_header = "X-Sendfile"
```
from _config/environments/production.rb_ file.
None

View file

@ -1,7 +1,7 @@
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__)
require 'rake'
Mailr::Application.load_tasks

21
TODO.markdown Executable file
View file

@ -0,0 +1,21 @@
## Todo
* add themes
app/controllers/folders_controller.rb:
* [ 29] [TODO] recreate local copy of folders
* [ 98] [TODO] save system folders
app/controllers/messages_controller.rb:
* [101] [FIXME] missing fields and support arrays
app/controllers/messages_ops_controller.rb:
* [261] [FIXME] edit does not support attachments
* [325] [TODO] check if email address is valid if not get address from contacts
app/models/prefs.rb:
* [ 21] [TODO] move refresh to prefs and make refresh page with messages

View file

@ -1,3 +1,5 @@
## License
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
app/assets/images/logo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 6.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

View file

@ -0,0 +1,15 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery_ujs
//= require_tree .

1
app/assets/javascripts/bootstrap.min.js vendored Executable file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,498 @@
/*!
* jQuery Migrate - v1.0.0 - 2013-01-14
* https://github.com/jquery/jquery-migrate
* Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
*/
(function( jQuery, window, undefined ) {
"use strict";
var warnedAbout = {};
// List of warnings already given; public read only
jQuery.migrateWarnings = [];
// Set to true to prevent console output; migrateWarnings still maintained
// jQuery.migrateMute = false;
// Forget any warnings we've already given; public
jQuery.migrateReset = function() {
warnedAbout = {};
jQuery.migrateWarnings.length = 0;
};
function migrateWarn( msg) {
if ( !warnedAbout[ msg ] ) {
warnedAbout[ msg ] = true;
jQuery.migrateWarnings.push( msg );
if ( window.console && console.warn && !jQuery.migrateMute ) {
console.warn( "JQMIGRATE: " + msg );
}
}
}
function migrateWarnProp( obj, prop, value, msg ) {
if ( Object.defineProperty ) {
// On ES5 browsers (non-oldIE), warn if the code tries to get prop;
// allow property to be overwritten in case some other plugin wants it
try {
Object.defineProperty( obj, prop, {
configurable: true,
enumerable: true,
get: function() {
migrateWarn( msg );
return value;
},
set: function( newValue ) {
migrateWarn( msg );
value = newValue;
}
});
return;
} catch( err ) {
// IE8 is a dope about Object.defineProperty, can't warn there
}
}
// Non-ES5 (or broken) browser; just set the property
jQuery._definePropertyBroken = true;
obj[ prop ] = value;
}
if ( document.compatMode === "BackCompat" ) {
// jQuery has never supported or tested Quirks Mode
migrateWarn( "jQuery is not compatible with Quirks Mode" );
}
var attrFn = {},
attr = jQuery.attr,
valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
function() { return null; },
valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
function() { return undefined; },
rnoType = /^(?:input|button)$/i,
rnoAttrNodeType = /^[238]$/,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
ruseDefault = /^(?:checked|selected)$/i;
// jQuery.attrFn
migrateWarnProp( jQuery, "attrFn", attrFn, "jQuery.attrFn is deprecated" );
jQuery.attr = function( elem, name, value, pass ) {
var lowerName = name.toLowerCase(),
nType = elem && elem.nodeType;
if ( pass ) {
migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
if ( elem && !rnoAttrNodeType.test( nType ) && jQuery.isFunction( jQuery.fn[ name ] ) ) {
return jQuery( elem )[ name ]( value );
}
}
// Warn if user tries to set `type` since it breaks on IE 6/7/8
if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) ) {
migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
}
// Restore boolHook for boolean property/attribute synchronization
if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
jQuery.attrHooks[ lowerName ] = {
get: function( elem, name ) {
// Align boolean attributes with corresponding properties
// Fall back to attribute presence where some booleans are not supported
var attrNode,
property = jQuery.prop( elem, name );
return property === true || typeof property !== "boolean" &&
( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
name.toLowerCase() :
undefined;
},
set: function( elem, value, name ) {
var propName;
if ( value === false ) {
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
} else {
// value is true since we know at this point it's type boolean and not false
// Set boolean attributes to the same name and set the DOM property
propName = jQuery.propFix[ name ] || name;
if ( propName in elem ) {
// Only set the IDL specifically if it already exists on the element
elem[ propName ] = true;
}
elem.setAttribute( name, name.toLowerCase() );
}
return name;
}
};
// Warn only for attributes that can remain distinct from their properties post-1.9
if ( ruseDefault.test( lowerName ) ) {
migrateWarn( "jQuery.fn.attr(" + lowerName + ") may use property instead of attribute" );
}
}
return attr.call( jQuery, elem, name, value );
};
// attrHooks: value
jQuery.attrHooks.value = {
get: function( elem, name ) {
var nodeName = ( elem.nodeName || "" ).toLowerCase();
if ( nodeName === "button" ) {
return valueAttrGet.apply( this, arguments );
}
if ( nodeName !== "input" && nodeName !== "option" ) {
migrateWarn("property-based jQuery.fn.attr('value') is deprecated");
}
return name in elem ?
elem.value :
null;
},
set: function( elem, value ) {
var nodeName = ( elem.nodeName || "" ).toLowerCase();
if ( nodeName === "button" ) {
return valueAttrSet.apply( this, arguments );
}
if ( nodeName !== "input" && nodeName !== "option" ) {
migrateWarn("property-based jQuery.fn.attr('value', val) is deprecated");
}
// Does not return so that setAttribute is also used
elem.value = value;
}
};
var matched, browser,
oldInit = jQuery.fn.init,
// Note this does NOT include the # XSS fix from 1.7!
rquickExpr = /^(?:.*(<[\w\W]+>)[^>]*|#([\w\-]*))$/;
// $(html) "looks like html" rule change
jQuery.fn.init = function( selector, context, rootjQuery ) {
var match;
if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
(match = rquickExpr.exec( selector )) && match[1] ) {
// This is an HTML string according to the "old" rules; is it still?
if ( selector.charAt( 0 ) !== "<" ) {
migrateWarn("$(html) HTML strings must start with '<' character");
}
// Now process using loose rules; let pre-1.8 play too
if ( context && context.context ) {
// jQuery object as context; parseHTML expects a DOM object
context = context.context;
}
if ( jQuery.parseHTML ) {
return oldInit.call( this, jQuery.parseHTML( jQuery.trim(selector), context, true ),
context, rootjQuery );
}
}
return oldInit.apply( this, arguments );
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
matched = jQuery.uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
jQuery.browser = browser;
// Warn if the code tries to get jQuery.browser
migrateWarnProp( jQuery, "browser", browser, "jQuery.browser is deprecated" );
jQuery.sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, this );
jQuerySub.superclass = this;
jQuerySub.fn = jQuerySub.prototype = this();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
context = jQuerySub( context );
}
return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
migrateWarn( "jQuery.sub() is deprecated" );
return jQuerySub;
};
var oldFnData = jQuery.fn.data;
jQuery.fn.data = function( name ) {
var ret, evt,
elem = this[0];
// Handles 1.7 which has this behavior and 1.8 which doesn't
if ( elem && name === "events" && arguments.length === 1 ) {
ret = jQuery.data( elem, name );
evt = jQuery._data( elem, name );
if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
migrateWarn("Use of jQuery.fn.data('events') is deprecated");
return evt;
}
}
return oldFnData.apply( this, arguments );
};
var rscriptType = /\/(java|ecma)script/i,
oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack,
oldFragment = jQuery.buildFragment;
jQuery.fn.andSelf = function() {
migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
return oldSelf.apply( this, arguments );
};
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
if ( !jQuery.clean ) {
jQuery.clean = function( elems, context, fragment, scripts ) {
// Set context per 1.8 logic
context = context || document;
context = !context.nodeType && context[0] || context;
context = context.ownerDocument || context;
migrateWarn("jQuery.clean() is deprecated");
var i, elem, handleScript, jsTags,
ret = [];
jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
// Complex logic lifted directly from jQuery 1.8
if ( fragment ) {
// Special handling of each script element
handleScript = function( elem ) {
// Check if we consider it executable
if ( !elem.type || rscriptType.test( elem.type ) ) {
// Detach the script and store it in the scripts array (if provided) or the fragment
// Return truthy to indicate that it has been handled
return scripts ?
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
fragment.appendChild( elem );
}
};
for ( i = 0; (elem = ret[i]) != null; i++ ) {
// Check if we're done after handling an executable script
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
// Append to fragment and handle embedded scripts
fragment.appendChild( elem );
if ( typeof elem.getElementsByTagName !== "undefined" ) {
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
// Splice the scripts into ret after their former ancestor and advance our index beyond them
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
i += jsTags.length;
}
}
}
}
return ret;
};
}
jQuery.buildFragment = function( elems, context, scripts, selection ) {
var ret,
warning = "jQuery.buildFragment() is deprecated";
// Set context per 1.8 logic
context = context || document;
context = !context.nodeType && context[0] || context;
context = context.ownerDocument || context;
try {
ret = oldFragment.call( jQuery, elems, context, scripts, selection );
// jQuery < 1.8 required arrayish context; jQuery 1.9 fails on it
} catch( x ) {
ret = oldFragment.call( jQuery, elems, context.nodeType ? [ context ] : context[ 0 ], scripts, selection );
// Success from tweaking context means buildFragment was called by the user
migrateWarn( warning );
}
// jQuery < 1.9 returned an object instead of the fragment itself
if ( !ret.fragment ) {
migrateWarnProp( ret, "fragment", ret, warning );
migrateWarnProp( ret, "cacheable", false, warning );
}
return ret;
};
var eventAdd = jQuery.event.add,
eventRemove = jQuery.event.remove,
eventTrigger = jQuery.event.trigger,
oldToggle = jQuery.fn.toggle,
oldLive = jQuery.fn.live,
oldDie = jQuery.fn.die,
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
hoverHack = function( events ) {
if ( typeof( events ) != "string" || jQuery.event.special.hover ) {
return events;
}
if ( rhoverHack.test( events ) ) {
migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
}
return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
};
// Event props removed in 1.9, put them back if needed; no practical way to warn them
if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
}
// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
// Support for 'hover' pseudo-event and ajax event warnings
jQuery.event.add = function( elem, types, handler, data, selector ){
if ( elem !== document && rajaxEvent.test( types ) ) {
migrateWarn( "AJAX events should be attached to document: " + types );
}
eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
};
jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
};
jQuery.fn.error = function() {
var args = Array.prototype.slice.call( arguments, 0);
migrateWarn("jQuery.fn.error() is deprecated");
args.splice( 0, 0, "error" );
if ( arguments.length ) {
return this.bind.apply( this, args );
}
// error event should not bubble to window, although it does pre-1.7
this.triggerHandler.apply( this, args );
return this;
};
jQuery.fn.toggle = function( fn, fn2 ) {
// Don't mess with animation or css toggles
if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
return oldToggle.apply( this, arguments );
}
migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
// Save reference to arguments for access in closure
var args = arguments,
guid = fn.guid || jQuery.guid++,
i = 0,
toggler = function( event ) {
// Figure out which function to execute
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
// and execute the function
return args[ lastToggle ].apply( this, arguments ) || false;
};
// link all the functions, so any of them can unbind this click handler
toggler.guid = guid;
while ( i < args.length ) {
args[ i++ ].guid = guid;
}
return this.click( toggler );
};
jQuery.fn.live = function( types, data, fn ) {
migrateWarn("jQuery.fn.live() is deprecated");
if ( oldLive ) {
return oldLive.apply( this, arguments );
}
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
};
jQuery.fn.die = function( types, fn ) {
migrateWarn("jQuery.fn.die() is deprecated");
if ( oldDie ) {
return oldDie.apply( this, arguments );
}
jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
};
// Turn global events into document-triggered events
jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
if ( !elem & !rajaxEvent.test( event ) ) {
migrateWarn( "Global events are undocumented and deprecated" );
}
return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
};
jQuery.each( ajaxEvents.split("|"),
function( _, name ) {
jQuery.event.special[ name ] = {
setup: function() {
var elem = this;
// The document needs no shimming; must be !== for oldIE
if ( elem !== document ) {
jQuery.event.add( document, name + "." + jQuery.guid, function() {
jQuery.event.trigger( name, null, elem, true );
});
jQuery._data( this, name, jQuery.guid++ );
}
return false;
},
teardown: function() {
if ( this !== document ) {
jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
}
return false;
}
};
}
);
})( jQuery, window );

View file

@ -0,0 +1,9 @@
$(function() {
$("#toggleall").click(function() {
var checked_status = this.checked;
jQuery("input[type='checkbox']").each(function() {
this.checked = checked_status;
});
});
});

View file

@ -0,0 +1,13 @@
/*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the top of the
* compiled file, but it's generally better to create a new file per style scope.
*
*= require_self
*= require_tree .
*/

File diff suppressed because one or more lines are too long

632
app/assets/stylesheets/bootstrap.min.css vendored Executable file
View file

@ -0,0 +1,632 @@
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
audio:not([controls]){display:none;}
html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
a:hover,a:active{outline:0;}
sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
sup{top:-0.5em;}
sub{bottom:-0.25em;}
img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;}
button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
button,input{*overflow:visible;line-height:normal;}
button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
textarea{overflow:auto;vertical-align:top;}
.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";}
.clearfix:after{clear:both;}
body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
a{color:#0088cc;text-decoration:none;}
a:hover{color:#005580;text-decoration:underline;}
.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
.row:after{clear:both;}
[class*="span"]{float:left;margin-left:20px;}
.span1{width:60px;}
.span2{width:140px;}
.span3{width:220px;}
.span4{width:300px;}
.span5{width:380px;}
.span6{width:460px;}
.span7{width:540px;}
.span8{width:620px;}
.span9{width:700px;}
.span10{width:780px;}
.span11{width:860px;}
.span12,.container{width:940px;}
.offset1{margin-left:100px;}
.offset2{margin-left:180px;}
.offset3{margin-left:260px;}
.offset4{margin-left:340px;}
.offset5{margin-left:420px;}
.offset6{margin-left:500px;}
.offset7{margin-left:580px;}
.offset8{margin-left:660px;}
.offset9{margin-left:740px;}
.offset10{margin-left:820px;}
.offset11{margin-left:900px;}
.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
.row-fluid:after{clear:both;}
.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;}
.row-fluid>[class*="span"]:first-child{margin-left:0;}
.row-fluid>.span1{width:6.382978723%;}
.row-fluid>.span2{width:14.89361702%;}
.row-fluid>.span3{width:23.404255317%;}
.row-fluid>.span4{width:31.914893614%;}
.row-fluid>.span5{width:40.425531911%;}
.row-fluid>.span6{width:48.93617020799999%;}
.row-fluid>.span7{width:57.446808505%;}
.row-fluid>.span8{width:65.95744680199999%;}
.row-fluid>.span9{width:74.468085099%;}
.row-fluid>.span10{width:82.97872339599999%;}
.row-fluid>.span11{width:91.489361693%;}
.row-fluid>.span12{width:99.99999998999999%;}
.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
.container:after{clear:both;}
.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
.container-fluid:after{clear:both;}
p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}
.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;}
h4,h5,h6{line-height:18px;}
h4{font-size:14px;}h4 small{font-size:12px;}
h5{font-size:12px;}
h6{font-size:11px;color:#999999;text-transform:uppercase;}
.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
.page-header h1{line-height:1;}
ul,ol{padding:0;margin:0 0 9px 25px;}
ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
ul{list-style:disc;}
ol{list-style:decimal;}
li{line-height:18px;}
ul.unstyled,ol.unstyled{margin-left:0;list-style:none;}
dl{margin-bottom:18px;}
dt,dd{line-height:18px;}
dt{font-weight:bold;}
dd{margin-left:9px;}
hr{margin:18px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}
strong{font-weight:bold;}
em{font-style:italic;}
.muted{color:#999999;}
abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;}
blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
q:before,q:after,blockquote:before,blockquote:after{content:"";}
address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;}
small{font-size:100%;}
cite{font-style:normal;}
code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;word-wrap:break-word;}pre.prettyprint{margin-bottom:18px;}
pre code{padding:0;color:inherit;background-color:transparent;border:0;}
.pre-scrollable{max-height:340px;overflow-y:scroll;}
form{margin:0 0 18px;}
fieldset{padding:0;margin:0;border:0;}
legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}legend small{font-size:13.5px;color:#999999;}
label,input,button,select,textarea{font-size:13px;font-weight:normal;line-height:18px;}
input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;}
label{display:block;margin-bottom:5px;color:#333333;}
input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
.uneditable-textarea{width:auto;height:auto;}
label input,label textarea,label select{display:block;}
input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;cursor:pointer;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border:0 \9;}
input[type="image"]{border:0;}
input[type="file"]{width:auto;padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;}
select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
input[type="file"]{line-height:18px \9;}
select{width:220px;background-color:#ffffff;}
select[multiple],select[size]{height:auto;}
input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
textarea{height:auto;}
input[type="hidden"]{display:none;}
.radio,.checkbox{padding-left:18px;}
.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}
.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}
input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;}
input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
.input-mini{width:60px;}
.input-small{width:90px;}
.input-medium{width:150px;}
.input-large{width:210px;}
.input-xlarge{width:270px;}
.input-xxlarge{width:530px;}
input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;}
input.span1,textarea.span1,.uneditable-input.span1{width:50px;}
input.span2,textarea.span2,.uneditable-input.span2{width:130px;}
input.span3,textarea.span3,.uneditable-input.span3{width:210px;}
input.span4,textarea.span4,.uneditable-input.span4{width:290px;}
input.span5,textarea.span5,.uneditable-input.span5{width:370px;}
input.span6,textarea.span6,.uneditable-input.span6{width:450px;}
input.span7,textarea.span7,.uneditable-input.span7{width:530px;}
input.span8,textarea.span8,.uneditable-input.span8{width:610px;}
input.span9,textarea.span9,.uneditable-input.span9{width:690px;}
input.span10,textarea.span10,.uneditable-input.span10{width:770px;}
input.span11,textarea.span11,.uneditable-input.span11{width:850px;}
input.span12,textarea.span12,.uneditable-input.span12{width:930px;}
input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;}
.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
:-moz-placeholder{color:#999999;}
::-webkit-input-placeholder{color:#999999;}
.help-block{display:block;margin-top:5px;margin-bottom:0;color:#999999;}
.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;}
.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";}
.input-prepend:after,.input-append:after{clear:both;}
.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;}
.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
.input-prepend .add-on{*margin-top:1px;}
.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.input-append .uneditable-input{border-left-color:#eee;border-right-color:#ccc;}
.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;}
.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;}
.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}
.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;}
.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;}
.form-search .radio,.form-inline .radio,.form-search .checkbox,.form-inline .checkbox{margin-bottom:0;vertical-align:middle;}
.control-group{margin-bottom:9px;}
legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
.form-horizontal .control-group:after{clear:both;}
.form-horizontal .control-label{float:left;width:140px;padding-top:5px;text-align:right;}
.form-horizontal .controls{margin-left:160px;}
.form-horizontal .form-actions{padding-left:160px;}
table{max-width:100%;border-collapse:collapse;border-spacing:0;}
.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;vertical-align:top;border-top:1px solid #ddd;}
.table th{font-weight:bold;}
.table thead th{vertical-align:bottom;}
.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;}
.table tbody+tbody{border-top:2px solid #ddd;}
.table-condensed th,.table-condensed td{padding:4px 5px;}
.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;}
.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}
.table tbody tr:hover td,.table tbody tr:hover th{background-color:#f5f5f5;}
table .span1{float:none;width:44px;margin-left:0;}
table .span2{float:none;width:124px;margin-left:0;}
table .span3{float:none;width:204px;margin-left:0;}
table .span4{float:none;width:284px;margin-left:0;}
table .span5{float:none;width:364px;margin-left:0;}
table .span6{float:none;width:444px;margin-left:0;}
table .span7{float:none;width:524px;margin-left:0;}
table .span8{float:none;width:604px;margin-left:0;}
table .span9{float:none;width:684px;margin-left:0;}
table .span10{float:none;width:764px;margin-left:0;}
table .span11{float:none;width:844px;margin-left:0;}
table .span12{float:none;width:924px;margin-left:0;}
[class^="icon-"],[class*=" icon-"]{display:inline-block;width:14px;height:14px;line-height:14px;vertical-align:text-top;background-image:url("/assets/glyphicons-halflings.png");background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child,[class*=" icon-"]:last-child{*margin-left:0;}
.icon-white{background-image:url("/assets/glyphicons-halflings-white.png");}
.icon-glass{background-position:0 0;}
.icon-music{background-position:-24px 0;}
.icon-search{background-position:-48px 0;}
.icon-envelope{background-position:-72px 0;}
.icon-heart{background-position:-96px 0;}
.icon-star{background-position:-120px 0;}
.icon-star-empty{background-position:-144px 0;}
.icon-user{background-position:-168px 0;}
.icon-film{background-position:-192px 0;}
.icon-th-large{background-position:-216px 0;}
.icon-th{background-position:-240px 0;}
.icon-th-list{background-position:-264px 0;}
.icon-ok{background-position:-288px 0;}
.icon-remove{background-position:-312px 0;}
.icon-zoom-in{background-position:-336px 0;}
.icon-zoom-out{background-position:-360px 0;}
.icon-off{background-position:-384px 0;}
.icon-signal{background-position:-408px 0;}
.icon-cog{background-position:-432px 0;}
.icon-trash{background-position:-456px 0;}
.icon-home{background-position:0 -24px;}
.icon-file{background-position:-24px -24px;}
.icon-time{background-position:-48px -24px;}
.icon-road{background-position:-72px -24px;}
.icon-download-alt{background-position:-96px -24px;}
.icon-download{background-position:-120px -24px;}
.icon-upload{background-position:-144px -24px;}
.icon-inbox{background-position:-168px -24px;}
.icon-play-circle{background-position:-192px -24px;}
.icon-repeat{background-position:-216px -24px;}
.icon-refresh{background-position:-240px -24px;}
.icon-list-alt{background-position:-264px -24px;}
.icon-lock{background-position:-287px -24px;}
.icon-flag{background-position:-312px -24px;}
.icon-headphones{background-position:-336px -24px;}
.icon-volume-off{background-position:-360px -24px;}
.icon-volume-down{background-position:-384px -24px;}
.icon-volume-up{background-position:-408px -24px;}
.icon-qrcode{background-position:-432px -24px;}
.icon-barcode{background-position:-456px -24px;}
.icon-tag{background-position:0 -48px;}
.icon-tags{background-position:-25px -48px;}
.icon-book{background-position:-48px -48px;}
.icon-bookmark{background-position:-72px -48px;}
.icon-print{background-position:-96px -48px;}
.icon-camera{background-position:-120px -48px;}
.icon-font{background-position:-144px -48px;}
.icon-bold{background-position:-167px -48px;}
.icon-italic{background-position:-192px -48px;}
.icon-text-height{background-position:-216px -48px;}
.icon-text-width{background-position:-240px -48px;}
.icon-align-left{background-position:-264px -48px;}
.icon-align-center{background-position:-288px -48px;}
.icon-align-right{background-position:-312px -48px;}
.icon-align-justify{background-position:-336px -48px;}
.icon-list{background-position:-360px -48px;}
.icon-indent-left{background-position:-384px -48px;}
.icon-indent-right{background-position:-408px -48px;}
.icon-facetime-video{background-position:-432px -48px;}
.icon-picture{background-position:-456px -48px;}
.icon-pencil{background-position:0 -72px;}
.icon-map-marker{background-position:-24px -72px;}
.icon-adjust{background-position:-48px -72px;}
.icon-tint{background-position:-72px -72px;}
.icon-edit{background-position:-96px -72px;}
.icon-share{background-position:-120px -72px;}
.icon-check{background-position:-144px -72px;}
.icon-move{background-position:-168px -72px;}
.icon-step-backward{background-position:-192px -72px;}
.icon-fast-backward{background-position:-216px -72px;}
.icon-backward{background-position:-240px -72px;}
.icon-play{background-position:-264px -72px;}
.icon-pause{background-position:-288px -72px;}
.icon-stop{background-position:-312px -72px;}
.icon-forward{background-position:-336px -72px;}
.icon-fast-forward{background-position:-360px -72px;}
.icon-step-forward{background-position:-384px -72px;}
.icon-eject{background-position:-408px -72px;}
.icon-chevron-left{background-position:-432px -72px;}
.icon-chevron-right{background-position:-456px -72px;}
.icon-plus-sign{background-position:0 -96px;}
.icon-minus-sign{background-position:-24px -96px;}
.icon-remove-sign{background-position:-48px -96px;}
.icon-ok-sign{background-position:-72px -96px;}
.icon-question-sign{background-position:-96px -96px;}
.icon-info-sign{background-position:-120px -96px;}
.icon-screenshot{background-position:-144px -96px;}
.icon-remove-circle{background-position:-168px -96px;}
.icon-ok-circle{background-position:-192px -96px;}
.icon-ban-circle{background-position:-216px -96px;}
.icon-arrow-left{background-position:-240px -96px;}
.icon-arrow-right{background-position:-264px -96px;}
.icon-arrow-up{background-position:-289px -96px;}
.icon-arrow-down{background-position:-312px -96px;}
.icon-share-alt{background-position:-336px -96px;}
.icon-resize-full{background-position:-360px -96px;}
.icon-resize-small{background-position:-384px -96px;}
.icon-plus{background-position:-408px -96px;}
.icon-minus{background-position:-433px -96px;}
.icon-asterisk{background-position:-456px -96px;}
.icon-exclamation-sign{background-position:0 -120px;}
.icon-gift{background-position:-24px -120px;}
.icon-leaf{background-position:-48px -120px;}
.icon-fire{background-position:-72px -120px;}
.icon-eye-open{background-position:-96px -120px;}
.icon-eye-close{background-position:-120px -120px;}
.icon-warning-sign{background-position:-144px -120px;}
.icon-plane{background-position:-168px -120px;}
.icon-calendar{background-position:-192px -120px;}
.icon-random{background-position:-216px -120px;}
.icon-comment{background-position:-240px -120px;}
.icon-magnet{background-position:-264px -120px;}
.icon-chevron-up{background-position:-288px -120px;}
.icon-chevron-down{background-position:-313px -119px;}
.icon-retweet{background-position:-336px -120px;}
.icon-shopping-cart{background-position:-360px -120px;}
.icon-folder-close{background-position:-384px -120px;}
.icon-folder-open{background-position:-408px -120px;}
.icon-resize-vertical{background-position:-432px -119px;}
.icon-resize-horizontal{background-position:-456px -118px;}
.dropdown{position:relative;}
.dropdown-toggle{*margin-bottom:-3px;}
.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
.caret{display:inline-block;width:0;height:0;text-indent:-99999px;*text-indent:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"\2193";}
.dropdown .caret{margin-top:8px;margin-left:2px;}
.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);}
.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;_width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.bottom-up{top:auto;bottom:100%;margin-bottom:2px;}
.dropdown-menu .divider{height:1px;margin:5px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#555555;white-space:nowrap;}
.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;}
.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
.dropdown.open .dropdown-menu{display:block;}
.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;}
.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;}
.btn{display:inline-block;padding:4px 10px 4px;margin-bottom:0;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);vertical-align:middle;background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-ms-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(top, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);*margin-left:.3em;}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{background-color:#e6e6e6;}
.btn:active,.btn.active{background-color:#cccccc \9;}
.btn:first-child{*margin-left:0;}
.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;outline:0;}
.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.btn-large [class^="icon-"]{margin-top:1px;}
.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
.btn-small [class^="icon-"]{margin-top:-1px;}
.btn-mini{padding:2px 6px;font-size:11px;line-height:14px;}
.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover,.btn-inverse,.btn-inverse:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;}
.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-dark.active{color:rgba(255, 255, 255, 0.75);}
.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;}
.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;}
.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;}
.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;}
.btn-success:active,.btn-success.active{background-color:#408140 \9;}
.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;}
.btn-info:active,.btn-info.active{background-color:#24748c \9;}
.btn-inverse{background-color:#393939;background-image:-moz-linear-gradient(top, #454545, #262626);background-image:-ms-linear-gradient(top, #454545, #262626);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#454545), to(#262626));background-image:-webkit-linear-gradient(top, #454545, #262626);background-image:-o-linear-gradient(top, #454545, #262626);background-image:linear-gradient(top, #454545, #262626);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#454545', endColorstr='#262626', GradientType=0);border-color:#262626 #262626 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{background-color:#262626;}
.btn-inverse:active,.btn-inverse.active{background-color:#0c0c0c \9;}
button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;}
button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;}
.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
.btn-group:after{clear:both;}
.btn-group:first-child{*margin-left:0;}
.btn-group+.btn-group{margin-left:5px;}
.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;}
.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;}
.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);}
.btn .caret{margin-top:7px;margin-left:0;}
.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
.btn-primary .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
.btn-small .caret{margin-top:4px;}
.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.alert,.alert-heading{color:#c09853;}
.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
.alert-success{background-color:#dff0d8;border-color:#d6e9c6;}
.alert-success,.alert-success .alert-heading{color:#468847;}
.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;}
.alert-danger,.alert-error,.alert-danger .alert-heading,.alert-error .alert-heading{color:#b94a48;}
.alert-info{background-color:#d9edf7;border-color:#bce8f1;}
.alert-info,.alert-info .alert-heading{color:#3a87ad;}
.alert-block{padding-top:14px;padding-bottom:14px;}
.alert-block>p,.alert-block>ul{margin-bottom:0;}
.alert-block p+p{margin-top:5px;}
.nav{margin-left:0;margin-bottom:18px;list-style:none;}
.nav>li>a{display:block;}
.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
.nav .nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}
.nav li+.nav-header{margin-top:9px;}
.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;}
.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
.nav-list>li>a{padding:3px 15px;}
.nav-list .active>a,.nav-list .active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
.nav-list [class^="icon-"]{margin-right:2px;}
.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
.nav-tabs:after,.nav-pills:after{clear:both;}
.nav-tabs>li,.nav-pills>li{float:left;}
.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
.nav-tabs{border-bottom:1px solid #ddd;}
.nav-tabs>li{margin-bottom:-1px;}
.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;}
.nav-stacked>li{float:none;}
.nav-stacked>li>a{margin-right:0;}
.nav-tabs.nav-stacked{border-bottom:0;}
.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;}
.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;}
.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;}
.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;}
.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
.tabs-stacked .open>a:hover{border-color:#999999;}
.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
.tabbable:after{clear:both;}
.tab-content{overflow:hidden;}
.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;}
.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
.tab-content>.active,.pill-content>.active{display:block;}
.tabs-below .nav-tabs{border-top:1px solid #ddd;}
.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;}
.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;}
.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;}
.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
.navbar{overflow:visible;margin-bottom:18px;}
.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;}
.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;}
.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
.nav-collapse.collapse{height:auto;}
.navbar .brand:hover{text-decoration:none;}
.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;}
.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;}
.navbar .btn,.navbar .btn-group{margin-top:5px;}
.navbar .btn-group .btn{margin-top:0;}
.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";}
.navbar-form:after{clear:both;}
.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;}
.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}
.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;}
.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;}
.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);}
.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;}
.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
.navbar .nav.pull-right{float:right;}
.navbar .nav>li{display:block;float:left;}
.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;}
.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;}
.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;}
.navbar .nav.pull-right{margin-left:10px;margin-right:0;}
.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;}
.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);}
.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;}
.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;}
.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;}
.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;}
.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline-block;text-shadow:0 1px 0 #ffffff;}
.breadcrumb .divider{padding:0 5px;color:#999999;}
.breadcrumb .active a{color:#333333;}
.pagination{height:36px;margin:18px 0;}
.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
.pagination li{display:inline;}
.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;}
.pagination a:hover,.pagination .active a{background-color:#f5f5f5;}
.pagination .active a{color:#999999;cursor:default;}
.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;}
.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
.pagination-centered{text-align:center;}
.pagination-right{text-align:right;}
.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";}
.pager:after{clear:both;}
.pager li{display:inline;}
.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
.pager .next a{float:right;}
.pager .previous a{float:left;}
.modal-open .dropdown-menu{z-index:2050;}
.modal-open .dropdown.open{*z-index:2050;}
.modal-open .popover{z-index:2060;}
.modal-open .tooltip{z-index:2070;}
.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
.modal{position:fixed;top:50%;left:50%;z-index:1050;max-height:500px;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
.modal.fade.in{top:50%;}
.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
.modal-body{padding:15px;}
.modal-body .modal-form{margin-bottom:0;}
.modal-footer{padding:14px 15px 15px;margin-bottom:0;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";}
.modal-footer:after{clear:both;}
.modal-footer .btn{float:right;margin-left:5px;margin-bottom:0;}
.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
.tooltip.top{margin-top:-2px;}
.tooltip.right{margin-left:2px;}
.tooltip.bottom{margin-top:2px;}
.tooltip.left{margin-left:-2px;}
.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.tooltip-arrow{position:absolute;width:0;height:0;}
.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;}
.popover.right{margin-left:5px;}
.popover.bottom{margin-top:5px;}
.popover.left{margin-left:-5px;}
.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
.popover .arrow{position:absolute;width:0;height:0;}
.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}
.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";}
.thumbnails:after{clear:both;}
.thumbnails>li{float:left;margin:0 0 18px 20px;}
.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}
a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
.thumbnail .caption{padding:9px;}
.label{padding:2px 4px 3px;font-size:11.049999999999999px;font-weight:bold;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
.label:hover{color:#ffffff;text-decoration:none;}
.label-important{background-color:#b94a48;}
.label-important:hover{background-color:#953b39;}
.label-warning{background-color:#f89406;}
.label-warning:hover{background-color:#c67605;}
.label-success{background-color:#468847;}
.label-success:hover{background-color:#356635;}
.label-info{background-color:#3a87ad;}
.label-info:hover{background-color:#2d6987;}
@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);}
.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);}
.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);}
.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
.accordion{margin-bottom:18px;}
.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
.accordion-heading{border-bottom:0;}
.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
.carousel{position:relative;margin-bottom:18px;line-height:1;}
.carousel-inner{overflow:hidden;width:100%;position:relative;}
.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
.carousel .item>img{display:block;line-height:1;}
.carousel .active,.carousel .next,.carousel .prev{display:block;}
.carousel .active{left:0;}
.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
.carousel .next{left:100%;}
.carousel .prev{left:-100%;}
.carousel .next.left,.carousel .prev.right{left:0;}
.carousel .active.left{left:-100%;}
.carousel .active.right{left:100%;}
.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);}
.carousel-caption h4,.carousel-caption p{color:#ffffff;}
.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;}
.hero-unit p{font-size:18px;font-weight:200;line-height:27px;}
.pull-right{float:right;}
.pull-left{float:left;}
.hide{display:none;}
.show{display:block;}
.invisible{visibility:hidden;}

View file

@ -0,0 +1,55 @@
body.simple
margin-top: 20px
margin-bottom: 20px
#footer-simple
text-align: center
.top-pix18
margin-top: 18px
body.application
margin-top: 10px
margin-bottom: 10px
#sidebar
.logo
img
margin-bottom: 10px
p.version
text-align: center
tr.unseen
font-weight: bold
.bottom-pix18
margin-bottom: 18px
table.header
td.field_name
text-align: right
font-weight: bold
padding-right: 10px
p.help-block
font-size: 10px
.custom_pagination
text-align: right
a,span,em
line-height: 18px
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05)
margin-bottom: 0
margin-left: 0
border: 1px solid #DDDDDD
padding: 3px
table.records
font-size: 12px
td
padding: 4px
iframe
width: 700px
height: 800px

View file

@ -0,0 +1,53 @@
$blue: #0088CC
$outline: #DDDDDD
$month: #0044CC
$outside: #DDDDDD
$today: #DA4F49
.calendar
margin-bottom: 18px
h3
color: $month
table
width: 100%
border: 1px solid $outline
border-collapse: separate
border-radius: 4px 4px 4px 4px
td
text-align: right
margin: 2px
padding: 2px
border-top: 1px solid $outline
border-left: 1px solid $outline
td.wday
color: $blue
font-weight: bold
text-align: center
td.corner
border-top: 0 none
border-left: 0 none
td.weekend
background-color: $outline
td.outside
background-color: white
color: $outside
td.today
background-color: $today
color: white
font-weight: bold
td.weeknum
color: $blue
font-weight: bold
text-align: center
.calendar.square
td.wday
border-top: 0 none
td.weeknum
border-left: 0 none
.calendar.window
td.monthnum
border-top: 0 none
tr > td:first-child
border-left: 0 none

View file

@ -2,13 +2,14 @@ require 'yaml'
class ApplicationController < ActionController::Base
protect_from_forgery
#logger.custom("session",session.inspect)
#protect_from_forgery
before_filter :load_defaults,:current_user,:set_locale
before_filter :plugins_configuration
before_filter :load_settings,:current_user,:set_locale
#before_filter :plugins_configuration
def load_defaults
$defaults ||= YAML::load(File.open(Rails.root.join('config','defaults.yml')))
def load_settings
$defaults ||= YAML::load(File.open(Rails.root.join('config','settings.yml')))
end
################################# protected section ###########################################
@ -33,6 +34,7 @@ class ApplicationController < ActionController::Base
def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id]
logger.custom("current_user",@current_user.inspect)
end
def check_current_user
@ -63,15 +65,15 @@ class ApplicationController < ActionController::Base
def prepare_compose_buttons
@buttons = []
@buttons << {:text => 'send',:scope=>:compose,:image => 'email.png'}
@buttons << {:text => 'save_as_draft',:scope=>:compose,:image => 'save.png'}
@buttons << {:text => 'sendout',:scope=>:compose,:image => 'email.png'}
@buttons << {:text => 'save',:scope=>:compose,:image => 'save.png'}
end
def create_message_with_params
@message = Message.new
if params[:message]
@message.update_attributes(params[:message])
end
@message = Message.new(params[:message])
# if params[:message]
# @message.update_attributes(params[:message])
# end
files = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
@attachments = []
files.each do |f|
@ -88,12 +90,6 @@ class ApplicationController < ActionController::Base
##################################### private section ##########################################
private
def plugins_configuration
WillPaginate::ViewHelpers.pagination_options[:previous_label] = t(:previous_page,:scope=>:common)
WillPaginate::ViewHelpers.pagination_options[:next_label] = t(:next_page,:scope=>:common)
end
end

View file

@ -6,34 +6,10 @@ class ContactsController < ApplicationController
before_filter :get_contacts, :only => [:index]
before_filter :prepare_ops_buttons, :prepare_export_import_buttons,:only => [:index]
theme :theme_resolver
def index
end
def ops
if params["create_new"]
redirect_to(new_contact_path)
return
end
if !params["cids"]
flash[:warning] = t(:no_selected,:scope=>:contact)
else
if params["delete_selected"]
params["cids"].each do |id|
@current_user.contacts.find_by_id(id).destroy
end
elsif params["compose_to_selected"]
redirect_to :controller=>'messages',:action=>'compose',:cids=>params["cids"]
return
end
end
redirect_to(contacts_path)
end
#problem http://binary10ve.blogspot.com/2011/05/migrating-to-rails-3-got-stuck-with.html
#def destroy
# @current_user.contacts.find(params[:id]).destroy
@ -50,10 +26,25 @@ class ContactsController < ApplicationController
end
def create
if params["compose_to_selected"]
if params["items_ids"]
redirect_to compose_path(:cids => params["items_ids"])
return
end
end
if params["delete_selected"]
if params["items_ids"]
params["items_ids"].each do |id|
@current_user.contacts.find_by_id(id).destroy
end
end
redirect_to(contacts_path)
return
end
@contact = @current_user.contacts.build(params[:contact])
if @contact.valid?
@contact.save
flash[:notice] = t(:was_created,:scope=>:contact)
flash[:success] = t(:was_created,:scope=>:contact)
redirect_to(contacts_path)
else
render 'new'
@ -69,9 +60,16 @@ class ContactsController < ApplicationController
end
end
def external
def import_export
if params["export"]
redirect_to :action => 'export'
contacts = @current_user.contacts
s = ""
contacts.each do |c|
s += c.export + "\r\n"
end
headers['Content-type'] = "text/csv"
headers['Content-Disposition'] = %(attachment; filename="contacts.csv")
render :text => s
return
elsif params["import"]
begin
@ -82,44 +80,24 @@ class ContactsController < ApplicationController
tmp_file.flush
tmp_file.rewind
tmp_file.readlines.each do |line|
next if line =~ /^#/
Contact.import(@current_user,line)
end
rescue ActiveRecord::RecordInvalid => e
flash[:error] = {:title => e.to_s,:info => e.record.inspect + e.record.errors.inspect}
rescue Exception => e
flash[:error] = e.to_s
else
flash[:success] = t(:were_imported,:scope=>:contact)
end
end
flash[:notice] = t(:were_imported,:scope=>:contact) if not flash[:error]
redirect_to :action => 'index'
end
def export
contacts = @current_user.contacts
s = ""
contacts.each do |c|
s += c.export + "\r\n"
end
headers['Content-type'] = "text/csv"
headers['Content-Disposition'] = %(attachment; filename="contacts.csv")
render :text => s
end
####################################### protected section ################################
protected
def prepare_ops_buttons
@buttons = []
@buttons << {:text => 'compose_to_selected',:scope=> 'contact', :image => 'email.png'}
@buttons << {:text => 'create_new',:scope=> 'contact', :image => 'plus.png'}
@buttons << {:text => 'delete_selected',:scope=>'contact',:image => 'minus.png'}
end
def prepare_export_import_buttons
@ei_buttons = []
@ei_buttons << {:text => 'import',:scope=>'contact',:image => 'right.png'}
@ei_buttons << {:text => 'export',:scope=>'contact',:image => 'left.png'}
end
####################################### private section ##################################
private

View file

@ -12,13 +12,12 @@ class FoldersController < ApplicationController
after_filter :close_imap_session, :except => [:index,:show_hide,:system]
before_filter :get_folders
#before_filter :prepare_buttons_to_folders
theme :theme_resolver
#theme :theme_resolver
def index
@buttons = []
@buttons << {:text => 'show_hide',:scope=>'folder',:image => 'flag.png'}
@buttons << {:text => 'refresh',:scope=>'folder',:image => 'refresh.png'}
#before_filter
end
def create
@ -42,7 +41,7 @@ class FoldersController < ApplicationController
render 'index'
return
end
flash[:notice] = t(:was_created,:scope=>:folder)
flash[:success] = t(:was_created,:scope=>:folder)
redirect_to :action => 'index'
end
end
@ -67,7 +66,7 @@ class FoldersController < ApplicationController
render 'index'
return
end
flash[:notice] = t(:was_deleted,:scope=>:folder)
flash[:success] = t(:was_deleted,:scope=>:folder)
redirect_to :action => 'index'
end
end
@ -154,10 +153,16 @@ class FoldersController < ApplicationController
protected
#def prepare_buttons_to_folders
#@buttons = []
#@buttons << {:text => 'show_hide',:scope=>'folder',:image => 'flag.png'}
#@buttons << {:text => 'refresh',:scope=>'folder',:image => 'refresh.png'}
#end
def get_folders
@folders = @current_user.folders
@folders_shown = @current_user.folders.shown
#@folders_system = @current_user.folders.sys
@folders_system = @current_user.folders.sys
@current_user.folders.inbox.first.nil? ? @folder_inbox = "" : @folder_inbox = @current_user.folders.inbox.first.id
@current_user.folders.drafts.first.nil? ? @folder_drafts = "" : @folder_drafts = @current_user.folders.drafts.first.id
@current_user.folders.sent.first.nil? ? @folder_sent = "" : @folder_sent = @current_user.folders.sent.first.id

View file

@ -2,20 +2,21 @@ class InternalController < ApplicationController
before_filter :check_current_user ,:selected_folder, :get_current_folders, :only => [:about]
theme :theme_resolver
#theme :theme_resolver
layout "simple"
ERRORS = [
:internal_server_error,
:not_found,
:unprocessable_entity
:unprocessable_entity,
:allready_configured
].freeze
ERRORS.each do |e|
define_method e do
@title = t(e,:scope=>:internal)
@error = t(e,:scope=>:internal)
flash[:error] = t(e,:scope=>:internal)
render 'error'
end
end
@ -39,12 +40,19 @@ class InternalController < ApplicationController
redirect_to :controller=>'user', :action => 'login'
end
def onlycanlogins
reset_session
flash[:error] = t(:only_can_logins,:scope=>:user)
@current_user = nil
redirect_to :controller=>'user', :action => 'login'
end
#def onlycanlogins
#reset_session
#flash[:error] = t(:only_can_logins,:scope=>:user)
#@current_user = nil
#redirect_to :controller=>'user', :action => 'login'
#end
#def onlycanlogins
#reset_session
#flash[:error] = t(:allready_configured,:scope=>:user)
#@current_user = nil
#redirect_to :controller=>'user', :action => 'login'
#end
def about
render 'internal/about', :layout => 'application'

View file

@ -0,0 +1,97 @@
require 'tempfile'
class LinksController < ApplicationController
before_filter :check_current_user,:selected_folder, :get_current_folders
before_filter :get_links, :only => [:index]
def index
end
def new
@link = Link.new
end
def edit
@link = @current_user.links.find(params[:id])
render 'edit'
end
def create
if params["delete_selected"]
if params["items_ids"]
params["items_ids"].each do |id|
@current_user.links.find_by_id(id).destroy
end
end
redirect_to(links_path)
return
end
@link = @current_user.links.build(params[:link])
if @link.valid?
@link.save
flash[:success] = t(:was_created,:scope=>:link)
redirect_to(links_path)
else
render 'new'
end
end
def update
@link = @current_user.links.find(params[:id])
if @link.update_attributes(params[:link])
redirect_to(links_path)
else
render 'edit'
end
end
def import_export
if params["export"]
links = @current_user.links
s = ""
links.each do |l|
s += l.export + "\r\n"
end
headers['Content-type'] = "text/csv"
headers['Content-Disposition'] = %(attachment; filename="links.csv")
render :text => s
return
elsif params["import"]
begin
raise t(:no_file_chosen,:scope=>:common) if not params[:upload]
raise t(:no_tmp_dir,:scope=>:common) if not File.exists?($defaults["msg_upload_dir"])
tmp_file = Tempfile.new($defaults["contact_tmp_filename"],$defaults["msg_upload_dir"])
tmp_file.write(params[:upload][:datafile].read)
tmp_file.flush
tmp_file.rewind
tmp_file.readlines.each do |line|
next if line =~ /^#/
Link.import(@current_user,line)
end
rescue ActiveRecord::RecordInvalid => e
flash[:error] = {:title => e.to_s,:info => e.record.inspect + e.record.errors.inspect}
rescue Exception => e
flash[:error] = e.to_s
else
flash[:success] = t(:were_imported,:scope=>:link)
end
end
redirect_to :action => 'index'
end
####################################### protected section ################################
protected
####################################### private section ##################################
private
def get_links
@links = Link.getPageForUser(@current_user,params[:page],params[:sort_field],params[:sort_dir])
end
end

View file

@ -16,12 +16,12 @@ class MessagesController < ApplicationController
before_filter :prepare_compose_buttons, :only => [:compose]
before_filter :get_system_folders, :only => [:index]
before_filter :create_message_with_params, :only => [:compose]
before_filter :prepare_multi1_buttons, :only => [:index,:show]
before_filter :prepare_multi2_buttons, :only => [:index]
before_filter :prepare_multi3_buttons, :only => [:show]
#before_filter :prepare_multi1_buttons, :only => [:index,:show]
#before_filter :prepare_multi2_buttons, :only => [:index]
#before_filter :prepare_multi3_buttons, :only => [:show]
after_filter :close_imap_session
theme :theme_resolver
#theme :theme_resolver
def index
@ -90,11 +90,12 @@ class MessagesController < ApplicationController
@text_part = nil
@html_part = nil
@message = @current_user.messages.find_by_uid(params[:id])
@message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
@message.update_attributes(:unseen => false)
imap_message = @mailbox.fetch_body(@message.uid)
mail = Mail.new(imap_message)
@mail = Mail.new(imap_message)
@plain_header = mail.header.to_s
@ -103,8 +104,8 @@ class MessagesController < ApplicationController
#@to = mail.To.addrs.presence
@from = @message.from_addr
@to = @message.to_addr
@cc = mail.Cc.presence
@bcc = mail.Bcc.presence
#@cc = mail.cc
#@bcc = mail.bcc
#@subject = mail.Subject
@date = mail.date.presence
@ -129,7 +130,9 @@ class MessagesController < ApplicationController
end
end
else
part = Mail::Part.new(mail)
logger.custom('mail',mail.inspect)
part = mail
#part = Mail::Part.new(mail)
part.idx = 0
part.parent_id = @message.uid
if part.isText?
@ -145,7 +148,7 @@ class MessagesController < ApplicationController
end
def html_body
message = @current_user.messages.find(params[:id])
message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
mail = Mail.new(@mailbox.fetch_body(message.uid))
if mail.multipart?
@body = mail.html_part.decoded_and_charseted
@ -160,7 +163,7 @@ class MessagesController < ApplicationController
attachments = mail.attachments
if not attachments.size.zero?
for idx in 0..attachments.size - 1
@body.gsub!(/cid:#{attachments[idx].cid}/,messages_attachment_download_path(message.uid,idx))
@body.gsub!(/cid:#{attachments[idx].cid}/,attachment_download_path(message.uid,idx))
end
end
end
@ -170,12 +173,13 @@ class MessagesController < ApplicationController
def attachment
attachments = []
message = @current_user.messages.find(params[:id])
message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
mail = Mail.new(@mailbox.fetch_body(message.uid))
if mail.multipart? == true
attachments = mail.attachments
else
attachments << Mail::Part.new(mail)
#attachments << Mail::Part.new(mail)
attachments << mail
end
a = attachments[params[:idx].to_i]
headers['Content-type'] = a.main_type + "/" + a.sub_type
@ -188,23 +192,23 @@ class MessagesController < ApplicationController
protected
def prepare_multi2_buttons
@multi2_buttons = []
@multi2_buttons << {:text => 'trash',:scope=>:message,:image => 'trash.png'}
@multi2_buttons << {:text => 'set_unread',:scope=>:message,:image => 'unseen.png'}
@multi2_buttons << {:text => 'set_read',:scope=>:message,:image => 'seen.png'}
end
#def prepare_multi2_buttons
#@multi2_buttons = []
#@multi2_buttons << {:text => 'trash',:scope=>:message,:image => 'trash.png'}
#@multi2_buttons << {:text => 'set_unread',:scope=>:message,:image => 'unseen.png'}
#@multi2_buttons << {:text => 'set_read',:scope=>:message,:image => 'seen.png'}
#end
def prepare_multi1_buttons
@multi1_buttons = []
@multi1_buttons << {:text => 'copy',:scope=>:message,:image => 'copy.png'}
@multi1_buttons << {:text => 'move',:scope=>:message,:image => 'move.png'}
end
#def prepare_multi1_buttons
#@multi1_buttons = []
#@multi1_buttons << {:text => 'copy',:scope=>:message,:image => 'copy.png'}
#@multi1_buttons << {:text => 'move',:scope=>:message,:image => 'move.png'}
#end
def prepare_multi3_buttons
@multi3_buttons = []
@multi3_buttons << {:text => 'show_header',:scope=>:show,:image => 'zoom.png'}
@multi3_buttons << {:text => 'trash',:scope=>:show,:image => 'trash.png'}
@multi3_buttons << {:text => 'reply',:scope=>:show,:image => 'reply.png'}
end
#def prepare_multi3_buttons
#@multi3_buttons = []
#@multi3_buttons << {:text => 'show_header',:scope=>:show,:image => 'zoom.png'}
#@multi3_buttons << {:text => 'trash',:scope=>:show,:image => 'trash.png'}
#@multi3_buttons << {:text => 'reply',:scope=>:show,:image => 'reply.png'}
#end
end

View file

@ -3,6 +3,7 @@ require 'imap_mailbox'
require 'imap_message'
require 'mail'
require 'mail_plugin_extension'
require 'net/smtp'
class MessagesOpsController < ApplicationController
@ -14,16 +15,17 @@ class MessagesOpsController < ApplicationController
before_filter :check_current_user ,:selected_folder,:get_current_folders
before_filter :open_imap_session, :select_imap_folder
before_filter :prepare_compose_buttons
before_filter :get_system_folders, :only => [:sendout_or_save,:single,:multi]
before_filter :create_message_with_params , :only => [:sendout_or_save]
before_filter :get_system_folders, :only => [:composed,:single,:multi]
before_filter :prepare_composed , :only => [:composed]
before_filter :create_message_with_params, :only=> [:composed,:single,:multi]
after_filter :close_imap_session
theme :theme_resolver
#theme :theme_resolver
############################################### single #####################################
def single
if params[:reply]
if params[:reply] or params[:reply_all]
reply
return
elsif params[:trash]
@ -65,14 +67,14 @@ class MessagesOpsController < ApplicationController
def set_unread
params["uids"].each do |uid|
@mailbox.set_unread(uid)
@current_user.messages.find_by_uid(uid).update_attributes(:unseen => 1)
@current_user.messages.where('folder_id = ? and uid = ?',@current_folder,uid).first.update_attributes(:unseen => 1)
end
end
def set_read
params["uids"].each do |uid|
@mailbox.set_read(uid)
@current_user.messages.find_by_uid(uid).update_attributes(:unseen => 0)
@current_user.messages.where('folder_id = ? and uid = ?',@current_folder,uid).first.update_attributes(:unseen => 0)
end
end
@ -113,29 +115,41 @@ class MessagesOpsController < ApplicationController
flash[:warning] = t(:no_selected,:scope=>:folder)
else
dest_folder = @current_user.folders.find(params[:folder][:target])
logger.info "DEST: "+dest_folder.inspect
params["uids"].each do |uid|
logger.info "UID: "+uid
logger.info "DEST_FULL: "+dest_folder.full_name
@mailbox.move_message(uid,dest_folder.full_name)
message = @current_folder.messages.find_by_uid(uid)
logger.info "M: "+message.inspect
logger.info "UPDATE_DEST_BEFORE1: "+dest_folder.inspect
message.change_folder(dest_folder)
logger.info "UPDATE_DEST_BEFORE2: "+dest_folder.inspect
end
logger.info "UPDATE_DEST_BEFORE: "+dest_folder.inspect
@mailbox.expunge
dest_folder.update_stats
logger.info "UPDATE_DEST: "+dest_folder.inspect
@current_folder.update_stats
logger.info "UPDATE_CUT: "+@current_folder.inspect
end
end
def upload
#FIXME check if uploads directory exists
begin
raise MailrException.new :cause=>:no_tmp_dir,:scope=>:common if not File.exists?($defaults["msg_upload_dir"])
raise MailrException.new :cause=>:no_file_chosen,:scope=>:common if not params[:upload]
@operation = :upload
create_message_with_params
if not params[:upload]
flash[:error] = t(:no_file_chosen,:scope=>:common)
else
name = params[:upload][:datafile].original_filename
name = params[:file][:data].original_filename
upload_dir = $defaults["msg_upload_dir"]
path = File.join(upload_dir, @current_user.username + "_" + name)
File.open(path, "wb") { |f| f.write(params[:upload][:datafile].read) }
File.open(path, "wb") { |f| f.write(params[:file][:data].read) }
rescue MailrException => e
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
rescue Exception => e
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
end
create_message_with_params
render 'messages/compose'
end
@ -168,13 +182,7 @@ class MessagesOpsController < ApplicationController
# if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}")
# end
############################################### sendout_or_save ############################
def sendout_or_save
#FIXME check if domain is set
def composed
if params[:delete_marked] and params[:files]
params[:files].each do |filename|
path = File.join(Rails.root,$defaults["msg_upload_dir"],@current_user.username + "_" +filename)
@ -184,81 +192,78 @@ class MessagesOpsController < ApplicationController
@operation = :new
render 'messages/compose'
return
end
mail = Mail.new
mail.subject = params[:message][:subject]
mail.from = @current_user.full_address
#TODO check if email address is valid if not get address from contacts
mail.to = params[:message][:to_addr]
mail.body = params[:message][:body]
attachments = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
#logger.custom('attach',attachments.inspect)
attachments.each do |a|
mail.add_file :filename => File.basename(a.gsub(/#{@current_user.username}_/,"")), :content => File.read(a)
end
if params[:send]
smtp_server = @current_user.servers.primary_for_smtp
if smtp_server.nil?
flash[:error] = t(:not_configured_smtp,:scope => :compose)
@operation = :new
render 'messages/compose'
return
end
begin
set_mail_defaults(@current_user,smtp_server,session)
logger.custom('mail',Mail.delivery_method.inspect)
@response = mail.deliver!
logger.custom('response',@response.inspect)
if @sent_folder.nil?
raise t(:not_configured_sent,:scope=>:compose)
end
@mailbox.append(@sent_folder.full_name,mail.to_s,[:Seen])
rescue Exception => e
flash[:error] = "#{t(:imap_err,:scope=>:internal)} (#{e.to_s})"
elsif params[:upload]
upload
elsif params[:save]
save
elsif params[:sendout]
sendout
else
redirect_to :controller => 'messages', :action => 'index'
return
end
end
attachments.each do |filename|
path = File.join(Rails.root,filename)
def sendout
begin
smtp_server = @current_user.servers.primary_for_smtp
raise MailrException.new :cause=>:not_configured_smtp,:scope => :compose if smtp_server.nil?
raise MailrException.new :cause=>:has_no_domain,:scope=>:user if @current_user.has_domain?.nil?
raise MailrException.new :cause=>:not_configured_sent,:scope=>:compose if @sent_folder.nil?
send_mail_message( smtp_server,
@current_user.has_domain?,
@current_user.login,
@current_user.get_cached_password(session),
@mail.to_s,
@current_user.email,
params[:message][:to_addr]
)
@mailbox.append(@sent_folder.full_name,@mail.to_s,[:Seen])
upload_dir = $defaults["msg_upload_dir"]
@attachments.each do |file|
path = File.join(upload_dir, @current_user.username + "_" + file[:name])
File.delete(path) if File.exist?(path)
end
flash[:notice] = t(:was_sent,:scope => :compose)
rescue MailrException => e
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
rescue Exception => e
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
else
flash[:success] = t(:was_sent,:scope => :compose)
redirect_to :controller => 'messages', :action => 'index'
elsif params[:save_as_draft]
begin
if @drafts_folder.nil?
raise t(:not_configured_drafts,:scope=>:compose)
return
end
@mailbox.append(@drafts_folder.full_name,mail.to_s,[:Seen])
@operation = :new
render 'messages/compose'
end
def save
begin
raise MailrException.new :cause=>:not_configured_drafts,:scope=>:folder if @drafts_folder.nil?
@mailbox.append(@drafts_folder.full_name,@mail.to_s,[:Seen])
if params[:olduid].present?
@mailbox.move_message(params[:olduid],@trash_folder.full_name)
@mailbox.expunge
end
rescue MailrException => e
flash[:error] = t(e.message[:cause],:scope => e.message[:scope])
rescue Exception => e
flash[:error] = "#{t(:imap_error,:scope=>:internal)} (#{e.to_s})"
redirect_to :controller => 'messages', :action => 'index'
return
flash[:error] = t(:general_error,:scope=>:internal) + " (" + e.class.name + " " + e.to_s + ")"
else
@attachments.each do |filename|
path = File.join(Rails.root,filename[:name])
File.delete(path) if File.exist?(path)
end
flash[:success] = t(:was_saved,:scope => :compose)
end
flash[:notice] = t(:was_saved,:scope => :compose)
redirect_to :controller => 'messages', :action => 'index'
end
end
#FIXME edit does not support attachments
def edit
old_message = @current_user.messages.find(params[:id])
#logger.info @current_folder.inspect
#logger.info params.inspect
old_message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:id]).first
@message = Message.new
@message.to_addr = old_message.to_addr
@message.subject = old_message.subject
@ -266,7 +271,7 @@ class MessagesOpsController < ApplicationController
imap_message = @mailbox.fetch_body(old_message.uid)
mail = Mail.new(imap_message)
if mail.multipart?
@message.body = mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
@message.body = mail.text_part.nil? ? "" : mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
else
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
end
@ -277,15 +282,23 @@ class MessagesOpsController < ApplicationController
end
def reply
old_message = @current_user.messages.find(params[:uids].first)
old_message = @current_user.messages.where('folder_id = ? and uid = ?',@current_folder,params[:uids].first).first
@message = Message.new
@message.to_addr = old_message.from_addr
@message.subject = old_message.subject
#@message.to_addr = old_message.from_addr
#@message.to_addr = old_message.from.first
#@message.subject = old_message.subject
imap_message = @mailbox.fetch_body(old_message.uid)
mail = Mail.new(imap_message)
@message.to_addr = mail.from.first
@message.subject = mail.subject
if params[:reply_all]
@message.cc_addr = mail.cc.join('; ')
end
if mail.multipart?
@message.body = mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
@message.body = mail.text_part.nil? ? "" : mail.text_part.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
else
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
end
@ -293,11 +306,34 @@ class MessagesOpsController < ApplicationController
@operation = :reply
render 'messages/compose'
end
###################################### protected section #######################################
protected
def send_mail_message(smtp_server,domain,username,password,msgstr,from,to)
if smtp_server.auth.nil?
smtp = Net::SMTP.start(smtp_server.name, smtp_server.port, domain)
else
smtp = Net::SMTP.start(smtp_server.name, smtp_server.port, domain, username, password, smtp_server.auth)
end
smtp.send_message msgstr, from, to
smtp.finish
end
def prepare_composed
@mail = Mail.new
@mail.subject = params[:message][:subject]
@mail.from = @current_user.full_id
#TODO check if email address is valid if not get address from contacts
@mail.to = params[:message][:to_addr]
@mail.cc = params[:message][:cc_addr]
@mail.body = params[:message][:body]
@attachments = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
@attachments.each do |a|
@mail.add_file :filename => File.basename(a.gsub(/#{@current_user.username}_/,"")), :content => File.read(a)
end
end
############################################ set_mail_defaults ####################################
@ -313,7 +349,7 @@ class MessagesOpsController < ApplicationController
authentication = server.auth
enable_starttls_auto = server.use_tls
openssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
user_name = user.full_address
user_name = user.login
end
Mail.defaults do
delivery_method :smtp, {:address => server.name,

View file

@ -6,13 +6,13 @@ class PrefsController < ApplicationController
before_filter :get_prefs, :only => [:look,:update_look]
theme :theme_resolver
#theme :theme_resolver
def update_look
if params[:prefs]
@prefs.update_attributes(params[:prefs])
end
flash[:notice] = t(:were_saved,:scope=>:prefs)
flash[:success] = t(:were_saved,:scope=>:prefs)
redirect_to :action => 'look'
end
@ -23,9 +23,17 @@ class PrefsController < ApplicationController
def update_identity
if params[:user]
@current_user.update_attributes(params[:user])
end
@current_user.first_name = params[:user][:first_name]
@current_user.last_name = params[:user][:last_name]
@current_user.domain = params[:user][:domain]
if @current_user.valid?
@current_user.save
flash[:success] = t(:were_saved,:scope=>:prefs)
redirect_to :action => 'identity'
else
render 'prefs/identity'
end
end
end
def look
@ -33,7 +41,6 @@ class PrefsController < ApplicationController
end
def identity
@identity = @curent_user
end
def servers

View file

@ -1,36 +1,50 @@
class UserController < ApplicationController
theme :theme_resolver
#theme :theme_resolver
layout "simple"
def login
# database empty redirect to setup screen
users = User.all
if users.count.zero?
redirect_to :controller => 'user', :action => 'setup'
return false
end
end
def logout
reset_session
flash[:notice] = t(:logged_out,:scope=>:user)
flash[:success] = t(:logged_out,:scope=>:user)
redirect_to :action => "login"
end
def authenticate
# check if user can use application
if not $defaults["only_can_logins"].nil?
if not $defaults["only_can_logins"].include?(params[:user][:email])
redirect_to :controller => 'internal', :action => 'onlycanlogins'
if not $defaults["only_can_logins"].include?(params[:user][:login])
flash[:error] = t(:only_can_logins,:scope=>:user)
redirect_to :action => 'login'
return false
end
end
user = User.find_by_email(params[:user][:email])
user = User.find_by_login(params[:user][:login])
if user.nil?
redirect_to :action => 'unknown' ,:email=> params[:user][:email]
flash[:error] = t(:login_failure,:scope=>:user)
redirect_to :action => 'login'
return false
else
session[:user_id] = user.id
user.set_cached_password(session,params[:user][:password])
if session["return_to"]
redirect_to(session["return_to"])
redirect = session["return_to"]
session["return_to"] = nil
redirect_to(redirect)
else
redirect_to :controller=> 'messages', :action=> 'index'
end
@ -38,21 +52,23 @@ class UserController < ApplicationController
end
end
def loginfailure
end
#def loginfailure
#end
def setup
users = User.all
if !users.count.zero?
redirect_to :controller => 'internal', :action => 'allready_configured'
return false
end
@user = User.new
@server = Server.new
end
def unknown
end
def create
@user = User.new
@user.email = params[:user][:email]
@user.login = params[:user][:login]
@user.first_name = params[:user][:first_name]
@user.last_name = params[:user][:last_name]
@ -64,8 +80,8 @@ class UserController < ApplicationController
#@server.user_id = @user.id
#@server.save
Prefs.create_default(@user)
Server.create_defaults(@user)
flash[:notice] = t(:setup_done,:scope=>:user)
Server.create_server(@user,@server.name)
flash[:success] = t(:setup_done,:scope=>:user)
redirect_to :action => 'login'
else
render "setup"

View file

@ -2,328 +2,333 @@ require 'iconv'
module ApplicationHelper
def form_field(object,field,flabel,example,val)
model_name = eval(object.class.model_name)
html = ""
html << "<div class=\"group\">"
if not object.errors[field.to_sym].empty?
html << "<div class=\"fieldWithErrors\">"
#def form_field(object,field,flabel,example,val)
#model_name = eval(object.class.model_name)
#html = ""
#html << "<div class=\"param_group\">"
#if not object.errors[field.to_sym].empty?
#html << "<div class=\"fieldWithErrors\">"
end
#end
html << "<label class=\"label\">"
flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
html << "</label>"
#html << "<label class=\"label\">"
#flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
#html << "</label>"
if not object.errors[field.to_sym].empty?
html << "<span class=\"error\"> "
html << object.errors[field.to_sym].to_s
html << "</span>"
html << "</div>"
end
html << "<input id=\""
html << object.class.name.downcase+"_"+field
html << "\""
html << " name=\"#{object.class.name.downcase}[#{field}]\""
html << " type=\"text\" class=\"text_field\" value=\""
value = val || object.instance_eval(field) || ""
html << value
html << "\"/>"
html << "<span class=\"description\">"
html << t(:example,:scope=>:common)
html << ": "
html << example
html << "</span>"
html << "</div>"
#if not object.errors[field.to_sym].empty?
#html << "<span class=\"error\"> "
#html << object.errors[field.to_sym].to_s
#html << "</span>"
#html << "</div>"
#end
#html << "<input id=\""
#html << object.class.name.downcase+"_"+field
#html << "\""
#html << " name=\"#{object.class.name.downcase}[#{field}]\""
#html << " type=\"text\" class=\"text_field\" value=\""
#value = val || object.instance_eval(field) || ""
#html << value
#html << "\"/>"
#html << "<span class=\"description\">"
#html << t(:example,:scope=>:common)
#html << ": "
#html << example
#html << "</span>"
#html << "</div>"
end
#end
def show_param_view(object,field,value)
model_name = eval(object.class.model_name)
html = ""
html << "<div class=\"group\">"
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}: </label>"
html << value
html << "</div>"
html
end
#def show_param_view(object,field,value)
#model_name = eval(object.class.model_name)
#html = ""
#html << "<div class=\"group clearfix\">"
#html << "<label class=\"label\">#{model_name.human_attribute_name(field)}: </label>"
#html << value
#html << "</div>"
#html
#end
def area_field(object,field,flabel,example,val,cols,rows)
model_name = eval(object.class.model_name)
html = ""
html << "<div class=\"group\">"
if not object.errors[field.to_sym].empty?
html << "<div class=\"fieldWithErrors\">"
end
html << "<label class=\"label\">"
flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
html << "</label>"
if not object.errors[field.to_sym].empty?
html << "<span class=\"error\">"
html << object.errors[field.to_sym].to_s
html << "</span>"
html << "</div>"
end
name = object.class.name.downcase + '[' + field + ']'
id = object.class.name.downcase+"_"+field
value = val || object.instance_eval(field) || ""
html << "<textarea id=\"#{id}\" name=\"#{name}\" class=\"text_area\" cols=\"#{cols}\" rows=\"#{rows}\">#{value}</textarea>"
desc = t(:example,:scope=>:common) + ": " + example
html << "<span class=\"description\">#{desc}</span>"
html << "</div>"
end
def form_button(text,image)
html = ""
html << "<div class=\"group navform wat-cf\">"
html << "<button class=\"button\" type=\"submit\">"
html << "<img src=\""
html << current_theme_image_path(image)
html << "\" alt=\""
html << t(text.to_sym)
html << "\" />"
html << t(text.to_sym)
html << "</button></div>"
end
def single_action(text,scope,image)
html = ""
html << "<div class=\"actiongroup wat-cf\">"
html << "<button class=\"button\" name=\"#{text}\" type=\"submit\">"
html << "<img src=\""
html << current_theme_image_path(image)
html << "\" alt=\""
html << t(text.to_sym, :scope => scope.to_sym)
html << "\" />"
html << t(text.to_sym, :scope => scope.to_sym)
html << "</button></div>"
end
def single_action_onclick(text,scope,image,onclick)
html = ""
html << "<div class=\"actiongroup navform wat-cf\">"
html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
html << onclick
html << "'\">"
html << "<img src=\""
html << current_theme_image_path(image)
html << "\" alt=\""
html << t(text.to_sym, :scope => scope.to_sym)
html << "\" />"
html << t(text.to_sym, :scope => scope.to_sym)
html << "</button></div>"
end
def group_action(buttons)
html = ""
html << "<div class=\"actiongroup navform wat-cf\">"
buttons.each do |b|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
html << "<img src=\""
html << current_theme_image_path(b[:image])
html << "\" alt=\""
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
html << "\" />"
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
html << "</button> "
end
html << "</div>"
end
def group_action_text(buttons,text)
html = ""
html << "<div class=\"group navform wat-cf\">"
buttons.each do |b|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
html << "<img src=\""
html << current_theme_image_path(b[:image])
html << "\" alt=\""
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
html << "\" />"
html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
html << "</button> "
end
html << text
html << "</div>"
end
def form_buttons(buttons)
html = ""
html << "<div class=\"group navform wat-cf\">"
buttons.each do |b|
html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
html << "<img src=\""
html << current_theme_image_path(b[:image])
html << "\" alt=\""
html << t(b[:text].to_sym)
html << "\" />"
html << t(b[:text].to_sym)
html << "</button> "
end
html << "</div>"
end
def form_button_value(text,image,onclick)
html = ""
html << "<div class=\"group navform wat-cf\">"
html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
html << onclick
html << "'\">"
html << "<img src=\""
html << current_theme_image_path(image)
html << "\" alt=\""
html << text
html << "\" />"
html << t(text.to_sym)
html << "</button></div>"
end
def simple_input_field(name,id,label,value)
html = ""
html << "<div class=\"param_group\">"
html << "<label class=\"label\">#{label}</label>"
html << "<input name=\"#{name}[#{id}]\" id=\"#{name}_#{id} class=\"text_field\" type=\"text\" value=\"#{value}\">"
html << "</div>"
end
def select_field(name,object,label,blank)
html = ""
html << "<div class=\"group\">"
html << "<label class=\"label\">#{label}</label>"
html << select(name, name, object.all.collect {|p| [ p.name, p.id ] }, { :include_blank => (blank == true ? true : false)})
html << "</div>"
end
def select_field_table(object,field,table_choices,choice,blank)
model_name = eval(object.class.model_name)
html = ""
html << "<div class=\"param_group\">"
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
html << select(object.class.to_s.downcase, field, options_for_select(table_choices,choice), {:include_blank => blank})
html << "</div>"
end
def select_field_table_t(object,field,table_choices,choice,blank)
model_name = eval(object.class.model_name)
html = ""
html << "<div class=\"param_group\">"
html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
t = []
table_choices.each do |c|
t << [t(c.to_sym,:scope=>:prefs),c.to_s]
end
html << select(object.class.to_s.downcase, field, options_for_select(t,choice), {:include_blank => blank})
html << "</div>"
end
#def form_simle_field(name,label,value)
#def area_field(object,field,flabel,example,val,cols,rows)
#model_name = eval(object.class.model_name)
#html = ""
#html << "<div class=\"group\">"
# html << "<label class=\"label\">#{label}</label>"
# html << "<input class=\"text_field\" type=\"text\" value=\"#{value}\">"
#if not object.errors[field.to_sym].empty?
#html << "<div class=\"fieldWithErrors\">"
#end
#html << "<label class=\"label\">"
#flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
#html << "</label>"
#if not object.errors[field.to_sym].empty?
#html << "<span class=\"error\">"
#html << object.errors[field.to_sym].to_s
#html << "</span>"
#html << "</div>"
#end
#def nav_to_folders
# link_to( t(:folders,:scope=>:folder), :controller=>:folders, :action=>:index )
#end
#
#def nav_to_messages
# link_to( t(:messages,:scope=>:message), :controller=>:messages, :action=>:index )
#end
#
#def nav_to_compose
# link_to( t(:compose,:scope=>:compose), :controller=>:messages, :action=>:compose )
#end
#
#def nav_to_contacts
# link_to( t(:contacts,:scope=>:contact), contacts_path )
#end
#
#def nav_to_prefs
# link_to( t(:prefs,:scope=>:prefs), prefs_look_path )
#name = object.class.name.downcase + '[' + field + ']'
#id = object.class.name.downcase+"_"+field
#value = val || object.instance_eval(field) || ""
#html << "<textarea id=\"#{id}\" name=\"#{name}\" class=\"text_area\" cols=\"#{cols}\" rows=\"#{rows}\">#{value}</textarea>"
#desc = t(:example,:scope=>:common) + ": " + example
#html << "<span class=\"description\">#{desc}</span>"
#html << "</div>"
#end
def single_navigation(label,scope)
s = ""
s += "<ul class=\"wat-cf\">"
s += "<li class=\"first active\">#{link_to(t(label,:scope=>scope),'#')}</li>"
s += "<li class=\"last\">&nbsp;</li>"
s += "</ul>"
#def form_button(text,image)
#html = ""
#html << "<div class=\"group\">"
#html << "<button class=\"button\" type=\"submit\">"
#html << "<img src=\""
#html << current_theme_image_path(image)
#html << "\" alt=\""
#html << t(text.to_sym)
#html << "\" />"
#html << t(text.to_sym)
#html << "</button></div>"
#end
#def single_action(text,scope,image)
#html = ""
#html << "<div class=\"actiongroup clearfix\">"
#html << "<button class=\"button\" name=\"#{text}\" type=\"submit\">"
#html << "<img src=\""
#html << current_theme_image_path(image)
#html << "\" alt=\""
#html << t(text.to_sym, :scope => scope.to_sym)
#html << "\" />"
#html << t(text.to_sym, :scope => scope.to_sym)
#html << "</button></div>"
#end
#def single_action_onclick(text,scope,image,onclick)
#html = ""
#html << "<div class=\"actiongroup clearfix\">"
#html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
#html << onclick
#html << "'\">"
#html << "<img src=\""
#html << current_theme_image_path(image)
#html << "\" alt=\""
#html << t(text.to_sym, :scope => scope.to_sym)
#html << "\" />"
#html << t(text.to_sym, :scope => scope.to_sym)
#html << "</button>"
#html << "</div>"
#end
#def group_action(buttons)
#html = ""
#html << "<div class=\"actiongroup clearfix\">"
#buttons.each do |b|
#html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
#html << "<img src=\""
#html << current_theme_image_path(b[:image])
#html << "\" alt=\""
#html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
#html << "\" />"
#html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
#html << "</button> "
#end
#html << "</div>"
#end
#def group_action_text(buttons,text)
#html = ""
#html << "<div class=\"group\">"
#buttons.each do |b|
#html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
#html << "<img src=\""
#html << current_theme_image_path(b[:image])
#html << "\" alt=\""
#html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
#html << "\" />"
#html << t(b[:text].to_sym,:scope=>b[:scope].to_sym)
#html << "</button> "
#end
#html << text
#html << "</div>"
#end
#def form_buttons(buttons)
#html = ""
#html << "<div class=\"group\">"
#buttons.each do |b|
#html << "<button class=\"button\" type=\"submit\" name=\"#{b[:text]}\">"
#html << "<img src=\""
#html << current_theme_image_path(b[:image])
#html << "\" alt=\""
#html << t(b[:text].to_sym)
#html << "\" />"
#html << t(b[:text].to_sym)
#html << "</button> "
#end
#html << "</div>"
#end
#def form_button_value(text,image,onclick)
#html = ""
#html << "<div class=\"group\">"
#html << "<button class=\"button\" type=\"submit\" onclick=\"window.location='"
#html << onclick
#html << "'\">"
#html << "<img src=\""
#html << current_theme_image_path(image)
#html << "\" alt=\""
#html << text
#html << "\" />"
#html << t(text.to_sym)
#html << "</button></div>"
#end
#def simple_input_field(name,id,label,value)
#html = ""
#html << "<div class=\"param_group\">"
#html << "<label class=\"label\">#{label}</label>"
#html << "<input name=\"#{name}[#{id}]\" id=\"#{name}_#{id} class=\"text_field\" type=\"text\" value=\"#{value}\">"
#html << "</div>"
#end
#def select_field(name,object,label,blank)
#html = ""
#html << "<div class=\"group\">"
#html << "<label class=\"label\">#{label}</label>"
#html << select(name, name, object.all.collect {|p| [ p.name, p.id ] }, { :include_blank => (blank == true ? true : false)})
#html << "</div>"
#end
#def select_field_table(object,field,table_choices,choice,blank)
#model_name = eval(object.class.model_name)
#html = ""
#html << "<div class=\"param_group\">"
#html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
#html << select(object.class.to_s.downcase, field, options_for_select(table_choices,choice), {:include_blank => blank})
#html << "</div>"
#end
#def select_field_table_t(object,field,table_choices,choice,blank)
#model_name = eval(object.class.model_name)
#html = ""
#html << "<div class=\"param_group\">"
#html << "<label class=\"label\">#{model_name.human_attribute_name(field)}</label>"
#t = []
#table_choices.each do |c|
#t << [t(c.to_sym,:scope=>:prefs),c.to_s]
#end
#html << select(object.class.to_s.downcase, field, options_for_select(t,choice), {:include_blank => blank})
#html << "</div>"
#end
##def form_simle_field(name,label,value)
## html = ""
## html << "<div class=\"group\">"
## html << "<label class=\"label\">#{label}</label>"
## html << "<input class=\"text_field\" type=\"text\" value=\"#{value}\">"
## html << "</div>"
##end
##def nav_to_folders
## link_to( t(:folders,:scope=>:folder), :controller=>:folders, :action=>:index )
##end
##
##def nav_to_messages
## link_to( t(:messages,:scope=>:message), :controller=>:messages, :action=>:index )
##end
##
##def nav_to_compose
## link_to( t(:compose,:scope=>:compose), :controller=>:messages, :action=>:compose )
##end
##
##def nav_to_contacts
## link_to( t(:contacts,:scope=>:contact), contacts_path )
##end
##
##def nav_to_prefs
## link_to( t(:prefs,:scope=>:prefs), prefs_look_path )
##end
#def single_navigation(label,scope)
#s = ""
#s += "<ul>"
#s += "<li class=\"first active\">#{link_to(t(label,:scope=>scope),'#')}</li>"
#s += "<li class=\"last\">&nbsp;</li>"
#s += "</ul>"
#end
#def main_navigation(active)
#instance_variable_set("@#{active}", "active")
#s = ""
#s += "<ul>"
#s += "<li class=\"first #{@messages_tab}\">#{link_to( t(:messages,:scope=>:message), messages_path )}</li>"
#s += "<li class=\"#{@compose_tab}\">#{link_to( t(:compose,:scope=>:compose), compose_path )}</li>"
#s += "<li class=\"#{@folders_tab}\">#{link_to( t(:folders,:scope=>:folder), folders_path )}</li>"
#s += "<li class=\"#{@contacts_tab}\">#{link_to( t(:contacts,:scope=>:contact), contacts_path )}</li>"
#s += "<li class=\"#{@prefs_tab}\">#{link_to( t(:prefs,:scope=>:prefs), prefs_look_path )}</li>"
#s += "<li class=\"last #{@links_tab}\">#{link_to( t(:links,:scope=>:link), links_path )}</li>"
#s += "</ul>"
#end
#def prefs_navigation(active)
#instance_variable_set("@#{active}", "active")
#s = ""
#s += "<ul>"
#s += "<li class=\"first #{@look_tab}\">#{link_to( t(:look,:scope=>:prefs), prefs_look_path )}</li>"
#s += "<li class=\"#{@identity_tab}\">#{link_to( t(:identity,:scope=>:prefs), prefs_identity_path )}</li>"
#s += "<li class=\"last #{@servers_tab}\">#{link_to( t(:servers,:scope=>:prefs), prefs_servers_path )}</li>"
#s += "</ul>"
#end
#def multi_select(id, name, objects, selected_objects, label, value,joiner,content = {})
#options = ""
#objects.each do |o|
#selected = selected_objects.include?(o) ? " selected=\"selected\"" : ""
#option_value = escape_once(o.send(value))
#text = [option_value]
#unless content[:text].nil?
#text = []
#content[:text].each do |t|
#text << o.send(t)
#end
#text = text.join(joiner)
#end
#text.gsub!(/^\./,'')
#bracket = []
#unless content[:bracket].nil?
#content[:bracket].each do |b|
#bracket << o.send(b)
#end
#bracket = bracket.join(joiner)
#end
#option_content = bracket.empty? ? "#{text}" : "#{text} (#{bracket})"
#options << "<option value=\"#{option_value}\"#{selected}>&nbsp;&nbsp;#{option_content}&nbsp;&nbsp;</option>\n"
#end
#"<div class=\"param_group\"><label class=\"label\">#{label}</label><select multiple=\"multiple\" size=10 id=\"#{id}\" name=\"#{name}\">\n#{options}</select></div>"
#end
#def force_charset(text)
#begin
#Iconv.iconv("UTF-8",$defaults["msg_unknown_charset"],text)
#rescue
#text
#end
#end
#def content_for_sidebar
#s = render :partial => 'sidebar/logo'
#s += render :partial => 'folders/list'
#s += render :partial => 'sidebar/calendar_view'
#s += render :partial => 'internal/version'
#s
#end
def boolean_answer(answer)
answer == true ? t(:true_answer,:scope=>:common) : t(:false_answer,:scope=>:common)
end
def main_navigation(active)
instance_variable_set("@#{active}", "active")
s = ""
s += "<ul class=\"wat-cf\">"
s += "<li class=\"first #{@messages_tab}\">#{link_to( t(:messages,:scope=>:message), messages_path )}</li>"
s += "<li class=\"#{@compose_tab}\">#{link_to( t(:compose,:scope=>:compose), compose_path )}</li>"
s += "<li class=\"#{@folders_tab}\">#{link_to( t(:folders,:scope=>:folder), folders_path )}</li>"
s += "<li class=\"#{@contacts_tab}\">#{link_to( t(:contacts,:scope=>:contact), contacts_path )}</li>"
s += "<li class=\"last #{@prefs_tab}\">#{link_to( t(:prefs,:scope=>:prefs), prefs_look_path )}</li>"
s += "</ul>"
end
def prefs_navigation(active)
instance_variable_set("@#{active}", "active")
s = ""
s += "<ul class=\"wat-cf\">"
s += "<li class=\"first #{@look_tab}\">#{link_to( t(:look,:scope=>:prefs), prefs_look_path )}</li>"
s += "<li class=\"#{@identity_tab}\">#{link_to( t(:identity,:scope=>:prefs), prefs_identity_path )}</li>"
s += "<li class=\"last #{@servers_tab}\">#{link_to( t(:servers,:scope=>:prefs), prefs_servers_path )}</li>"
s += "</ul>"
end
def multi_select(id, name, objects, selected_objects, label, value,joiner,content = {})
options = ""
objects.each do |o|
selected = selected_objects.include?(o) ? " selected=\"selected\"" : ""
option_value = escape_once(o.send(value))
text = [option_value]
unless content[:text].nil?
text = []
content[:text].each do |t|
text << o.send(t)
end
text = text.join(joiner)
end
text.gsub!(/^\./,'')
bracket = []
unless content[:bracket].nil?
content[:bracket].each do |b|
bracket << o.send(b)
end
bracket = bracket.join(joiner)
end
option_content = bracket.empty? ? "#{text}" : "#{text} (#{bracket})"
options << "<option value=\"#{option_value}\"#{selected}>&nbsp;&nbsp;#{option_content}&nbsp;&nbsp;</option>\n"
end
"<div class=\"param_group\"><label class=\"label\">#{label}</label><select multiple=\"multiple\" size=10 id=\"#{id}\" name=\"#{name}\">\n#{options}</select></div>"
end
def force_charset(text)
begin
Iconv.iconv("UTF-8",$defaults["msg_unknown_charset"],text)
rescue
text
end
end
def content_for_sidebar
s = render :partial => 'sidebar/logo'
s += render :partial => 'folders/list'
s += render :partial => 'sidebar/calendar_view'
s += render :partial => 'internal/version'
s
end
end

View file

@ -1,34 +1,40 @@
module FolderHelper
def folder_link(folder)
def folder_link(options={})
folder = options[:folder]
active = ""
if options[:active]
active = "icon-white"
end
folder.parent.empty? ? name = folder.name : name = folder.parent.gsub(/\./,'#') + "#" + folder.name
if folder.isInbox?
name_shown = t(:inbox_name,:scope => :folder)
name_shown = "<i class=\"icon-inbox #{active}\"></i>" + t(:inbox_name,:scope => :folder)
elsif folder.isSent?
name_shown = t(:sent_name,:scope => :folder)
name_shown = "<i class=\"icon-plane #{active}\"></i>" + t(:sent_name,:scope => :folder)
elsif folder.isDrafts?
name_shown = t(:drafts_name,:scope => :folder)
name_shown = "<i class=\"icon-book #{active}\"></i>" + t(:drafts_name,:scope => :folder)
elsif folder.isTrash?
name_shown = t(:trash_name,:scope => :folder)
name_shown = "<i class=\"icon-trash #{active}\"></i>" +t(:trash_name,:scope => :folder)
else
name_shown = folder.name.capitalize
name_shown = "<i class=\"icon-none\"></i>" + folder.name.capitalize
end
s = link_to name_shown, folders_select_path(:id => name)
if folder.isTrash?
if not folder.total.zero?
s <<' ('
s << link_to(t(:emptybin,:scope=>:folder),folders_emptybin_path)
s << ')'
name_shown += " <button class=\"btn btn-mini btn-danger\" onclick=\"window.location='#{folders_emptybin_path}'\" href=\"#\">#{t(:emptybin,:scope=>:folder)}</button>"
#name_shown += raw link_to(t(:emptybin,:scope=>:folder),folders_emptybin_path)
#name_shown += ')'
end
else
if !folder.unseen.zero?
s += ' (' + folder.unseen.to_s + ')'
name_shown += ' (' + folder.unseen.to_s + ')'
end
end
s
link_to name_shown.html_safe, folders_select_path(:id => name)
end
def pretty_folder_name(folder)

17
app/helpers/links_helper.rb Executable file
View file

@ -0,0 +1,17 @@
module LinksHelper
def links_table_header
html = ""
$defaults["links_table_fields"].each do |f|
html << "<th>"
if params[:sort_field] == f
params[:sort_dir].nil? ? dir = 'desc' : dir = nil
end
html << link_to(Link.human_attribute_name(f), {:controller => 'links',:action => 'index',:sort_field => f,:sort_dir => dir}, {:class=>"header"})
html << "</th>"
end
html
end
end

View file

@ -15,12 +15,14 @@ module MessagesHelper
end
def address_formatter(addr,op)
return "" if addr.nil?
s = ""
return s if addr.nil?
return t(:no_address,:scope=>:message) if addr.empty?
length = $defaults["msg_address_length"].to_i
case op
when :index
logger.custom('addr',addr)
fs = addr.gsub(/\"/,"").split(/</)
fs[0].size.zero? ? s = fs[1] : s = fs[0]
s.length >= length ? s = s[0,length]+"..." : s
@ -34,7 +36,7 @@ module MessagesHelper
s = h(addr)
return s
when :reply
return h(addr)
return addr
end
end
@ -42,12 +44,19 @@ module MessagesHelper
case op
when :reply
s = "\n\n\n"
body.gsub(/^\s+/,"").split(/\n/).each do |line|
s += ">" + line + "\n"
body.split(/\n/).each do |line|
s += '>' + line.strip + "\n"
end
s
when :edit
return body
when :plain
safe_body = h(body)
s = ""
safe_body.split(/\n/).each do |line|
s += line.gsub(/^\s+/,"") + "<br/>"
end
s.html_safe
end
end
@ -77,7 +86,7 @@ module MessagesHelper
end
def attachment_formatter(message)
message.content_type =~ /^text\/plain/ ? "" : image_tag(current_theme_image_path('star.png'))
message.content_type =~ /^text\/plain/ ? "" : "<i class=\"icon-file\"></i>"
end
def headers_links
@ -98,15 +107,23 @@ module MessagesHelper
html << link_to(Message.human_attribute_name(f), {:controller => 'messages',:action => 'index',:sort_field => f,:sort_dir => dir}, {:class=>"header"})
html << "</th>"
end
if @current_folder == @drafts_folder
html << "<th>&nbsp;</th>"
end
html
end
def content_text_plain_for_render(text)
html = "<pre>"
#html << text.gsub!(/\r\n/,"\n")
html << h(text)
html << "</pre>"
html
#def content_text_plain_for_render(text)
#html = "<pre class=\"clearfix\">"
##html << text.gsub!(/\r\n/,"\n")
#html << h(text)
#html << "</pre>"
#html
#end
def humanize_attr(object,attr)
model_name = eval(object.class.model_name)
return model_name.human_attribute_name(attr)
end
end

View file

@ -1,2 +1,16 @@
module PrefsHelper
def servers_table_header
html = ""
$defaults["servers_table_fields"].each do |f|
html << "<th>"
if params[:sort_field] == f
params[:sort_dir].nil? ? dir = 'desc' : dir = nil
end
html << link_to(Server.human_attribute_name(f), {:controller => 'prefs',:action => 'servers',:sort_field => f,:sort_dir => dir}, {:class=>"header"})
html << "</th>"
end
html
end
end

View file

@ -1,17 +1,16 @@
class Contact < ActiveRecord::Base
validates_length_of :nick, :within => 5..15
validates_length_of :first_name,:last_name, :within => 3..20
validates_length_of :name, :within => 3..20
validates_length_of :email, :within => 5..50
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i
validates_length_of :info, :maximum => 50
validate :check_unique_nick, :on => :create
validates_length_of :info, :maximum => 100
validate :check_unique_name, :on => :create
default_scope :order => 'name ASC'
belongs_to :user
def self.getPageForUser(user,page,sort_field,sort_dir)
order = 'last_name asc'
if sort_field
if Contact.attribute_method?(sort_field) == true
order = sort_field
@ -22,21 +21,15 @@ class Contact < ActiveRecord::Base
Contact.paginate :page => page , :per_page => $defaults["contacts_per_page"], :conditions=> ['user_id = ?', user.id],:order => order
end
def full_name
first_name + ' ' + last_name
end
def check_unique_nick
if !Contact.where('upper(nick) = ? and user_id = ?',nick.upcase,user_id).size.zero?
errors.add(:nick, :not_unique)
def check_unique_name
if !Contact.where('upper(name) = ? and user_id = ?',name.upcase,user_id).size.zero?
errors.add(:name, :not_unique)
end
end
def export
fields = []
fields << nick.presence || ""
fields << first_name || ""
fields << last_name || ""
fields << name || ""
fields << email || ""
fields << info || ""
fields.join(';')
@ -44,11 +37,9 @@ class Contact < ActiveRecord::Base
def self.import(user,line)
fields = line.split(/;/)
contact = user.contacts.build( :nick => fields[0],
:first_name => fields[1],
:last_name => fields[2],
:email => fields[3],
:info => fields[4])
contact = user.contacts.build( :name => fields[0].strip,
:email => fields[1].strip,
:info => fields[2].strip)
contact.save!
end
end

View file

@ -1,2 +0,0 @@
class Event < ActiveRecord::Base
end

View file

@ -38,8 +38,11 @@ class Folder < ActiveRecord::Base
end
def update_stats
logger.info "MESS_BEFORE: "+messages.inspect
unseen = messages.where(:unseen => true).count
total = messages.count
logger.info "MESS: "+messages.inspect
logger.info "MESS: #{unseen} #{total}"
update_attributes(:unseen => unseen, :total => total)
end

33
app/models/link.rb Executable file
View file

@ -0,0 +1,33 @@
class Link < ActiveRecord::Base
validates_length_of :url, :within => 5..150
validates_length_of :info, :maximum => 50
belongs_to :user
default_scope :order => 'url asc'
def self.getPageForUser(user,page,sort_field,sort_dir)
if sort_field
if Link.attribute_method?(sort_field) == true
order = sort_field
sort_dir == 'desc' ? order += ' desc' : sort_dir
end
end
Link.paginate :page => page , :per_page => $defaults["links_per_page"], :conditions=> ['user_id = ?', user.id],:order => order
end
def export
fields = []
fields << url || ""
fields << info || ""
fields.join(';')
end
def self.import(user,line)
fields = line.split(/;/)
contact = user.links.build( :url => fields[0].strip,
:info => fields[1].strip)
contact.save!
end
end

View file

@ -6,7 +6,8 @@ class Message < ActiveRecord::Base
belongs_to :user
belongs_to :folder
set_primary_key :uid
#set_primary_key :uid
self.primary_key = :uid
attr_accessible :unseen, :to_addr, :size, :content_type, :folder_id, :subject, :date, :uid, :from_addr, :user_id, :msg_id, :body, :cc_addr, :bcc_addr
attr_accessor :body

View file

@ -11,7 +11,9 @@ class Prefs < ActiveRecord::Base
:theme => $defaults['theme'],
:locale => $defaults['locale'],
:msgs_per_page => $defaults['msgs_per_page'],
:msg_send_type => $defaults['msg_send_type']
:msg_send_type => $defaults['msg_send_type'],
:msg_image_view_as => 'attachment',
:msg_image_thumbnail_size => '192x144'
)
end
end

View file

@ -12,9 +12,13 @@ class Server < ActiveRecord::Base
where(:for_smtp=>true).first
end
def self.create_defaults(user)
def self.create_default(user)
create_server(user,"localhost")
end
def self.create_server(user,server)
create( :user_id=>user.id,
:name=>"localhost",
:name=>server,
:port=>$defaults['imap_port'],
:use_ssl=>false,
:use_tls=>false,
@ -22,7 +26,7 @@ class Server < ActiveRecord::Base
:for_imap=>true
)
create( :user_id=>user.id,
:name=>"localhost",
:name=>server,
:port=>$defaults['smtp_port'],
:use_ssl=>false,
:use_tls=>false,

View file

@ -4,13 +4,14 @@ class User < ActiveRecord::Base
#acts_as_notes_owner
validates_presence_of :first_name,:last_name
validates_uniqueness_of :email
validates_presence_of :first_name,:last_name,:login
validates_uniqueness_of :login
has_many :servers, :dependent => :destroy
has_one :prefs, :dependent => :destroy
has_many :folders, :dependent => :destroy
has_many :messages, :dependent => :destroy
has_many :contacts, :dependent => :destroy
has_many :links, :dependent => :destroy
def set_cached_password(session,password)
if $defaults['session_encryption']
@ -33,21 +34,31 @@ class User < ActiveRecord::Base
(0...8).map{65.+(rand(25)).chr}.join
end
def full_name
def name
first_name + " " + last_name
end
def full_address
d = domain.presence || ""
if email =~ /\@/
email
def full_id
(name + " <" + email + ">") if email
end
def email
if login =~ /\@/
login
else
email + "@" + d
(login + "@" + domain) if domain.presence
end
end
def username
email.gsub(/\@/,"_").gsub(/\./,"_")
login.gsub(/\@/,"_").gsub(/\./,"_")
end
def has_domain?
return domain if domain.presence
if login =~ /\@/
login.split(/\@/)[1]
end
end
end

View file

@ -0,0 +1,8 @@
- size ||= "btn-small"
- type ||= "btn-primary"
- icon ||= ""
%a{:class=>"btn #{size} #{type}",:href=>"#{href}"}
- if !icon.empty?
%i{:class=>"#{icon}"}
= caption

View file

@ -0,0 +1,27 @@
- model = eval(object.class.model_name)
- model_string = object.class.model_name.downcase
- label.nil? ? model_label = model.human_attribute_name(attr) : model_label = t(label.to_sym)
- val = value || object.instance_eval(attr) || ""
- if object.errors[attr.to_sym].empty?
- to_class ||= ""
- rows ||= 5
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
%textarea{:rows=>"#{rows}",:class=>"#{to_class}",:id=>"#{model_string}_#{attr}",:name=>"#{model_string}[#{attr}]"}
= val
%p{:class=>"help-block"}
= t(:example,:scope=>:common)
= example
- else
.control-group.error
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
%input{:id=>"#{model_string}_#{attr}",:name=>"#{model_string}[#{attr}]",:value=>"#{val}"}
%span{:class=>"help-inline"}
= object.errors[attr.to_sym].to_s
%p{:class=>"help-block"}
= t(:example,:scope=>:common)
= example

View file

@ -0,0 +1,19 @@
- size ||= "btn-small"
- type ||= "btn-primary"
- icon ||= ""
- onclick ||= 'empty'
- def isOnclick(value)
- if value != 'empty'
- {:onclick => "#{value}"}
- else
- {}
%button{isOnclick(onclick),:class=>"btn #{size} #{type}",
:type=>"submit",
:name=>"#{name}"}
- if !icon.empty?
%i{:class=>"#{icon}"}
= caption

View file

@ -0,0 +1,5 @@
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
%input{:id=>"#{model_string}_#{attr}",:name=>"#{model_string}[#{attr}]",:type=>"file"}

View file

@ -0,0 +1,12 @@
%form{:enctype=>"multipart/form-data", :class=>"form-horizontal top-pix18",:action=>"#{im_ex_path}",:method=>"post"}
= render :partial => "common/file_select", :locals => { :model_label => "#{im_ex_label}",
:model_string => "upload",
:attr => "datafile"}
%p
= render :partial => "common/button", :locals => {:name=>'import',
:caption=>t('import',:scope=>'contact'),
:icon=>'icon-upload icon-white'}
- if !im_ex_size.zero?
= render :partial => "common/button", :locals => {:name=>'export',
:caption=>t('export',:scope=>'contact'),
:icon=>'icon-download icon-white'}

View file

@ -0,0 +1,27 @@
- model = eval(object.class.model_name)
- model_string = object.class.model_name.downcase
- label.nil? ? model_label = model.human_attribute_name(attr) : model_label = t(label.to_sym)
- val = value || object.instance_eval(attr) || ""
- if object.errors[attr.to_sym].empty?
- to_class ||= ""
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
%input{:class=>"#{to_class}",:id=>"#{model_string}_#{attr}",:name=>"#{model_string}[#{attr}]",:value=>"#{val}"}
%p{:class=>"help-block"}
= t(:example,:scope=>:common)
= example
- else
.control-group.error
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
%input{:id=>"#{model_string}_#{attr}",:name=>"#{model_string}[#{attr}]",:value=>"#{val}"}
%span{:class=>"help-inline"}
= object.errors[attr.to_sym].to_s
%p{:class=>"help-block"}
= t(:example,:scope=>:common)
= example
-#= render :partial => "common/input_form_desc_field",:locals => {:object => @user,:attr => 'login',:label => nil,:example => 'joe.doe',:value => params[:user] ? params[:user][:login] : "" }

View file

@ -0,0 +1,8 @@
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model.capitalize.constantize.human_attribute_name(attr)
.controls
%input{:type=>"text",:id=>"#{model}_#{attr}",:name=>"#{model}[#{attr}]"}
-#= render :partial => "common/input_form_field",:locals => { :model => 'user',:attr => 'login'}

View file

@ -0,0 +1,5 @@
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model.capitalize.constantize.human_attribute_name(attr)
.controls
%input{:type=>"password",:id=>"#{model}_#{attr}",:name=>"#{model}[#{attr}]"}

View file

@ -0,0 +1,2 @@
.logo
= link_to image_tag("logo.png",:alt=> t(:mailr,:scope=>:common)), root_path

View file

@ -0,0 +1 @@
= calendar_window(:title=>t(:calendar,:scope=>:common))

View file

@ -0,0 +1,21 @@
- messages ||= ""
- compose ||= ""
- folders ||= ""
- contacts ||= ""
- prefs ||= ""
- links ||= ""
%ul{:class=>"nav nav-pills"}
%li{:class=>"#{messages}"}
= link_to( t(:messages,:scope=>:message), messages_path )
%li{:class=>"#{compose}"}
= link_to( t(:compose,:scope=>:compose), compose_path )
%li{:class=>"#{folders}"}
= link_to( t(:folders,:scope=>:folder), folders_path )
%li{:class=>"#{contacts}"}
= link_to( t(:contacts,:scope=>:contact), contacts_path )
%li{:class=>"#{links}"}
= link_to( t(:links,:scope=>:link), links_path )
%li{:class=>"#{prefs}"}
= link_to( t(:prefs,:scope=>:prefs), prefs_look_path )

View file

@ -0,0 +1,22 @@
%select{:multiple=>"multiple",:class=>"#{style}",:id=>"#{id}",:name=>"#{name}"}
- objects.each do |o|
- option_value = escape_once(o.send(value))
- option_text = [option_value]
- unless text.nil?
- option_text = []
- text.each do |t|
- option_text << o.send(t)
- option_text = option_text.join(joiner)
- option_text.gsub!(/^\./,'')
- if selected_objects.include?(o)
%option{:value=>"#{option_value}",:selected=>"selected"}
= option_text
- else
%option{:value=>"#{option_value}"}
= option_text
-#<%= raw multi_select("", 'folders_to_show[]', @folders, @folders_shown,t(:shown,:scope=>:folder),:id,"",{:text => [:parent,:delim,:name]}) %>
-#def multi_select(id, name, objects, selected_objects, label, value,joiner,content = {})

View file

@ -0,0 +1,11 @@
- look ||= ""
- identity ||= ""
- servers ||= ""
%ul{:class=>"nav nav-pills"}
%li{:class=>"#{look}"}
= link_to( t(:look,:scope=>:prefs), prefs_look_path )
%li{:class=>"#{identity}"}
= link_to( t(:identity,:scope=>:prefs), prefs_identity_path )
%li{:class=>"#{servers}"}
= link_to( t(:servers,:scope=>:prefs), prefs_servers_path )

View file

@ -0,0 +1,22 @@
- model = eval(object.class.model_name)
- model_string = object.class.model_name.downcase
- model_label = model.human_attribute_name(attr)
- translation_scope ||= false
.control-group
%label{:class=>"control-label",:for=>"#{attr}"}
= model_label
.controls
- if translation_scope
- t = []
- choices.each do |c|
- t << [t(c.to_sym,:scope=>translation_scope),c.to_s]
= select(model_string, attr, options_for_select(t,choice), {:include_blank => blank})
- else
= select(model_string, attr, options_for_select(choices,choice), {:include_blank => blank})
-# select(model.downcase, attr, options_for_select(choices,choice), {:include_blank => blank})

View file

@ -0,0 +1,5 @@
.control-group
%label{:class=>"control-label"}
= label
.controls
= raw simple_select_for_folders(name,id,collection,choice,blank)

View file

@ -0,0 +1,2 @@
%p{:class=>"version"}
= link_to (t(:version,:scope=>:common) + " " + $defaults["version"]),about_path

View file

@ -0,0 +1,18 @@
= render :partial => "common/input_form_desc_field",:locals => {:object => @contact,
:attr => 'name',
:label => nil,
:example => 'Joe Doe',
:value => @contact.name,
:to_class=>"span6" }
= render :partial => "common/input_form_desc_field",:locals => {:object => @contact,
:attr => 'email',
:label => nil,
:example => 'joe.doe@domain.com',
:value => @contact.email,
:to_class=>"span6" }
= render :partial => "common/input_form_desc_field",:locals => {:object => @contact,
:attr => 'info',
:label => nil,
:example => t(:some_add_info,:scope=>:common),
:value => @contact.info,
:to_class=>"span6" }

View file

@ -0,0 +1,11 @@
%tr
%td{:nowrap=>"nowrap"}
= check_box_tag "items_ids[]", contact.id
\/
= link_to "<i class=\"icon-edit\"></i>".html_safe,edit_contact_path(contact)
%td{:nowrap=>"nowrap"}
= link_to contact.name,compose_contact_path(contact.id)
%td{:nowrap=>"nowrap"}
= link_to contact.email, compose_contact_path(contact.id)
%td{:nowrap=>"nowrap"}
= contact.info

View file

@ -0,0 +1,13 @@
= will_paginate @contacts
%table{:class=>"table table-bordered records"}
%thead
%tr
%th
%input{:id=>"toggleall",:type=>"checkbox",:name=>"allbox"}
= raw contacts_table_header
%tbody
- @contacts.each do |c|
= render :partial => 'contact', :locals => {:contact => c}
= will_paginate @contacts

View file

@ -0,0 +1,20 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:contacts,:scope=>:contact)
= render :partial => 'common/main_navigation', :locals => { :contacts => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:modifying,:scope=>:contact)
%form{:class=>"form-horizontal",:action=>url_for(@contact),:method=>"post"}
%input{:name=>"_method",:type=>"hidden",:value=>"put"}
%fieldset
= render :partial => "attrs"
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:save, :caption => t(:save,:scope=>:common), :icon =>'icon-cog icon-white'}

View file

@ -0,0 +1,38 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:contacts,:scope=>:contact)
= render :partial => 'common/main_navigation', :locals => { :contacts => :active }
%form{:class=>"form-horizontal top-pix18",:action=>url_for(@contact),:method=>"post"}
- if @contacts.size.zero?
.alert
= t(:no_entries,:scope=>:contact)
%p{:class=>"bottom-pix18"}
= render :partial => "common/anchor", :locals => {:caption=>t('create_new',:scope=>'contact'),
:icon=>'icon-plus icon-white',
:href=>new_contact_path}
- else
.well{:style=>"padding: 5px 3pt;"}
%h5
= t(:total_entries,:scope=>:contact)
\:
= @contacts.total_entries
%p{:class=>"bottom-pix18"}
= render :partial => "common/anchor", :locals => {:caption=>t('create_new',:scope=>'contact'),
:icon=>'icon-plus icon-white',
:href=>new_contact_path}
= render :partial => "common/button", :locals => {:name=>'delete_selected',
:caption=>t('delete_selected',:scope=>'contact'),
:icon=>'icon-minus icon-white'}
= render :partial => "common/button", :locals => {:name=>'compose_to_selected',
:caption=>t('compose_to_selected',:scope=>'contact'),
:icon=>'icon-envelope icon-white'}
= render :partial => 'list'
= render :partial => 'common/import_export',:locals=>{:im_ex_path => contacts_import_export_path,
:im_ex_label => t(:select_file,:scope=>:contact),
:im_ex_size => @contacts.total_entries }

View file

@ -0,0 +1,19 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:contacts,:scope=>:contact)
= render :partial => 'common/main_navigation', :locals => { :contacts => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:creating_new,:scope=>:contact)
%form{:class=>"form-horizontal",:action=>url_for(@contact),:method=>"post"}
%fieldset
= render :partial => "attrs"
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:save, :caption => t(:save,:scope=>:common), :icon =>'icon-cog icon-white'}

View file

@ -0,0 +1,8 @@
%form{:class=>"form-horizontal",:action=>folders_create_path,:method=>"post"}
%fieldset
= render :partial => "common/select_for_folders",:locals => { :label=> t(:parent,:scope=>:folder), :name => "folder", :id => "parent", :collection => @folders, :choice => "", :blank => true}
= render :partial => "common/input_form_field",:locals => { :model => 'folder',:attr => 'target'}
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:create, :caption => t(:create,:scope=>:common), :icon =>'icon-plus icon-white'}

View file

@ -0,0 +1,6 @@
%form{:class=>"form-horizontal",:action=>folders_delete_path,:method=>"post"}
%fieldset
= render :partial => "common/select_for_folders",:locals => { :label=> t(:to_delete,:scope=>:folder), :name => "folder", :id => "delete", :collection => @folders, :choice => "", :blank => true}
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:delete, :caption => t(:delete,:scope=>:common), :icon =>'icon-minus icon-white'}

View file

@ -0,0 +1,16 @@
.well{:style=>"padding: 8px 3pt;"}
- if @folders_shown.nil? or @folders_shown.size.zero?
%p
= t(:no_shown,:scope=>:folder)
= link_to t(:folders,:scope=>:folder), folders_path
- else
%ul{:class=>"nav nav-list"}
%li{:class=>"nav-header"}
=t(:folders,:scope=>:folder)
- @folders_shown.each do |folder|
- if folder == @current_folder
%li{:class=>"active"}
= folder_link(:folder=>folder,:active=>true)
- else
%li
= folder_link(:folder=>folder,:active=>false)

View file

@ -0,0 +1,11 @@
%form{:class=>"form-horizontal",:action=>folders_refresh_path,:method=>"post"}
%fieldset
.control-group
%label{:class=>"control-label"}
= t(:presentation,:scope=>:folder)
.controls
= render :partial=>"common/multiselect",:locals => {:objects => @folders, :selected_objects => @folders_shown,:style=>"",:id=>"multiselect_form",:name=>"folders_to_show[]",:value=>:id,:joiner=>"",:text=>[:parent,:delim,:name]}
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:show_hide, :caption => t(:show_hide,:scope=>:folder), :icon =>'icon-eye-open icon-white'}
= render :partial => "common/button",:locals => { :name=>:refresh, :caption => t(:refresh,:scope=>:folder), :icon =>'icon-refresh icon-white'}

View file

@ -0,0 +1,9 @@
%form{:class=>"form-horizontal",:action=>folders_system_path,:method=>"post"}
%fieldset
= render :partial => "common/select_for_folders",:locals => { :label=> t(:folder,:scope => :folder) + " " + t(:inbox_name,:scope=>:folder), :name => "folder", :id => "mailbox_inbox", :collection => @folders, :choice => @folder_inbox, :blank => true}
= render :partial => "common/select_for_folders",:locals => { :label=> t(:folder,:scope => :folder) + " " + t(:trash_name,:scope=>:folder), :name => "folder", :id => "mailbox_trash", :collection => @folders, :choice => @folder_trash, :blank => true}
= render :partial => "common/select_for_folders",:locals => { :label=> t(:folder,:scope => :folder) + " " + t(:sent_name,:scope=>:folder), :name => "folder", :id => "mailbox_sent", :collection => @folders, :choice => @folder_sent, :blank => true}
= render :partial => "common/select_for_folders",:locals => { :label=> t(:folder,:scope => :folder) + " " + t(:drafts_name,:scope=>:folder), :name => "folder", :id => "mailbox_drafts", :collection => @folders, :choice => @folder_drafts, :blank => true}
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:set, :caption => t(:set,:scope=>:common), :icon =>'icon-cog icon-white'}

View file

@ -0,0 +1,16 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:folders,:scope=>:folder)
= render :partial => 'common/main_navigation', :locals => { :folders => :active }
.row
.span9
= render :partial => "refresh"
= render :partial => "create"
= render :partial => "delete"
= render :partial => "system"

View file

@ -0,0 +1,23 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:about,:scope=>:internal)
= render :partial => 'common/main_navigation', :locals => { :about => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:current_version,:scope=>:internal) + ": " + $defaults["version"]
.well
= raw BlueCloth::new(render :file => 'README.markdown').to_html
.well
= raw BlueCloth::new(render :file => 'CHANGES.markdown').to_html
.well
= raw BlueCloth::new(render :file => 'TODO.markdown').to_html
.well
= raw BlueCloth::new(render :file => 'AUTHORS.markdown').to_html
.well
= raw BlueCloth::new(render :file => 'UNLICENSE.markdown').to_html

View file

@ -0,0 +1,32 @@
!!!
%html
%head
%title
=t(:mailr,:scope=>:common)
= yield :title
%li{:rel=>"shortcut icon", :href=>"/favicon.ico"}/
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body{:class=>"application"}
.container
.row
.span3#sidebar
= yield :sidebar
.span9#main
- if flash[:error]
.alert.alert-error
= flash[:error]
- elsif flash[:info]
.alert.alert-info
= flash[:info]
- elsif flash[:success]
.alert.alert-success
= flash[:success]
= render :partial => "common/main_header"
= yield
%hr/
.row
#footer-simple
%a{:href=>"https://github.com/musashimm/mailr"} MailR
\- open source web mail client

View file

@ -0,0 +1,32 @@
!!!
%html
%head
%title
=t(:mailr,:scope=>:common)
= yield :title
%li{:rel=>"shortcut icon", :href=>"/favicon.ico"}/
= stylesheet_link_tag "application", :media => "all"
= javascript_include_tag "application"
= csrf_meta_tags
%body{:class=>"simple"}
.container
.row
.span6.offset3
.row
%a{:href=>"/"}
= image_tag "logo.png"
.row
- if flash[:error]
.alert.alert-error
= flash[:error]
- elsif flash[:info]
.alert.alert-info
= flash[:info]
- elsif flash[:success]
.alert.alert-success
= flash[:success]
= yield
.row
#footer-simple
%a{:href=>"https://github.com/musashimm/mailr"} MailR
\- open source web mail client

View file

@ -0,0 +1,12 @@
= render :partial => "common/input_form_desc_field",:locals => {:object => @link,
:attr => 'url',
:label => nil,
:example => 'www.example.com',
:value => @link.url,
:to_class=>"span6" }
= render :partial => "common/input_form_desc_field",:locals => {:object => @link,
:attr => 'info',
:label => nil,
:example => t(:some_add_info,:scope=>:common),
:value => @link.info,
:to_class=>"span6" }

View file

@ -0,0 +1,9 @@
%tr
%td{:nowrap=>"nowrap"}
= check_box_tag "items_ids[]", link.id
\/
= link_to "<i class=\"icon-edit\"></i>".html_safe,edit_link_path(link)
%td{:nowrap=>"nowrap"}
= link_to link.url,"http://"+link.url
%td{:nowrap=>"nowrap"}
= link.info

13
app/views/links/_list.html.haml Executable file
View file

@ -0,0 +1,13 @@
= will_paginate @links , :class => "custom_pagination bottom-pix18"
%table{:class=>"table table-bordered records"}
%thead
%tr
%th
%input{:id=>"toggleall",:type=>"checkbox",:name=>"allbox"}
= raw links_table_header
%tbody
- @links.each do |l|
= render :partial => 'link', :locals => {:link => l}
= will_paginate @links , :class => "custom_pagination bottom-pix18"

20
app/views/links/edit.html.haml Executable file
View file

@ -0,0 +1,20 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:links,:scope=>:link)
= render :partial => 'common/main_navigation', :locals => { :links => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:modifying,:scope=>:link)
%form{:class=>"form-horizontal",:action=>url_for(@link),:method=>"post"}
%input{:name=>"_method",:type=>"hidden",:value=>"put"}
%fieldset
= render :partial => "attrs"
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:save, :caption => t(:save,:scope=>:common), :icon =>'icon-cog icon-white'}

35
app/views/links/index.html.haml Executable file
View file

@ -0,0 +1,35 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:links,:scope=>:link)
= render :partial => 'common/main_navigation', :locals => { :links => :active }
%form{:class=>"form-horizontal top-pix18",:action=>url_for(@link),:method=>"post"}
- if @links.size.zero?
.alert
= t(:no_entries,:scope=>:link)
%p{:class=>"bottom-pix18"}
= render :partial => "common/anchor", :locals => {:caption=>t('create_new',:scope=>'link'),
:icon=>'icon-plus icon-white',
:href=>new_link_path}
- else
.well{:style=>"padding: 5px 3pt;"}
%h5
= t(:total_entries,:scope=>:link)
\:
= @links.total_entries
%p{:class=>"bottom-pix18"}
= render :partial => "common/anchor", :locals => {:caption=>t('create_new',:scope=>'link'),
:icon=>'icon-plus icon-white',
:href=>new_link_path}
= render :partial => "common/button", :locals => {:name=>'delete_selected',
:caption=>t('delete_selected',:scope=>'link'),
:icon=>'icon-minus icon-white'}
= render :partial => 'list'
= render :partial => 'common/import_export',:locals=>{:im_ex_path => links_import_export_path,
:im_ex_label => t(:select_file,:scope=>:link),
:im_ex_size => @links.total_entries }

19
app/views/links/new.html.haml Executable file
View file

@ -0,0 +1,19 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:links,:scope=>:link)
= render :partial => 'common/main_navigation', :locals => { :links => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:create_new,:scope=>:link)
%form{:class=>"form-horizontal",:action=>url_for(@link),:method=>"post"}
%fieldset
= render :partial => "attrs"
.control-group
.controls
= render :partial => "common/button",:locals => { :name=>:save, :caption => t(:save,:scope=>:common), :icon =>'icon-cog icon-white'}

View file

@ -0,0 +1,14 @@
%td
= attachment.filename_charseted
%td
= attachment.main_type
\/
= attachment.sub_type
%td
= attachment.charset
%td
= attachment.content_transfer_encoding
%td
= size_formatter(attachment.getSize)
%td
= link_to "<i class=\"icon-download-alt\"></i>".html_safe, attachment_download_path(attachment.parent_id,attachment.idx)

View file

@ -0,0 +1,9 @@
%h1
%small
= t(:attachments,:scope=>:message)
%table{:class=>"table table-bordered"}
%tbody
- for idx in 0..@attachments.size-1
%tr
= render :partial => 'attachment', :locals => { :attachment => @attachments[idx] }

View file

@ -0,0 +1,10 @@
%tr
%td
= check_box_tag "files[]", file_attach[:name]
%td
= file_attach[:name]
%td
= size_formatter(file_attach[:size])
%td
&nbsp;

View file

@ -0,0 +1,40 @@
%div{:class=>"well",:style=>"padding: 7px 5pt;"}
%table{:class=>"header"}
%tbody
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'from_addr') + ':'
%td
= address_formatter(@from,:show)
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'to_addr') + ':'
%td
= address_formatter(@to,:show)
- if not @mail.cc.nil?
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'cc_addr') + ':'
%td
= address_formatter(@mail.Cc.to_s,:show)
- if not @mail.bcc.nil?
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'bcc_addr') + ':'
%td
= address_formatter(@mail.Bcc.to_s,:show)
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'subject') + ':'
%td
= subject_formatter(@message,:show)
%tr
%td{:class=>"field_name"}
= humanize_attr(@message,'date') + ':'
%td
= date_formatter(@date)
= hidden_field_tag 'uids[]', @message.uid
= hidden_field_tag 'source', 'show'
%pre{:class=>"header_raw",:style=>"display: none;"}
= @plain_header

View file

@ -0,0 +1,3 @@
%iframe{:frameborder=>"0",:src=>"#{html_body_path(@message.uid)}"}/

View file

@ -0,0 +1,22 @@
%li{:class=>"span3"}
.thumbnail
%a{:href=>"#"}
%img{:alt=>image.filename,:src=>attachment_download_path(image.parent_id,image.idx),:size => @current_user.prefs.msg_image_thumbnail_size,:title=>image.filename}
.caption
%h5
= link_to "<i class=\"icon-download-alt\"></i>".html_safe, attachment_download_path(image.parent_id,image.idx)
= image.filename
%small
= size_formatter(image.getSize)
-#
<div class="image">
<%= image_tag(attachment_download_path(image.parent_id,image.idx), :size => @current_user.prefs.msg_image_thumbnail_size, :alt=>image.filename, :title=>image.filename) %>
<div class="desc">
<span class="name"><%= link_to (image.filename,attachment_download_path(image.parent_id,image.idx)) %></span>
<span class="size"><%= size_formatter(image.getSize) %></span>
</div>
</div>
= link_to "<i class=\"icon-download-alt\"></i>".html_safe, "#"

View file

@ -0,0 +1,3 @@
%ul{:class=>"thumbnails"}
- for idx in 0..@images.size-1
= render :partial => 'image', :locals => { :image => @images[idx] }

View file

@ -0,0 +1,18 @@
%td
= check_box_tag "uids[]", message.uid
%td
= raw attachment_formatter(message)
%td
- if @current_folder == @sent_folder || @current_folder == @drafts_folder
= address_formatter(message.to_addr,:index)
- else
= address_formatter(message.from_addr,:index)
%td
= subject_formatter(message,:index)
%td{:nowrap=>"nowrap"}
= date_formatter(message.date)
%td
= size_formatter(message.size)
- if @current_folder == @drafts_folder
%td
= link_to(t(:edit,:scope=>:message),edit_path(message.uid))

View file

@ -0,0 +1,20 @@
= will_paginate @messages, :class => "custom_pagination bottom-pix18"
%table{:class=>"table table-bordered records"}
%thead
%tr
%th
%input{:id=>"toggleall",:type=>"checkbox",:name=>"allbox"}
%th
%i{:class=>"icon-file"}
= raw headers_links
%tbody
- @messages.each do |m|
- m.unseen == true ? unseen = "unseen" : unseen = ""
%tr{:class=>"#{unseen}"}
= render :partial => 'messages/message', :locals => {:message => m}
= will_paginate @messages , :class => "custom_pagination bottom-pix18"

View file

@ -0,0 +1,21 @@
%p
= render :partial => "common/button", :locals => {:name=>'copy',
:caption=>t('copy',:scope=>'message'),
:icon=>'icon-tags icon-white'}
= render :partial => "common/button", :locals => {:name=>'move',
:caption=>t('move',:scope=>'message'),
:icon=>'icon-chevron-right icon-white'}
= t(:to_folder,:scope=>:folder) + " "
= raw simple_select_for_folders("folder","target",@folders_shown,'',true)
%p{:class=>"bottom-pix18"}
= render :partial => "common/button", :locals => {:name=>'trash',
:caption=>t('trash',:scope=>'message'),
:icon=>'icon-trash icon-white'}
= render :partial => "common/button", :locals => {:name=>'set_unread',
:caption=>t('set_unread',:scope=>'message'),
:icon=>'icon-eye-close icon-white'}
= render :partial => "common/button", :locals => {:name=>'set_read',
:caption=>t('set_read',:scope=>'message'),
:icon=>'icon-eye-open icon-white'}

View file

@ -0,0 +1,28 @@
%p
= render :partial => "common/button", :locals => {:name=>'copy',
:caption=>t('copy',:scope=>'message'),
:icon=>'icon-tags icon-white'}
= render :partial => "common/button", :locals => {:name=>'move',
:caption=>t('move',:scope=>'message'),
:icon=>'icon-chevron-right icon-white'}
= t(:to_folder,:scope=>:folder) + " "
= raw simple_select_for_folders("folder","target",@folders_shown,'',true)
%p{:class=>"bottom-pix18"}
= render :partial => "common/button", :locals => {:name=>'show_header',
:caption=>t('show_header',:scope=>'show'),
:icon=>'icon-zoom-in icon-white'}
= render :partial => "common/button", :locals => {:name=>'trash',
:caption=>t('trash',:scope=>'show'),
:icon=>'icon-trash icon-white'}
= render :partial => "common/button", :locals => {:name=>'reply',
:caption=>t('reply',:scope=>'show'),
:icon=>'icon-arrow-left icon-white'}
= render :partial => "common/button", :locals => {:name=>'reply_all',
:caption=>t('reply_all',:scope=>'show'),
:icon=>'icon-backward icon-white'}
= render :partial => "common/button", :locals => {:name=>'forward',
:caption=>t('forward',:scope=>'show'),
:icon=>'icon-arrow-right icon-white'}

View file

@ -0,0 +1,48 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:compose,:scope=>:compose)
= render :partial => 'common/main_navigation', :locals => { :compose => :active }
%form{:enctype=>"multipart/form-data",:class=>"form-horizontal",:action=>composed_path,:method=>"post"}
%fieldset
= render :partial => "common/input_form_desc_field",:locals => {:object => @message,:attr => 'to_addr',:label => nil,:example => 'joe@domain.com',:value => address_formatter(@message.to_addr,@operation),:to_class=>"span7" }
= render :partial => "common/input_form_desc_field",:locals => {:object => @message,:attr => 'cc_addr',:label => nil,:example => 'joe@domain.com',:value => address_formatter(@message.cc_addr,@operation),:to_class=>"span7" }
= render :partial => "common/input_form_desc_field",:locals => {:object => @message,:attr => 'subject',:label => nil,:example => t(:subject_of_the_message,:scope=>:compose),:value => subject_formatter(@message.subject,@operation),:to_class=>"span7" }
= render :partial => "common/area_form_desc_field",:locals => {:object => @message,:attr => 'body',:label => nil,:example => t(:write_your_message_here,:scope=>:compose),:value => body_formatter(@message.body,@operation),:to_class=>"span7",:rows=>20 }
- if !@olduid.nil?
= hidden_field_tag 'olduid', @olduid
.control-group
.controls
%h1
%small
= t(:attachments,:scope=>:message)
- if not @attachments.size.zero?
%table{:class=>"table table-bordered"}
%tbody
- @attachments.each do |a|
= render :partial => "messages/file_attach", :locals => {:file_attach => a }
= render :partial => "common/button", :locals => {:name=>'delete_marked',
:caption=>t('delete_marked',:scope=>'compose'),
:icon=>'icon-minus icon-white'}
= render :partial => "common/file_select", :locals => { :model_label => t(:select_file,:scope=>:compose),
:model_string => "file",
:attr => "data"}
.control-group
.controls
= render :partial => "common/button", :locals => {:name=>'upload',
:caption=>t('upload',:scope=>'compose'),
:icon=>'icon-upload icon-white'}
.control-group
.controls
= render :partial => "common/button", :locals => {:name=>'sendout',
:caption=>t('sendout',:scope=>'compose'),
:icon=>'icon-envelope icon-white'}
= render :partial => "common/button", :locals => {:name=>'save',
:caption=>t('save',:scope=>'compose'),
:icon=>'icon-folder-open icon-white'}

View file

@ -0,0 +1,2 @@
= raw @body

View file

@ -0,0 +1,30 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= t(:messages,:scope=>:message)
= render :partial => 'common/main_navigation', :locals => { :messages => :active }
.well{:style=>"padding: 5px 3pt;"}
%h3
= t(:current,:scope=>:folder)
\:
= pretty_folder_name(@current_folder)
%h5
= t(:total,:scope=>:message)
\:
= @messages.total_entries
%form{:class=>"form-horizontal top-pix18",:action=>"#{messages_ops_multi_path}",:method=>"post"}
- if @current_folder.nil?
.alert
= t(:no_selected,:scope=>:folder)
- if @messages.size.zero?
.alert
= t(:no_in,:scope=>:message)
- else
= render :partial => 'multi_ops'
= render :partial => 'messages'

View file

@ -0,0 +1,29 @@
= content_for :sidebar do
= render :partial => "sidebar/sidebar"
= content_for :title do
\-
= subject_formatter(@message,:show)
= render :partial => 'common/main_navigation', :locals => { :show => :active }
%form{:class=>"form-horizontal top-pix18",:action=>"#{messages_ops_single_path}",:method=>"post"}
= render :partial => 'header'
= render :partial => 'single_ops'
- if not @attachments.size.zero?
= render :partial => 'attachments'
- if not @images.size.zero?
= render :partial => 'images'
- if not @html_part.nil?
= render :partial => 'html_part'
- else
- if @text_part.nil?
.alert
= t(:no_content,:scope => :message)
- else
.well
= body_formatter(@text_part,:plain)

Some files were not shown because too many files have changed in this diff Show more