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 # See http://help.github.com/ignore-files/ for more about ignoring files.
db/*.sqlite3 #
log/*.log # If you find yourself ignoring temporary files generated by your text editor
tmp/ # or operating system, you probably want to add a global ignore instead:
config/database.yml # 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> * Luben Manolov <luben.manolov@gmail.com>
* Nick Penkov <nick.penkov@gmail.com> * Nick Penkov <nick.penkov@gmail.com>
* Eugene Korbut * 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' # Bundle edge Rails instead:
gem 'will_paginate', '~> 3.0.beta' # gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'themes_for_rails'
gem "ezcrypto", "~> 0.7.2" 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 ## 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. **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. * Checkout the source code.
* Install all dependiences. Check if proper gems (sqlite3/mysql/postgresql) are defined in _Gemfile_ and installed. Use _bundler_ for that: * Install all dependiences. Check if proper gems (sqlite3/mysql/postgresql) are defined in _Gemfile_ and installed. Use _bundler_ for that:
```shell ```shell
bundle install 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_). * Prepare config/database.yml file (see _config/database.yml.example_).
* Migrate database (rake db:migrate) * Migrate database (rake db:migrate)
* Start rails server if applicable * Start rails server if applicable
* Point your browser to application URL: * Point your browser to application URL:
For local access: http://localhost:3000 For local access: http://localhost:3000
For remote access: http://some_url/mailr 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: * Using browser do basic setup. If You make a mistake delete all data from DB using rake task:
```shell ```shell
@ -37,12 +33,6 @@ rake db:clear_data
* Use it. * Use it.
### Specific configuration ## Specific configuration
For themes: if server sends files with no content in production mode comment out None
```ruby
config.action_dispatch.x_sendfile_header = "X-Sendfile"
```
from _config/environments/production.rb_ file.

View file

@ -1,7 +1,7 @@
#!/usr/bin/env rake
# Add your own tasks in files placed in lib/tasks ending in .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. # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
require File.expand_path('../config/application', __FILE__) require File.expand_path('../config/application', __FILE__)
require 'rake'
Mailr::Application.load_tasks 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. This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or 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 class ApplicationController < ActionController::Base
protect_from_forgery #logger.custom("session",session.inspect)
#protect_from_forgery
before_filter :load_settings,:current_user,:set_locale
#before_filter :plugins_configuration
before_filter :load_defaults,:current_user,:set_locale def load_settings
before_filter :plugins_configuration $defaults ||= YAML::load(File.open(Rails.root.join('config','settings.yml')))
def load_defaults
$defaults ||= YAML::load(File.open(Rails.root.join('config','defaults.yml')))
end end
################################# protected section ########################################### ################################# protected section ###########################################
@ -32,13 +33,14 @@ class ApplicationController < ActionController::Base
end end
def current_user def current_user
@current_user ||= User.find(session[:user_id]) if session[:user_id] @current_user ||= User.find(session[:user_id]) if session[:user_id]
logger.custom("current_user",@current_user.inspect)
end end
def check_current_user def check_current_user
if @current_user.nil? if @current_user.nil?
session["return_to"] = request.fullpath session["return_to"] = request.fullpath
redirect_to :controller => 'user', :action => 'login' redirect_to :controller => 'user', :action => 'login'
return false return false
end end
end end
@ -63,15 +65,15 @@ class ApplicationController < ActionController::Base
def prepare_compose_buttons def prepare_compose_buttons
@buttons = [] @buttons = []
@buttons << {:text => 'send',:scope=>:compose,:image => 'email.png'} @buttons << {:text => 'sendout',:scope=>:compose,:image => 'email.png'}
@buttons << {:text => 'save_as_draft',:scope=>:compose,:image => 'save.png'} @buttons << {:text => 'save',:scope=>:compose,:image => 'save.png'}
end end
def create_message_with_params def create_message_with_params
@message = Message.new @message = Message.new(params[:message])
if params[:message] # if params[:message]
@message.update_attributes(params[:message]) # @message.update_attributes(params[:message])
end # end
files = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*")) files = Dir.glob(File.join($defaults["msg_upload_dir"],@current_user.username + "*"))
@attachments = [] @attachments = []
files.each do |f| files.each do |f|
@ -88,12 +90,6 @@ class ApplicationController < ActionController::Base
##################################### private section ########################################## ##################################### 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 end

View file

@ -6,34 +6,10 @@ class ContactsController < ApplicationController
before_filter :get_contacts, :only => [:index] before_filter :get_contacts, :only => [:index]
before_filter :prepare_ops_buttons, :prepare_export_import_buttons,:only => [:index]
theme :theme_resolver
def index def index
end 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 #problem http://binary10ve.blogspot.com/2011/05/migrating-to-rails-3-got-stuck-with.html
#def destroy #def destroy
# @current_user.contacts.find(params[:id]).destroy # @current_user.contacts.find(params[:id]).destroy
@ -50,10 +26,25 @@ class ContactsController < ApplicationController
end end
def create 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]) @contact = @current_user.contacts.build(params[:contact])
if @contact.valid? if @contact.valid?
@contact.save @contact.save
flash[:notice] = t(:was_created,:scope=>:contact) flash[:success] = t(:was_created,:scope=>:contact)
redirect_to(contacts_path) redirect_to(contacts_path)
else else
render 'new' render 'new'
@ -69,10 +60,17 @@ class ContactsController < ApplicationController
end end
end end
def external def import_export
if params["export"] if params["export"]
redirect_to :action => 'export' contacts = @current_user.contacts
return 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"] elsif params["import"]
begin begin
raise t(:no_file_chosen,:scope=>:common) if not params[:upload] raise t(:no_file_chosen,:scope=>:common) if not params[:upload]
@ -82,44 +80,24 @@ class ContactsController < ApplicationController
tmp_file.flush tmp_file.flush
tmp_file.rewind tmp_file.rewind
tmp_file.readlines.each do |line| tmp_file.readlines.each do |line|
Contact.import(@current_user,line) next if line =~ /^#/
Contact.import(@current_user,line)
end end
rescue Exception => e rescue ActiveRecord::RecordInvalid => e
flash[:error] = e.to_s 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
end end
flash[:notice] = t(:were_imported,:scope=>:contact) if not flash[:error]
redirect_to :action => 'index' redirect_to :action => 'index'
end 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 section ################################
protected 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 section ##################################
private private

View file

@ -3,22 +3,21 @@ require 'imap_session'
class FoldersController < ApplicationController class FoldersController < ApplicationController
include ImapMailboxModule include ImapMailboxModule
include ImapSessionModule include ImapSessionModule
before_filter :check_current_user,:selected_folder, :get_current_folders before_filter :check_current_user,:selected_folder, :get_current_folders
before_filter :open_imap_session, :except => [:index,:show_hide,:system] before_filter :open_imap_session, :except => [:index,:show_hide,:system]
after_filter :close_imap_session, :except => [:index,:show_hide,:system] after_filter :close_imap_session, :except => [:index,:show_hide,:system]
before_filter :get_folders before_filter :get_folders
#before_filter :prepare_buttons_to_folders
theme :theme_resolver #theme :theme_resolver
def index def index
@buttons = [] #before_filter
@buttons << {:text => 'show_hide',:scope=>'folder',:image => 'flag.png'}
@buttons << {:text => 'refresh',:scope=>'folder',:image => 'refresh.png'}
end end
def create def create
@ -42,7 +41,7 @@ class FoldersController < ApplicationController
render 'index' render 'index'
return return
end end
flash[:notice] = t(:was_created,:scope=>:folder) flash[:success] = t(:was_created,:scope=>:folder)
redirect_to :action => 'index' redirect_to :action => 'index'
end end
end end
@ -67,7 +66,7 @@ class FoldersController < ApplicationController
render 'index' render 'index'
return return
end end
flash[:notice] = t(:was_deleted,:scope=>:folder) flash[:success] = t(:was_deleted,:scope=>:folder)
redirect_to :action => 'index' redirect_to :action => 'index'
end end
end end
@ -154,10 +153,16 @@ class FoldersController < ApplicationController
protected 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 def get_folders
@folders = @current_user.folders @folders = @current_user.folders
@folders_shown = @current_user.folders.shown @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.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.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 @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] before_filter :check_current_user ,:selected_folder, :get_current_folders, :only => [:about]
theme :theme_resolver #theme :theme_resolver
layout "simple" layout "simple"
ERRORS = [ ERRORS = [
:internal_server_error, :internal_server_error,
:not_found, :not_found,
:unprocessable_entity :unprocessable_entity,
:allready_configured
].freeze ].freeze
ERRORS.each do |e| ERRORS.each do |e|
define_method e do define_method e do
@title = t(e,:scope=>:internal) @title = t(e,:scope=>:internal)
@error = t(e,:scope=>:internal) flash[:error] = t(e,:scope=>:internal)
render 'error' render 'error'
end end
end end
@ -29,7 +30,7 @@ class InternalController < ApplicationController
@title = t(:imap_error,:scope => :internal) @title = t(:imap_error,:scope => :internal)
@error = params[:error] || t(:unspecified_error, :scope => :internal) @error = params[:error] || t(:unspecified_error, :scope => :internal)
logger.error "!!! InternalControllerImapError: " + @error logger.error "!!! InternalControllerImapError: " + @error
render 'error' render 'error'
end end
def loginfailure def loginfailure
@ -39,12 +40,19 @@ class InternalController < ApplicationController
redirect_to :controller=>'user', :action => 'login' redirect_to :controller=>'user', :action => 'login'
end end
def onlycanlogins #def onlycanlogins
reset_session #reset_session
flash[:error] = t(:only_can_logins,:scope=>:user) #flash[:error] = t(:only_can_logins,:scope=>:user)
@current_user = nil #@current_user = nil
redirect_to :controller=>'user', :action => 'login' #redirect_to :controller=>'user', :action => 'login'
end #end
#def onlycanlogins
#reset_session
#flash[:error] = t(:allready_configured,:scope=>:user)
#@current_user = nil
#redirect_to :controller=>'user', :action => 'login'
#end
def about def about
render 'internal/about', :layout => 'application' 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 :prepare_compose_buttons, :only => [:compose]
before_filter :get_system_folders, :only => [:index] before_filter :get_system_folders, :only => [:index]
before_filter :create_message_with_params, :only => [:compose] before_filter :create_message_with_params, :only => [:compose]
before_filter :prepare_multi1_buttons, :only => [:index,:show] #before_filter :prepare_multi1_buttons, :only => [:index,:show]
before_filter :prepare_multi2_buttons, :only => [:index] #before_filter :prepare_multi2_buttons, :only => [:index]
before_filter :prepare_multi3_buttons, :only => [:show] #before_filter :prepare_multi3_buttons, :only => [:show]
after_filter :close_imap_session after_filter :close_imap_session
theme :theme_resolver #theme :theme_resolver
def index def index
@ -90,11 +90,12 @@ class MessagesController < ApplicationController
@text_part = nil @text_part = nil
@html_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) @message.update_attributes(:unseen => false)
imap_message = @mailbox.fetch_body(@message.uid) imap_message = @mailbox.fetch_body(@message.uid)
mail = Mail.new(imap_message) mail = Mail.new(imap_message)
@mail = Mail.new(imap_message)
@plain_header = mail.header.to_s @plain_header = mail.header.to_s
@ -103,8 +104,8 @@ class MessagesController < ApplicationController
#@to = mail.To.addrs.presence #@to = mail.To.addrs.presence
@from = @message.from_addr @from = @message.from_addr
@to = @message.to_addr @to = @message.to_addr
@cc = mail.Cc.presence #@cc = mail.cc
@bcc = mail.Bcc.presence #@bcc = mail.bcc
#@subject = mail.Subject #@subject = mail.Subject
@date = mail.date.presence @date = mail.date.presence
@ -129,7 +130,9 @@ class MessagesController < ApplicationController
end end
end end
else else
part = Mail::Part.new(mail) logger.custom('mail',mail.inspect)
part = mail
#part = Mail::Part.new(mail)
part.idx = 0 part.idx = 0
part.parent_id = @message.uid part.parent_id = @message.uid
if part.isText? if part.isText?
@ -145,7 +148,7 @@ class MessagesController < ApplicationController
end end
def html_body 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)) mail = Mail.new(@mailbox.fetch_body(message.uid))
if mail.multipart? if mail.multipart?
@body = mail.html_part.decoded_and_charseted @body = mail.html_part.decoded_and_charseted
@ -160,7 +163,7 @@ class MessagesController < ApplicationController
attachments = mail.attachments attachments = mail.attachments
if not attachments.size.zero? if not attachments.size.zero?
for idx in 0..attachments.size - 1 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 end
end end
@ -170,12 +173,13 @@ class MessagesController < ApplicationController
def attachment def attachment
attachments = [] 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)) mail = Mail.new(@mailbox.fetch_body(message.uid))
if mail.multipart? == true if mail.multipart? == true
attachments = mail.attachments attachments = mail.attachments
else else
attachments << Mail::Part.new(mail) #attachments << Mail::Part.new(mail)
attachments << mail
end end
a = attachments[params[:idx].to_i] a = attachments[params[:idx].to_i]
headers['Content-type'] = a.main_type + "/" + a.sub_type headers['Content-type'] = a.main_type + "/" + a.sub_type
@ -188,23 +192,23 @@ class MessagesController < ApplicationController
protected protected
def prepare_multi2_buttons #def prepare_multi2_buttons
@multi2_buttons = [] #@multi2_buttons = []
@multi2_buttons << {:text => 'trash',:scope=>:message,:image => 'trash.png'} #@multi2_buttons << {:text => 'trash',:scope=>:message,:image => 'trash.png'}
@multi2_buttons << {:text => 'set_unread',:scope=>:message,:image => 'unseen.png'} #@multi2_buttons << {:text => 'set_unread',:scope=>:message,:image => 'unseen.png'}
@multi2_buttons << {:text => 'set_read',:scope=>:message,:image => 'seen.png'} #@multi2_buttons << {:text => 'set_read',:scope=>:message,:image => 'seen.png'}
end #end
def prepare_multi1_buttons #def prepare_multi1_buttons
@multi1_buttons = [] #@multi1_buttons = []
@multi1_buttons << {:text => 'copy',:scope=>:message,:image => 'copy.png'} #@multi1_buttons << {:text => 'copy',:scope=>:message,:image => 'copy.png'}
@multi1_buttons << {:text => 'move',:scope=>:message,:image => 'move.png'} #@multi1_buttons << {:text => 'move',:scope=>:message,:image => 'move.png'}
end #end
def prepare_multi3_buttons #def prepare_multi3_buttons
@multi3_buttons = [] #@multi3_buttons = []
@multi3_buttons << {:text => 'show_header',:scope=>:show,:image => 'zoom.png'} #@multi3_buttons << {:text => 'show_header',:scope=>:show,:image => 'zoom.png'}
@multi3_buttons << {:text => 'trash',:scope=>:show,:image => 'trash.png'} #@multi3_buttons << {:text => 'trash',:scope=>:show,:image => 'trash.png'}
@multi3_buttons << {:text => 'reply',:scope=>:show,:image => 'reply.png'} #@multi3_buttons << {:text => 'reply',:scope=>:show,:image => 'reply.png'}
end #end
end end

View file

@ -3,6 +3,7 @@ require 'imap_mailbox'
require 'imap_message' require 'imap_message'
require 'mail' require 'mail'
require 'mail_plugin_extension' require 'mail_plugin_extension'
require 'net/smtp'
class MessagesOpsController < ApplicationController class MessagesOpsController < ApplicationController
@ -14,16 +15,17 @@ class MessagesOpsController < ApplicationController
before_filter :check_current_user ,:selected_folder,:get_current_folders before_filter :check_current_user ,:selected_folder,:get_current_folders
before_filter :open_imap_session, :select_imap_folder before_filter :open_imap_session, :select_imap_folder
before_filter :prepare_compose_buttons before_filter :prepare_compose_buttons
before_filter :get_system_folders, :only => [:sendout_or_save,:single,:multi] before_filter :get_system_folders, :only => [:composed,:single,:multi]
before_filter :create_message_with_params , :only => [:sendout_or_save] before_filter :prepare_composed , :only => [:composed]
before_filter :create_message_with_params, :only=> [:composed,:single,:multi]
after_filter :close_imap_session after_filter :close_imap_session
theme :theme_resolver #theme :theme_resolver
############################################### single ##################################### ############################################### single #####################################
def single def single
if params[:reply] if params[:reply] or params[:reply_all]
reply reply
return return
elsif params[:trash] elsif params[:trash]
@ -65,14 +67,14 @@ class MessagesOpsController < ApplicationController
def set_unread def set_unread
params["uids"].each do |uid| params["uids"].each do |uid|
@mailbox.set_unread(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
end end
def set_read def set_read
params["uids"].each do |uid| params["uids"].each do |uid|
@mailbox.set_read(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
end end
@ -113,29 +115,41 @@ class MessagesOpsController < ApplicationController
flash[:warning] = t(:no_selected,:scope=>:folder) flash[:warning] = t(:no_selected,:scope=>:folder)
else else
dest_folder = @current_user.folders.find(params[:folder][:target]) dest_folder = @current_user.folders.find(params[:folder][:target])
logger.info "DEST: "+dest_folder.inspect
params["uids"].each do |uid| 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) @mailbox.move_message(uid,dest_folder.full_name)
message = @current_folder.messages.find_by_uid(uid) 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) message.change_folder(dest_folder)
logger.info "UPDATE_DEST_BEFORE2: "+dest_folder.inspect
end end
logger.info "UPDATE_DEST_BEFORE: "+dest_folder.inspect
@mailbox.expunge @mailbox.expunge
dest_folder.update_stats dest_folder.update_stats
logger.info "UPDATE_DEST: "+dest_folder.inspect
@current_folder.update_stats @current_folder.update_stats
logger.info "UPDATE_CUT: "+@current_folder.inspect
end end
end end
def upload def upload
#FIXME check if uploads directory exists begin
@operation = :upload raise MailrException.new :cause=>:no_tmp_dir,:scope=>:common if not File.exists?($defaults["msg_upload_dir"])
create_message_with_params raise MailrException.new :cause=>:no_file_chosen,:scope=>:common if not params[:upload]
if not params[:upload] @operation = :upload
flash[:error] = t(:no_file_chosen,:scope=>:common) name = params[:file][:data].original_filename
else
name = params[:upload][:datafile].original_filename
upload_dir = $defaults["msg_upload_dir"] upload_dir = $defaults["msg_upload_dir"]
path = File.join(upload_dir, @current_user.username + "_" + name) 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 end
create_message_with_params
render 'messages/compose' render 'messages/compose'
end end
@ -168,13 +182,7 @@ class MessagesOpsController < ApplicationController
# if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}") # if File.exist?("#{RAILS_ROOT}/dirname/#{@filename}")
# end # end
def composed
############################################### sendout_or_save ############################
def sendout_or_save
#FIXME check if domain is set
if params[:delete_marked] and params[:files] if params[:delete_marked] and params[:files]
params[:files].each do |filename| params[:files].each do |filename|
path = File.join(Rails.root,$defaults["msg_upload_dir"],@current_user.username + "_" +filename) path = File.join(Rails.root,$defaults["msg_upload_dir"],@current_user.username + "_" +filename)
@ -184,81 +192,78 @@ class MessagesOpsController < ApplicationController
@operation = :new @operation = :new
render 'messages/compose' render 'messages/compose'
return return
end elsif params[:upload]
upload
mail = Mail.new elsif params[:save]
mail.subject = params[:message][:subject] save
mail.from = @current_user.full_address elsif params[:sendout]
#TODO check if email address is valid if not get address from contacts sendout
mail.to = params[:message][:to_addr] else
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})"
redirect_to :controller => 'messages', :action => 'index'
return
end
attachments.each do |filename|
path = File.join(Rails.root,filename)
File.delete(path) if File.exist?(path)
end
flash[:notice] = 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)
end
@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 Exception => e
flash[:error] = "#{t(:imap_error,:scope=>:internal)} (#{e.to_s})"
redirect_to :controller => 'messages', :action => 'index'
return
end
flash[:notice] = t(:was_saved,:scope => :compose)
redirect_to :controller => 'messages', :action => 'index' redirect_to :controller => 'messages', :action => 'index'
end end
end end
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
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'
return
end
@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(: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
redirect_to :controller => 'messages', :action => 'index'
end
#FIXME edit does not support attachments #FIXME edit does not support attachments
def edit 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 = Message.new
@message.to_addr = old_message.to_addr @message.to_addr = old_message.to_addr
@message.subject = old_message.subject @message.subject = old_message.subject
@ -266,7 +271,7 @@ class MessagesOpsController < ApplicationController
imap_message = @mailbox.fetch_body(old_message.uid) imap_message = @mailbox.fetch_body(old_message.uid)
mail = Mail.new(imap_message) mail = Mail.new(imap_message)
if mail.multipart? 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 else
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "") @message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
end end
@ -277,27 +282,58 @@ class MessagesOpsController < ApplicationController
end end
def reply 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 = Message.new
@message.to_addr = old_message.from_addr #@message.to_addr = old_message.from_addr
@message.subject = old_message.subject #@message.to_addr = old_message.from.first
#@message.subject = old_message.subject
imap_message = @mailbox.fetch_body(old_message.uid) imap_message = @mailbox.fetch_body(old_message.uid)
mail = Mail.new(imap_message) 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? 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 else
@message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "") @message.body = mail.decoded_and_charseted.gsub(/<\/?[^>]*>/, "")
end end
@attachments = [] @attachments = []
@operation = :reply @operation = :reply
render 'messages/compose' render 'messages/compose'
end end
###################################### protected section ####################################### ###################################### protected section #######################################
protected 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 #################################### ############################################ set_mail_defaults ####################################
@ -313,7 +349,7 @@ class MessagesOpsController < ApplicationController
authentication = server.auth authentication = server.auth
enable_starttls_auto = server.use_tls enable_starttls_auto = server.use_tls
openssl_verify_mode = OpenSSL::SSL::VERIFY_NONE openssl_verify_mode = OpenSSL::SSL::VERIFY_NONE
user_name = user.full_address user_name = user.login
end end
Mail.defaults do Mail.defaults do
delivery_method :smtp, {:address => server.name, delivery_method :smtp, {:address => server.name,

View file

@ -6,13 +6,13 @@ class PrefsController < ApplicationController
before_filter :get_prefs, :only => [:look,:update_look] before_filter :get_prefs, :only => [:look,:update_look]
theme :theme_resolver #theme :theme_resolver
def update_look def update_look
if params[:prefs] if params[:prefs]
@prefs.update_attributes(params[:prefs]) @prefs.update_attributes(params[:prefs])
end end
flash[:notice] = t(:were_saved,:scope=>:prefs) flash[:success] = t(:were_saved,:scope=>:prefs)
redirect_to :action => 'look' redirect_to :action => 'look'
end end
@ -22,10 +22,18 @@ class PrefsController < ApplicationController
end end
def update_identity def update_identity
if params[:user] if params[:user]
@current_user.update_attributes(params[:user]) @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
redirect_to :action => 'identity'
end end
def look def look
@ -33,7 +41,6 @@ class PrefsController < ApplicationController
end end
def identity def identity
@identity = @curent_user
end end
def servers def servers

View file

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

View file

@ -2,328 +2,333 @@ require 'iconv'
module ApplicationHelper module ApplicationHelper
def form_field(object,field,flabel,example,val) #def form_field(object,field,flabel,example,val)
model_name = eval(object.class.model_name) #model_name = eval(object.class.model_name)
html = "" #html = ""
html << "<div class=\"group\">" #html << "<div class=\"param_group\">"
if not object.errors[field.to_sym].empty? #if not object.errors[field.to_sym].empty?
html << "<div class=\"fieldWithErrors\">" #html << "<div class=\"fieldWithErrors\">"
end #end
html << "<label class=\"label\">" #html << "<label class=\"label\">"
flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym) #flabel.nil? ? html << model_name.human_attribute_name(field) : html << t(flabel.to_sym)
html << "</label>" #html << "</label>"
if not object.errors[field.to_sym].empty? #if not object.errors[field.to_sym].empty?
html << "<span class=\"error\"> " #html << "<span class=\"error\"> "
html << object.errors[field.to_sym].to_s #html << object.errors[field.to_sym].to_s
html << "</span>" #html << "</span>"
html << "</div>" #html << "</div>"
end #end
html << "<input id=\"" #html << "<input id=\""
html << object.class.name.downcase+"_"+field #html << object.class.name.downcase+"_"+field
html << "\"" #html << "\""
html << " name=\"#{object.class.name.downcase}[#{field}]\"" #html << " name=\"#{object.class.name.downcase}[#{field}]\""
html << " type=\"text\" class=\"text_field\" value=\"" #html << " type=\"text\" class=\"text_field\" value=\""
value = val || object.instance_eval(field) || "" #value = val || object.instance_eval(field) || ""
html << value #html << value
html << "\"/>" #html << "\"/>"
html << "<span class=\"description\">" #html << "<span class=\"description\">"
html << t(:example,:scope=>:common) #html << t(:example,:scope=>:common)
html << ": " #html << ": "
html << example #html << example
html << "</span>" #html << "</span>"
html << "</div>" #html << "</div>"
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 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)
# html = ""
# html << "<div class=\"group\">"
# html << "<label class=\"label\">#{label}</label>"
# html << "<input class=\"text_field\" type=\"text\" value=\"#{value}\">"
# html << "</div>"
#end #end
#def nav_to_folders #def show_param_view(object,field,value)
# link_to( t(:folders,:scope=>:folder), :controller=>:folders, :action=>:index ) #model_name = eval(object.class.model_name)
#end #html = ""
# #html << "<div class=\"group clearfix\">"
#def nav_to_messages #html << "<label class=\"label\">#{model_name.human_attribute_name(field)}: </label>"
# link_to( t(:messages,:scope=>:message), :controller=>:messages, :action=>:index ) #html << value
#end #html << "</div>"
# #html
#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 #end
def single_navigation(label,scope) #def area_field(object,field,flabel,example,val,cols,rows)
s = "" #model_name = eval(object.class.model_name)
s += "<ul class=\"wat-cf\">" #html = ""
s += "<li class=\"first active\">#{link_to(t(label,:scope=>scope),'#')}</li>" #html << "<div class=\"group\">"
s += "<li class=\"last\">&nbsp;</li>"
s += "</ul>" #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\">"
#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 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 end

View file

@ -1,34 +1,40 @@
module FolderHelper 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 folder.parent.empty? ? name = folder.name : name = folder.parent.gsub(/\./,'#') + "#" + folder.name
if folder.isInbox? 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? 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? 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? elsif folder.isTrash?
name_shown = t(:trash_name,:scope => :folder) name_shown = "<i class=\"icon-trash #{active}\"></i>" +t(:trash_name,:scope => :folder)
else else
name_shown = folder.name.capitalize name_shown = "<i class=\"icon-none\"></i>" + folder.name.capitalize
end end
s = link_to name_shown, folders_select_path(:id => name)
if folder.isTrash? if folder.isTrash?
if not folder.total.zero? if not folder.total.zero?
s <<' (' name_shown += " <button class=\"btn btn-mini btn-danger\" onclick=\"window.location='#{folders_emptybin_path}'\" href=\"#\">#{t(:emptybin,:scope=>:folder)}</button>"
s << link_to(t(:emptybin,:scope=>:folder),folders_emptybin_path) #name_shown += raw link_to(t(:emptybin,:scope=>:folder),folders_emptybin_path)
s << ')' #name_shown += ')'
end end
else else
if !folder.unseen.zero? if !folder.unseen.zero?
s += ' (' + folder.unseen.to_s + ')' name_shown += ' (' + folder.unseen.to_s + ')'
end end
end end
s
link_to name_shown.html_safe, folders_select_path(:id => name)
end end
def pretty_folder_name(folder) 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 end
def address_formatter(addr,op) def address_formatter(addr,op)
return "" if addr.nil?
s = "" s = ""
return s if addr.nil? return t(:no_address,:scope=>:message) if addr.empty?
length = $defaults["msg_address_length"].to_i length = $defaults["msg_address_length"].to_i
case op case op
when :index when :index
logger.custom('addr',addr)
fs = addr.gsub(/\"/,"").split(/</) fs = addr.gsub(/\"/,"").split(/</)
fs[0].size.zero? ? s = fs[1] : s = fs[0] fs[0].size.zero? ? s = fs[1] : s = fs[0]
s.length >= length ? s = s[0,length]+"..." : s s.length >= length ? s = s[0,length]+"..." : s
@ -33,22 +35,29 @@ module MessagesHelper
#fs[0].size.zero? ? s = fs[1] : s << fs[0] + " <" + fs[1] + ">" #fs[0].size.zero? ? s = fs[1] : s << fs[0] + " <" + fs[1] + ">"
s = h(addr) s = h(addr)
return s return s
when :reply when :reply
return h(addr) return addr
end end
end end
def body_formatter(body,op) def body_formatter(body,op)
case op case op
when :reply when :reply
s = "\n\n\n" s = "\n\n\n"
body.gsub(/^\s+/,"").split(/\n/).each do |line| body.split(/\n/).each do |line|
s += ">" + line + "\n" s += '>' + line.strip + "\n"
end end
s s
when :edit when :edit
return body return body
end 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 end
def subject_formatter(message,op) def subject_formatter(message,op)
@ -77,7 +86,7 @@ module MessagesHelper
end end
def attachment_formatter(message) 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 end
def headers_links 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 << link_to(Message.human_attribute_name(f), {:controller => 'messages',:action => 'index',:sort_field => f,:sort_dir => dir}, {:class=>"header"})
html << "</th>" html << "</th>"
end end
if @current_folder == @drafts_folder
html << "<th>&nbsp;</th>"
end
html html
end end
def content_text_plain_for_render(text) #def content_text_plain_for_render(text)
html = "<pre>" #html = "<pre class=\"clearfix\">"
#html << text.gsub!(/\r\n/,"\n") ##html << text.gsub!(/\r\n/,"\n")
html << h(text) #html << h(text)
html << "</pre>" #html << "</pre>"
html #html
#end
def humanize_attr(object,attr)
model_name = eval(object.class.model_name)
return model_name.human_attribute_name(attr)
end end
end end

View file

@ -1,2 +1,16 @@
module PrefsHelper 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 end

View file

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

View file

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

View file

@ -38,8 +38,11 @@ class Folder < ActiveRecord::Base
end end
def update_stats def update_stats
logger.info "MESS_BEFORE: "+messages.inspect
unseen = messages.where(:unseen => true).count unseen = messages.where(:unseen => true).count
total = messages.count total = messages.count
logger.info "MESS: "+messages.inspect
logger.info "MESS: #{unseen} #{total}"
update_attributes(:unseen => unseen, :total => total) update_attributes(:unseen => unseen, :total => total)
end 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,8 +6,9 @@ class Message < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :folder belongs_to :folder
set_primary_key :uid #set_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 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 attr_accessor :body
def self.addr_to_db(addr) def self.addr_to_db(addr)

View file

@ -11,7 +11,9 @@ class Prefs < ActiveRecord::Base
:theme => $defaults['theme'], :theme => $defaults['theme'],
:locale => $defaults['locale'], :locale => $defaults['locale'],
:msgs_per_page => $defaults['msgs_per_page'], :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
end end

View file

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

View file

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