Merge pull request #482 from metamaps/develop

merge develop into master (version 2.8!)
This commit is contained in:
Connor Turland 2016-03-27 00:43:54 -07:00
commit 8cbb79d04a
193 changed files with 47993 additions and 30125 deletions

3
.gitignore vendored
View file

@ -7,6 +7,7 @@
#assety stuff #assety stuff
realtime/node_modules realtime/node_modules
public/assets public/assets
public/metamaps_mobile
vendor/ vendor/
#secrets and config #secrets and config
@ -19,6 +20,8 @@ vendor/
log/*.log log/*.log
tmp tmp
coverage
.DS_Store .DS_Store
*/.DS_Store */.DS_Store
.DS_Store? .DS_Store?

3
.simplecov Normal file
View file

@ -0,0 +1,3 @@
if ENV['COVERAGE'] == 'on'
SimpleCov.start 'rails'
end

9
.travis.yml Normal file
View file

@ -0,0 +1,9 @@
sudo: false
language: ruby
rvm:
- 2.1.3
before_script:
- export RAILS_ENV=test
- cp .example-env .env
- bundle exec rake db:create
- bundle exec rake db:schema:load

11
Gemfile
View file

@ -6,7 +6,9 @@ gem 'rails', '4.2.4'
gem 'devise' gem 'devise'
gem 'redis' gem 'redis'
gem 'pg' gem 'pg'
gem 'cancancan' gem 'pundit'
gem 'pundit_extra'
gem 'doorkeeper'
gem 'formula' gem 'formula'
gem 'formtastic' gem 'formtastic'
gem 'json' gem 'json'
@ -15,6 +17,11 @@ gem 'best_in_place' #in-place editing
gem 'kaminari' # pagination gem 'kaminari' # pagination
gem 'uservoice-ruby' gem 'uservoice-ruby'
gem 'dotenv' gem 'dotenv'
gem 'snorlax'
gem 'httparty'
gem 'active_model_serializers', '~> 0.8.1'
gem 'delayed_job', '~> 4.0.2'
gem 'delayed_job_active_record', '~> 4.0.1'
gem 'paperclip' gem 'paperclip'
gem 'aws-sdk', '< 2.0' gem 'aws-sdk', '< 2.0'
@ -42,6 +49,8 @@ group :test do
gem 'rspec-rails' gem 'rspec-rails'
gem 'factory_girl_rails' gem 'factory_girl_rails'
gem 'shoulda-matchers' gem 'shoulda-matchers'
gem 'simplecov', require: false
gem 'json-schema'
end end
group :production do #this is used on heroku group :production do #this is used on heroku

View file

@ -20,6 +20,8 @@ GEM
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activejob (4.2.4) activejob (4.2.4)
activesupport (= 4.2.4) activesupport (= 4.2.4)
globalid (>= 0.3.0) globalid (>= 0.3.0)
@ -36,14 +38,15 @@ GEM
minitest (~> 5.1) minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4) thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1) tzinfo (~> 1.1)
addressable (2.3.8)
arel (6.0.3) arel (6.0.3)
aws-sdk (1.66.0) aws-sdk (1.66.0)
aws-sdk-v1 (= 1.66.0) aws-sdk-v1 (= 1.66.0)
aws-sdk-v1 (1.66.0) aws-sdk-v1 (1.66.0)
json (~> 1.4) json (~> 1.4)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
bcrypt (3.1.10) bcrypt (3.1.11)
best_in_place (3.0.3) best_in_place (3.1.0)
actionpack (>= 3.2) actionpack (>= 3.2)
railties (>= 3.2) railties (>= 3.2)
better_errors (2.1.1) better_errors (2.1.1)
@ -53,24 +56,27 @@ GEM
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
builder (3.2.2) builder (3.2.2)
byebug (5.0.0) byebug (8.2.2)
columnize (= 0.9.0)
cancancan (1.13.1)
climate_control (0.0.3) climate_control (0.0.3)
activesupport (>= 3.0) activesupport (>= 3.0)
cocaine (0.5.7) cocaine (0.5.8)
climate_control (>= 0.0.3, < 1.0) climate_control (>= 0.0.3, < 1.0)
coderay (1.1.0) coderay (1.1.1)
coffee-rails (4.1.0) coffee-rails (4.1.1)
coffee-script (>= 2.2.0) coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0) railties (>= 4.0.0, < 5.1.x)
coffee-script (2.4.1) coffee-script (2.4.1)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.9.1.1) coffee-script-source (1.10.0)
columnize (0.9.0) concurrent-ruby (1.0.1)
debug_inspector (0.0.2) debug_inspector (0.0.2)
devise (3.5.2) delayed_job (4.0.6)
activesupport (>= 3.0, < 5.0)
delayed_job_active_record (4.0.3)
activerecord (>= 3.0, < 5.0)
delayed_job (>= 3.0, < 4.1)
devise (3.5.6)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5) railties (>= 3.2.6, < 5)
@ -78,13 +84,16 @@ GEM
thread_safe (~> 0.1) thread_safe (~> 0.1)
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.2.5) diff-lcs (1.2.5)
dotenv (2.0.2) docile (1.1.5)
doorkeeper (3.1.0)
railties (>= 3.2)
dotenv (2.1.0)
erubis (2.7.0) erubis (2.7.0)
execjs (2.6.0) execjs (2.6.0)
ezcrypto (0.7.2) ezcrypto (0.7.2)
factory_girl (4.5.0) factory_girl (4.5.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_girl_rails (4.5.0) factory_girl_rails (4.6.0)
factory_girl (~> 4.5.0) factory_girl (~> 4.5.0)
railties (>= 3.0.0) railties (>= 3.0.0)
formtastic (3.1.3) formtastic (3.1.3)
@ -93,50 +102,61 @@ GEM
rails (> 3.0.0) rails (> 3.0.0)
globalid (0.3.6) globalid (0.3.6)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
httparty (0.13.7)
json (~> 1.8)
multi_xml (>= 0.5.2)
i18n (0.7.0) i18n (0.7.0)
jbuilder (2.3.2) jbuilder (2.4.1)
activesupport (>= 3.0.0, < 5) activesupport (>= 3.0.0, < 5.1)
multi_json (~> 1.2) multi_json (~> 1.2)
jquery-rails (4.0.5) jquery-rails (4.1.1)
rails-dom-testing (~> 1.0) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
jquery-ui-rails (5.0.5) jquery-ui-rails (5.0.5)
railties (>= 3.2.16) railties (>= 3.2.16)
json (1.8.3) json (1.8.3)
json-schema (2.6.1)
addressable (~> 2.3.8)
kaminari (0.16.3) kaminari (0.16.3)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
loofah (2.0.3) loofah (2.0.3)
nokogiri (>= 1.5.9) nokogiri (>= 1.5.9)
mail (2.6.3) mail (2.6.4)
mime-types (>= 1.16, < 3) mime-types (>= 1.16, < 4)
method_source (0.8.2) method_source (0.8.2)
mime-types (2.6.2) mime-types (3.0)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0221)
mimemagic (0.3.0) mimemagic (0.3.0)
mini_portile (0.6.2) mini_portile2 (2.0.0)
minitest (5.8.2) minitest (5.8.4)
multi_json (1.11.2) multi_json (1.11.2)
nokogiri (1.6.6.2) multi_xml (0.5.5)
mini_portile (~> 0.6.0) nokogiri (1.6.7.2)
oauth (0.4.7) mini_portile2 (~> 2.0.0.rc2)
oauth (0.5.1)
orm_adapter (0.5.0) orm_adapter (0.5.0)
paperclip (4.3.1) paperclip (4.3.5)
activemodel (>= 3.2.0) activemodel (>= 3.2.0)
activesupport (>= 3.2.0) activesupport (>= 3.2.0)
cocaine (~> 0.5.5) cocaine (~> 0.5.5)
mime-types mime-types
mimemagic (= 0.3.0) mimemagic (= 0.3.0)
pg (0.18.3) pg (0.18.4)
pry (0.10.3) pry (0.10.3)
coderay (~> 1.1.0) coderay (~> 1.1.0)
method_source (~> 0.8.1) method_source (~> 0.8.1)
slop (~> 3.4) slop (~> 3.4)
pry-byebug (3.2.0) pry-byebug (3.3.0)
byebug (~> 5.0) byebug (~> 8.0)
pry (~> 0.10) pry (~> 0.10)
pry-rails (0.3.4) pry-rails (0.3.4)
pry (>= 0.9.10) pry (>= 0.9.10)
pundit (1.1.0)
activesupport (>= 3.0.0)
pundit_extra (0.1.1)
quiet_assets (1.1.0) quiet_assets (1.1.0)
railties (>= 3.1, < 5.0) railties (>= 3.1, < 5.0)
rack (1.6.4) rack (1.6.4)
@ -159,61 +179,69 @@ GEM
activesupport (>= 4.2.0.beta, < 5.0) activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0) nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.2) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
rails3-jquery-autocomplete (1.0.15) rails3-jquery-autocomplete (1.0.15)
rails (>= 3.2) rails (>= 3.2)
rails_12factor (0.0.3) rails_12factor (0.0.3)
rails_serve_static_assets rails_serve_static_assets
rails_stdout_logging rails_stdout_logging
rails_serve_static_assets (0.0.4) rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.4) rails_stdout_logging (0.0.4)
railties (4.2.4) railties (4.2.4)
actionpack (= 4.2.4) actionpack (= 4.2.4)
activesupport (= 4.2.4) activesupport (= 4.2.4)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rake (10.4.2) rake (11.1.1)
redis (3.2.1) redis (3.2.2)
responders (2.1.0) responders (2.1.1)
railties (>= 4.2.0, < 5) railties (>= 4.2.0, < 5.1)
rspec-core (3.3.2) rspec-core (3.4.4)
rspec-support (~> 3.3.0) rspec-support (~> 3.4.0)
rspec-expectations (3.3.1) rspec-expectations (3.4.0)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0) rspec-support (~> 3.4.0)
rspec-mocks (3.3.2) rspec-mocks (3.4.1)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.3.0) rspec-support (~> 3.4.0)
rspec-rails (3.3.3) rspec-rails (3.4.2)
actionpack (>= 3.0, < 4.3) actionpack (>= 3.0, < 4.3)
activesupport (>= 3.0, < 4.3) activesupport (>= 3.0, < 4.3)
railties (>= 3.0, < 4.3) railties (>= 3.0, < 4.3)
rspec-core (~> 3.3.0) rspec-core (~> 3.4.0)
rspec-expectations (~> 3.3.0) rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.3.0) rspec-mocks (~> 3.4.0)
rspec-support (~> 3.3.0) rspec-support (~> 3.4.0)
rspec-support (3.3.0) rspec-support (3.4.1)
sass (3.4.19) sass (3.4.21)
sass-rails (5.0.4) sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0) railties (>= 4.0.0, < 5.0)
sass (~> 3.1) sass (~> 3.1)
sprockets (>= 2.8, < 4.0) sprockets (>= 2.8, < 4.0)
sprockets-rails (>= 2.0, < 4.0) sprockets-rails (>= 2.0, < 4.0)
tilt (>= 1.1, < 3) tilt (>= 1.1, < 3)
shoulda-matchers (3.0.1) shoulda-matchers (3.1.1)
activesupport (>= 4.0.0) activesupport (>= 4.0.0)
simplecov (0.11.2)
docile (~> 1.1.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0) slop (3.6.0)
sprockets (3.4.0) snorlax (0.1.5)
rails (> 4.1)
sprockets (3.5.2)
concurrent-ruby (~> 1.0)
rack (> 1, < 3) rack (> 1, < 3)
sprockets-rails (2.3.3) sprockets-rails (3.0.4)
actionpack (>= 3.0) actionpack (>= 4.0)
activesupport (>= 3.0) activesupport (>= 4.0)
sprockets (>= 2.8, < 4.0) sprockets (>= 3.0.0)
thor (0.19.1) thor (0.19.1)
thread_safe (0.3.5) thread_safe (0.3.5)
tilt (2.0.1) tilt (2.0.2)
tunemygc (1.0.61) tunemygc (1.0.65)
tzinfo (1.2.2) tzinfo (1.2.2)
thread_safe (~> 0.1) thread_safe (~> 0.1)
uglifier (2.7.2) uglifier (2.7.2)
@ -223,33 +251,40 @@ GEM
ezcrypto (>= 0.7.2) ezcrypto (>= 0.7.2)
json (>= 1.7.5) json (>= 1.7.5)
oauth (>= 0.4.7) oauth (>= 0.4.7)
warden (1.2.3) warden (1.2.6)
rack (>= 1.0) rack (>= 1.0)
PLATFORMS PLATFORMS
ruby ruby
DEPENDENCIES DEPENDENCIES
active_model_serializers (~> 0.8.1)
aws-sdk (< 2.0) aws-sdk (< 2.0)
best_in_place best_in_place
better_errors better_errors
binding_of_caller binding_of_caller
cancancan
coffee-rails coffee-rails
delayed_job (~> 4.0.2)
delayed_job_active_record (~> 4.0.1)
devise devise
doorkeeper
dotenv dotenv
factory_girl_rails factory_girl_rails
formtastic formtastic
formula formula
httparty
jbuilder jbuilder
jquery-rails jquery-rails
jquery-ui-rails jquery-ui-rails
json json
json-schema
kaminari kaminari
paperclip paperclip
pg pg
pry-byebug pry-byebug
pry-rails pry-rails
pundit
pundit_extra
quiet_assets quiet_assets
rails (= 4.2.4) rails (= 4.2.4)
rails3-jquery-autocomplete rails3-jquery-autocomplete
@ -258,9 +293,11 @@ DEPENDENCIES
rspec-rails rspec-rails
sass-rails sass-rails
shoulda-matchers shoulda-matchers
simplecov
snorlax
tunemygc tunemygc
uglifier uglifier
uservoice-ruby uservoice-ruby
BUNDLED WITH BUNDLED WITH
1.10.6 1.11.2

View file

@ -1 +1,3 @@
web: bundle exec rails server -p $PORT web: bundle exec rails server -p $PORT
worker: bundle exec rake jobs:work

View file

@ -2,9 +2,9 @@ Metamaps
======= =======
[![Join the chat at https://gitter.im/metamaps/metamaps_gen002](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/metamaps/metamaps_gen002?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Join the chat at https://gitter.im/metamaps/metamaps_gen002](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/metamaps/metamaps_gen002?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
![Build Status](https://jenkins.devinhoward.ca/job/metamaps_gen002.develop/badge/icon) [![Build Status](https://travis-ci.org/metamaps/metamaps_gen002.svg)](https://travis-ci.org/metamaps/metamaps_gen002)
Welcome to the Metamaps GitHub repo. Welcome to the Metamaps GitHub repo.
## About ## About
@ -12,7 +12,7 @@ Metamaps is a free and AGPL open source technology for changemakers, innovators,
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in a private beta. You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in a private beta.
Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter. Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter.
To get connected with the community interested in Metamaps, join our [Google+ community][community]. To get connected with the community interested in Metamaps, join our [Google+ community][community].
@ -52,7 +52,7 @@ We haven't figured out Vagrant for Windows yet, but we have a set of manual inst
## Contributing ## Contributing
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved. Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
## Community ## Community

1
Vagrantfile vendored
View file

@ -16,7 +16,6 @@ sudo apt-get install nodejs -y
sudo apt-get install npm -y sudo apt-get install npm -y
sudo apt-get install postgresql -y sudo apt-get install postgresql -y
sudo apt-get install libpq-dev -y sudo apt-get install libpq-dev -y
sudo apt-get install redis-server -y
# get imagemagick # get imagemagick
sudo apt-get install imagemagick --fix-missing sudo apt-get install imagemagick --fix-missing

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 466 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

BIN
app/assets/images/junto.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,28 +1,32 @@
// This is a manifest file that'll be compiled into application.js, which will include all the files // This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below. // listed below.
// //
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, // 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. // 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 // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file. // the compiled file.
// //
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW. // GO AFTER THE REQUIRES BELOW.
// //
//= require jquery //= require jquery
//= require jquery-ui //= require jquery-ui
//= require jquery_ujs //= require jquery_ujs
//= require ./orderedLibraries/underscore //= require ./orderedLibraries/underscore
//= require ./orderedLibraries/backbone //= require ./orderedLibraries/backbone
//= require_directory ./lib //= require_directory ./lib
//= require ./src/Metamaps.GlobalUI //= require ./src/Metamaps.GlobalUI
//= require ./src/Metamaps.Router //= require ./src/Metamaps.Router
//= require ./src/Metamaps.Backbone //= require ./src/Metamaps.Backbone
//= require ./src/Metamaps.Views //= require ./src/Metamaps.Views
//= require ./src/JIT //= require ./src/views/chatView
//= require ./src/Metamaps //= require ./src/views/videoView
//= require ./src/Metamaps.JIT //= require ./src/views/room
//= require_directory ./shims //= require ./src/JIT
//= require_directory ./require //= require ./src/Metamaps
//= require_directory ./famous //= require ./src/Metamaps.Import
//= require ./src/Metamaps.JIT
//= require_directory ./shims
//= require_directory ./require
//= require_directory ./famous

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,39 @@
var attachMediaStream = function (stream, el, options) {
var URL = window.URL;
var opts = {
autoplay: true,
mirror: false,
muted: false
};
var element = el || document.createElement('video');
var item;
if (options) {
for (item in options) {
opts[item] = options[item];
}
}
if (opts.autoplay) element.autoplay = 'autoplay';
if (opts.muted) element.muted = true;
if (opts.mirror) {
['', 'moz', 'webkit', 'o', 'ms'].forEach(function (prefix) {
var styleName = prefix ? prefix + 'Transform' : 'transform';
element.style[styleName] = 'scaleX(-1)';
});
}
// this first one should work most everywhere now
// but we have a few fallbacks just in case.
if (URL && URL.createObjectURL) {
element.src = URL.createObjectURL(stream);
} else if (element.srcObject) {
element.srcObject = stream;
} else if (element.mozSrcObject) {
element.mozSrcObject = stream;
} else {
return false;
}
return element;
};

View file

@ -1,426 +1,426 @@
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
// CloudCarousel V1.0.5 // CloudCarousel V1.0.5
// (c) 2011 by R Cecco. <http://www.professorcloud.com> // (c) 2011 by R Cecco. <http://www.professorcloud.com>
// MIT License // MIT License
// //
// Reflection code based on plugin by Christophe Beyls <http://www.digitalia.be> // Reflection code based on plugin by Christophe Beyls <http://www.digitalia.be>
// //
// Please retain this copyright header in all versions of the software // Please retain this copyright header in all versions of the software
////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////
var matched, browser; var matched, browser;
jQuery.uaMatch = function( ua ) { jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase(); ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) || var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) || /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) || /(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[]; [];
return { return {
browser: match[ 1 ] || "", browser: match[ 1 ] || "",
version: match[ 2 ] || "0" version: match[ 2 ] || "0"
}; };
}; };
matched = jQuery.uaMatch( navigator.userAgent ); matched = jQuery.uaMatch( navigator.userAgent );
browser = {}; browser = {};
if ( matched.browser ) { if ( matched.browser ) {
browser[ matched.browser ] = true; browser[ matched.browser ] = true;
browser.version = matched.version; browser.version = matched.version;
} }
// Chrome is Webkit, but Webkit is also Safari. // Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) { if ( browser.chrome ) {
browser.webkit = true; browser.webkit = true;
} else if ( browser.webkit ) { } else if ( browser.webkit ) {
browser.safari = true; browser.safari = true;
} }
jQuery.browser = browser; jQuery.browser = browser;
(function($) { (function($) {
// START Reflection object. // START Reflection object.
// Creates a reflection for underneath an image. // Creates a reflection for underneath an image.
// IE uses an image with IE specific filter properties, other browsers use the Canvas tag. // IE uses an image with IE specific filter properties, other browsers use the Canvas tag.
// The position and size of the reflection gets updated by updateAll() in Controller. // The position and size of the reflection gets updated by updateAll() in Controller.
function Reflection(img, reflHeight, opacity) { function Reflection(img, reflHeight, opacity) {
var reflection, cntx, imageWidth = img.width, imageHeight = img.width, gradient, parent; var reflection, cntx, imageWidth = img.width, imageHeight = img.width, gradient, parent;
parent = $(img.parentNode); parent = $(img.parentNode);
this.element = reflection = parent.append("<canvas class='reflection' style='position:absolute'/>").find(':last')[0]; this.element = reflection = parent.append("<canvas class='reflection' style='position:absolute'/>").find(':last')[0];
if ( !reflection.getContext && $.browser.msie) { if ( !reflection.getContext && $.browser.msie) {
this.element = reflection = parent.append("<img class='reflection' style='position:absolute'/>").find(':last')[0]; this.element = reflection = parent.append("<img class='reflection' style='position:absolute'/>").find(':last')[0];
reflection.src = img.src; reflection.src = img.src;
reflection.style.filter = "flipv progid:DXImageTransform.Microsoft.Alpha(opacity=" + (opacity * 100) + ", style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy=" + (reflHeight / imageHeight * 100) + ")"; reflection.style.filter = "flipv progid:DXImageTransform.Microsoft.Alpha(opacity=" + (opacity * 100) + ", style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy=" + (reflHeight / imageHeight * 100) + ")";
} else { } else {
cntx = reflection.getContext("2d"); cntx = reflection.getContext("2d");
try { try {
$(reflection).attr({width: imageWidth, height: reflHeight}); $(reflection).attr({width: imageWidth, height: reflHeight});
cntx.save(); cntx.save();
cntx.translate(0, imageHeight-1); cntx.translate(0, imageHeight-1);
cntx.scale(1, -1); cntx.scale(1, -1);
cntx.drawImage(img, 0, 0, imageWidth, imageHeight); cntx.drawImage(img, 0, 0, imageWidth, imageHeight);
cntx.restore(); cntx.restore();
cntx.globalCompositeOperation = "destination-out"; cntx.globalCompositeOperation = "destination-out";
gradient = cntx.createLinearGradient(0, 0, 0, reflHeight); gradient = cntx.createLinearGradient(0, 0, 0, reflHeight);
gradient.addColorStop(0, "rgba(255, 255, 255, " + (1 - opacity) + ")"); gradient.addColorStop(0, "rgba(255, 255, 255, " + (1 - opacity) + ")");
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)"); gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
cntx.fillStyle = gradient; cntx.fillStyle = gradient;
cntx.fillRect(0, 0, imageWidth, reflHeight); cntx.fillRect(0, 0, imageWidth, reflHeight);
} catch(e) { } catch(e) {
return; return;
} }
} }
// Store a copy of the alt and title attrs into the reflection // Store a copy of the alt and title attrs into the reflection
$(reflection).attr({ 'alt': $(img).attr('alt'), title: $(img).attr('title')} ); $(reflection).attr({ 'alt': $(img).attr('alt'), title: $(img).attr('title')} );
} //END Reflection object } //END Reflection object
// START Item object. // START Item object.
// A wrapper object for items within the carousel. // A wrapper object for items within the carousel.
var Item = function(imgIn, options) var Item = function(imgIn, options)
{ {
this.orgWidth = imgIn.width; this.orgWidth = imgIn.width;
this.orgHeight = imgIn.height; this.orgHeight = imgIn.height;
this.image = imgIn; this.image = imgIn;
this.reflection = null; this.reflection = null;
this.alt = imgIn.alt; this.alt = imgIn.alt;
this.title = imgIn.title; this.title = imgIn.title;
this.imageOK = false; this.imageOK = false;
this.options = options; this.options = options;
this.imageOK = true; this.imageOK = true;
if (this.options.reflHeight > 0) if (this.options.reflHeight > 0)
{ {
this.reflection = new Reflection(this.image, this.options.reflHeight, this.options.reflOpacity); this.reflection = new Reflection(this.image, this.options.reflHeight, this.options.reflOpacity);
} }
$(this.image).css('position','absolute'); // Bizarre. This seems to reset image width to 0 on webkit! $(this.image).css('position','absolute'); // Bizarre. This seems to reset image width to 0 on webkit!
};// END Item object };// END Item object
// Controller object. // Controller object.
// This handles moving all the items, dealing with mouse clicks etc. // This handles moving all the items, dealing with mouse clicks etc.
var Controller = function(container, images, options) var Controller = function(container, images, options)
{ {
var items = [], funcSin = Math.sin, funcCos = Math.cos, ctx=this; var items = [], funcSin = Math.sin, funcCos = Math.cos, ctx=this;
this.controlTimer = 0; this.controlTimer = 0;
this.stopped = false; this.stopped = false;
//this.imagesLoaded = 0; //this.imagesLoaded = 0;
this.container = container; this.container = container;
this.xRadius = options.xRadius; this.xRadius = options.xRadius;
this.yRadius = options.yRadius; this.yRadius = options.yRadius;
this.showFrontTextTimer = 0; this.showFrontTextTimer = 0;
this.autoRotateTimer = 0; this.autoRotateTimer = 0;
if (options.xRadius === 0) if (options.xRadius === 0)
{ {
this.xRadius = ($(container).width()/2.3); this.xRadius = ($(container).width()/2.3);
} }
if (options.yRadius === 0) if (options.yRadius === 0)
{ {
this.yRadius = ($(container).height()/6); this.yRadius = ($(container).height()/6);
} }
this.xCentre = options.xPos; this.xCentre = options.xPos;
this.yCentre = options.yPos; this.yCentre = options.yPos;
this.frontIndex = 0; // Index of the item at the front this.frontIndex = 0; // Index of the item at the front
// Start with the first item at the front. // Start with the first item at the front.
this.rotation = this.destRotation = Math.PI/2; this.rotation = this.destRotation = Math.PI/2;
this.timeDelay = 1000/options.FPS; this.timeDelay = 1000/options.FPS;
// Turn on the infoBox // Turn on the infoBox
if(options.altBox !== null) if(options.altBox !== null)
{ {
$(options.altBox).css('display','block'); $(options.altBox).css('display','block');
$(options.titleBox).css('display','block'); $(options.titleBox).css('display','block');
} }
// Turn on relative position for container to allow absolutely positioned elements // Turn on relative position for container to allow absolutely positioned elements
// within it to work. // within it to work.
$(container).css({ position:'relative', overflow:'hidden'} ); $(container).css({ position:'relative', overflow:'hidden'} );
$(options.buttonLeft).css('display','inline'); $(options.buttonLeft).css('display','inline');
$(options.buttonRight).css('display','inline'); $(options.buttonRight).css('display','inline');
// Setup the buttons. // Setup the buttons.
$(options.buttonLeft).bind('mouseup',this,function(event){ $(options.buttonLeft).bind('mouseup',this,function(event){
event.data.rotate(-1); event.data.rotate(-1);
return false; return false;
}); });
$(options.buttonRight).bind('mouseup',this,function(event){ $(options.buttonRight).bind('mouseup',this,function(event){
event.data.rotate(1); event.data.rotate(1);
return false; return false;
}); });
// Add code that makes tab and shift+tab scroll through metacodes // Add code that makes tab and shift+tab scroll through metacodes
$('.new_topic').bind('keydown',this,function(event){ $('.new_topic').bind('keydown',this,function(event){
if (event.keyCode == 9 && event.shiftKey) { if (event.keyCode == 9 && event.shiftKey) {
event.data.rotate(-1); event.data.rotate(-1);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} else if (event.keyCode == 9) { } else if (event.keyCode == 9) {
event.data.rotate(1); event.data.rotate(1);
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} }
}); });
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel // You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
if (options.mouseWheel) if (options.mouseWheel)
{ {
// START METAMAPS CODE // START METAMAPS CODE
$('body').bind('mousewheel',this,function(event, delta) { $('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) { if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) {
event.data.rotate(delta); event.data.rotate(delta);
return false; return false;
} }
}); });
// END METAMAPS CODE // END METAMAPS CODE
/* ORIGINAL CODE /* ORIGINAL CODE
$(container).bind('mousewheel',this,function(event, delta) { $(container).bind('mousewheel',this,function(event, delta) {
event.data.rotate(delta); event.data.rotate(delta);
return false; return false;
}); });
*/ */
} }
$(container).bind('mouseover click',this,function(event){ $(container).bind('mouseover click',this,function(event){
clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over. clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over.
var text = $(event.target).attr('alt'); var text = $(event.target).attr('alt');
// If we have moved over a carousel item, then show the alt and title text. // If we have moved over a carousel item, then show the alt and title text.
if ( text !== undefined && text !== null ) if ( text !== undefined && text !== null )
{ {
clearTimeout(event.data.showFrontTextTimer); clearTimeout(event.data.showFrontTextTimer);
$(options.altBox).html( ($(event.target).attr('alt') )); $(options.altBox).html( ($(event.target).attr('alt') ));
//$(options.titleBox).html( ($(event.target).attr('title') )); //$(options.titleBox).html( ($(event.target).attr('title') ));
if ( options.bringToFront && event.type == 'click' ) if ( options.bringToFront && event.type == 'click' )
{ {
$(options.titleBox).html( ($(event.target).attr('title') )); $(options.titleBox).html( ($(event.target).attr('title') ));
// METAMAPS CODE // METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id'); Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
// NOT METAMAPS CODE // NOT METAMAPS CODE
var idx = $(event.target).data('itemIndex'); var idx = $(event.target).data('itemIndex');
var frontIndex = event.data.frontIndex; var frontIndex = event.data.frontIndex;
//var diff = idx - frontIndex; //var diff = idx - frontIndex;
var diff = (idx - frontIndex) % images.length; var diff = (idx - frontIndex) % images.length;
if (Math.abs(diff) > images.length / 2) { if (Math.abs(diff) > images.length / 2) {
diff += (diff > 0 ? -images.length : images.length); diff += (diff > 0 ? -images.length : images.length);
} }
event.data.rotate(-diff); event.data.rotate(-diff);
} }
} }
}); });
// If we have moved out of a carousel item (or the container itself), // If we have moved out of a carousel item (or the container itself),
// restore the text of the front item in 1 second. // restore the text of the front item in 1 second.
$(container).bind('mouseout',this,function(event){ $(container).bind('mouseout',this,function(event){
var context = event.data; var context = event.data;
clearTimeout(context.showFrontTextTimer); clearTimeout(context.showFrontTextTimer);
context.showFrontTextTimer = setTimeout( function(){context.showFrontText();},1000); context.showFrontTextTimer = setTimeout( function(){context.showFrontText();},1000);
context.autoRotate(); // Start auto rotation. context.autoRotate(); // Start auto rotation.
}); });
// Prevent items from being selected as mouse is moved and clicked in the container. // Prevent items from being selected as mouse is moved and clicked in the container.
$(container).bind('mousedown',this,function(event){ $(container).bind('mousedown',this,function(event){
event.data.container.focus(); event.data.container.focus();
return false; return false;
}); });
container.onselectstart = function () { return false; }; // For IE. container.onselectstart = function () { return false; }; // For IE.
this.innerWrapper = $(container).wrapInner('<div style="position:absolute;width:100%;height:100%;"/>').children()[0]; this.innerWrapper = $(container).wrapInner('<div style="position:absolute;width:100%;height:100%;"/>').children()[0];
// Shows the text from the front most item. // Shows the text from the front most item.
this.showFrontText = function() this.showFrontText = function()
{ {
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet. if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
// METAMAPS CODE // METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('data-id'); Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('data-id');
//$('img.cloudcarousel').css({"background":"none", "width":"","height":""}); //$('img.cloudcarousel').css({"background":"none", "width":"","height":""});
//$(items[this.frontIndex].image).css({"width":"45px","height":"45px"}); //$(items[this.frontIndex].image).css({"width":"45px","height":"45px"});
// NOT METAMAPS CODE // NOT METAMAPS CODE
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title')); $(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt')); $(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
}; };
this.go = function() this.go = function()
{ {
if(this.controlTimer !== 0) { return; } if(this.controlTimer !== 0) { return; }
var context = this; var context = this;
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay); this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
}; };
this.stop = function() this.stop = function()
{ {
clearTimeout(this.controlTimer); clearTimeout(this.controlTimer);
this.controlTimer = 0; this.controlTimer = 0;
}; };
// Starts the rotation of the carousel. Direction is the number (+-) of carousel items to rotate by. // Starts the rotation of the carousel. Direction is the number (+-) of carousel items to rotate by.
this.rotate = function(direction) this.rotate = function(direction)
{ {
this.frontIndex -= direction; this.frontIndex -= direction;
if (this.frontIndex == -1) this.frontIndex = items.length - 1; if (this.frontIndex == -1) this.frontIndex = items.length - 1;
this.frontIndex %= items.length; this.frontIndex %= items.length;
this.destRotation += ( Math.PI / items.length ) * ( 2*direction ); this.destRotation += ( Math.PI / items.length ) * ( 2*direction );
this.showFrontText(); this.showFrontText();
this.go(); this.go();
}; };
this.autoRotate = function() this.autoRotate = function()
{ {
if ( options.autoRotate !== 'no' ) if ( options.autoRotate !== 'no' )
{ {
var dir = (options.autoRotate === 'right')? 1 : -1; var dir = (options.autoRotate === 'right')? 1 : -1;
this.autoRotateTimer = setInterval( function(){ctx.rotate(dir); }, options.autoRotateDelay ); this.autoRotateTimer = setInterval( function(){ctx.rotate(dir); }, options.autoRotateDelay );
} }
}; };
// This is the main loop function that moves everything. // This is the main loop function that moves everything.
this.updateAll = function() this.updateAll = function()
{ {
var minScale = options.minScale; // This is the smallest scale applied to the furthest item. var minScale = options.minScale; // This is the smallest scale applied to the furthest item.
var smallRange = (1-minScale) * 0.5; var smallRange = (1-minScale) * 0.5;
var w,h,x,y,scale,item,sinVal; var w,h,x,y,scale,item,sinVal;
var change = (this.destRotation - this.rotation); var change = (this.destRotation - this.rotation);
var absChange = Math.abs(change); var absChange = Math.abs(change);
this.rotation += change * options.speed; this.rotation += change * options.speed;
if ( absChange < 0.001 ) { this.rotation = this.destRotation; } if ( absChange < 0.001 ) { this.rotation = this.destRotation; }
var itemsLen = items.length; var itemsLen = items.length;
var spacing = (Math.PI / itemsLen) * 2; var spacing = (Math.PI / itemsLen) * 2;
//var wrapStyle = null; //var wrapStyle = null;
var radians = this.rotation; var radians = this.rotation;
var isMSIE = $.browser.msie; var isMSIE = $.browser.msie;
// Turn off display. This can reduce repaints/reflows when making style and position changes in the loop. // Turn off display. This can reduce repaints/reflows when making style and position changes in the loop.
// See http://dev.opera.com/articles/view/efficient-javascript/?page=3 // See http://dev.opera.com/articles/view/efficient-javascript/?page=3
this.innerWrapper.style.display = 'none'; this.innerWrapper.style.display = 'none';
var style; var style;
var px = 'px', reflHeight; var px = 'px', reflHeight;
var context = this; var context = this;
for (var i = 0; i<itemsLen ;i++) for (var i = 0; i<itemsLen ;i++)
{ {
item = items[i]; item = items[i];
sinVal = funcSin(radians); sinVal = funcSin(radians);
scale = ((sinVal+1) * smallRange) + minScale; scale = ((sinVal+1) * smallRange) + minScale;
x = this.xCentre + (( (funcCos(radians) * this.xRadius) - (item.orgWidth*0.5)) * scale); x = this.xCentre + (( (funcCos(radians) * this.xRadius) - (item.orgWidth*0.5)) * scale);
y = this.yCentre + (( (sinVal * this.yRadius) ) * scale); y = this.yCentre + (( (sinVal * this.yRadius) ) * scale);
if (item.imageOK) if (item.imageOK)
{ {
var img = item.image; var img = item.image;
img.style.zIndex = "" + (scale * 100)>>0; // >>0 = Math.foor(). Firefox doesn't like fractional decimals in z-index. img.style.zIndex = "" + (scale * 100)>>0; // >>0 = Math.foor(). Firefox doesn't like fractional decimals in z-index.
w = img.width = item.orgWidth * scale; w = img.width = item.orgWidth * scale;
h = img.height = item.orgHeight * scale; h = img.height = item.orgHeight * scale;
img.style.left = x + px ; img.style.left = x + px ;
img.style.top = y + px; img.style.top = y + px;
if (item.reflection !== null) if (item.reflection !== null)
{ {
reflHeight = options.reflHeight * scale; reflHeight = options.reflHeight * scale;
style = item.reflection.element.style; style = item.reflection.element.style;
style.left = x + px; style.left = x + px;
style.top = y + h + options.reflGap * scale + px; style.top = y + h + options.reflGap * scale + px;
style.width = w + px; style.width = w + px;
if (isMSIE) if (isMSIE)
{ {
style.filter.finishy = (reflHeight / h * 100); style.filter.finishy = (reflHeight / h * 100);
}else }else
{ {
style.height = reflHeight + px; style.height = reflHeight + px;
} }
} }
} }
radians += spacing; radians += spacing;
} }
// Turn display back on. // Turn display back on.
this.innerWrapper.style.display = 'block'; this.innerWrapper.style.display = 'block';
// If we have a preceptable change in rotation then loop again next frame. // If we have a preceptable change in rotation then loop again next frame.
if ( absChange >= 0.001 ) if ( absChange >= 0.001 )
{ {
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay); this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
}else }else
{ {
// Otherwise just stop completely. // Otherwise just stop completely.
this.stop(); this.stop();
} }
}; // END updateAll }; // END updateAll
// Create an Item object for each image // Create an Item object for each image
// func = function(){return;ctx.updateAll();} ; // func = function(){return;ctx.updateAll();} ;
// Check if images have loaded. We need valid widths and heights for the reflections. // Check if images have loaded. We need valid widths and heights for the reflections.
this.checkImagesLoaded = function() this.checkImagesLoaded = function()
{ {
var i; var i;
for(i=0;i<images.length;i++) { for(i=0;i<images.length;i++) {
if ( (images[i].width === undefined) || ( (images[i].complete !== undefined) && (!images[i].complete) )) if ( (images[i].width === undefined) || ( (images[i].complete !== undefined) && (!images[i].complete) ))
{ {
return; return;
} }
} }
for(i=0;i<images.length;i++) { for(i=0;i<images.length;i++) {
items.push( new Item( images[i], options ) ); items.push( new Item( images[i], options ) );
$(images[i]).data('itemIndex',i); $(images[i]).data('itemIndex',i);
} }
// If all images have valid widths and heights, we can stop checking. // If all images have valid widths and heights, we can stop checking.
clearInterval(this.tt); clearInterval(this.tt);
this.showFrontText(); this.showFrontText();
this.autoRotate(); this.autoRotate();
this.updateAll(); this.updateAll();
}; };
this.tt = setInterval( function(){ctx.checkImagesLoaded();},50); this.tt = setInterval( function(){ctx.checkImagesLoaded();},50);
}; // END Controller object }; // END Controller object
// The jQuery plugin part. Iterates through items specified in selector and inits a Controller class for each one. // The jQuery plugin part. Iterates through items specified in selector and inits a Controller class for each one.
$.fn.CloudCarousel = function(options) { $.fn.CloudCarousel = function(options) {
this.each( function() { this.each( function() {
options = $.extend({}, { options = $.extend({}, {
reflHeight:0, reflHeight:0,
reflOpacity:0.5, reflOpacity:0.5,
reflGap:0, reflGap:0,
minScale:0.5, minScale:0.5,
xPos:0, xPos:0,
yPos:0, yPos:0,
xRadius:0, xRadius:0,
yRadius:0, yRadius:0,
altBox:null, altBox:null,
titleBox:null, titleBox:null,
FPS: 30, FPS: 30,
autoRotate: 'no', autoRotate: 'no',
autoRotateDelay: 1500, autoRotateDelay: 1500,
speed:0.2, speed:0.2,
mouseWheel: false, mouseWheel: false,
bringToFront: false bringToFront: false
},options ); },options );
// Create a Controller for each carousel. // Create a Controller for each carousel.
$(this).data('cloudcarousel', new Controller( this, $('.cloudcarousel',$(this)), options) ); $(this).data('cloudcarousel', new Controller( this, $('.cloudcarousel',$(this)), options) );
}); });
return this; return this;
}; };
})(jQuery); })(jQuery);

File diff suppressed because it is too large Load diff

View file

@ -1,180 +1,180 @@
/** /**
* jquery.purr.js * jquery.purr.js
* Copyright (c) 2008 Net Perspective (net-perspective.com) * Copyright (c) 2008 Net Perspective (net-perspective.com)
* Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php) * Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
* *
* @author R.A. Ray * @author R.A. Ray
* @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl." * @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
* @version 0.1.0 * @version 0.1.0
* *
* @requires jquery.js (tested with 1.2.6) * @requires jquery.js (tested with 1.2.6)
* *
* @param fadeInSpeed int - Duration of fade in animation in miliseconds * @param fadeInSpeed int - Duration of fade in animation in miliseconds
* default: 500 * default: 500
* @param fadeOutSpeed int - Duration of fade out animationin miliseconds * @param fadeOutSpeed int - Duration of fade out animationin miliseconds
default: 500 default: 500
* @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list * @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
default: 4000 default: 4000
* @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed * @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed
default: false default: false
* @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling * @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling
default: false default: false
*/ */
( function( $ ) { ( function( $ ) {
$.purr = function ( notice, options ) $.purr = function ( notice, options )
{ {
// Convert notice to a jQuery object // Convert notice to a jQuery object
notice = $( notice ); notice = $( notice );
// Add a class to denote the notice as not sticky // Add a class to denote the notice as not sticky
if ( !options.isSticky ) if ( !options.isSticky )
{ {
notice.addClass( 'not-sticky' ); notice.addClass( 'not-sticky' );
}; };
// Get the container element from the page // Get the container element from the page
var cont = document.getElementById( 'purr-container' ); var cont = document.getElementById( 'purr-container' );
// If the container doesn't yet exist, we need to create it // If the container doesn't yet exist, we need to create it
if ( !cont ) if ( !cont )
{ {
cont = '<div id="purr-container"></div>'; cont = '<div id="purr-container"></div>';
} }
// Convert cont to a jQuery object // Convert cont to a jQuery object
cont = $( cont ); cont = $( cont );
// Add the container to the page // Add the container to the page
$( 'body' ).append( cont ); $( 'body' ).append( cont );
notify(); notify();
function notify () function notify ()
{ {
// Set up the close button // Set up the close button
var close = document.createElement( 'a' ); var close = document.createElement( 'a' );
$( close ).attr( $( close ).attr(
{ {
className: 'close', className: 'close',
href: '#close', href: '#close',
innerHTML: 'Close' innerHTML: 'Close'
} }
) )
.appendTo( notice ) .appendTo( notice )
.click( function () .click( function ()
{ {
removeNotice(); removeNotice();
return false; return false;
} }
); );
// Add the notice to the page and keep it hidden initially // Add the notice to the page and keep it hidden initially
notice.appendTo( cont ) notice.appendTo( cont )
.hide(); .hide();
if ( jQuery.browser.msie && options.usingTransparentPNG ) if ( jQuery.browser.msie && options.usingTransparentPNG )
{ {
// IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
// notice style, we'll just skip the fading in. // notice style, we'll just skip the fading in.
notice.show(); notice.show();
} }
else else
{ {
//Fade in the notice we just added //Fade in the notice we just added
notice.fadeIn( options.fadeInSpeed ); notice.fadeIn( options.fadeInSpeed );
} }
// Set up the removal interval for the added notice if that notice is not a sticky // Set up the removal interval for the added notice if that notice is not a sticky
if ( !options.isSticky ) if ( !options.isSticky )
{ {
var topSpotInt = setInterval( function () var topSpotInt = setInterval( function ()
{ {
// Check to see if our notice is the first non-sticky notice in the list // Check to see if our notice is the first non-sticky notice in the list
if ( notice.prevAll( '.not-sticky' ).length == 0 ) if ( notice.prevAll( '.not-sticky' ).length == 0 )
{ {
// Stop checking once the condition is met // Stop checking once the condition is met
clearInterval( topSpotInt ); clearInterval( topSpotInt );
// Call the close action after the timeout set in options // Call the close action after the timeout set in options
setTimeout( function () setTimeout( function ()
{ {
removeNotice(); removeNotice();
}, options.removeTimer }, options.removeTimer
); );
} }
}, 200 ); }, 200 );
} }
} }
function removeNotice () function removeNotice ()
{ {
// IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our // IE7 and earlier can't handle the combination of opacity and transparent pngs, so if we're using transparent pngs in our
// notice style, we'll just skip the fading out. // notice style, we'll just skip the fading out.
if ( jQuery.browser.msie && options.usingTransparentPNG ) if ( jQuery.browser.msie && options.usingTransparentPNG )
{ {
notice.css( { opacity: 0 } ) notice.css( { opacity: 0 } )
.animate( .animate(
{ {
height: '0px' height: '0px'
}, },
{ {
duration: options.fadeOutSpeed, duration: options.fadeOutSpeed,
complete: function () complete: function ()
{ {
notice.remove(); notice.remove();
} }
} }
); );
} }
else else
{ {
// Fade the object out before reducing its height to produce the sliding effect // Fade the object out before reducing its height to produce the sliding effect
notice.animate( notice.animate(
{ {
opacity: '0' opacity: '0'
}, },
{ {
duration: options.fadeOutSpeed, duration: options.fadeOutSpeed,
complete: function () complete: function ()
{ {
notice.animate( notice.animate(
{ {
height: '0px' height: '0px'
}, },
{ {
duration: options.fadeOutSpeed, duration: options.fadeOutSpeed,
complete: function () complete: function ()
{ {
notice.remove(); notice.remove();
} }
} }
); );
} }
} }
); );
} }
}; };
}; };
$.fn.purr = function ( options ) $.fn.purr = function ( options )
{ {
options = options || {}; options = options || {};
options.fadeInSpeed = options.fadeInSpeed || 500; options.fadeInSpeed = options.fadeInSpeed || 500;
options.fadeOutSpeed = options.fadeOutSpeed || 500; options.fadeOutSpeed = options.fadeOutSpeed || 500;
options.removeTimer = options.removeTimer || 4000; options.removeTimer = options.removeTimer || 4000;
options.isSticky = options.isSticky || false; options.isSticky = options.isSticky || false;
options.usingTransparentPNG = options.usingTransparentPNG || false; options.usingTransparentPNG = options.usingTransparentPNG || false;
this.each( function() this.each( function()
{ {
new $.purr( this, options ); new $.purr( this, options );
} }
); );
return this; return this;
}; };
})( jQuery ); })( jQuery );

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,23 @@
function SocketIoConnection(config) {
this.connection = io.connect(config.url, config.socketio);
}
SocketIoConnection.prototype.on = function (ev, fn) {
this.connection.on(ev, fn);
};
SocketIoConnection.prototype.emit = function () {
this.connection.emit.apply(this.connection, arguments);
};
SocketIoConnection.prototype.removeAllListeners = function () {
this.connection.removeAllListeners();
};
SocketIoConnection.prototype.getSessionid = function () {
return this.connection.socket.sessionid;
};
SocketIoConnection.prototype.disconnect = function () {
return this.connection.disconnect();
};

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,227 +1,247 @@
Metamaps.Backbone = {}; Metamaps.Backbone = {};
Metamaps.Backbone.Map = Backbone.Model.extend({ Metamaps.Backbone.Map = Backbone.Model.extend({
urlRoot: '/maps', urlRoot: '/maps',
blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'], blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'],
toJSON: function (options) { toJSON: function (options) {
return _.omit(this.attributes, this.blacklist); return _.omit(this.attributes, this.blacklist);
}, },
save: function (key, val, options) { save: function (key, val, options) {
var attrs; var attrs;
// Handle both `"key", value` and `{key: value}` -style arguments. // Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') { if (key == null || typeof key === 'object') {
attrs = key; attrs = key;
options = val; options = val;
} else { } else {
(attrs = {})[key] = val; (attrs = {})[key] = val;
} }
var newOptions = options || {}; var newOptions = options || {};
var s = newOptions.success; var s = newOptions.success;
newOptions.success = function (model, response, opt) { newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt); if (s) s(model, response, opt);
model.trigger('saved'); model.trigger('saved');
}; };
return Backbone.Model.prototype.save.call(this, attrs, newOptions); return Backbone.Model.prototype.save.call(this, attrs, newOptions);
}, },
initialize: function () { initialize: function () {
this.on('changeByOther', this.updateView); this.on('changeByOther', this.updateView);
this.on('saved', this.savedEvent); this.on('saved', this.savedEvent);
}, },
savedEvent: function() { savedEvent: function() {
Metamaps.Realtime.sendMapChange(this); Metamaps.Realtime.sendMapChange(this);
}, },
authorizeToEdit: function (mapper) { authorizeToEdit: function (mapper) {
if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true; if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true;
else return false; else return false;
}, },
authorizePermissionChange: function (mapper) { authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) return true; if (mapper && this.get('user_id') === mapper.get('id')) return true;
else return false; else return false;
}, },
getUser: function () { getUser: function () {
return Metamaps.Mapper.get(this.get('user_id')); return Metamaps.Mapper.get(this.get('user_id'));
}, },
fetchContained: function () { fetchContained: function () {
var bb = Metamaps.Backbone; var bb = Metamaps.Backbone;
var that = this; var that = this;
var start = function (data) { var start = function (data) {
that.set('mappers', new bb.MapperCollection(data.mappers)); that.set('mappers', new bb.MapperCollection(data.mappers));
that.set('topics', new bb.TopicCollection(data.topics)); that.set('topics', new bb.TopicCollection(data.topics));
that.set('synapses', new bb.SynapseCollection(data.synapses)); that.set('synapses', new bb.SynapseCollection(data.synapses));
that.set('mappings', new bb.MappingCollection(data.mappings)); that.set('mappings', new bb.MappingCollection(data.mappings));
}; };
var e = $.ajax({ var e = $.ajax({
url: "/maps/" + this.id + "/contains.json", url: "/maps/" + this.id + "/contains.json",
success: start, success: start,
error: errorFunc, error: errorFunc,
async: false async: false
}); });
}, },
getTopics: function () { getTopics: function () {
if (!this.get('topics')) { if (!this.get('topics')) {
this.fetchContained(); this.fetchContained();
} }
return this.get('topics'); return this.get('topics');
}, },
getSynapses: function () { getSynapses: function () {
if (!this.get('synapses')) { if (!this.get('synapses')) {
this.fetchContained(); this.fetchContained();
} }
return this.get('synapses'); return this.get('synapses');
}, },
getMappings: function () { getMappings: function () {
if (!this.get('mappings')) { if (!this.get('mappings')) {
this.fetchContained(); this.fetchContained();
} }
return this.get('mappings'); return this.get('mappings');
}, },
getMappers: function () { getMappers: function () {
if (!this.get('mappers')) { if (!this.get('mappers')) {
this.fetchContained(); this.fetchContained();
} }
return this.get('mappers'); return this.get('mappers');
}, },
attrForCards: function () { attrForCards: function () {
function capitalize(string) { function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1); return string.charAt(0).toUpperCase() + string.slice(1);
} }
var n = this.get('name'); var n = this.get('name');
var d = this.get('desc'); var d = this.get('desc');
var maxNameLength = 32; var maxNameLength = 32;
var maxDescLength = 118; var maxDescLength = 118;
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + "..." : n) : ""; var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + "..." : n) : "";
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + "..." : d) : ""; var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + "..." : d) : "";
var obj = { var obj = {
id: this.id, id: this.id,
name: truncatedName, name: truncatedName,
fullName: n, fullName: n,
desc: truncatedDesc, desc: truncatedDesc,
permission: this.get("permission") ? capitalize(this.get("permission")) : "Commons", permission: this.get("permission") ? capitalize(this.get("permission")) : "Commons",
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit', editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>', contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
contributor_count_string: this.get('contributor_count') == 1 ? ' contributor' : ' contributors', contributor_count_string: this.get('contributor_count') == 1 ? ' contributor' : ' contributors',
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>', topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
topic_count_string: this.get('topic_count') == 1 ? ' topic' : ' topics', topic_count_string: this.get('topic_count') == 1 ? ' topic' : ' topics',
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>', synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
synapse_count_string: this.get('synapse_count') == 1 ? ' synapse' : ' synapses', synapse_count_string: this.get('synapse_count') == 1 ? ' synapse' : ' synapses',
screenshot: '<img src="' + this.get('screenshot_url') + '" />' screenshot: '<img src="' + this.get('screenshot_url') + '" />'
}; };
return obj; return obj;
}, },
updateView: function() { updateView: function() {
var map = Metamaps.Active.Map; var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id; var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : ''; var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : ''; var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) { if (isActiveMap) {
Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission')); Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'));
this.updateMapWrapper(); this.updateMapWrapper();
} }
}, },
updateMapWrapper: function() { updateMapWrapper: function() {
var map = Metamaps.Active.Map; var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id; var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : ''; var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : ''; var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) { if (isActiveMap) {
$('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap); $('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap);
} }
} }
}); });
Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({ Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Map, model: Metamaps.Backbone.Map,
initialize: function(models, options) { initialize: function(models, options) {
this.id = options.id; this.id = options.id;
this.sortBy = options.sortBy; this.sortBy = options.sortBy;
if (options.mapperId) { if (options.mapperId) {
this.mapperId = options.mapperId; this.mapperId = options.mapperId;
} }
// this.page represents the NEXT page to fetch // this.page represents the NEXT page to fetch
this.page = models.length > 0 ? (models.length < 20 ? "loadedAll" : 2) : 1; this.page = models.length > 0 ? (models.length < 20 ? "loadedAll" : 2) : 1;
}, },
url: function() { url: function() {
if (!this.mapperId) { if (!this.mapperId) {
return '/explore/' + this.id + '.json'; return '/explore/' + this.id + '.json';
} }
else { else {
return '/explore/mapper/' + this.mapperId + '.json'; return '/explore/mapper/' + this.mapperId + '.json';
} }
}, },
comparator: function (a, b) { comparator: function (a, b) {
a = a.get(this.sortBy); a = a.get(this.sortBy);
b = b.get(this.sortBy); b = b.get(this.sortBy);
var temp; var temp;
if (this.sortBy === 'name') { if (this.sortBy === 'name') {
a = a ? a.toLowerCase() : ""; a = a ? a.toLowerCase() : "";
b = b ? b.toLowerCase() : ""; b = b ? b.toLowerCase() : "";
} }
else { else {
// this is for updated_at and created_at // this is for updated_at and created_at
temp = a; temp = a;
a = b; a = b;
b = temp; b = temp;
a = (new Date(a)).getTime(); a = (new Date(a)).getTime();
b = (new Date(b)).getTime(); b = (new Date(b)).getTime();
} }
return a > b ? 1 : a < b ? -1 : 0; return a > b ? 1 : a < b ? -1 : 0;
}, },
getMaps: function (cb) { getMaps: function (cb) {
var self = this; var self = this;
Metamaps.Loading.show(); Metamaps.Loading.show();
if (this.page != "loadedAll") { if (this.page != "loadedAll") {
var numBefore = this.length; var numBefore = this.length;
this.fetch({ this.fetch({
remove: false, remove: false,
silent: true, silent: true,
data: { page: this.page }, data: { page: this.page },
success: function (collection, response, options) { success: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well // you can pass additional options to the event you trigger here as well
if (collection.length - numBefore < 20) { if (collection.length - numBefore < 20) {
self.page = "loadedAll"; self.page = "loadedAll";
} }
else self.page += 1; else self.page += 1;
self.trigger('successOnFetch', cb); self.trigger('successOnFetch', cb);
}, },
error: function (collection, response, options) { error: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well // you can pass additional options to the event you trigger here as well
self.trigger('errorOnFetch'); self.trigger('errorOnFetch');
} }
}); });
} }
else { else {
self.trigger('successOnFetch', cb); self.trigger('successOnFetch', cb);
} }
} }
}); });
Metamaps.Backbone.Mapper = Backbone.Model.extend({ Metamaps.Backbone.Message = Backbone.Model.extend({
urlRoot: '/users', urlRoot: '/messages',
blacklist: ['created_at', 'updated_at'], blacklist: ['created_at', 'updated_at'],
toJSON: function (options) { toJSON: function (options) {
return _.omit(this.attributes, this.blacklist); return _.omit(this.attributes, this.blacklist);
}, },
prepareLiForFilter: function () { prepareLiForFilter: function () {
var li = ''; /*var li = '';
li += '<li data-id="' + this.id.toString() + '">'; li += '<li data-id="' + this.id.toString() + '">';
li += '<img src="' + this.get("image") + '" data-id="' + this.id.toString() + '"'; li += '<img src="' + this.get("image") + '" data-id="' + this.id.toString() + '"';
li += ' alt="' + this.get('name') + '" />'; li += ' alt="' + this.get('name') + '" />';
li += '<p>' + this.get('name') + '</p></li>'; li += '<p>' + this.get('name') + '</p></li>';
return li; return li;*/
} }
}); });
Metamaps.Backbone.MapperCollection = Backbone.Collection.extend({ Metamaps.Backbone.MessageCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Mapper, model: Metamaps.Backbone.Message,
url: '/users' url: '/messages'
}); });
Metamaps.Backbone.Mapper = Backbone.Model.extend({
urlRoot: '/users',
blacklist: ['created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist);
},
prepareLiForFilter: function () {
var li = '';
li += '<li data-id="' + this.id.toString() + '">';
li += '<img src="' + this.get("image") + '" data-id="' + this.id.toString() + '"';
li += ' alt="' + this.get('name') + '" />';
li += '<p>' + this.get('name') + '</p></li>';
return li;
}
});
Metamaps.Backbone.MapperCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Mapper,
url: '/users'
});

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,327 @@
/*
* Example tab-separated input:
* Some fields will be ignored
*
* Topics
* Id Name Metacode X Y Description Link User Permission
* 8 topic8 Action -231 131 admin commons
* 5 topic Action -229 -131 admin commons
* 7 topic7.1 Action -470 -55 hey admin commons
* 2 topic2 Event -57 -63 admin commons
* 1 topic1 Catalyst -51 50 admin commons
* 6 topic6 Action -425 63 admin commons
*
* Synapses
* Topic1 Topic2 Category Description User Permission
* 6 2 from-to admin commons
* 6 1 from-to admin commons
* 6 5 from-to admin commons
* 2 7 from-to admin commons
* 8 6 from-to admin commons
* 8 1 from-to admin commons
*
*/
Metamaps.Import = {
// note that user is not imported
topicWhitelist: [
'id', 'name', 'metacode', 'x', 'y', 'description', 'link', 'permission'
],
synapseWhitelist: [
'topic1', 'topic2', 'category', 'desc', 'description', 'permission'
],
cidMappings: {}, //to be filled by import_id => cid mappings
init: function() {
var self = Metamaps.Import;
$('body').bind('paste', function(e) {
if (e.target.tagName === "INPUT") return;
var text = e.originalEvent.clipboardData.getData('text/plain');
var results;
if (text[0] === '{') {
try {
results = JSON.parse(text);
} catch (e) {
results = false;
}
} else {
results = self.parseTabbedString(text);
}
if (results === false) return;
var topics = results.topics;
var synapses = results.synapses;
if (topics.length > 0 || synapses.length > 0) {
if (confirm("Are you sure you want to create " + topics.length +
" new topics and " + synapses.length + " new synapses?")) {
self.importTopics(topics);
self.importSynapses(synapses);
}//if
}//if
});
},
abort: function(message) {
console.error(message);
},
simplify: function(string) {
return string
.replace(/(^\s*|\s*$)/g, '')
.toLowerCase();
},
parseTabbedString: function(text) {
var self = Metamaps.Import;
// determine line ending and split lines
var delim = "\n";
if (text.indexOf("\r\n") !== -1) {
delim = "\r\n";
} else if (text.indexOf("\r") !== -1) {
delim = "\r";
}//if
var STATES = {
ABORT: -1,
UNKNOWN: 0,
TOPICS_NEED_HEADERS: 1,
SYNAPSES_NEED_HEADERS: 2,
TOPICS: 3,
SYNAPSES: 4,
};
// state & lines determine parser behaviour
var state = STATES.UNKNOWN;
var lines = text.split(delim);
var results = { topics: [], synapses: [] }
var topicHeaders = [];
var synapseHeaders = [];
lines.forEach(function(line_raw, index) {
var line = line_raw.split("\t");
var noblanks = line.filter(function(elt) {
return elt !== "";
});
switch(state) {
case STATES.UNKNOWN:
if (noblanks.length === 0) {
state = STATES.UNKNOWN;
break;
} else if (noblanks.length === 1 && self.simplify(line[0]) === 'topics') {
state = STATES.TOPICS_NEED_HEADERS;
break;
} else if (noblanks.length === 1 && self.simplify(line[0]) === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS;
break;
}
state = STATES.TOPICS_NEED_HEADERS;
// FALL THROUGH - if we're not sure what to do, pretend
// we're on the TOPICS_NEED_HEADERS state and parse some headers
case STATES.TOPICS_NEED_HEADERS:
if (noblanks.length < 2) {
self.abort("Not enough topic headers on line " + index);
state = STATES.ABORT;
}
topicHeaders = line.map(function(header, index) {
return header.toLowerCase().replace('description', 'desc');
});
state = STATES.TOPICS;
break;
case STATES.SYNAPSES_NEED_HEADERS:
if (noblanks.length < 2) {
self.abort("Not enough synapse headers on line " + index);
state = STATES.ABORT;
}
synapseHeaders = line.map(function(header, index) {
return header.toLowerCase().replace('description', 'desc');
});
state = STATES.SYNAPSES;
break;
case STATES.TOPICS:
if (noblanks.length === 0) {
state = STATES.UNKNOWN;
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'topics') {
state = STATES.TOPICS_NEED_HEADERS;
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS;
} else {
var topic = {};
line.forEach(function(field, index) {
var header = topicHeaders[index];
if (self.topicWhitelist.indexOf(header) === -1) return;
topic[header] = field;
if (['id', 'x', 'y'].indexOf(header) !== -1) {
topic[header] = parseInt(topic[header]);
}//if
});
results.topics.push(topic);
}
break;
case STATES.SYNAPSES:
if (noblanks.length === 0) {
state = STATES.UNKNOWN;
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'topics') {
state = STATES.TOPICS_NEED_HEADERS;
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS;
} else {
var synapse = {};
line.forEach(function(field, index) {
var header = synapseHeaders[index];
if (self.synapseWhitelist.indexOf(header) === -1) return;
synapse[header] = field;
if (['id', 'topic1', 'topic2'].indexOf(header) !== -1) {
synapse[header] = parseInt(synapse[header]);
}//if
});
results.synapses.push(synapse);
}
break;
case STATES.ABORT:
;
default:
self.abort("Invalid state while parsing import data. Check code.");
state = STATES.ABORT;
}
});
if (state === STATES.ABORT) {
return false;
} else {
return results;
}
},
importTopics: function(parsedTopics) {
var self = Metamaps.Import;
// up to 25 topics: scale 100
// up to 81 topics: scale 200
// up to 169 topics: scale 300
var scale = Math.floor((Math.sqrt(parsedTopics.length) - 1) / 4) * 100;
if (scale < 100) scale = 100;
var autoX = -scale;
var autoY = -scale;
parsedTopics.forEach(function(topic) {
var x, y;
if (topic.x && topic.y) {
x = topic.x;
y = topic.y;
} else {
x = autoX;
y = autoY;
autoX += 50;
if (autoX > scale) {
autoY += 50;
autoX = -scale;
}
}
self.createTopicWithParameters(
topic.name, topic.metacode, topic.permission,
topic.desc, topic.link, x, y, topic.id
);
});
},
importSynapses: function(parsedSynapses) {
var self = Metamaps.Import;
parsedSynapses.forEach(function(synapse) {
//only createSynapseWithParameters once both topics are persisted
var topic1 = Metamaps.Topics.get(self.cidMappings[node1_id]);
var topic2 = Metamaps.Topics.get(self.cidMappings[node2_id]);
var synapse_created = false
topic1.once('sync', function() {
if (topic1.id && topic2.id && !synapse_created) {
synaprse_created = true
self.createSynapseWithParameters(
synapse.desc, synapse.category, synapse.permission,
topic1, topic2
);
}//if
});
topic2.once('sync', function() {
if (topic1.id && topic2.id && !synapse_created) {
synaprse_created = true
self.createSynapseWithParameters(
synapse.desc, synapse.category, synapse.permission,
topic1, topic2
);
}//if
});
});
},
createTopicWithParameters: function(name, metacode_name, permission, desc,
link, xloc, yloc, import_id) {
var self = Metamaps.Import;
$(document).trigger(Metamaps.Map.events.editedByActiveMapper);
var metacode = Metamaps.Metacodes.where({name: metacode_name})[0] || null;
if (metacode === null) return console.error("metacode not found");
var topic = new Metamaps.Backbone.Topic({
name: name,
metacode_id: metacode.id,
permission: permission || Metamaps.Active.Map.get('permission'),
desc: desc,
link: link,
});
Metamaps.Topics.add(topic);
self.cidMappings[import_id] = topic.cid;
var mapping = new Metamaps.Backbone.Mapping({
xloc: xloc,
yloc: yloc,
mappable_id: topic.cid,
mappable_type: "Topic",
});
Metamaps.Mappings.add(mapping);
// this function also includes the creation of the topic in the database
Metamaps.Topic.renderTopic(mapping, topic, true, true);
Metamaps.Famous.viz.hideInstructions();
},
createSynapseWithParameters: function(description, category, permission,
topic1, topic2) {
var self = Metamaps.Import;
var node1 = topic1.get('node');
var node2 = topic2.get('node');
if (!topic1.id || !topic2.id) {
console.error("missing topic id when creating synapse")
return;
}//if
var synapse = new Metamaps.Backbone.Synapse({
desc: description,
category: category,
permission: permission,
node1_id: topic1.id,
node2_id: topic2.id
});
Metamaps.Synapses.add(synapse);
var mapping = new Metamaps.Backbone.Mapping({
mappable_type: "Synapse",
mappable_id: synapse.cid,
});
Metamaps.Mappings.add(mapping);
Metamaps.Synapse.renderSynapse(mapping, synapse, node1, node2, true);
},
};

File diff suppressed because it is too large Load diff

View file

@ -1,262 +1,262 @@
(function () { (function () {
Metamaps.currentPage = ""; Metamaps.currentPage = "";
var Router = Backbone.Router.extend({ var Router = Backbone.Router.extend({
routes: { routes: {
"": "home", // #home "": "home", // #home
"explore/:section": "explore", // #explore/active "explore/:section": "explore", // #explore/active
"explore/:section/:id": "explore", // #explore/mapper/1234 "explore/:section/:id": "explore", // #explore/mapper/1234
"maps/:id": "maps" // #maps/7 "maps/:id": "maps" // #maps/7
}, },
home: function () { home: function () {
clearTimeout(Metamaps.routerTimeoutId); clearTimeout(Metamaps.routerTimeoutId);
if (Metamaps.Active.Mapper) document.title = 'Explore Active Maps | Metamaps'; if (Metamaps.Active.Mapper) document.title = 'Explore Active Maps | Metamaps';
else document.title = 'Home | Metamaps'; else document.title = 'Home | Metamaps';
Metamaps.currentSection = ""; Metamaps.currentSection = "";
Metamaps.currentPage = ""; Metamaps.currentPage = "";
$('.wrapper').removeClass('mapPage topicPage'); $('.wrapper').removeClass('mapPage topicPage');
var classes = Metamaps.Active.Mapper ? "homePage explorePage" : "homePage"; var classes = Metamaps.Active.Mapper ? "homePage explorePage" : "homePage";
$('.wrapper').addClass(classes); $('.wrapper').addClass(classes);
var navigate = function() { var navigate = function() {
Metamaps.routerTimeoutId = setTimeout(function() { Metamaps.routerTimeoutId = setTimeout(function() {
Metamaps.Router.navigate(""); Metamaps.Router.navigate("");
}, 300); }, 300);
}; };
// all this only for the logged in home page // all this only for the logged in home page
if (Metamaps.Active.Mapper) { if (Metamaps.Active.Mapper) {
Metamaps.Famous.yield.hide(); Metamaps.Famous.yield.hide();
Metamaps.Famous.explore.set('active'); Metamaps.Famous.explore.set('active');
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.explore.show(); Metamaps.Famous.explore.show();
Metamaps.Famous.maps.show(); Metamaps.Famous.maps.show();
Metamaps.GlobalUI.Search.open(); Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock(); Metamaps.GlobalUI.Search.lock();
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active ); Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active );
if (Metamaps.Maps.Active.length === 0) { if (Metamaps.Maps.Active.length === 0) {
Metamaps.Maps.Active.getMaps(navigate); // this will trigger an explore maps render Metamaps.Maps.Active.getMaps(navigate); // this will trigger an explore maps render
} }
else { else {
Metamaps.Views.exploreMaps.render(navigate); Metamaps.Views.exploreMaps.render(navigate);
} }
} }
// logged out home page // logged out home page
else { else {
Metamaps.Famous.yield.show(); Metamaps.Famous.yield.show();
Metamaps.Famous.explore.hide(); Metamaps.Famous.explore.hide();
Metamaps.GlobalUI.Search.unlock(); Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true); Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Famous.maps.hide(); Metamaps.Famous.maps.hide();
Metamaps.routerTimeoutId = setTimeout(navigate, 500); Metamaps.routerTimeoutId = setTimeout(navigate, 500);
} }
Metamaps.Famous.viz.hide(); Metamaps.Famous.viz.hide();
Metamaps.Map.end(); Metamaps.Map.end();
Metamaps.Topic.end(); Metamaps.Topic.end();
Metamaps.Active.Map = null; Metamaps.Active.Map = null;
Metamaps.Active.Topic = null; Metamaps.Active.Topic = null;
}, },
explore: function (section, id) { explore: function (section, id) {
clearTimeout(Metamaps.routerTimeoutId); clearTimeout(Metamaps.routerTimeoutId);
// just capitalize the variable section // just capitalize the variable section
// either 'featured', 'mapper', or 'active' // either 'featured', 'mapper', or 'active'
var capitalize = section.charAt(0).toUpperCase() + section.slice(1); var capitalize = section.charAt(0).toUpperCase() + section.slice(1);
if (section === "featured" || section === "active") { if (section === "featured" || section === "active") {
document.title = 'Explore ' + capitalize + ' Maps | Metamaps'; document.title = 'Explore ' + capitalize + ' Maps | Metamaps';
} }
else if (section === "mapper") { else if (section === "mapper") {
$.ajax({ $.ajax({
url: "/users/" + id + ".json", url: "/users/" + id + ".json",
success: function (response) { success: function (response) {
document.title = response.name + ' | Metamaps'; document.title = response.name + ' | Metamaps';
}, },
error: function () { error: function () {
} }
}); });
} }
else if (section === "mine") { else if (section === "mine") {
document.title = 'Explore My Maps | Metamaps'; document.title = 'Explore My Maps | Metamaps';
} }
$('.wrapper').removeClass('homePage mapPage topicPage'); $('.wrapper').removeClass('homePage mapPage topicPage');
$('.wrapper').addClass('explorePage'); $('.wrapper').addClass('explorePage');
Metamaps.currentSection = "explore"; Metamaps.currentSection = "explore";
Metamaps.currentPage = section; Metamaps.currentPage = section;
// this will mean it's a mapper page being loaded // this will mean it's a mapper page being loaded
if (id) { if (id) {
if (Metamaps.Maps.Mapper.mapperId !== id) { if (Metamaps.Maps.Mapper.mapperId !== id) {
// empty the collection if we are trying to load the maps // empty the collection if we are trying to load the maps
// collection of a different mapper than we had previously // collection of a different mapper than we had previously
Metamaps.Maps.Mapper.reset(); Metamaps.Maps.Mapper.reset();
Metamaps.Maps.Mapper.page = 1; Metamaps.Maps.Mapper.page = 1;
} }
Metamaps.Maps.Mapper.mapperId = id; Metamaps.Maps.Mapper.mapperId = id;
} }
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] ); Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] );
var navigate = function(){ var navigate = function(){
var path = "/explore/" + Metamaps.currentPage; var path = "/explore/" + Metamaps.currentPage;
// alter url if for mapper profile page // alter url if for mapper profile page
if (Metamaps.currentPage == "mapper") { if (Metamaps.currentPage == "mapper") {
path += "/" + Metamaps.Maps.Mapper.mapperId; path += "/" + Metamaps.Maps.Mapper.mapperId;
} }
Metamaps.Router.navigate(path); Metamaps.Router.navigate(path);
}; };
var navigateTimeout = function() { var navigateTimeout = function() {
Metamaps.routerTimeoutId = setTimeout(navigate, 300); Metamaps.routerTimeoutId = setTimeout(navigate, 300);
}; };
if (Metamaps.Maps[capitalize].length === 0) { if (Metamaps.Maps[capitalize].length === 0) {
Metamaps.Loading.show(); Metamaps.Loading.show();
setTimeout(function(){ setTimeout(function(){
Metamaps.Maps[capitalize].getMaps(navigate); // this will trigger an explore maps render Metamaps.Maps[capitalize].getMaps(navigate); // this will trigger an explore maps render
}, 300); // wait 300 milliseconds till the other animations are done to do the fetch }, 300); // wait 300 milliseconds till the other animations are done to do the fetch
} }
else { else {
if (id) { if (id) {
Metamaps.Views.exploreMaps.fetchUserThenRender(navigateTimeout); Metamaps.Views.exploreMaps.fetchUserThenRender(navigateTimeout);
} }
else { else {
Metamaps.Views.exploreMaps.render(navigateTimeout); Metamaps.Views.exploreMaps.render(navigateTimeout);
} }
} }
Metamaps.GlobalUI.Search.open(); Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock(); Metamaps.GlobalUI.Search.lock();
Metamaps.Famous.yield.hide(); Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.maps.show(); Metamaps.Famous.maps.show();
Metamaps.Famous.explore.set(section, id); Metamaps.Famous.explore.set(section, id);
Metamaps.Famous.explore.show(); Metamaps.Famous.explore.show();
Metamaps.Famous.viz.hide(); Metamaps.Famous.viz.hide();
Metamaps.Map.end(); Metamaps.Map.end();
Metamaps.Topic.end(); Metamaps.Topic.end();
Metamaps.Active.Map = null; Metamaps.Active.Map = null;
Metamaps.Active.Topic = null; Metamaps.Active.Topic = null;
}, },
maps: function (id) { maps: function (id) {
clearTimeout(Metamaps.routerTimeoutId); clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Map ' + id + ' | Metamaps'; document.title = 'Map ' + id + ' | Metamaps';
Metamaps.currentSection = "map"; Metamaps.currentSection = "map";
Metamaps.currentPage = id; Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage topicPage'); $('.wrapper').removeClass('homePage explorePage topicPage');
$('.wrapper').addClass('mapPage'); $('.wrapper').addClass('mapPage');
// another class will be added to wrapper if you // another class will be added to wrapper if you
// can edit this map '.canEditMap' // can edit this map '.canEditMap'
Metamaps.Famous.yield.hide(); Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide(); Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide(); Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again // clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) { if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty(); Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot(); Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas); Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
} }
Metamaps.Famous.viz.show(); Metamaps.Famous.viz.show();
Metamaps.Topic.end(); Metamaps.Topic.end();
Metamaps.Active.Topic = null; Metamaps.Active.Topic = null;
Metamaps.GlobalUI.Search.unlock(); Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true); Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Loading.show(); Metamaps.Loading.show();
Metamaps.Map.end(); Metamaps.Map.end();
Metamaps.Map.launch(id); Metamaps.Map.launch(id);
}, },
topics: function (id) { topics: function (id) {
clearTimeout(Metamaps.routerTimeoutId); clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Topic ' + id + ' | Metamaps'; document.title = 'Topic ' + id + ' | Metamaps';
Metamaps.currentSection = "topic"; Metamaps.currentSection = "topic";
Metamaps.currentPage = id; Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage mapPage'); $('.wrapper').removeClass('homePage explorePage mapPage');
$('.wrapper').addClass('topicPage'); $('.wrapper').addClass('topicPage');
Metamaps.Famous.yield.hide(); Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide(); Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide(); Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again // clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) { if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty(); Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot(); Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas); Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
} }
Metamaps.Famous.viz.show(); Metamaps.Famous.viz.show();
Metamaps.Map.end(); Metamaps.Map.end();
Metamaps.Active.Map = null; Metamaps.Active.Map = null;
Metamaps.GlobalUI.Search.unlock(); Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true); Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Topic.end(); Metamaps.Topic.end();
Metamaps.Topic.launch(id); Metamaps.Topic.launch(id);
} }
}); });
Metamaps.Router = new Router(); Metamaps.Router = new Router();
Metamaps.Router.intercept = function (evt) { Metamaps.Router.intercept = function (evt) {
var segments; var segments;
var href = { var href = {
prop: $(this).prop("href"), prop: $(this).prop("href"),
attr: $(this).attr("href") attr: $(this).attr("href")
}; };
var root = location.protocol + "//" + location.host + Backbone.history.options.root; var root = location.protocol + "//" + location.host + Backbone.history.options.root;
if (href.prop && href.prop === root) href.attr = ""; if (href.prop && href.prop === root) href.attr = "";
if (href.prop && href.prop.slice(0, root.length) === root) { if (href.prop && href.prop.slice(0, root.length) === root) {
evt.preventDefault(); evt.preventDefault();
segments = href.attr.split('/'); segments = href.attr.split('/');
segments.splice(0,1); // pop off the element created by the first / segments.splice(0,1); // pop off the element created by the first /
if (href.attr === "") Metamaps.Router.home(); if (href.attr === "") Metamaps.Router.home();
else { else {
Metamaps.Router[segments[0]](segments[1], segments[2]); Metamaps.Router[segments[0]](segments[1], segments[2]);
} }
} }
}; };
Metamaps.Router.init = function () { Metamaps.Router.init = function () {
Backbone.history.start({ Backbone.history.start({
silent: true, silent: true,
pushState: true, pushState: true,
root: '/' root: '/'
}); });
$(document).on("click", "a:not([data-bypass])", Metamaps.Router.intercept); $(document).on("click", "a:not([data-bypass])", Metamaps.Router.intercept);
}; };
})(); })();

View file

@ -1,133 +1,133 @@
(function () { (function () {
Metamaps.Views = {}; Metamaps.Views = {};
var initialized = false; var initialized = false;
Metamaps.Views.init = function () { Metamaps.Views.init = function () {
Metamaps.Views.MapperCard = Backbone.View.extend({ Metamaps.Views.MapperCard = Backbone.View.extend({
template: Hogan.compile( $('#mapperCardTemplate').html() ), template: Hogan.compile( $('#mapperCardTemplate').html() ),
tagNamea: "div", tagNamea: "div",
className: "mapper", className: "mapper",
render: function () { render: function () {
this.$el.html( this.template.render(this.model) ); this.$el.html( this.template.render(this.model) );
return this; return this;
} }
}); });
Metamaps.Views.MapCard = Backbone.View.extend({ Metamaps.Views.MapCard = Backbone.View.extend({
template: Hogan.compile( $('#mapCardTemplate').html() ), template: Hogan.compile( $('#mapCardTemplate').html() ),
tagName: "div", tagName: "div",
className: "map", className: "map",
id: function() { id: function() {
return this.model.id; return this.model.id;
}, },
initialize: function () { initialize: function () {
this.listenTo(this.model, "change", this.render); this.listenTo(this.model, "change", this.render);
}, },
render: function () { render: function () {
this.$el.html( this.template.render(this.model.attrForCards()) ); this.$el.html( this.template.render(this.model.attrForCards()) );
return this; return this;
} }
}); });
var mapsWrapper = Backbone.View.extend({ var mapsWrapper = Backbone.View.extend({
initialize: function (opts) { initialize: function (opts) {
}, },
setCollection: function (collection) { setCollection: function (collection) {
if (this.collection) this.stopListening(this.collection); if (this.collection) this.stopListening(this.collection);
this.collection = collection; this.collection = collection;
this.listenTo(this.collection, 'add', this.render); this.listenTo(this.collection, 'add', this.render);
this.listenTo(this.collection, 'successOnFetch', this.handleSuccess); this.listenTo(this.collection, 'successOnFetch', this.handleSuccess);
this.listenTo(this.collection, 'errorOnFetch', this.handleError); this.listenTo(this.collection, 'errorOnFetch', this.handleError);
}, },
render: function (mapperObj, cb) { render: function (mapperObj, cb) {
var that = this; var that = this;
if (typeof mapperObj === "function") { if (typeof mapperObj === "function") {
var cb = mapperObj; var cb = mapperObj;
mapperObj = null; mapperObj = null;
} }
this.el.innerHTML = ""; this.el.innerHTML = "";
// in case it is a page where we have to display the mapper card // in case it is a page where we have to display the mapper card
if (mapperObj) { if (mapperObj) {
var view = new Metamaps.Views.MapperCard({ model: mapperObj }); var view = new Metamaps.Views.MapperCard({ model: mapperObj });
that.el.appendChild( view.render().el ); that.el.appendChild( view.render().el );
} }
this.collection.each(function (map) { this.collection.each(function (map) {
var view = new Metamaps.Views.MapCard({ model: map }); var view = new Metamaps.Views.MapCard({ model: map });
that.el.appendChild( view.render().el ); that.el.appendChild( view.render().el );
}); });
this.$el.append('<div class="clearfloat"></div>'); this.$el.append('<div class="clearfloat"></div>');
var m = Metamaps.Famous.maps.surf; var m = Metamaps.Famous.maps.surf;
m.setContent(this.el); m.setContent(this.el);
var updateHeight = function(){ var updateHeight = function(){
var height = $(that.el).height() + 32 + 56; var height = $(that.el).height() + 32 + 56;
m.setSize([undefined, height]); m.setSize([undefined, height]);
Metamaps.Famous.maps.lock = false; Metamaps.Famous.maps.lock = false;
if (cb) cb(); if (cb) cb();
}; };
if (!initialized) { if (!initialized) {
m.deploy(m._currTarget); m.deploy(m._currTarget);
initialized = true; initialized = true;
setTimeout(updateHeight, 100); setTimeout(updateHeight, 100);
} else { } else {
setTimeout(updateHeight, 100); setTimeout(updateHeight, 100);
} }
Metamaps.Loading.hide(); Metamaps.Loading.hide();
}, },
handleSuccess: function (cb) { handleSuccess: function (cb) {
var that = this; var that = this;
if (this.collection && this.collection.id === "mapper") { if (this.collection && this.collection.id === "mapper") {
this.fetchUserThenRender(cb); this.fetchUserThenRender(cb);
} }
else { else {
this.render(cb); this.render(cb);
} }
}, },
handleError: function () { handleError: function () {
console.log('error loading maps!'); //TODO console.log('error loading maps!'); //TODO
}, },
fetchUserThenRender: function (cb) { fetchUserThenRender: function (cb) {
var that = this; var that = this;
// first load the mapper object and then call the render function // first load the mapper object and then call the render function
$.ajax({ $.ajax({
url: "/users/" + this.collection.mapperId + "/details.json", url: "/users/" + this.collection.mapperId + "/details.json",
success: function (response) { success: function (response) {
that.render(response, cb); that.render(response, cb);
}, },
error: function () { error: function () {
that.render(cb); that.render(cb);
} }
}); });
} }
}); });
Metamaps.Views.exploreMaps = new mapsWrapper(); Metamaps.Views.exploreMaps = new mapsWrapper();
}; };
})(); })();

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,339 @@
Metamaps.Views = Metamaps.Views || {};
Metamaps.Views.chatView = (function () {
var
chatView,
linker = new Autolinker({ newWindow: true, truncate: 50, email: false, phone: false, twitter: false });
var Private = {
messageHTML: "<div class='chat-message'>" +
"<div class='chat-message-user'><img src='{{ user_image }}' title='{{user_name }}'/></div>" +
"<div class='chat-message-text'>{{ message }}</div>" +
"<div class='chat-message-time'>{{ timestamp }}</div>" +
"<div class='clearfloat'></div>" +
"</div>",
participantHTML: "<div class='participant participant-{{ id }} {{ selfClass }}'>" +
"<div class='chat-participant-image'><img src='{{ image }}' style='border: 2px solid {{ color }};' /></div>" +
"<div class='chat-participant-name'>{{ username }} {{ selfName }}</div>" +
"<button type='button' class='button chat-participant-invite-call' onclick='Metamaps.Realtime.inviteACall({{ id}});'></button>" +
"<button type='button' class='button chat-participant-invite-join' onclick='Metamaps.Realtime.inviteToJoin({{ id}});'></button>" +
"<span class='chat-participant-participating'><div class='green-dot'></div></span>" +
"<div class='clearfloat'></div>" +
"</div>",
templates: function() {
_.templateSettings = {
interpolate: /\{\{(.+?)\}\}/g
};
this.messageTemplate = _.template(Private.messageHTML);
this.participantTemplate = _.template(Private.participantHTML);
},
createElements: function() {
this.$unread = $('<div class="chat-unread"></div>');
this.$button = $('<div class="chat-button"><div class="tooltips">Chat</div></div>');
this.$messageInput = $('<textarea placeholder="Send a message..." class="chat-input"></textarea>');
this.$juntoHeader = $('<div class="junto-header">PARTICIPANTS</div>');
this.$videoToggle = $('<div class="video-toggle"></div>');
this.$cursorToggle = $('<div class="cursor-toggle"></div>');
this.$participants = $('<div class="participants"></div>');
this.$conversationInProgress = $('<div class="conversation-live">LIVE <span class="call-action leave" onclick="Metamaps.Realtime.leaveCall();">LEAVE</span><span class="call-action join" onclick="Metamaps.Realtime.joinCall();">JOIN</span></div>');
this.$chatHeader = $('<div class="chat-header">CHAT</div>');
this.$soundToggle = $('<div class="sound-toggle active"></div>');
this.$messages = $('<div class="chat-messages"></div>');
this.$container = $('<div class="chat-box"></div>');
},
attachElements: function() {
this.$button.append(this.$unread);
this.$juntoHeader.append(this.$videoToggle);
this.$juntoHeader.append(this.$cursorToggle);
this.$chatHeader.append(this.$soundToggle);
this.$participants.append(this.$conversationInProgress);
this.$container.append(this.$juntoHeader);
this.$container.append(this.$participants);
this.$container.append(this.$chatHeader);
this.$container.append(this.$button);
this.$container.append(this.$messages);
this.$container.append(this.$messageInput);
},
addEventListeners: function() {
var self = this;
this.participants.on('add', function (participant) {
Private.addParticipant.call(self, participant);
});
this.participants.on('remove', function (participant) {
Private.removeParticipant.call(self, participant);
});
this.$button.on('click', function () {
Handlers.buttonClick.call(self);
});
this.$videoToggle.on('click', function () {
Handlers.videoToggleClick.call(self);
});
this.$cursorToggle.on('click', function () {
Handlers.cursorToggleClick.call(self);
});
this.$soundToggle.on('click', function () {
Handlers.soundToggleClick.call(self);
});
this.$messageInput.on('keyup', function (event) {
Handlers.keyUp.call(self, event);
});
this.$messageInput.on('focus', function () {
Handlers.inputFocus.call(self);
});
this.$messageInput.on('blur', function () {
Handlers.inputBlur.call(self);
});
},
initializeSounds: function() {
this.sound = new Howl({
urls: ["<%= asset_path 'sounds/sounds.mp3' %>", "<%= asset_path 'sounds/sounds.ogg' %>"],
sprite: {
laser: [3000, 700]
}
});
},
incrementUnread: function() {
this.unreadMessages++;
this.$unread.html(this.unreadMessages);
this.$unread.show();
},
addMessage: function(message, isInitial) {
if (!this.isOpen && !isInitial) Private.incrementUnread.call(this);
function addZero(i) {
if (i < 10) {
i = "0" + i;
}
return i;
}
var m = _.clone(message.attributes);
var today = new Date();
m.timestamp = new Date(m.created_at);
var date = (m.timestamp.getMonth() + 1) + '/' + m.timestamp.getDate();
date += " " + addZero(m.timestamp.getHours()) + ":" + addZero(m.timestamp.getMinutes());
m.timestamp = date;
m.image = m.user_image || 'http://www.hotpepper.ca/wp-content/uploads/2014/11/default_profile_1_200x200.png'; // TODO: remove
m.message = linker.link(m.message);
var $html = $(this.messageTemplate(m));
this.$messages.append($html);
if (!isInitial) this.scrollMessages(200);
if (!isInitial && this.alertSound) this.sound.play('laser');
},
initialMessages: function() {
var messages = this.messages.models;
for (var i = 0; i < messages.length; i++) {
Private.addMessage.call(this, messages[i], true);
}
},
handleInputMessage: function() {
var message = {
message: this.$messageInput.val(),
};
this.$messageInput.val('');
$(document).trigger(chatView.events.message + '-' + this.room, [message]);
},
addParticipant: function(participant) {
var p = _.clone(participant.attributes);
if (p.self) {
p.selfClass = 'is-self';
p.selfName = '(me)';
} else {
p.selfClass = '';
p.selfName = '';
}
var html = this.participantTemplate(p);
this.$participants.append(html);
},
removeParticipant: function(participant) {
this.$container.find('.participant-' + participant.get('id')).remove();
}
};
var Handlers = {
buttonClick: function() {
if (this.isOpen) this.close();
else if (!this.isOpen) this.open();
},
videoToggleClick: function() {
this.$videoToggle.toggleClass('active');
this.videosShowing = !this.videosShowing;
$(document).trigger(this.videosShowing ? chatView.events.videosOn : chatView.events.videosOff);
},
cursorToggleClick: function() {
this.$cursorToggle.toggleClass('active');
this.cursorsShowing = !this.cursorsShowing;
$(document).trigger(this.cursorsShowing ? chatView.events.cursorsOn : chatView.events.cursorsOff);
},
soundToggleClick: function() {
this.alertSound = !this.alertSound;
this.$soundToggle.toggleClass('active');
},
keyUp: function(event) {
switch(event.which) {
case 13: // enter
Private.handleInputMessage.call(this);
break;
}
},
inputFocus: function() {
$(document).trigger(chatView.events.inputFocus);
},
inputBlur: function() {
$(document).trigger(chatView.events.inputBlur);
}
};
chatView = function(messages, mapper, room) {
var self = this;
this.room = room;
this.mapper = mapper;
this.messages = messages; // backbone collection
this.isOpen = false;
this.alertSound = false; // whether to play sounds on arrival of new messages or not
this.cursorsShowing = true;
this.videosShowing = true;
this.unreadMessages = 0;
this.participants = new Backbone.Collection();
Private.templates.call(this);
Private.createElements.call(this);
Private.attachElements.call(this);
Private.addEventListeners.call(this);
Private.initialMessages.call(this);
Private.initializeSounds.call(this);
this.$container.css({
right: '-300px'
});
};
chatView.prototype.conversationInProgress = function (participating) {
this.$conversationInProgress.show();
this.$participants.addClass('is-live');
if (participating) this.$participants.addClass('is-participating');
this.$button.addClass('active');
// hide invite to call buttons
}
chatView.prototype.conversationEnded = function () {
this.$conversationInProgress.hide();
this.$participants.removeClass('is-live');
this.$participants.removeClass('is-participating');
this.$button.removeClass('active');
this.$participants.find('.participant').removeClass('active');
this.$participants.find('.participant').removeClass('pending');
}
chatView.prototype.leaveConversation = function () {
this.$participants.removeClass('is-participating');
}
chatView.prototype.mapperJoinedCall = function (id) {
this.$participants.find('.participant-' + id).addClass('active');
}
chatView.prototype.mapperLeftCall = function (id) {
this.$participants.find('.participant-' + id).removeClass('active');
}
chatView.prototype.invitationPending = function (id) {
this.$participants.find('.participant-' + id).addClass('pending');
}
chatView.prototype.invitationAnswered = function (id) {
this.$participants.find('.participant-' + id).removeClass('pending');
}
chatView.prototype.addParticipant = function (participant) {
this.participants.add(participant);
}
chatView.prototype.removeParticipant = function (username) {
var p = this.participants.find(function (p) { return p.get('username') === username; });
if (p) {
this.participants.remove(p);
}
}
chatView.prototype.removeParticipants = function () {
this.participants.remove(this.participants.models);
}
chatView.prototype.open = function () {
this.$container.css({
right: '0'
});
this.$messageInput.focus();
this.isOpen = true;
this.unreadMessages = 0;
this.$unread.hide();
this.scrollMessages(0);
$(document).trigger(chatView.events.openTray);
}
chatView.prototype.addMessage = function(message, isInitial) {
this.messages.add(message);
Private.addMessage.call(this, message, isInitial);
}
chatView.prototype.scrollMessages = function(duration) {
duration = duration || 0;
this.$messages.animate({
scrollTop: this.$messages[0].scrollHeight
}, duration);
}
chatView.prototype.clearMessages = function () {
this.unreadMessages = 0;
this.$unread.hide();
this.$messages.empty();
}
chatView.prototype.close = function () {
this.$container.css({
right: '-300px'
});
this.$messageInput.blur();
this.isOpen = false;
$(document).trigger(chatView.events.closeTray);
}
chatView.prototype.remove = function () {
this.$button.off();
this.$container.remove();
}
/**
* @class
* @static
*/
chatView.events = {
message: 'ChatView:message',
openTray: 'ChatView:openTray',
closeTray: 'ChatView:closeTray',
inputFocus: 'ChatView:inputFocus',
inputBlur: 'ChatView:inputBlur',
cursorsOff: 'ChatView:cursorsOff',
cursorsOn: 'ChatView:cursorsOn',
videosOff: 'ChatView:videosOff',
videosOn: 'ChatView:videosOn'
};
return chatView;
})();

View file

@ -0,0 +1,194 @@
Metamaps.Views = Metamaps.Views || {};
Metamaps.Views.room = (function () {
var ChatView = Metamaps.Views.chatView;
var VideoView = Metamaps.Views.videoView;
var room = function(opts) {
var self = this;
this.isActiveRoom = false;
this.socket = opts.socket;
this.webrtc = opts.webrtc;
//this.roomRef = opts.firebase;
this.room = opts.room;
this.config = opts.config;
this.peopleCount = 0;
this.$myVideo = opts.$video;
this.myVideo = opts.myVideoView;
this.messages = new Backbone.Collection();
this.currentMapper = new Backbone.Model({ name: opts.username, image: opts.image });
this.chat = new ChatView(this.messages, this.currentMapper, this.room);
this.videos = {};
this.init();
};
room.prototype.join = function(cb) {
this.isActiveRoom = true;
this.webrtc.joinRoom(this.room, cb);
this.chat.conversationInProgress(true); // true indicates participation
}
room.prototype.conversationInProgress = function() {
this.chat.conversationInProgress(false); // false indicates not participating
}
room.prototype.conversationEnding = function() {
this.chat.conversationEnded();
}
room.prototype.leaveVideoOnly = function() {
this.chat.leaveConversation(); // the conversation will carry on without you
for (var id in this.videos) {
this.removeVideo(id);
}
this.isActiveRoom = false;
this.webrtc.leaveRoom();
}
room.prototype.leave = function() {
for (var id in this.videos) {
this.removeVideo(id);
}
this.isActiveRoom = false;
this.webrtc.leaveRoom();
this.chat.conversationEnded();
this.chat.removeParticipants();
this.chat.clearMessages();
this.messages.reset();
}
room.prototype.setPeopleCount = function(count) {
this.peopleCount = count;
}
room.prototype.init = function () {
var self = this;
$(document).on(VideoView.events.audioControlClick, function (event, videoView) {
if (!videoView.audioStatus) self.webrtc.mute();
else if (videoView.audioStatus) self.webrtc.unmute();
});
$(document).on(VideoView.events.videoControlClick, function (event, videoView) {
if (!videoView.videoStatus) self.webrtc.pauseVideo();
else if (videoView.videoStatus) self.webrtc.resumeVideo();
});
this.webrtc.webrtc.off('peerStreamAdded');
this.webrtc.webrtc.off('peerStreamRemoved');
this.webrtc.on('peerStreamAdded', function (peer) {
var mapper = Metamaps.Realtime.mappersOnMap[peer.nick];
peer.avatar = mapper.image;
peer.username = mapper.name;
if (self.isActiveRoom) {
self.addVideo(peer);
}
});
this.webrtc.on('peerStreamRemoved', function (peer) {
if (self.isActiveRoom) {
self.removeVideo(peer);
}
});
this.webrtc.on('mute', function (data) {
var v = self.videos[data.id];
if (!v) return;
if (data.name === 'audio') {
v.audioStatus = false;
}
else if (data.name === 'video') {
v.videoStatus = false;
v.$avatar.show();
}
if (!v.audioStatus && !v.videoStatus) v.$container.hide();
});
this.webrtc.on('unmute', function (data) {
var v = self.videos[data.id];
if (!v) return;
if (data.name === 'audio') {
v.audioStatus = true;
}
else if (data.name === 'video') {
v.videoStatus = true;
v.$avatar.hide();
}
v.$container.show();
});
var sendChatMessage = function (event, data) {
self.sendChatMessage(data);
};
$(document).on(ChatView.events.message + '-' + this.room, sendChatMessage);
}
room.prototype.videoAdded = function (callback) {
this._videoAdded = callback;
}
room.prototype.addVideo = function (peer) {
var
id = this.webrtc.getDomId(peer),
video = attachMediaStream(peer.stream);
var
v = new VideoView(video, null, id, false, { DOUBLE_CLICK_TOLERANCE: 200, avatar: peer.avatar, username: peer.username });
this.videos[peer.id] = v;
if (this._videoAdded) this._videoAdded(v, peer.nick);
}
room.prototype.removeVideo = function (peer) {
var id = typeof peer == 'string' ? peer : peer.id;
if (this.videos[id]) {
this.videos[id].remove();
delete this.videos[id];
}
}
room.prototype.sendChatMessage = function (data) {
var self = this;
//this.roomRef.child('messages').push(data);
var m = new Metamaps.Backbone.Message({
message: data.message,
resource_id: Metamaps.Active.Map.id,
resource_type: "Map"
});
m.save(null, {
success: function (model, response) {
self.addMessages(new Metamaps.Backbone.MessageCollection(model));
$(document).trigger(room.events.newMessage, [model]);
},
error: function (model, response) {
console.log('error!', response);
}
});
}
// they should be instantiated as backbone models before they get
// passed to this function
room.prototype.addMessages = function (messages, isInitial) {
var self = this;
messages.models.forEach(function (message) {
self.chat.addMessage(message, isInitial);
});
}
/**
* @class
* @static
*/
room.events = {
newMessage: "Room:newMessage"
};
return room;
})();

View file

@ -0,0 +1,207 @@
Metamaps.Views = Metamaps.Views || {};
Metamaps.Views.videoView = (function () {
var videoView;
var Private = {
addControls: function() {
var self = this;
this.$audioControl = $('<div class="video-audio"></div>');
this.$videoControl = $('<div class="video-video"></div>');
this.$audioControl.on('click', function () {
Handlers.audioControlClick.call(self);
});
this.$videoControl.on('click', function () {
Handlers.videoControlClick.call(self);
});
this.$container.append(this.$audioControl);
this.$container.append(this.$videoControl);
},
cancelClick: function() {
this.mouseIsDown = false;
if (this.hasMoved) {
}
$(document).trigger(videoView.events.dragEnd);
}
};
var Handlers = {
mousedown: function(event) {
this.mouseIsDown = true;
this.hasMoved = false;
this.mouseMoveStart = {
x: event.pageX,
y: event.pageY
};
this.posStart = {
x: parseInt(this.$container.css('left'), '10'),
y: parseInt(this.$container.css('top'), '10')
}
$(document).trigger(videoView.events.mousedown);
},
mouseup: function(event) {
$(document).trigger(videoView.events.mouseup, [this]);
var storedTime = this.lastClick;
var now = Date.now();
this.lastClick = now;
if (now - storedTime < this.config.DOUBLE_CLICK_TOLERANCE) {
$(document).trigger(videoView.events.doubleClick, [this]);
}
},
mousemove: function(event) {
var
diffX,
diffY,
newX,
newY;
if (this.$parent && this.mouseIsDown) {
this.manuallyPositioned = true;
this.hasMoved = true;
diffX = event.pageX - this.mouseMoveStart.x;
diffY = this.mouseMoveStart.y - event.pageY;
newX = this.posStart.x + diffX;
newY = this.posStart.y - diffY;
this.$container.css({
top: newY,
left: newX
});
}
},
audioControlClick: function() {
if (this.audioStatus) {
this.audioOff();
} else {
this.audioOn();
}
$(document).trigger(videoView.events.audioControlClick, [this]);
},
videoControlClick: function() {
if (this.videoStatus) {
this.videoOff();
} else {
this.videoOn();
}
$(document).trigger(videoView.events.videoControlClick, [this]);
},
};
var videoView = function(video, $parent, id, isMyself, config) {
var self = this;
this.$parent = $parent; // mapView
this.video = video;
this.id = id;
this.config = config;
this.mouseIsDown = false;
this.mouseDownOffset = { x: 0, y: 0 };
this.lastClick = null;
this.hasMoved = false;
this.audioStatus = true;
this.videoStatus = true;
this.$container = $('<div></div>');
this.$container.addClass('collaborator-video' + (isMyself ? ' my-video' : ''));
this.$container.attr('id', 'container_' + id);
var $vidContainer = $('<div></div>');
$vidContainer.addClass('video-cutoff');
$vidContainer.append(this.video);
this.avatar = config.avatar;
this.$avatar = $('<img draggable="false" class="collaborator-video-avatar" src="' + config.avatar + '" width="150" height="150" />');
$vidContainer.append(this.$avatar);
this.$container.append($vidContainer);
this.$container.on('mousedown', function (event) {
Handlers.mousedown.call(self, event);
});
if (isMyself) {
Private.addControls.call(this);
}
// suppress contextmenu
this.video.oncontextmenu = function () { return false; };
if (this.$parent) this.setParent(this.$parent);
};
videoView.prototype.setParent = function($parent) {
var self = this;
this.$parent = $parent;
this.$parent.off('.video' + this.id);
this.$parent.on('mouseup.video' + this.id, function (event) {
Handlers.mouseup.call(self, event);
Private.cancelClick.call(self);
});
this.$parent.on('mousemove.video' + this.id, function (event) {
Handlers.mousemove.call(self, event);
});
}
videoView.prototype.setAvatar = function (src) {
this.$avatar.attr('src', src);
this.avatar = src;
}
videoView.prototype.remove = function () {
this.$container.off();
if (this.$parent) this.$parent.off('.video' + this.id);
this.$container.remove();
}
videoView.prototype.videoOff = function () {
this.$videoControl.addClass('active');
this.$avatar.show();
this.videoStatus = false;
}
videoView.prototype.videoOn = function () {
this.$videoControl.removeClass('active');
this.$avatar.hide();
this.videoStatus = true;
}
videoView.prototype.audioOff = function () {
this.$audioControl.addClass('active');
this.audioStatus = false;
}
videoView.prototype.audioOn = function () {
this.$audioControl.removeClass('active');
this.audioStatus = true;
}
/**
* @class
* @static
*/
videoView.events = {
mousedown: "VideoView:mousedown",
mouseup: "VideoView:mouseup",
doubleClick: "VideoView:doubleClick",
dragEnd: "VideoView:dragEnd",
audioControlClick: "VideoView:audioControlClick",
videoControlClick: "VideoView:videoControlClick",
};
return videoView;
})();

View file

@ -1,63 +0,0 @@
.allMetacodes {
float:left;
}
.allMetacodes span {
margin:4px 8px;
color:#67AF9F;
}
.editMetacodes {
z-index:12;
width:auto;
color: #67AF9F;
padding:10px;
float:left;
}
.editMetacodes ul {
display:block;
}
.editMetacodes ul li {
clear:both;
list-style-type:none;
display:block;
padding:3px;
}
.editMetacodes ul img {
width:40px;
height:40px;
float:left;
}
.editMetacodes ul p {
float:left;
display: block;
margin: 0;
background: none;
padding: 10px 4px 2px 4px;
}
.editMetacodes #filters-one {
float:left;
}
.editMetacodes #filters-two {
float:left;
}
.editMetacodes #filters-three {
float:left;
}
.editMetacodes #filters-four {
float:left;
}
.editMetacodes li.toggledOff {
opacity: 0.4;
}

View file

@ -0,0 +1,188 @@
.allMetacodes {
float:left;
span {
margin:4px 8px;
color:#67AF9F;
}
}
.editMetacodes {
z-index:12;
width:auto;
color: #67AF9F;
padding:10px;
float:left;
ul {
display:block;
}
ul li {
clear:both;
list-style-type:none;
display:block;
padding:3px;
}
ul img {
width:40px;
height:40px;
float:left;
}
ul p {
float:left;
display: block;
margin: 0;
background: none;
padding: 10px 4px 2px 4px;
}
#filters-one {
float:left;
}
#filters-two {
float:left;
}
#filters-three {
float:left;
}
#filters-four {
float:left;
}
li.toggledOff {
opacity: 0.4;
}
}
.blackBox {
width: 760px;
margin: 0 auto;
padding: 20px 0 60px 20px;
background: rgba(0, 0, 0, 0.4);
color: white;
overflow: hidden;
position: relative;
.metacodeSetsDescription {
width: 314px;
}
td.metacodeSetDesc {
width: 314px;
word-wrap: break-word;
}
.metacodeSetImage {
width: 36px;
height: 36px;
float: left;
}
tr {
display: table-row;
}
tr:nth-child(odd) {
background: rgba(0, 0, 0, 0.2);
}
tr:nth-child(even) {
background: rgba(0, 0, 0, 0.3);
}
th,
td {
padding: 10px;
}
td.iconURL {
max-width: 415px;
word-wrap: break-word;
}
.field {
margin: 15px 0 5px;
}
label {
float: left;
width: 100px;
margin-right: 15px;
margin-top: 0px;
}
input[type="text"] {
width: 336px;
height: 32px;
font-size: 15px;
direction: ltr;
-webkit-appearance: none;
appearance: none;
display: inline-block;
margin: 0;
padding: 0 8px;
background: #fff;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 1px;
-moz-border-radius: 1px;
border-radius: 1px;
font: -webkit-small-control;
color: initial;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block;
text-align: start;
font-family: arial;
}
textarea:hover,
input[type="text"]:hover {
border: 1px solid #b9b9b9;
border-top: 1px solid #a0a0a0;
-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);
}
textarea {
padding: 8px;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
resize: none;
font: -webkit-small-control;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
text-align: start;
font-family: arial;
font-size: 15px;
line-height: 17px;
width: 318px;
}
.allMetacodes {
padding: 5px 0;
}
a.button {
margin-right: 20px;
line-height: 40px;
}
a.button,
input.add {
float: left;
margin-top: 5px;
height: 40px;
font-size: 17px;
width: auto;
padding: 0 30px;
cursor: pointer;
font-weight: normal;
}
a.button:hover,
input.add:hover {
-webkit-box-shadow: none;
box-shadow: none;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,131 @@
.centerContent {
position: relative;
margin: 92px auto 0 auto;
padding: 20px 0 60px 20px;
width: 760px;
overflow: hidden;
box-shadow: 0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);
background: #fff;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
border: 1px solid #dcdcdc;
margin-bottom: 10px;
padding: 15px;
}
.centerContent .page-header {
margin-bottom: 20px;
padding-bottom: 8px;
border-bottom: 1px solid #DCDCDC;
}
.centerContent .form-group {
margin-bottom: 20px;
}
.centerContent .inline-button {
display: inline-block;
}
.centerContent.showApp p {
margin-bottom: 20px;
}
.centerContent a {
color: #4fb5c0;
}
.centerContent a:hover {
text-decoration: underline;
}
.centerContent a.button {
color: #FFFFFF;
}
.centerContent a.button:hover {
text-decoration: none;
}
.centerContent th {
text-align: left;
}
.centerContent td {
padding-right: 20px;
padding-bottom: 20px;
}
.centerContent .link-button {
line-height: 32px;
color: #FFFFFF;
}
.centerContent .button-margin {
margin-bottom: 20px;
}
.centerContent .button-margin-top {
margin-top: 20px;
}
.centerContent a.red-button, .centerContent button.red-button,
.centerContent input[type="submit"].red-button {
color: #c04f4f;
background: transparent;
text-transform: none;
}
.centerContent .red-button:hover {
background: transparent;
color: #9A3E3E !important;
}
.centerContent input[type="text"] {
font-family: 'din-medium', helvetica, sans-serif;
width: 400px;
height: 32px;
font-size: 14px;
direction: ltr;
-webkit-appearance: none;
appearance: none;
display: inline-block;
margin: 0;
padding: 0 8px;
background: #fff;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
-webkit-border-radius: 1px;
-moz-border-radius: 1px;
border-radius: 2px;
color: #424242;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
display: inline-block;
text-align: start;
}
.centerContent textarea {
color: #424242;
padding: 8px;
border: 1px solid #d9d9d9;
border-top: 1px solid #c0c0c0;
resize: none;
letter-spacing: normal;
word-spacing: normal;
text-transform: none;
text-indent: 0px;
text-shadow: none;
text-align: start;
font-family: 'din-medium', helvetica, sans-serif;
font-size: 14px;
line-height: 17px;
width: 400px;
box-sizing: border-box;
border-radius: 2px;
}

File diff suppressed because it is too large Load diff

View file

@ -25,7 +25,7 @@
} }
#famousOverlay { #famousOverlay {
position:fixed; position:absolute;
top: 0; top: 0;
width: 100%; width: 100%;
height: 100%; height: 100%;
@ -116,7 +116,7 @@
/* upperLeftUI */ /* upperLeftUI */
.upperLeftUI { .upperLeftUI {
position: fixed; position: absolute;
top: 10px; top: 10px;
left: 24px; left: 24px;
z-index:3; z-index:3;
@ -155,7 +155,7 @@
/* upperRightUI */ /* upperRightUI */
.upperRightUI { .upperRightUI {
position: fixed; position: absolute;
top: 10px; top: 10px;
right: 24px; right: 24px;
z-index:4; z-index:4;
@ -166,9 +166,9 @@
} }
.upperRightBox { .upperRightBox {
position: fixed; position: absolute;
top:52px; top:42px;
right:24px; right:0;
background-color: #E0E0E0; background-color: #E0E0E0;
border-radius: 2px; border-radius: 2px;
box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16); box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
@ -187,17 +187,12 @@
} }
.upperRightMapButtons { .upperRightMapButtons {
position: relative;
top: -42px; /* puts it just offscreen */ top: -42px; /* puts it just offscreen */
} }
.mapPage .upperRightMapButtons, .topicPage .upperRightMapButtons { .mapPage .upperRightMapButtons, .topicPage .upperRightMapButtons {
top: 0; top: 0;
} }
.topicPage .sidebarCollaborate {
display: none;
}
.upperRightIcon { .upperRightIcon {
width: 32px; width: 32px;
height: 32px; height: 32px;
@ -205,20 +200,6 @@
background-repeat: no-repeat; background-repeat: no-repeat;
cursor: pointer; cursor: pointer;
} }
.sidebarCollaborateIcon {
background-position: 0 0;
display: none;
}
.sidebarCollaborateIcon.blue {
background-position: -32px 0;
}
.sidebarCollaborateIcon.blue:hover {
background-position: -32px -32px;
}
/* only show the collaborate icon on commons */
.commonsMap .sidebarCollaborateIcon {
display: block;
}
.sidebarFilterIcon { .sidebarFilterIcon {
background-position: -64px 0; background-position: -64px 0;
} }
@ -384,7 +365,7 @@
} }
.infoAndHelp { .infoAndHelp {
position: fixed; position: absolute;
bottom: 20px; bottom: 20px;
right: 20px; right: 20px;
z-index: 3; z-index: 3;
@ -424,14 +405,14 @@
/* mapControls */ /* mapControls */
.mapControls { .mapControls {
position: fixed; position: absolute;
bottom: 24px; bottom: 24px;
right:-32px; /* puts it just offscreen */ right:-32px; /* puts it just offscreen */
width:32px; width:32px;
z-index: 3; z-index: 3;
} }
.mapPage .mapControls, .topicPage .mapControls { .mapPage .mapControls, .topicPage .mapControls {
right: 24px; right: 24px;
} }
.topicPage .zoomExtents { .topicPage .zoomExtents {
@ -474,14 +455,13 @@
background-position: -32px 0; background-position: -32px 0;
} }
.zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .takeScreenshot:hover .tooltips, .sidebarCollaborateIcon:hover .tooltipsUnder, .zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .takeScreenshot:hover .tooltips, .sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder,
.sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder, .mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips {
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove {
display: block; display: block;
} }
.hide { .hide {
display: none !important; display: none !important;
} }
.tooltips { .tooltips {
@ -532,10 +512,6 @@
font-style: normal; font-style: normal;
} }
.sidebarCollaborateIcon .tooltipsUnder {
margin-left: -3px;
}
.sidebarFilterIcon .tooltipsUnder { .sidebarFilterIcon .tooltipsUnder {
margin-left: -4px; margin-left: -4px;
} }
@ -560,16 +536,20 @@
left: -11px; left: -11px;
} }
.chat-button .tooltips {
top: 10px;
}
.openCheatsheet .tooltipsAbove { .openCheatsheet .tooltipsAbove {
left: -4px; left: -4px;
} }
.sidebarAccountIcon .tooltipsUnder { .sidebarAccountIcon .tooltipsUnder {
margin-left: -8px; margin-left: -12px;
margin-top: 40px; margin-top: 40px;
} }
.zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .takeScreenshot div:after { .zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .takeScreenshot div:after, .chat-button div.tooltips::after {
content: ''; content: '';
position: absolute; position: absolute;
top: 57%; top: 57%;
@ -582,21 +562,20 @@
border-bottom: 5px solid transparent; border-bottom: 5px solid transparent;
} }
.sidebarCollaborateIcon div:after, .sidebarFilterIcon div:after, .sidebarAccountIcon .tooltipsUnder:after { .sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
left: 38%;
}
.sidebarCollaborateIcon div:after, .sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
content: ''; content: '';
position: absolute; position: absolute;
top: 129%; right: 40%;
margin-top: -30px; margin-top: -7px;
width: 0; width: 0;
height: 0; height: 0;
border-bottom: 4px solid #000000; border-bottom: 4px solid #000000;
border-left: 5px solid transparent; border-left: 5px solid transparent;
border-right: 5px solid transparent; border-right: 5px solid transparent;
} }
.sidebarFilterIcon div:after {
right: 37% !important;
}
.mapInfoIcon div:after, .openCheatsheet div:after { .mapInfoIcon div:after, .openCheatsheet div:after {
content: ''; content: '';
@ -735,7 +714,7 @@
color: #F5F5F5; color: #F5F5F5;
padding: 16px; padding: 16px;
border-radius: 2px; border-radius: 2px;
z-index: 1 !important; /* important necessary for firefox */ z-index: 4 !important; /* important necessary for firefox */
font-size: 14px; font-size: 14px;
line-height:14px; line-height:14px;
} }
@ -764,3 +743,11 @@ box-shadow: 0px 1px 1.5px rgba(0,0,0,0.12), 0 1px 1px rgba(0,0,0,0.24);
body a#barometer_tab:hover { body a#barometer_tab:hover {
background-position: 0 -110px; background-position: 0 -110px;
} }
.hideVideos .collaborator-video {
display: none !important;
}
.hideCursors .collabCompass {
display: none !important;
}

View file

@ -1,474 +1,474 @@
/*! jQuery UI - v1.9.2 - 2012-11-23 /*! jQuery UI - v1.9.2 - 2012-11-23
* http://jqueryui.com * http://jqueryui.com
* Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css * Includes: jquery.ui.core.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css, jquery.ui.theme.css
* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */ * Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */
/* Layout helpers /* Layout helpers
----------------------------------*/ ----------------------------------*/
.ui-helper-hidden { display: none; } .ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; } .ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } .ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } .ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
.ui-helper-clearfix:after { clear: both; } .ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; } .ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } .ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues /* Interaction Cues
----------------------------------*/ ----------------------------------*/
.ui-state-disabled { cursor: default !important; } .ui-state-disabled { cursor: default !important; }
/* Icons /* Icons
----------------------------------*/ ----------------------------------*/
/* states and images */ /* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } .ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals /* Misc visuals
----------------------------------*/ ----------------------------------*/
/* Overlays */ /* Overlays */
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
.ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; } .ui-accordion .ui-accordion-header { display: block; cursor: pointer; position: relative; margin-top: 2px; padding: .5em .5em .5em .7em; zoom: 1; }
.ui-accordion .ui-accordion-icons { padding-left: 2.2em; } .ui-accordion .ui-accordion-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-noicons { padding-left: .7em; } .ui-accordion .ui-accordion-noicons { padding-left: .7em; }
.ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; } .ui-accordion .ui-accordion-icons .ui-accordion-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; } .ui-accordion .ui-accordion-header .ui-accordion-header-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; } .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
.ui-autocomplete { .ui-autocomplete {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
cursor: default; cursor: default;
} }
/* workarounds */ /* workarounds */
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */ .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
.ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; } .ui-button, .ui-button:link, .ui-button:visited, .ui-button:hover, .ui-button:active { text-decoration: none; }
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */ .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */ button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; } .ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; } button.ui-button-icons-only { width: 3.7em; }
/*button text element */ /*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; } .ui-button .ui-button-text { display: block; line-height: 1.4; }
.ui-button-text-only .ui-button-text { padding: .4em 1em; } .ui-button-text-only .ui-button-text { padding: .4em 1em; }
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; } .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; } .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; } .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; } .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */ /* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; } input.ui-button { padding: .4em 1em; }
/*button icon element(s) */ /*button icon element(s) */
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; } .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; } .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; } .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; } .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
/*button sets*/ /*button sets*/
.ui-buttonset { margin-right: 7px; } .ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; } .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */ /* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; } .ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; } .ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left:1px; } .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
.ui-datepicker .ui-datepicker-next-hover { right:1px; } .ui-datepicker .ui-datepicker-next-hover { right:1px; }
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
.ui-datepicker select.ui-datepicker-month-year {width: 100%;} .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month, .ui-datepicker select.ui-datepicker-month,
.ui-datepicker select.ui-datepicker-year { width: 49%;} .ui-datepicker select.ui-datepicker-year { width: 49%;}
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.ui-datepicker td { border: 0; padding: 1px; } .ui-datepicker td { border: 0; padding: 1px; }
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
/* with multiple calendars */ /* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; } .ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; } .ui-datepicker-multi .ui-datepicker-group { float:left; }
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } .ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */ /* RTL support */
.ui-datepicker-rtl { direction: rtl; } .ui-datepicker-rtl { direction: rtl; }
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
.ui-datepicker-rtl .ui-datepicker-group { float:right; } .ui-datepicker-rtl .ui-datepicker-group { float:right; }
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover { .ui-datepicker-cover {
position: absolute; /*must have*/ position: absolute; /*must have*/
z-index: -1; /*must have*/ z-index: -1; /*must have*/
filter: mask(); /*must have*/ filter: mask(); /*must have*/
top: -4px; /*must have*/ top: -4px; /*must have*/
left: -4px; /*must have*/ left: -4px; /*must have*/
width: 200px; /*must have*/ width: 200px; /*must have*/
height: 200px; /*must have*/ height: 200px; /*must have*/
} }
.ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; } .ui-dialog { position: absolute; top: 0; left: 0; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; } .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; } .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; } .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; } .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; } .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; } .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; } .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; } .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; } .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; } .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; } .ui-draggable .ui-dialog-titlebar { cursor: move; }
.ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; } .ui-menu { list-style:none; padding: 2px; margin: 0; display:block; outline: none; }
.ui-menu .ui-menu { margin-top: -3px; position: absolute; } .ui-menu .ui-menu { margin-top: -3px; position: absolute; }
.ui-menu .ui-menu-topic { margin: 0; padding: 0; zoom: 1; width: 100%; } .ui-menu .ui-menu-topic { margin: 0; padding: 0; zoom: 1; width: 100%; }
.ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; } .ui-menu .ui-menu-divider { margin: 5px -2px 5px -2px; height: 0; font-size: 0; line-height: 0; border-width: 1px 0 0 0; }
.ui-menu .ui-menu-topic a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; } .ui-menu .ui-menu-topic a { text-decoration: none; display: block; padding: 2px .4em; line-height: 1.5; zoom: 1; font-weight: normal; }
.ui-menu .ui-menu-topic a.ui-state-focus, .ui-menu .ui-menu-topic a.ui-state-focus,
.ui-menu .ui-menu-topic a.ui-state-active { font-weight: normal; margin: -1px; } .ui-menu .ui-menu-topic a.ui-state-active { font-weight: normal; margin: -1px; }
.ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; } .ui-menu .ui-state-disabled { font-weight: normal; margin: .4em 0 .2em; line-height: 1.5; }
.ui-menu .ui-state-disabled a { cursor: default; } .ui-menu .ui-state-disabled a { cursor: default; }
/* icon support */ /* icon support */
.ui-menu-icons { position: relative; } .ui-menu-icons { position: relative; }
.ui-menu-icons .ui-menu-topic a { position: relative; padding-left: 2em; } .ui-menu-icons .ui-menu-topic a { position: relative; padding-left: 2em; }
/* left-aligned */ /* left-aligned */
.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; } .ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
/* right-aligned */ /* right-aligned */
.ui-menu .ui-menu-icon { position: static; float: right; } .ui-menu .ui-menu-icon { position: static; float: right; }
.ui-progressbar { height:2em; text-align: left; overflow: hidden; } .ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; } .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
.ui-resizable { position: relative;} .ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; } .ui-resizable-handle { position: absolute;font-size: 0.1px; display: block; }
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; } .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; } .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; } .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; } .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; } .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; } .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; } .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; } .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;} .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; } .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
.ui-slider { position: relative; text-align: left; } .ui-slider { position: relative; text-align: left; }
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; } .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; } .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
.ui-slider-horizontal { height: .8em; } .ui-slider-horizontal { height: .8em; }
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; } .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; } .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
.ui-slider-horizontal .ui-slider-range-min { left: 0; } .ui-slider-horizontal .ui-slider-range-min { left: 0; }
.ui-slider-horizontal .ui-slider-range-max { right: 0; } .ui-slider-horizontal .ui-slider-range-max { right: 0; }
.ui-slider-vertical { width: .8em; height: 100px; } .ui-slider-vertical { width: .8em; height: 100px; }
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; } .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; } .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 0; } .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
.ui-slider-vertical .ui-slider-range-max { top: 0; } .ui-slider-vertical .ui-slider-range-max { top: 0; }
.ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; } .ui-spinner { position:relative; display: inline-block; overflow: hidden; padding: 0; vertical-align: middle; }
.ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; } .ui-spinner-input { border: none; background: none; padding: 0; margin: .2em 0; vertical-align: middle; margin-left: .4em; margin-right: 22px; }
.ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; } .ui-spinner-button { width: 16px; height: 50%; font-size: .5em; padding: 0; margin: 0; text-align: center; position: absolute; cursor: default; display: block; overflow: hidden; right: 0; }
.ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */ .ui-spinner a.ui-spinner-button { border-top: none; border-bottom: none; border-right: none; } /* more specificity required here to overide default borders */
.ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */ .ui-spinner .ui-icon { position: absolute; margin-top: -8px; top: 50%; left: 0; } /* vertical centre icon */
.ui-spinner-up { top: 0; } .ui-spinner-up { top: 0; }
.ui-spinner-down { bottom: 0; } .ui-spinner-down { bottom: 0; }
/* TR overrides */ /* TR overrides */
.ui-spinner .ui-icon-triangle-1-s { .ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */ /* need to fix icons sprite */
background-position:-65px -16px; background-position:-65px -16px;
} }
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; } .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; } .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 0; margin: 1px .2em 0 0; border-bottom: 0; padding: 0; white-space: nowrap; }
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; } .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
.ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; } .ui-tabs .ui-tabs-nav li.ui-tabs-active { margin-bottom: -1px; padding-bottom: 1px; }
.ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; } .ui-tabs .ui-tabs-nav li.ui-tabs-active a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-tabs-loading a { cursor: text; }
.ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ .ui-tabs .ui-tabs-nav li a, .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; } .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tooltip { .ui-tooltip {
padding: 8px; padding: 8px;
position: absolute; position: absolute;
z-index: 9999; z-index: 9999;
max-width: 300px; max-width: 300px;
-webkit-box-shadow: 0 0 5px #aaa; -webkit-box-shadow: 0 0 5px #aaa;
box-shadow: 0 0 5px #aaa; box-shadow: 0 0 5px #aaa;
} }
/* Fades and background-images don't work well together in IE6, drop the image */ /* Fades and background-images don't work well together in IE6, drop the image */
* html .ui-tooltip { * html .ui-tooltip {
background-image: none; background-image: none;
} }
body .ui-tooltip { border-width: 2px; } body .ui-tooltip { border-width: 2px; }
/* Component containers /* Component containers
----------------------------------*/ ----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; } .ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
.ui-widget .ui-widget { font-size: 1em; } .ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
.ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(<%= asset_data_uri('ui-bg_flat_75_ffffff_40x100.png') %>)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; } .ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ url(<%= asset_data_uri('ui-bg_flat_75_ffffff_40x100.png') %>)/*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
.ui-widget-content a { color: #222222/*{fcContent}*/; } .ui-widget-content a { color: #222222/*{fcContent}*/; }
.ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(<%= asset_data_uri('images/ui-bg_highlight-soft_75_cccccc_1x100.png') %>)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; } .ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ url(<%= asset_data_uri('images/ui-bg_highlight-soft_75_cccccc_1x100.png') %>)/*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
.ui-widget-header a { color: #222222/*{fcHeader}*/; } .ui-widget-header a { color: #222222/*{fcHeader}*/; }
/* Interaction states /* Interaction states
----------------------------------*/ ----------------------------------*/
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(<%= asset_data_uri('images/ui-bg_glass_75_e6e6e6_1x400.png') %>)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(<%= asset_data_uri('images/ui-bg_glass_75_e6e6e6_1x400.png') %>)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; } .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 0px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(<%= asset_data_uri('images/ui-bg_glass_75_dadada_1x400.png') %>)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; } .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 0px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(<%= asset_data_uri('images/ui-bg_glass_75_dadada_1x400.png') %>)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
.ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121/*{fcHover}*/; text-decoration: none; } .ui-state-hover a, .ui-state-hover a:hover, .ui-state-hover a:link, .ui-state-hover a:visited { color: #212121/*{fcHover}*/; text-decoration: none; }
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(<%= asset_data_uri('images/ui-bg_glass_65_ffffff_1x400.png') %>)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; } .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(<%= asset_data_uri('images/ui-bg_glass_65_ffffff_1x400.png') %>)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; } .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
/* Interaction Cues /* Interaction Cues
----------------------------------*/ ----------------------------------*/
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(<%= asset_data_uri('images/ui-bg_glass_55_fbf9ee_1x400.png') %>)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; } .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(<%= asset_data_uri('images/ui-bg_glass_55_fbf9ee_1x400.png') %>)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; } .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(<%= asset_data_uri('images/ui-bg_glass_95_fef1ec_1x400.png') %>)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; } .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(<%= asset_data_uri('images/ui-bg_glass_95_fef1ec_1x400.png') %>)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; } .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; } .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
.ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */ .ui-state-disabled .ui-icon { filter:Alpha(Opacity=35); } /* For IE8 - See #6059 */
/* Icons /* Icons
----------------------------------*/ ----------------------------------*/
/* states and images */ /* states and images */
.ui-icon { width: 16px; height: 16px; background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsContent}*/; } .ui-icon { width: 16px; height: 16px; background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsContent}*/; }
.ui-widget-content .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsContent}*/; } .ui-widget-content .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsContent}*/; }
.ui-widget-header .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsHeader}*/; } .ui-widget-header .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_222222_256x240.png') %>)/*{iconsHeader}*/; }
.ui-state-default .ui-icon { background-image: url(<%= asset_data_uri('images/ui-icons_888888_256x240.png') %>)/*{iconsDefault}*/; } .ui-state-default .ui-icon { background-image: url(<%= asset_data_uri('images/ui-icons_888888_256x240.png') %>)/*{iconsDefault}*/; }
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_454545_256x240.png') %>)/*{iconsHover}*/; } .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_454545_256x240.png') %>)/*{iconsHover}*/; }
.ui-state-active .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_454545_256x240.png') %>)/*{iconsActive}*/; } .ui-state-active .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_454545_256x240.png') %>)/*{iconsActive}*/; }
.ui-state-highlight .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_2e83ff_256x240.png') %>)/*{iconsHighlight}*/; } .ui-state-highlight .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_2e83ff_256x240.png') %>)/*{iconsHighlight}*/; }
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_cd0a0a_256x240.png') %>)/*{iconsError}*/; } .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(<%= asset_data_uri('images/ui-icons_cd0a0a_256x240.png') %>)/*{iconsError}*/; }
/* positioning */ /* positioning */
.ui-icon-carat-1-n { background-position: 0 0; } .ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; } .ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; } .ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; } .ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; } .ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; } .ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; } .ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; } .ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; } .ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; } .ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; } .ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; } .ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; } .ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; } .ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; } .ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; } .ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; } .ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; } .ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; } .ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; } .ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; } .ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; } .ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; } .ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; } .ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; } .ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; } .ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; } .ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -32px; } .ui-icon-arrow-1-nw { background-position: -112px -32px; }
.ui-icon-arrow-2-n-s { background-position: -128px -32px; } .ui-icon-arrow-2-n-s { background-position: -128px -32px; }
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
.ui-icon-arrow-2-e-w { background-position: -160px -32px; } .ui-icon-arrow-2-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } .ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; } .ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; } .ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; } .ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; } .ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; } .ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } .ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; } .ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; } .ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; } .ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } .ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; } .ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } .ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } .ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } .ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } .ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } .ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; } .ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; } .ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; } .ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; } .ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; } .ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; } .ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; } .ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; } .ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; } .ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; } .ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; } .ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; } .ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; } .ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; } .ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; } .ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; } .ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; } .ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; } .ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; } .ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; } .ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; } .ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; } .ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; } .ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; } .ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; } .ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; } .ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; } .ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; } .ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; } .ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; } .ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; } .ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; } .ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; } .ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; } .ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; } .ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; } .ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; } .ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; } .ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; } .ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; } .ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; } .ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; } .ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; } .ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; } .ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; } .ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; } .ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; } .ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; } .ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; } .ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; } .ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; } .ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; } .ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; } .ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; } .ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; } .ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; } .ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; } .ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; } .ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; } .ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; } .ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; } .ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; } .ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; } .ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; } .ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; } .ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; } .ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; } .ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; } .ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; } .ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; } .ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -160px; } .ui-icon-seek-end { background-position: -64px -160px; }
.ui-icon-seek-start { background-position: -80px -160px; } .ui-icon-seek-start { background-position: -80px -160px; }
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
.ui-icon-seek-first { background-position: -80px -160px; } .ui-icon-seek-first { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; } .ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; } .ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; } .ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; } .ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; } .ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; } .ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; } .ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; } .ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; } .ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; } .ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; } .ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; } .ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; } .ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; } .ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; } .ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; } .ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; } .ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; } .ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; } .ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; } .ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; } .ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; } .ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; } .ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; } .ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; } .ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; } .ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; } .ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; } .ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; } .ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; } .ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; } .ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } .ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; } .ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } .ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; } .ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals /* Misc visuals
----------------------------------*/ ----------------------------------*/
/* Corner radius */ /* Corner radius */
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; } .ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; -khtml-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; -khtml-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; } .ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; } .ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; -khtml-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
/* Overlays */ /* Overlays */
.ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(<%= asset_data_uri('images/ui-bg_flat_0_aaaaaa_40x100.png') %>)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; } .ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(<%= asset_data_uri('images/ui-bg_flat_0_aaaaaa_40x100.png') %>)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
.ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/<%= asset_data_uri('ui-bg_flat_0_aaaaaa_40x100.png') %>)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; } .ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/<%= asset_data_uri('ui-bg_flat_0_aaaaaa_40x100.png') %>)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -khtml-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }

View file

@ -1,473 +1,473 @@
/* basic scrollbar styling */ /* basic scrollbar styling */
/* vertical scrollbar */ /* vertical scrollbar */
.mCSB_container{ .mCSB_container{
width:auto; width:auto;
margin-right:30px; margin-right:30px;
overflow:hidden; overflow:hidden;
} }
.mCSB_container.mCS_no_scrollbar{ .mCSB_container.mCS_no_scrollbar{
margin-right:0; margin-right:0;
} }
.mCS_disabled>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar, .mCS_disabled>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar{ .mCS_destroyed>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar{
margin-right:30px; margin-right:30px;
} }
.mCustomScrollBox>.mCSB_scrollTools{ .mCustomScrollBox>.mCSB_scrollTools{
width:16px; width:16px;
height:100%; height:100%;
top:0; top:0;
right:0; right:0;
} }
.mCSB_scrollTools .mCSB_draggerContainer{ .mCSB_scrollTools .mCSB_draggerContainer{
position:absolute; position:absolute;
top:0; top:0;
left:0; left:0;
bottom:0; bottom:0;
right:0; right:0;
height:auto; height:auto;
} }
.mCSB_scrollTools a+.mCSB_draggerContainer{ .mCSB_scrollTools a+.mCSB_draggerContainer{
margin:20px 0; margin:20px 0;
} }
.mCSB_scrollTools .mCSB_draggerRail{ .mCSB_scrollTools .mCSB_draggerRail{
width:2px; width:2px;
height:100%; height:100%;
margin:0 auto; margin:0 auto;
-webkit-border-radius:10px; -webkit-border-radius:10px;
-moz-border-radius:10px; -moz-border-radius:10px;
border-radius:10px; border-radius:10px;
} }
.mCSB_scrollTools .mCSB_dragger{ .mCSB_scrollTools .mCSB_dragger{
cursor:pointer; cursor:pointer;
width:100%; width:100%;
height:30px; height:30px;
} }
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px; width:4px;
height:100%; height:100%;
margin:0 auto; margin:0 auto;
-webkit-border-radius:10px; -webkit-border-radius:10px;
-moz-border-radius:10px; -moz-border-radius:10px;
border-radius:10px; border-radius:10px;
text-align:center; text-align:center;
} }
.mCSB_scrollTools .mCSB_buttonUp, .mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown{ .mCSB_scrollTools .mCSB_buttonDown{
display:block; display:block;
position:relative; position:relative;
height:20px; height:20px;
overflow:hidden; overflow:hidden;
margin:0 auto; margin:0 auto;
cursor:pointer; cursor:pointer;
} }
.mCSB_scrollTools .mCSB_buttonDown{ .mCSB_scrollTools .mCSB_buttonDown{
top:100%; top:100%;
margin-top:-40px; margin-top:-40px;
} }
/* horizontal scrollbar */ /* horizontal scrollbar */
.mCSB_horizontal>.mCSB_container{ .mCSB_horizontal>.mCSB_container{
height:auto; height:auto;
margin-right:0; margin-right:0;
margin-bottom:30px; margin-bottom:30px;
overflow:hidden; overflow:hidden;
} }
.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{ .mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-bottom:0; margin-bottom:0;
} }
.mCS_disabled>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar, .mCS_disabled>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{ .mCS_destroyed>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-right:0; margin-right:0;
margin-bottom:30px; margin-bottom:30px;
} }
.mCSB_horizontal.mCustomScrollBox>.mCSB_scrollTools{ .mCSB_horizontal.mCustomScrollBox>.mCSB_scrollTools{
width:100%; width:100%;
height:16px; height:16px;
top:auto; top:auto;
right:auto; right:auto;
bottom:0; bottom:0;
left:0; left:0;
overflow:hidden; overflow:hidden;
} }
.mCSB_horizontal>.mCSB_scrollTools a+.mCSB_draggerContainer{ .mCSB_horizontal>.mCSB_scrollTools a+.mCSB_draggerContainer{
margin:0 20px; margin:0 20px;
} }
.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
height:2px; height:2px;
margin:7px 0; margin:7px 0;
-webkit-border-radius:10px; -webkit-border-radius:10px;
-moz-border-radius:10px; -moz-border-radius:10px;
border-radius:10px; border-radius:10px;
} }
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger{ .mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger{
width:30px; width:30px;
height:100%; height:100%;
} }
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:4px; height:4px;
margin:6px auto; margin:6px auto;
-webkit-border-radius:10px; -webkit-border-radius:10px;
-moz-border-radius:10px; -moz-border-radius:10px;
border-radius:10px; border-radius:10px;
} }
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonLeft, .mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{ .mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
display:block; display:block;
position:relative; position:relative;
width:20px; width:20px;
height:100%; height:100%;
overflow:hidden; overflow:hidden;
margin:0 auto; margin:0 auto;
cursor:pointer; cursor:pointer;
float:left; float:left;
} }
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{ .mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
margin-left:-40px; margin-left:-40px;
float:right; float:right;
} }
.mCustomScrollBox{ .mCustomScrollBox{
-ms-touch-action:none; /*MSPointer events - direct all pointer events to js*/ -ms-touch-action:none; /*MSPointer events - direct all pointer events to js*/
} }
/* default scrollbar colors and backgrounds (default theme) */ /* default scrollbar colors and backgrounds (default theme) */
.mCustomScrollBox>.mCSB_scrollTools{ .mCustomScrollBox>.mCSB_scrollTools{
opacity:0.75; opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */ filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
} }
.mCustomScrollBox:hover>.mCSB_scrollTools{ .mCustomScrollBox:hover>.mCSB_scrollTools{
opacity:1; opacity:1;
filter:"alpha(opacity=100)"; -ms-filter:"alpha(opacity=100)"; /* old ie */ filter:"alpha(opacity=100)"; -ms-filter:"alpha(opacity=100)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_draggerRail{ .mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.4); background:rgba(0,0,0,0.4);
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */ filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75); background:rgba(255,255,255,0.75);
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */ filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(255,255,255,0.85); background:rgba(255,255,255,0.85);
filter:"alpha(opacity=85)"; -ms-filter:"alpha(opacity=85)"; /* old ie */ filter:"alpha(opacity=85)"; -ms-filter:"alpha(opacity=85)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9); background:rgba(255,255,255,0.9);
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */ filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_buttonUp, .mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown, .mCSB_scrollTools .mCSB_buttonDown,
.mCSB_scrollTools .mCSB_buttonLeft, .mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_scrollTools .mCSB_buttonRight{ .mCSB_scrollTools .mCSB_buttonRight{
background-repeat:no-repeat; background-repeat:no-repeat;
opacity:0.4; opacity:0.4;
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */ filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_buttonUp{ .mCSB_scrollTools .mCSB_buttonUp{
background-position:0 0; background-position:0 0;
/* /*
sprites locations are 0 0/-16px 0/-32px 0/-48px 0 (light) and -80px 0/-96px 0/-112px 0/-128px 0 (dark) sprites locations are 0 0/-16px 0/-32px 0/-48px 0 (light) and -80px 0/-96px 0/-112px 0/-128px 0 (dark)
*/ */
} }
.mCSB_scrollTools .mCSB_buttonDown{ .mCSB_scrollTools .mCSB_buttonDown{
background-position:0 -20px; background-position:0 -20px;
/* /*
sprites locations are 0 -20px/-16px -20px/-32px -20px/-48px -20px (light) and -80px -20px/-96px -20px/-112px -20px/-128px -20px (dark) sprites locations are 0 -20px/-16px -20px/-32px -20px/-48px -20px (light) and -80px -20px/-96px -20px/-112px -20px/-128px -20px (dark)
*/ */
} }
.mCSB_scrollTools .mCSB_buttonLeft{ .mCSB_scrollTools .mCSB_buttonLeft{
background-position:0 -40px; background-position:0 -40px;
/* /*
sprites locations are 0 -40px/-20px -40px/-40px -40px/-60px -40px (light) and -80px -40px/-100px -40px/-120px -40px/-140px -40px (dark) sprites locations are 0 -40px/-20px -40px/-40px -40px/-60px -40px (light) and -80px -40px/-100px -40px/-120px -40px/-140px -40px (dark)
*/ */
} }
.mCSB_scrollTools .mCSB_buttonRight{ .mCSB_scrollTools .mCSB_buttonRight{
background-position:0 -56px; background-position:0 -56px;
/* /*
sprites locations are 0 -56px/-20px -56px/-40px -56px/-60px -56px (light) and -80px -56px/-100px -56px/-120px -56px/-140px -56px (dark) sprites locations are 0 -56px/-20px -56px/-40px -56px/-60px -56px (light) and -80px -56px/-100px -56px/-120px -56px/-140px -56px (dark)
*/ */
} }
.mCSB_scrollTools .mCSB_buttonUp:hover, .mCSB_scrollTools .mCSB_buttonUp:hover,
.mCSB_scrollTools .mCSB_buttonDown:hover, .mCSB_scrollTools .mCSB_buttonDown:hover,
.mCSB_scrollTools .mCSB_buttonLeft:hover, .mCSB_scrollTools .mCSB_buttonLeft:hover,
.mCSB_scrollTools .mCSB_buttonRight:hover{ .mCSB_scrollTools .mCSB_buttonRight:hover{
opacity:0.75; opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */ filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
} }
.mCSB_scrollTools .mCSB_buttonUp:active, .mCSB_scrollTools .mCSB_buttonUp:active,
.mCSB_scrollTools .mCSB_buttonDown:active, .mCSB_scrollTools .mCSB_buttonDown:active,
.mCSB_scrollTools .mCSB_buttonLeft:active, .mCSB_scrollTools .mCSB_buttonLeft:active,
.mCSB_scrollTools .mCSB_buttonRight:active{ .mCSB_scrollTools .mCSB_buttonRight:active{
opacity:0.9; opacity:0.9;
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */ filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
} }
/*scrollbar themes*/ /*scrollbar themes*/
/*dark (dark colored scrollbar)*/ /*dark (dark colored scrollbar)*/
.mCS-dark>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15); background:rgba(0,0,0,0.15);
} }
.mCS-dark>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75); background:rgba(0,0,0,0.75);
} }
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-dark>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85); background:rgba(0,0,0,0.85);
} }
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-dark>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-dark>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9); background:rgba(0,0,0,0.9);
} }
.mCS-dark>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-dark>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0; background-position:-80px 0;
} }
.mCS-dark>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-dark>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px; background-position:-80px -20px;
} }
.mCS-dark>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-dark>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px; background-position:-80px -40px;
} }
.mCS-dark>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-dark>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-80px -56px; background-position:-80px -56px;
} }
/*light-2*/ /*light-2*/
.mCS-light-2>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px; width:4px;
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1); background:rgba(255,255,255,0.1);
-webkit-border-radius:1px; -webkit-border-radius:1px;
-moz-border-radius:1px; -moz-border-radius:1px;
border-radius:1px; border-radius:1px;
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px; width:4px;
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75); background:rgba(255,255,255,0.75);
-webkit-border-radius:1px; -webkit-border-radius:1px;
-moz-border-radius:1px; -moz-border-radius:1px;
border-radius:1px; border-radius:1px;
} }
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
height:4px; height:4px;
margin:6px 0; margin:6px 0;
} }
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:4px; height:4px;
margin:6px auto; margin:6px auto;
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-light-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(255,255,255,0.85); background:rgba(255,255,255,0.85);
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-light-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-light-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9); background:rgba(255,255,255,0.9);
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-light-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-32px 0; background-position:-32px 0;
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-light-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-32px -20px; background-position:-32px -20px;
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-light-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-40px -40px; background-position:-40px -40px;
} }
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-light-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-40px -56px; background-position:-40px -56px;
} }
/*dark-2*/ /*dark-2*/
.mCS-dark-2>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px; width:4px;
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1); background:rgba(0,0,0,0.1);
-webkit-border-radius:1px; -webkit-border-radius:1px;
-moz-border-radius:1px; -moz-border-radius:1px;
border-radius:1px; border-radius:1px;
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px; width:4px;
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75); background:rgba(0,0,0,0.75);
-webkit-border-radius:1px; -webkit-border-radius:1px;
-moz-border-radius:1px; -moz-border-radius:1px;
border-radius:1px; border-radius:1px;
} }
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
height:4px; height:4px;
margin:6px 0; margin:6px 0;
} }
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:4px; height:4px;
margin:6px auto; margin:6px auto;
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85); background:rgba(0,0,0,0.85);
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-dark-2>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9); background:rgba(0,0,0,0.9);
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-dark-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-112px 0; background-position:-112px 0;
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-dark-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-112px -20px; background-position:-112px -20px;
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-dark-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-120px -40px; background-position:-120px -40px;
} }
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-dark-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-120px -56px; background-position:-120px -56px;
} }
/*light-thick*/ /*light-thick*/
.mCS-light-thick>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px; width:4px;
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1); background:rgba(255,255,255,0.1);
-webkit-border-radius:2px; -webkit-border-radius:2px;
-moz-border-radius:2px; -moz-border-radius:2px;
border-radius:2px; border-radius:2px;
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px; width:6px;
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75); background:rgba(255,255,255,0.75);
-webkit-border-radius:2px; -webkit-border-radius:2px;
-moz-border-radius:2px; -moz-border-radius:2px;
border-radius:2px; border-radius:2px;
} }
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
height:4px; height:4px;
margin:6px 0; margin:6px 0;
} }
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:6px; height:6px;
margin:5px auto; margin:5px auto;
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(255,255,255,0.85); background:rgba(255,255,255,0.85);
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-light-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9); background:rgba(255,255,255,0.9);
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-light-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-16px 0; background-position:-16px 0;
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-light-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-16px -20px; background-position:-16px -20px;
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-light-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-20px -40px; background-position:-20px -40px;
} }
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-light-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-20px -56px; background-position:-20px -56px;
} }
/*dark-thick*/ /*dark-thick*/
.mCS-dark-thick>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px; width:4px;
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1); background:rgba(0,0,0,0.1);
-webkit-border-radius:2px; -webkit-border-radius:2px;
-moz-border-radius:2px; -moz-border-radius:2px;
border-radius:2px; border-radius:2px;
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px; width:6px;
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75); background:rgba(0,0,0,0.75);
-webkit-border-radius:2px; -webkit-border-radius:2px;
-moz-border-radius:2px; -moz-border-radius:2px;
border-radius:2px; border-radius:2px;
} }
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
height:4px; height:4px;
margin:6px 0; margin:6px 0;
} }
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:6px; height:6px;
margin:5px auto; margin:5px auto;
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85); background:rgba(0,0,0,0.85);
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9); background:rgba(0,0,0,0.9);
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-96px 0; background-position:-96px 0;
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-96px -20px; background-position:-96px -20px;
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-100px -40px; background-position:-100px -40px;
} }
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-100px -56px; background-position:-100px -56px;
} }
/*light-thin*/ /*light-thin*/
.mCS-light-thin>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#fff; /* rgba fallback */ background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1); background:rgba(255,255,255,0.1);
} }
.mCS-light-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px; width:2px;
} }
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
} }
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:2px; height:2px;
margin:7px auto; margin:7px auto;
} }
/*dark-thin*/ /*dark-thin*/
.mCS-dark-thin>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15); background:rgba(0,0,0,0.15);
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px; width:2px;
background:#000; /* rgba fallback */ background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75); background:rgba(0,0,0,0.75);
} }
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{ .mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%; width:100%;
} }
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{ .mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%; width:100%;
height:2px; height:2px;
margin:7px auto; margin:7px auto;
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85); background:rgba(0,0,0,0.85);
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar, .mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9); background:rgba(0,0,0,0.9);
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonUp{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0; background-position:-80px 0;
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonDown{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px; background-position:-80px -20px;
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonLeft{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px; background-position:-80px -40px;
} }
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonRight{ .mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-80px -56px; background-position:-80px -56px;
} }

View file

@ -0,0 +1,348 @@
.collaborator-video {
z-index: 1;
position: absolute;
width: 150px;
height: 150px;
cursor: default;
color: #FFF;
}
.collaborator-video .video-receive {
position: absolute;
width: 160px;
padding: 20px 20px 20px 170px;
background: #424242;
height: 110px;
border-top-left-radius: 75px;
border-bottom-left-radius: 75px;
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
.collaborator-video .video-receive .video-statement {
margin-bottom: 10px;
}
.collaborator-video .video-receive .btn-group .btn-yes {
margin-right: 10px;
}
.collaborator-video .video-receive .btn-group .btn-no {
background-color: #c04f4f;
}
.collaborator-video .video-receive .btn-group .btn-no:hover {
background-color: #A54242;
}
.collaborator-video .video-cutoff {
width: 150px;
height: 150px;
overflow: hidden;
border-radius: 75px;
z-index: 0;
position: relative;
-webkit-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
}
.collaborator-video .video-cutoff video {
height: 150px;
margin-left: -25px;
}
.collaborator-video .video-cutoff .collaborator-video-avatar {
position: absolute;
top: 0;
left: 0;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-o-user-select: none;
user-select: none;
-webkit-user-drag: none;
display: none;
}
.collaborator-video .video-audio {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
right: 0px;
cursor: pointer;
background: url(<%= asset_path 'audio_sprite.png' %>) no-repeat;
}
.collaborator-video .video-audio:hover {
background-position-x: -24px;
}
.collaborator-video .video-audio.active {
background-position-y: -24px;
}
.collaborator-video .video-video {
position: absolute;
width: 24px;
height: 24px;
top: 85%;
left: 0px;
cursor: pointer;
background: url(<%= asset_path 'camera_sprite.png' %>) no-repeat;
}
.collaborator-video .video-video:hover {
background-position-x: -24px;
}
.collaborator-video .video-video.active {
background-position-y: -24px;
}
.collaborator-video.my-video {
left: 30px;
top: 72px;
}
.chat-box {
position: relative;
display: flex;
flex-direction: column;
z-index: 1;
width: 300px;
float: right;
height: 100%;
background: #424242;
box-shadow: 0px 0px 16px 8px rgba(0, 0, 0, 0.23), -2px 10px 10px rgba(0, 0, 0, 0.19);
}
.chat-box .chat-button {
position: absolute;
top: 50%;
left: -36px;
width: 36px;
height: 49px;
background: url(<%= asset_path 'junto.png' %>) no-repeat 2px 9px, url(<%= asset_path 'tray_tab.png' %>) no-repeat;
cursor: pointer;
}
.chat-box .chat-button.active {
background: url(<%= asset_path 'junto_spinner_dark.gif' %>) no-repeat 2px 8px, url(<%= asset_path 'tray_tab.png' %>) no-repeat !important;
}
.chat-box .chat-button .chat-unread {
display: none;
background: #DAB539;
position: absolute;
top: -3px;
left: -11px;
width: 20px;
height: 20px;
border-radius: 11px;
border: 2px solid #424242;
color: #424242;
text-align: center;
font-size: 12px;
font-weight: bold;
line-height: 20px;
}
.chat-box .junto-header {
width: 100%;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
}
.chat-box .junto-header .cursor-toggle {
width: 32px;
height: 32px;
margin-right: 8px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'cursor_sprite.png' %>) no-repeat;
}
.chat-box .junto-header .cursor-toggle:hover {
background-position-x: -32px;
}
.chat-box .junto-header .cursor-toggle.active {
background-position-y: -32px;
}
.chat-box .junto-header .video-toggle {
width: 32px;
height: 32px;
margin-right: 32px;
margin-top: -8px;
float: right;
background: url(<%= asset_path 'video_sprite.png' %>) no-repeat;
}
.chat-box .junto-header .video-toggle:hover {
background-position-x: -32px;
}
.chat-box .junto-header .video-toggle.active {
background-position-y: -32px;
}
.chat-box .participants {
width: 100%;
min-height: 150px;
padding: 16px 0px 16px 0px;
text-align: left;
color: #f5f5f5;
overflow-y: auto;
}
.chat-box .participants .conversation-live {
display: none;
padding: 5px 10px 5px 10px;
background: #c04f4f;
margin: 5px 10px;
border-radius: 2px;
}
.chat-box .participants .conversation-live .call-action {
float: right;
cursor: pointer;
color: #EBFF00;
}
.chat-box .participants .conversation-live .leave {
display: none;
}
.chat-box .participants.is-participating .conversation-live .leave {
display: block;
}
.chat-box .participants.is-participating .conversation-live .join {
display: none;
}
.chat-box .participants .participant {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: 13px;
line-height: 14px;
}
.chat-box .participants .participant .chat-participant-image {
width: 15%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-box .participants .participant .chat-participant-image img {
width: 32px;
height: 32px;
border-radius: 18px;
}
.chat-box .participants .participant .chat-participant-name {
width: 53%;
float: left;
font-size: 13px;
font-weight: bold;
margin-top: 12px;
padding: 2px 8px 0;
text-align: left;
}
.chat-box .participants .participant.is-self .chat-participant-invite-call,
.chat-box .participants .participant.is-self .chat-participant-invite-join {
display: none !important;
}
.chat-box .participants.is-live .participant .chat-participant-invite-call {
display: none;
}
.chat-box .participants .participant .chat-participant-invite-join {
display: none;
}
.chat-box .participants.is-live.is-participating .participant:not(.active) .chat-participant-invite-join {
display: block;
}
.chat-box .participants .participant .chat-participant-invite-call,
.chat-box .participants .participant .chat-participant-invite-join
{
float: right;
background: #4FC059 url(<%= asset_path 'invitepeer16.png' %>) no-repeat center center;
}
.chat-box .participants .participant.pending .chat-participant-invite-call,
.chat-box .participants .participant.pending .chat-participant-invite-join {
background: #dab539 url(<%= asset_path 'ellipsis.gif' %>) no-repeat center center;
}
.chat-box .participants .participant .chat-participant-participating {
float: right;
display: none;
margin-top: 14px;
}
.chat-box .participants .participant .chat-participant-participating .green-dot {
background: #4fc059;
width: 12px;
height: 12px;
border-radius: 6px;
}
.chat-box .participants .participant.active .chat-participant-participating {
display: block;
}
.chat-box .chat-header {
width: 100%;
padding: 16px 8px 16px 16px;
font-size: 16px;
text-align: left;
font-weight: bold;
background-color: #000000;
color: #f5f5f5;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
}
.chat-box .chat-header .sound-toggle {
display: none;
width: 24px;
height: 24px;
margin-right: 32px;
margin-top: -2px;
float: right;
background: url(<%= asset_path 'sound_sprite.png' %>) no-repeat;
}
.chat-box .chat-header .sound-toggle:hover {
background-position-x: -24px;
}
.chat-box .chat-header .sound-toggle.active {
background-position-y: -24px;
}
.chat-box .chat-input {
min-height: 80px;
width: 94%;
padding: 8px 3% 8px 3%;
font-size: 13px;
outline: none;
resize: none;
}
.chat-box .chat-messages {
width: 100%;
padding: 16px 0px 0px 0px;
overflow-y: auto;
flex-grow: 1;
}
.chat-box .chat-messages .chat-message {
width: 89%;
padding: 8px 8px 2px 8px;
color: #f5f5f5;
font-family: arial, sans-serif;
font-size: 13px;
line-height: 14px;
}
.chat-box .chat-messages .chat-message a:link {
color: #4fb5c0;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message a:visited {
color: #aea9fd;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message a:hover {
color: #dab539;
text-decoration: underline;
}
.chat-box .chat-messages .chat-message .chat-message-user {
width: 15%;
float: left;
overflow: hidden;
color: #BBB;
padding-top: 2px;
}
.chat-box .chat-messages .chat-message .chat-message-user img {
border: 2px solid #424242;
width: 32px;
height: 32px;
border-radius: 18px;
}
.chat-box .chat-messages .chat-message .chat-message-text {
width: 73%;
float: left;
margin-top: 12px;
padding: 2px 8px 0;
text-align: left;
}
.chat-box .chat-messages .chat-message .chat-message-time {
float: right;
font-size: 10px;
color: #757575;
}

View file

@ -0,0 +1,3 @@
class Api::MappingsController < API::RestfulController
end

View file

@ -0,0 +1,3 @@
class Api::MapsController < API::RestfulController
end

View file

@ -0,0 +1,53 @@
class API::RestfulController < ActionController::Base
include Pundit
include PunditExtra
snorlax_used_rest!
load_and_authorize_resource only: [:show, :update, :destroy]
def create
instantiate_resource
resource.user = current_user
authorize resource
create_action
respond_with_resource
end
private
def resource_serializer
"new_#{resource_name}_serializer".camelize.constantize
end
def accessible_records
if current_user
visible_records
else
public_records
end
end
def current_user
super || token_user || doorkeeper_user || nil
end
def token_user
token = params[:access_token]
access_token = Token.find_by_token(token)
if access_token
@token_user ||= access_token.user
end
end
def doorkeeper_user
return unless doorkeeper_token.present?
doorkeeper_render_error unless valid_doorkeeper_token?
@doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id)
end
def permitted_params
@permitted_params ||= PermittedParams.new(params)
end
end

View file

@ -0,0 +1,3 @@
class Api::SynapsesController < API::RestfulController
end

View file

@ -0,0 +1,19 @@
class Api::TokensController < API::RestfulController
def my_tokens
raise Pundit::NotAuthorizedError.new unless current_user
instantiate_collection page_collection: false, timeframe_collection: false
respond_with_collection
end
private
def resource_serializer
"#{resource_name}_serializer".camelize.constantize
end
def visible_records
current_user.tokens
end
end

View file

@ -0,0 +1,3 @@
class Api::TopicsController < API::RestfulController
end

View file

@ -1,23 +1,25 @@
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
include ApplicationHelper
include Pundit
include PunditExtra
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
protect_from_forgery protect_from_forgery
before_filter :get_invite_link after_action :allow_embedding
def default_serializer_options
{ root: false }
end
# this is for global login # this is for global login
include ContentHelper include ContentHelper
helper_method :user helper_method :user
helper_method :authenticated? helper_method :authenticated?
helper_method :admin? helper_method :admin?
def after_sign_in_path_for(resource) def after_sign_in_path_for(resource)
unsafe_uri = request.env["REQUEST_URI"] sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => 'https')
if unsafe_uri.starts_with?('http') && !unsafe_uri.starts_with?('https')
protocol = 'http'
else
protocol = 'https'
end
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => protocol)
if request.referer == sign_in_url if request.referer == sign_in_url
super super
@ -27,7 +29,11 @@ class ApplicationController < ActionController::Base
stored_location_for(resource) || request.referer || root_path stored_location_for(resource) || request.referer || root_path
end end
end end
def handle_unauthorized
head :forbidden # TODO make this better
end
private private
def require_no_user def require_no_user
@ -36,37 +42,37 @@ private
return false return false
end end
end end
def require_user def require_user
unless authenticated? unless authenticated?
redirect_to new_user_session_path, notice: "You must be logged in." redirect_to new_user_session_path, notice: "You must be logged in."
return false return false
end end
end end
def require_admin def require_admin
unless authenticated? && admin? unless authenticated? && admin?
redirect_to root_url, notice: "You need to be an admin for that." redirect_to root_url, notice: "You need to be an admin for that."
return false return false
end end
end end
def user def user
current_user current_user
end end
def authenticated? def authenticated?
current_user current_user
end end
def admin? def admin?
authenticated? && current_user.admin authenticated? && current_user.admin
end end
def get_invite_link def allow_embedding
unsafe_uri = request.env["REQUEST_URI"] || 'https://metamaps.cc' #allow all
valid_url = /^https?:\/\/([\w\.-]+)(:\d{1,5})?\/?$/ response.headers.except! 'X-Frame-Options'
safe_uri = (unsafe_uri.match(valid_url)) ? unsafe_uri : '//metamaps.cc/' # or allow a whitelist
@invite_link = "#{safe_uri}join" + (current_user ? "?code=#{current_user.code}" : "") # response.headers['X-Frame-Options'] = 'ALLOW-FROM http://blog.metamaps.cc'
end end
end end

View file

@ -3,20 +3,20 @@ class MainController < ApplicationController
include MapsHelper include MapsHelper
include UsersHelper include UsersHelper
include SynapsesHelper include SynapsesHelper
after_action :verify_policy_scoped
respond_to :html, :json respond_to :html, :json
# home page # home page
def home def home
@current = current_user @maps = policy_scope(Map).order("updated_at DESC").page(1).per(20)
respond_to do |format| respond_to do |format|
format.html { format.html {
if authenticated? if not authenticated?
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(1).per(20) render 'main/home'
respond_with(@maps, @current)
else else
respond_with(@current) render 'maps/activemaps'
end end
} }
end end
@ -59,69 +59,35 @@ class MainController < ApplicationController
filterByMetacode = m filterByMetacode = m
end end
end end
search = '%' + term.downcase + '%'
builder = policy_scope(Topic)
if filterByMetacode if filterByMetacode
if term == "" if term == ""
@topics = [] builder = builder.none
else else
search = term.downcase + '%' builder = builder.where('LOWER("name") like ? OR
LOWER("desc") like ? OR
if user LOWER("link") like ?', search, search, search)
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"')) builder = builder.where(metacode_id: filterByMetacode.id)
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
else
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics2 = Set.new(Topic.where('LOWER("name") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics3 = Set.new(Topic.where('LOWER("desc") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
@topics4 = Set.new(Topic.where('LOWER("link") like ?', '%' + search).where('metacode_id = ?', filterByMetacode.id).order('"name"'))
end
#get unique elements only through the magic of Sets
@topics = (@topics + @topics2 + @topics3 + @topics4).to_a
end end
elsif desc elsif desc
search = '%' + term.downcase + '%' builder = builder.where('LOWER("desc") like ?', search)
if !user
@topics = Topic.where('LOWER("desc") like ?', search).order('"name"')
elsif user
@topics = Topic.where('LOWER("desc") like ?', search).where('user_id = ?', user).order('"name"')
end
elsif link elsif link
search = '%' + term.downcase + '%' builder = builder.where('LOWER("link") like ?', search)
if !user
@topics = Topic.where('LOWER("link") like ?', search).order('"name"')
elsif user
@topics = Topic.where('LOWER("link") like ?', search).where('user_id = ?', user).order('"name"')
end
else #regular case, just search the name else #regular case, just search the name
search = term.downcase + '%' builder = builder.where('LOWER("name") like ? OR
if !user LOWER("desc") like ? OR
@topics = Topic.where('LOWER("name") like ?', search).order('"name"') LOWER("link") like ?', search, search, search)
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).order('"name"')
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).order('"name"')
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).order('"name"')
@topics = @topics + (@topics2 - @topics)
@topics = @topics + (@topics3 - @topics)
@topics = @topics + (@topics4 - @topics)
elsif user
@topics = Topic.where('LOWER("name") like ?', search).where('user_id = ?', user).order('"name"')
@topics2 = Topic.where('LOWER("name") like ?', '%' + search).where('user_id = ?', user).order('"name"')
@topics3 = Topic.where('LOWER("desc") like ?', '%' + search).where('user_id = ?', user).order('"name"')
@topics4 = Topic.where('LOWER("link") like ?', '%' + search).where('user_id = ?', user).order('"name"')
@topics = @topics + (@topics2 - @topics)
@topics = @topics + (@topics3 - @topics)
@topics = @topics + (@topics4 - @topics)
end
end end
builder = builder.where(user: user) if user
@topics = builder.order(:name)
else else
@topics = [] @topics = []
end end
#read this next line as 'delete a topic if its private and you're either 1. logged out or 2. logged in but not the topic creator
@topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
render json: autocomplete_array_json(@topics) render json: autocomplete_array_json(@topics)
end end
@ -141,21 +107,21 @@ class MainController < ApplicationController
term = term[5..-1] term = term[5..-1]
desc = true desc = true
end end
search = '%' + term.downcase + '%' search = '%' + term.downcase + '%'
query = desc ? 'LOWER("desc") like ?' : 'LOWER("name") like ?' builder = policy_scope(Map)
if !user
# !connor why is the limit 5 done here and not above? also, why not limit after sorting alphabetically? if desc
@maps = Map.where(query, search).limit(5).order('"name"') builder = builder.where('LOWER("desc") like ?', search)
elsif user else
@maps = Map.where(query, search).where('user_id = ?', user).order('"name"') builder = builder.where('LOWER("name") like ?', search)
end end
builder = builder.where(user: user) if user
@maps = builder.order(:name)
else else
@maps = [] @maps = []
end end
#read this next line as 'delete a map if its private and you're either 1. logged out or 2. logged in but not the map creator
@maps.to_a.delete_if {|m| m.permission == "private" && (!authenticated? || (authenticated? && current_user.id != m.user_id)) }
render json: autocomplete_map_array_json(@maps) render json: autocomplete_map_array_json(@maps)
end end
@ -166,7 +132,10 @@ class MainController < ApplicationController
#remove "mapper:" if appended at beginning #remove "mapper:" if appended at beginning
term = term[7..-1] if term.downcase[0..6] == "mapper:" term = term[7..-1] if term.downcase[0..6] == "mapper:"
@mappers = User.where('LOWER("name") like ?', term.downcase + '%').order('"name"') search = term.downcase + '%'
builder = policy_scope(User) # TODO do I need to policy scope? I guess yes to verify_policy_scoped
builder = builder.where('LOWER("name") like ?', search)
@mappers = builder.order(:name)
else else
@mappers = [] @mappers = []
end end
@ -181,7 +150,7 @@ class MainController < ApplicationController
topic2id = params[:topic2id] topic2id = params[:topic2id]
if term && !term.empty? if term && !term.empty?
@synapses = Synapse.where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"') @synapses = policy_scope(Synapse).where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
# remove any duplicate synapse types that just differ by # remove any duplicate synapse types that just differ by
# leading or trailing whitespaces # leading or trailing whitespaces
@ -195,23 +164,18 @@ class MainController < ApplicationController
boolean = true boolean = true
end end
} }
#limit to 5 results
@synapses = @synapses.slice(0,5)
elsif topic1id && !topic1id.empty? elsif topic1id && !topic1id.empty?
@one = Synapse.where('node1_id = ? AND node2_id = ?', topic1id, topic2id) @one = policy_scope(Synapse).where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
@two = Synapse.where('node2_id = ? AND node1_id = ?', topic1id, topic2id) @two = policy_scope(Synapse).where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
@synapses = @one + @two @synapses = @one + @two
@synapses.sort! {|s1,s2| s1.desc <=> s2.desc }.to_a @synapses.sort! {|s1,s2| s1.desc <=> s2.desc }.to_a
#permissions
@synapses.delete_if {|s| s.permission == "private" && !authenticated? }
@synapses.delete_if {|s| s.permission == "private" && authenticated? && current_user.id != s.user_id }
else else
@synapses = [] @synapses = []
end end
#limit to 5 results
@synapses = @synapses.slice(0,5)
render json: autocomplete_synapse_array_json(@synapses) render json: autocomplete_synapse_array_json(@synapses)
end end
end end

View file

@ -1,12 +1,15 @@
class MappingsController < ApplicationController class MappingsController < ApplicationController
before_filter :require_user, only: [:create, :update, :destroy] before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index
respond_to :json respond_to :json
# GET /mappings/1.json # GET /mappings/1.json
def show def show
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
authorize @mapping
render json: @mapping render json: @mapping
end end
@ -14,11 +17,12 @@ class MappingsController < ApplicationController
# POST /mappings.json # POST /mappings.json
def create def create
@mapping = Mapping.new(mapping_params) @mapping = Mapping.new(mapping_params)
authorize @mapping
@mapping.map.touch(:updated_at) @mapping.user = current_user
if @mapping.save if @mapping.save
render json: @mapping, status: :created render json: @mapping, status: :created
Events::NewMapping.publish!(@mapping, current_user)
else else
render json: @mapping.errors, status: :unprocessable_entity render json: @mapping.errors, status: :unprocessable_entity
end end
@ -27,8 +31,7 @@ class MappingsController < ApplicationController
# PUT /mappings/1.json # PUT /mappings/1.json
def update def update
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
authorize @mapping
@mapping.map.touch(:updated_at)
if @mapping.update_attributes(mapping_params) if @mapping.update_attributes(mapping_params)
head :no_content head :no_content
@ -40,18 +43,16 @@ class MappingsController < ApplicationController
# DELETE /mappings/1.json # DELETE /mappings/1.json
def destroy def destroy
@mapping = Mapping.find(params[:id]) @mapping = Mapping.find(params[:id])
@map = @mapping.map authorize @mapping
@mapping.destroy @mapping.destroy
@map.touch(:updated_at)
head :no_content head :no_content
end end
private private
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def mapping_params def mapping_params
params.require(:mapping).permit(:id, :xloc, :yloc, :mappable_id, :mappable_type, :map_id, :user_id) params.require(:mapping).permit(:id, :xloc, :yloc, :mappable_id, :mappable_type, :map_id)
end end
end end

View file

@ -1,106 +1,119 @@
class MapsController < ApplicationController class MapsController < ApplicationController
before_filter :require_user, only: [:create, :update, :screenshot, :destroy] before_action :require_user, only: [:create, :update, :screenshot, :destroy]
after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :usermaps]
after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :usermaps]
respond_to :html, :json respond_to :html, :json, :csv
autocomplete :map, :name, :full => true, :extra_data => [:user_id] autocomplete :map, :name, :full => true, :extra_data => [:user_id]
# GET /explore/active # GET /explore/active
# GET /explore/featured def activemaps
# GET /explore/mapper/:id page = params[:page].present? ? params[:page] : 1
def index @maps = policy_scope(Map).order("updated_at DESC")
.page(page).per(20)
if request.path == "/explore"
redirect_to activemaps_url and return
end
@current = current_user
@user = nil
@maps = []
@mapperId = nil
if !params[:page]
page = 1
else
page = params[:page]
end
if request.path.index("/explore/active") != nil
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(page).per(20)
@request = "active"
elsif request.path.index("/explore/featured") != nil
@maps = Map.where("maps.featured = ? AND maps.permission != ?", true, "private").order("updated_at DESC").page(page).per(20)
@request = "featured"
elsif request.path.index('/explore/mine') != nil # looking for maps by me
if !authenticated?
redirect_to activemaps_url and return
end
# don't need to exclude private maps because they all belong to you
@maps = Map.where("maps.user_id = ?", @current.id).order("updated_at DESC").page(page).per(20)
@request = "you"
elsif request.path.index('/explore/mapper/') != nil # looking for maps by a mapper
@user = User.find(params[:id])
@maps = Map.where("maps.user_id = ? AND maps.permission != ?", @user.id, "private").order("updated_at DESC").page(page).per(20)
@request = "mapper"
end
respond_to do |format| respond_to do |format|
format.html { format.html {
if @request == "active" && authenticated? # root url => main/home. main/home renders maps/activemaps view.
redirect_to root_url and return redirect_to root_url and return if authenticated?
end respond_with(@maps, @user)
respond_with(@maps, @request, @user)
} }
format.json { render json: @maps } format.json { render json: @maps }
end end
end end
# GET /explore/featured
def featuredmaps
page = params[:page].present? ? params[:page] : 1
@maps = policy_scope(
Map.where("maps.featured = ? AND maps.permission != ?",
true, "private")
).order("updated_at DESC").page(page).per(20)
respond_to do |format|
format.html { respond_with(@maps, @user) }
format.json { render json: @maps }
end
end
# GET /explore/mine
def mymaps
return redirect_to activemaps_url if !authenticated?
page = params[:page].present? ? params[:page] : 1
@maps = policy_scope(
Map.where("maps.user_id = ?", current_user.id)
).order("updated_at DESC").page(page).per(20)
respond_to do |format|
format.html { respond_with(@maps, @user) }
format.json { render json: @maps }
end
end
# GET /explore/mapper/:id
def usermaps
page = params[:page].present? ? params[:page] : 1
@user = User.find(params[:id])
@maps = policy_scope(Map.where(user: @user))
.order("updated_at DESC").page(page).per(20)
respond_to do |format|
format.html { respond_with(@maps, @user) }
format.json { render json: @maps }
end
end
# GET maps/:id # GET maps/:id
def show def show
@map = Map.find(params[:id])
@current = current_user authorize @map
@map = Map.find(params[:id]).authorize_to_show(@current)
if not @map
redirect_to root_url, notice: "Access denied. That map is private." and return
end
respond_to do |format| respond_to do |format|
format.html { format.html {
@allmappers = @map.contributors @allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } @alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) } @allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && current_user.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m| @allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable object = m.mappable
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id))) !object || (object.permission == "private" && (!authenticated? || (authenticated? && current_user.id != object.user_id)))
} }
@allmessages = @map.messages.sort_by(&:created_at)
respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @map) respond_with(@allmappers, @allmappings, @allsynapses, @alltopics, @allmessages, @map)
} }
format.json { render json: @map } format.json { render json: @map }
format.csv { redirect_to action: :export, format: :csv }
format.xls { redirect_to action: :export, format: :xls }
end end
end end
# GET maps/:id/export
def export
map = Map.find(params[:id])
authorize map
exporter = MapExportService.new(current_user, map)
respond_to do |format|
format.json { render json: exporter.json }
format.csv { send_data exporter.csv }
format.xls { @spreadsheet = exporter.xls }
end
end
# GET maps/:id/contains # GET maps/:id/contains
def contains def contains
@map = Map.find(params[:id])
@current = current_user authorize @map
@map = Map.find(params[:id]).authorize_to_show(@current)
if not @map
redirect_to root_url, notice: "Access denied. That map is private." and return
end
@allmappers = @map.contributors @allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } @alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && current_user.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) } @allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && current_user.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m| @allmappings = @map.mappings.to_a.delete_if {|m|
object = m.mappable object = m.mappable
!object || (object.permission == "private" && (!authenticated? || (authenticated? && @current.id != object.user_id))) !object || (object.permission == "private" && (!authenticated? || (authenticated? && current_user.id != object.user_id)))
} }
@json = Hash.new() @json = Hash.new()
@ -109,6 +122,7 @@ class MapsController < ApplicationController
@json['synapses'] = @allsynapses @json['synapses'] = @allsynapses
@json['mappings'] = @allmappings @json['mappings'] = @allmappings
@json['mappers'] = @allmappers @json['mappers'] = @allmappers
@json['messages'] = @map.messages.sort_by(&:created_at)
respond_to do |format| respond_to do |format|
format.json { render json: @json } format.json { render json: @json }
@ -117,60 +131,66 @@ class MapsController < ApplicationController
# POST maps # POST maps
def create def create
@user = current_user @user = current_user
@map = Map.new() @map = Map.new()
@map.name = params[:name] @map.name = params[:name]
@map.desc = params[:desc] @map.desc = params[:desc]
@map.permission = params[:permission] @map.permission = params[:permission]
@map.user = @user @map.user = @user
@map.arranged = false @map.arranged = false
@map.save
if params[:topicsToMap] if params[:topicsToMap]
@all = params[:topicsToMap] @all = params[:topicsToMap]
@all = @all.split(',') @all = @all.split(',')
@all.each do |topic| @all.each do |topic|
topic = topic.split('/') topic = topic.split('/')
@mapping = Mapping.new() mapping = Mapping.new()
@mapping.user = @user mapping.user = @user
@mapping.map = @map mapping.mappable = Topic.find(topic[0])
@mapping.mappable = Topic.find(topic[0]) mapping.xloc = topic[1]
@mapping.xloc = topic[1] mapping.yloc = topic[2]
@mapping.yloc = topic[2] @map.topicmappings << mapping
@mapping.save authorize mapping, :create
mapping.save
end end
if params[:synapsesToMap] if params[:synapsesToMap]
@synAll = params[:synapsesToMap] @synAll = params[:synapsesToMap]
@synAll = @synAll.split(',') @synAll = @synAll.split(',')
@synAll.each do |synapse_id| @synAll.each do |synapse_id|
@mapping = Mapping.new() mapping = Mapping.new()
@mapping.user = @user mapping.user = @user
@mapping.map = @map mapping.map = @map
@mapping.mappable = Synapse.find(synapse_id) mapping.mappable = Synapse.find(synapse_id)
@mapping.save @map.synapsemappings << mapping
authorize mapping, :create
mapping.save
end end
end end
@map.arranged = true @map.arranged = true
@map.save
end end
respond_to do |format| authorize @map
if @map.save
respond_to do |format|
format.json { render :json => @map } format.json { render :json => @map }
end
else
respond_to do |format|
format.json { render :json => "invalid params" }
end
end end
end end
# PUT maps/:id # PUT maps/:id
def update def update
@current = current_user @map = Map.find(params[:id])
@map = Map.find(params[:id]).authorize_to_edit(@current) authorize @map
respond_to do |format| respond_to do |format|
if !@map if @map.update_attributes(map_params)
format.json { render json: "unauthorized" }
elsif @map.update_attributes(map_params)
format.json { head :no_content } format.json { head :no_content }
else else
format.json { render json: @map.errors, status: :unprocessable_entity } format.json { render json: @map.errors, status: :unprocessable_entity }
@ -180,51 +200,42 @@ class MapsController < ApplicationController
# POST maps/:id/upload_screenshot # POST maps/:id/upload_screenshot
def screenshot def screenshot
@current = current_user @map = Map.find(params[:id])
@map = Map.find(params[:id]).authorize_to_edit(@current) authorize @map
if @map png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1]) StringIO.open(png) do |data|
StringIO.open(png) do |data| data.class.class_eval { attr_accessor :original_filename, :content_type }
data.class.class_eval { attr_accessor :original_filename, :content_type } data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png" data.content_type = "image/png"
data.content_type = "image/png" @map.screenshot = data
@map.screenshot = data end
end
if @map.save if @map.save
render :json => {:message => "Successfully uploaded the map screenshot."} render :json => {:message => "Successfully uploaded the map screenshot."}
else else
render :json => {:message => "Failed to upload image."} render :json => {:message => "Failed to upload image."}
end end
else
render :json => {:message => "Unauthorized to set map screenshot."}
end
end end
# DELETE maps/:id # DELETE maps/:id
def destroy def destroy
@current = current_user @map = Map.find(params[:id])
authorize @map
@map = Map.find(params[:id]).authorize_to_delete(@current) @map.delete
@map.delete if @map respond_to do |format|
format.json do
respond_to do |format| head :no_content
format.json {
if @map
render json: "success"
else
render json: "unauthorized"
end
}
end end
end
end end
private private
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def map_params def map_params
params.require(:map).permit(:id, :name, :arranged, :desc, :permission, :user_id) params.require(:map).permit(:id, :name, :arranged, :desc, :permission)
end end
end end

View file

@ -0,0 +1,67 @@
class MessagesController < ApplicationController
before_action :require_user, except: [:show]
after_action :verify_authorized
# GET /messages/1.json
def show
@message = Message.find(params[:id])
authorize @message
respond_to do |format|
format.json { render json: @message }
end
end
# POST /messages
# POST /messages.json
def create
@message = Message.new(message_params)
@message.user = current_user
authorize @message
respond_to do |format|
if @message.save
format.json { render json: @message, status: :created, location: messages_url }
else
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
# PUT /messages/1
# PUT /messages/1.json
def update
@message = Message.find(params[:id])
authorize @message
respond_to do |format|
if @message.update_attributes(message_params)
format.json { head :no_content }
else
format.json { render json: @message.errors, status: :unprocessable_entity }
end
end
end
# DELETE /messages/1
# DELETE /messages/1.json
def destroy
@message = Message.find(params[:id])
authorize @message
@message.destroy
respond_to do |format|
format.json { head :no_content }
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
def message_params
#params.require(:message).permit(:id, :resource_id, :message)
params.permit(:id, :resource_id, :resource_type, :message)
end
end

View file

@ -1,6 +1,6 @@
class MetacodeSetsController < ApplicationController class MetacodeSetsController < ApplicationController
before_filter :require_admin before_action :require_admin
# GET /metacode_sets # GET /metacode_sets
# GET /metacode_sets.json # GET /metacode_sets.json

View file

@ -1,13 +1,10 @@
class MetacodesController < ApplicationController class MetacodesController < ApplicationController
before_filter :require_admin, except: [:index] before_action :require_admin, except: [:index, :show]
# GET /metacodes # GET /metacodes
# GET /metacodes.json # GET /metacodes.json
def index def index
@metacodes = Metacode.order("name").all @metacodes = Metacode.order("name").all
@metacodes.map do |metacode|
metacode.icon = ActionController::Base.helpers.asset_path(metacode.icon)
end
respond_to do |format| respond_to do |format|
format.html { format.html {
@ -15,23 +12,23 @@ class MetacodesController < ApplicationController
redirect_to root_url, notice: "You need to be an admin for that." redirect_to root_url, notice: "You need to be an admin for that."
return false return false
end end
render action: "index" render :index
} }
format.json { render json: @metacodes } format.json { render json: @metacodes }
end end
end end
### SHOW IS CURRENTLY DISABLED
# GET /metacodes/1
# GET /metacodes/1.json # GET /metacodes/1.json
# def show # GET /metacodes/Action.json
# @metacode = Metacode.find(params[:id]) # GET /metacodes/action.json
# def show
# respond_to do |format| @metacode = Metacode.where('DOWNCASE(name) = ?', downcase(params[:name])).first if params[:name]
# format.html # show.html.erb @metacode = Metacode.find(params[:id]) unless @metacode
# format.json { render json: @metacode }
# end respond_to do |format|
# end format.json { render json: @metacode }
end
end
# GET /metacodes/new # GET /metacodes/new
# GET /metacodes/new.json # GET /metacodes/new.json
@ -59,7 +56,7 @@ class MetacodesController < ApplicationController
format.html { redirect_to metacodes_url, notice: 'Metacode was successfully created.' } format.html { redirect_to metacodes_url, notice: 'Metacode was successfully created.' }
format.json { render json: @metacode, status: :created, location: metacodes_url } format.json { render json: @metacode, status: :created, location: metacodes_url }
else else
format.html { render action: "new" } format.html { render :new }
format.json { render json: @metacode.errors, status: :unprocessable_entity } format.json { render json: @metacode.errors, status: :unprocessable_entity }
end end
end end
@ -71,34 +68,20 @@ class MetacodesController < ApplicationController
@metacode = Metacode.find(params[:id]) @metacode = Metacode.find(params[:id])
respond_to do |format| respond_to do |format|
if @metacode.update_attributes(metacode_params) if @metacode.update(metacode_params)
format.html { redirect_to metacodes_url, notice: 'Metacode was successfully updated.' } format.html { redirect_to metacodes_url, notice: 'Metacode was successfully updated.' }
format.json { head :no_content } format.json { head :no_content }
else else
format.html { render action: "edit" } format.html { render :edit }
format.json { render json: @metacode.errors, status: :unprocessable_entity } format.json { render json: @metacode.errors, status: :unprocessable_entity }
end end
end end
end end
### DESTROY IS CURRENTLY DISABLED
# DELETE /metacodes/1
# DELETE /metacodes/1.json
# def destroy
# @metacode = Metacode.find(params[:id])
# @metacode.destroy
#
# respond_to do |format|
# format.html { redirect_to metacodes_url }
# format.json { head :no_content }
# end
# end
private private
# Never trust parameters from the scary internet, only allow the white list through. # Never trust parameters from the scary internet, only allow the white list through.
def metacode_params def metacode_params
params.require(:metacode).permit(:id, :name, :icon, :color) params.require(:metacode).permit(:id, :name, :aws_icon, :manual_icon, :color)
end end
end end

View file

@ -1,20 +1,17 @@
class SynapsesController < ApplicationController class SynapsesController < ApplicationController
include TopicsHelper include TopicsHelper
before_filter :require_user, only: [:create, :update, :destroy] before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :index
after_action :verify_policy_scoped, only: :index
respond_to :json respond_to :json
# GET /synapses/1.json # GET /synapses/1.json
def show def show
@synapse = Synapse.find(params[:id]) @synapse = Synapse.find(params[:id])
authorize @synapse
#.authorize_to_show(@current)
#if not @synapse
# redirect_to root_url and return
#end
render json: @synapse render json: @synapse
end end
@ -22,7 +19,8 @@ class SynapsesController < ApplicationController
# POST /synapses.json # POST /synapses.json
def create def create
@synapse = Synapse.new(synapse_params) @synapse = Synapse.new(synapse_params)
@synapse.update_attribute :desc, "" if @synapse.desc.nil? @synapse.desc = "" if @synapse.desc.nil?
authorize @synapse
respond_to do |format| respond_to do |format|
if @synapse.save if @synapse.save
@ -37,7 +35,8 @@ class SynapsesController < ApplicationController
# PUT /synapses/1.json # PUT /synapses/1.json
def update def update
@synapse = Synapse.find(params[:id]) @synapse = Synapse.find(params[:id])
@synapse.update_attribute :desc, "" if @synapse.desc.nil? @synapse.desc = "" if @synapse.desc.nil?
authorize @synapse
respond_to do |format| respond_to do |format|
if @synapse.update_attributes(synapse_params) if @synapse.update_attributes(synapse_params)
@ -50,8 +49,9 @@ class SynapsesController < ApplicationController
# DELETE synapses/:id # DELETE synapses/:id
def destroy def destroy
@synapse = Synapse.find(params[:id]).authorize_to_delete(current_user) @synapse = Synapse.find(params[:id])
@synapse.delete if @synapse authorize @synapse
@synapse.delete
respond_to do |format| respond_to do |format|
format.json { head :no_content } format.json { head :no_content }

View file

@ -1,215 +1,164 @@
class TopicsController < ApplicationController class TopicsController < ApplicationController
include TopicsHelper include TopicsHelper
before_filter :require_user, only: [:create, :update, :destroy] before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :autocomplete_topic
respond_to :html, :js, :json
respond_to :html, :js, :json
# GET /topics/autocomplete_topic
def autocomplete_topic # GET /topics/autocomplete_topic
@current = current_user def autocomplete_topic
term = params[:term] term = params[:term]
if term && !term.empty? if term && !term.empty?
@topics = Topic.where('LOWER("name") like ?', term.downcase + '%').order('"name"') @topics = policy_scope(Topic.where('LOWER("name") like ?', term.downcase + '%')).order('"name"')
else
#read this next line as 'delete a topic if its private and you're either @topics = []
#1. logged out or 2. logged in but not the topic creator end
@topics.to_a.delete_if {|t| t.permission == "private" && render json: autocomplete_array_json(@topics)
(!authenticated? || (authenticated? && @current.id != t.user_id)) } end
else
@topics = [] # GET topics/:id
end def show
render json: autocomplete_array_json(@topics) @topic = Topic.find(params[:id])
end authorize @topic
# GET topics/:id respond_to do |format|
def show format.html {
@current = current_user @alltopics = [@topic].concat(policy_scope(Topic.relatives1(@topic.id)).to_a).concat(policy_scope(Topic.relatives2(@topic.id)).to_a)
@topic = Topic.find(params[:id]).authorize_to_show(@current) @allsynapses = policy_scope(Synapse.for_topic(@topic.id)).to_a
puts @alltopics.length
if not @topic puts @allsynapses.length
redirect_to root_url, notice: "Access denied. That topic is private." and return @allcreators = @alltopics.map(&:user).uniq
end @allcreators += @allsynapses.map(&:user).uniq
respond_to do |format| respond_with(@allsynapses, @alltopics, @allcreators, @topic)
format.html { }
@alltopics = ([@topic] + @topic.relatives).delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) } # should limit to topics visible to user format.json { render json: @topic }
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) } end
end
@allcreators = []
@alltopics.each do |t| # GET topics/:id/network
if @allcreators.index(t.user) == nil def network
@allcreators.push(t.user) @topic = Topic.find(params[:id])
end authorize @topic
end
@allsynapses.each do |s| @alltopics = [@topic].concat(policy_scope(Topic.relatives1(@topic.id)).to_a).concat(policy_scope(Topic.relatives2(@topic.id)).to_a)
if @allcreators.index(s.user) == nil @allsynapses = policy_scope(Synapse.for_topic(@topic.id))
@allcreators.push(s.user)
end @allcreators = @alltopics.map(&:user).uniq
end @allcreators += @allsynapses.map(&:user).uniq
respond_with(@allsynapses, @alltopics, @allcreators, @topic) @json = Hash.new()
} @json['topic'] = @topic
format.json { render json: @topic } @json['creators'] = @allcreators
end @json['relatives'] = @alltopics
end @json['synapses'] = @allsynapses
# GET topics/:id/network respond_to do |format|
def network format.json { render json: @json }
@current = current_user end
@topic = Topic.find(params[:id]).authorize_to_show(@current) end
if not @topic # GET topics/:id/relative_numbers
redirect_to root_url, notice: "Access denied. That topic is private." and return def relative_numbers
end @topic = Topic.find(params[:id])
authorize @topic
@alltopics = @topic.relatives.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) } topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
@allcreators = []
@allcreators.push(@topic.user) @alltopics = policy_scope(Topic.relatives1(@topic.id)).to_a.concat(policy_scope(Topic.relatives2(@topic.id)).to_a).uniq
@alltopics.each do |t| @alltopics.delete_if do |topic|
if @allcreators.index(t.user) == nil topicsAlreadyHas.index(topic.id) != nil
@allcreators.push(t.user) end
end
end @json = Hash.new(0)
@allsynapses.each do |s| @alltopics.each do |t|
if @allcreators.index(s.user) == nil @json[t.metacode.id] += 1
@allcreators.push(s.user) end
end
end respond_to do |format|
format.json { render json: @json }
@json = Hash.new() end
@json['topic'] = @topic end
@json['creators'] = @allcreators
@json['relatives'] = @alltopics # GET topics/:id/relatives
@json['synapses'] = @allsynapses def relatives
@topic = Topic.find(params[:id])
respond_to do |format| authorize @topic
format.json { render json: @json }
end topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
end
alltopics = policy_scope(Topic.relatives1(@topic.id)).to_a.concat(policy_scope(Topic.relatives2(@topic.id)).to_a).uniq
# GET topics/:id/relative_numbers alltopics.delete_if do |topic|
def relative_numbers topicsAlreadyHas.index(topic.id.to_s) != nil
@current = current_user end
@topic = Topic.find(params[:id]).authorize_to_show(@current)
#find synapses between topics in alltopics array
if not @topic allsynapses = policy_scope(Synapse.for_topic(@topic.id)).to_a
redirect_to root_url, notice: "Access denied. That topic is private." and return synapse_ids = (allsynapses.map(&:node1_id) + allsynapses.map(&:node2_id)).uniq
end allsynapses.delete_if do |synapse|
synapse_ids.index(synapse.id) != nil
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : [] end
@alltopics = @topic.relatives.to_a.delete_if {|t| creatorsAlreadyHas = params[:creators] ? params[:creators].split(',').map(&:to_i) : []
@topicsAlreadyHas.index(t.id.to_s) != nil || allcreators = (alltopics.map(&:user) + allsynapses.map(&:user)).uniq.delete_if do |user|
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id))) creatorsAlreadyHas.index(user.id) != nil
} end
@alltopics.uniq! @json = Hash.new()
@json['topics'] = alltopics
@json = Hash.new() @json['synapses'] = allsynapses
@alltopics.each do |t| @json['creators'] = allcreators
if @json[t.metacode.id]
@json[t.metacode.id] += 1 respond_to do |format|
else format.json { render json: @json }
@json[t.metacode.id] = 1 end
end end
end
# POST /topics
respond_to do |format| # POST /topics.json
format.json { render json: @json } def create
end @topic = Topic.new(topic_params)
end authorize @topic
# GET topics/:id/relatives respond_to do |format|
def relatives if @topic.save
@current = current_user format.json { render json: @topic, status: :created }
@topic = Topic.find(params[:id]).authorize_to_show(@current) else
format.json { render json: @topic.errors, status: :unprocessable_entity }
if not @topic end
redirect_to root_url, notice: "Access denied. That topic is private." and return end
end end
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : [] # PUT /topics/1
# PUT /topics/1.json
@alltopics = @topic.relatives.to_a.delete_if {|t| def update
@topicsAlreadyHas.index(t.id.to_s) != nil || @topic = Topic.find(params[:id])
(params[:metacode] && t.metacode_id.to_s != params[:metacode]) || authorize @topic
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
} respond_to do |format|
if @topic.update_attributes(topic_params)
@alltopics.uniq! format.json { head :no_content }
else
@allsynapses = @topic.synapses.to_a.delete_if {|s| format.json { render json: @topic.errors, status: :unprocessable_entity }
(s.topic1 == @topic && @alltopics.index(s.topic2) == nil) || end
(s.topic2 == @topic && @alltopics.index(s.topic1) == nil) end
} end
@creatorsAlreadyHas = params[:creators] ? params[:creators].split(',') : [] # DELETE topics/:id
@allcreators = [] def destroy
@alltopics.each do |t| @topic = Topic.find(params[:id])
if @allcreators.index(t.user) == nil && @creatorsAlreadyHas.index(t.user_id.to_s) == nil authorize @topic
@allcreators.push(t.user)
end @topic.delete
end respond_to do |format|
@allsynapses.each do |s| format.json { head :no_content }
if @allcreators.index(s.user) == nil && @creatorsAlreadyHas.index(s.user_id.to_s) == nil end
@allcreators.push(s.user) end
end
end private
@json = Hash.new() def topic_params
@json['topics'] = @alltopics params.require(:topic).permit(:id, :name, :desc, :link, :permission, :user_id, :metacode_id)
@json['synapses'] = @allsynapses end
@json['creators'] = @allcreators end
respond_to do |format|
format.json { render json: @json }
end
end
# POST /topics
# POST /topics.json
def create
@topic = Topic.new(topic_params)
respond_to do |format|
if @topic.save
format.json { render json: @topic, status: :created }
else
format.json { render json: @topic.errors, status: :unprocessable_entity }
end
end
end
# PUT /topics/1
# PUT /topics/1.json
def update
@topic = Topic.find(params[:id])
respond_to do |format|
if @topic.update_attributes(topic_params)
format.json { head :no_content }
else
format.json { render json: @topic.errors, status: :unprocessable_entity }
end
end
end
# DELETE topics/:id
def destroy
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_delete(@current)
@topic.delete if @topic
respond_to do |format|
format.json { head :no_content }
end
end
private
def topic_params
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :user_id, :metacode_id)
end
end

View file

@ -1,6 +1,6 @@
class Users::RegistrationsController < Devise::RegistrationsController class Users::RegistrationsController < Devise::RegistrationsController
before_filter :configure_sign_up_params, only: [:create] before_action :configure_sign_up_params, only: [:create]
before_filter :configure_account_update_params, only: [:update] before_action :configure_account_update_params, only: [:update]
protected protected
def after_sign_up_path_for(resource) def after_sign_up_path_for(resource)

View file

@ -1,5 +1,5 @@
class UsersController < ApplicationController class UsersController < ApplicationController
before_filter :require_user, only: [:edit, :update, :updatemetacodes] before_action :require_user, only: [:edit, :update, :updatemetacodes]
respond_to :html, :json respond_to :html, :json

View file

@ -1,12 +1,12 @@
module ApplicationHelper module ApplicationHelper
def get_metacodeset def get_metacodeset
@m = user.settings.metacodes @m = current_user.settings.metacodes
set = @m[0].include?("metacodeset") ? MetacodeSet.find(@m[0].sub("metacodeset-","").to_i) : false set = @m[0].include?("metacodeset") ? MetacodeSet.find(@m[0].sub("metacodeset-","").to_i) : false
return set return set
end end
def user_metacodes def user_metacodes
@m = user.settings.metacodes @m = current_user.settings.metacodes
set = get_metacodeset set = get_metacodeset
if set if set
@metacodes = set.metacodes.to_a @metacodes = set.metacodes.to_a
@ -15,4 +15,8 @@ module ApplicationHelper
end end
@metacodes.sort! {|m1,m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1) @metacodes.sort! {|m1,m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
end end
def determine_invite_link
"#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : "")
end
end end

View file

@ -8,7 +8,7 @@ module TopicsHelper
topic['id'] = t.id topic['id'] = t.id
topic['label'] = t.name topic['label'] = t.name
topic['value'] = t.name topic['value'] = t.name
topic['description'] = t.desc.truncate(70) # make this return matched results topic['description'] = t.desc ? t.desc.truncate(70) : '' # make this return matched results
topic['type'] = t.metacode.name topic['type'] = t.metacode.name
topic['typeImageURL'] = t.metacode.icon topic['typeImageURL'] = t.metacode.icon
topic['permission'] = t.permission topic['permission'] = t.permission

View file

@ -0,0 +1,10 @@
module Routing
extend ActiveSupport::Concern
include Rails.application.routes.url_helpers
included do
def default_url_options
ActionMailer::Base.default_url_options
end
end
end

31
app/models/event.rb Normal file
View file

@ -0,0 +1,31 @@
class Event < ActiveRecord::Base
KINDS = %w[topic_added_to_map synapse_added_to_map]
#has_many :notifications, dependent: :destroy
belongs_to :eventable, polymorphic: true
belongs_to :map
belongs_to :user
scope :chronologically, -> { order('created_at asc') }
after_create :notify_webhooks!, if: :map
validates_inclusion_of :kind, :in => KINDS
validates_presence_of :eventable
#def notify!(user)
# notifications.create!(user: user)
#end
def belongs_to?(this_user)
self.user_id == this_user.id
end
def notify_webhooks!
#group = self.discussion.group
self.map.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
#group.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
end
handle_asynchronously :notify_webhooks!
end

View file

@ -0,0 +1,18 @@
class Events::NewMapping < Event
#after_create :notify_users!
def self.publish!(mapping, user)
create!(kind: mapping.mappable_type == "Topic" ? "topic_added_to_map" : "synapse_added_to_map",
eventable: mapping,
map: mapping.map,
user: user)
end
private
#def notify_users!
# unless comment_vote.user == comment_vote.comment_user
# notify!(comment_vote.comment_user)
# end
#end
end

View file

@ -6,6 +6,10 @@ class Map < ActiveRecord::Base
has_many :synapsemappings, -> { Mapping.synapsemapping }, class_name: :Mapping, dependent: :destroy has_many :synapsemappings, -> { Mapping.synapsemapping }, class_name: :Mapping, dependent: :destroy
has_many :topics, through: :topicmappings, source: :mappable, source_type: "Topic" has_many :topics, through: :topicmappings, source: :mappable, source_type: "Topic"
has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse" has_many :synapses, through: :synapsemappings, source: :mappable, source_type: "Synapse"
has_many :messages, as: :resource, dependent: :destroy
has_many :webhooks, as: :hookable
has_many :events, -> { includes :user }, as: :eventable, dependent: :destroy
# This method associates the attribute ":image" with a file attachment # This method associates the attribute ":image" with a file attachment
has_attached_file :screenshot, :styles => { has_attached_file :screenshot, :styles => {
@ -13,15 +17,16 @@ class Map < ActiveRecord::Base
#:full => ['940x630#', :png] #:full => ['940x630#', :png]
}, },
:default_url => 'https://s3.amazonaws.com/metamaps-assets/site/missing-map.png' :default_url => 'https://s3.amazonaws.com/metamaps-assets/site/missing-map.png'
validates :name, presence: true validates :name, presence: true
validates :arranged, inclusion: { in: [true, false] } validates :arranged, inclusion: { in: [true, false] }
validates :permission, presence: true validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) } validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
# Validate the attached image is image/jpg, image/png, etc # Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :screenshot, :content_type => /\Aimage\/.*\Z/ validates_attachment_content_type :screenshot, :content_type => /\Aimage\/.*\Z/
def mappings def mappings
topicmappings + synapsemappings topicmappings + synapsemappings
end end
@ -32,85 +37,56 @@ class Map < ActiveRecord::Base
#return an array of the contributors to the map #return an array of the contributors to the map
def contributors def contributors
contributors = [] contributors = []
self.mappings.each do |m| self.mappings.each do |m|
contributors.push(m.user) if !contributors.include?(m.user) contributors.push(m.user) if !contributors.include?(m.user)
end end
return contributors return contributors
end end
def topic_count def topic_count
self.topics.length topics.length
end end
def synapse_count def synapse_count
self.synapses.length synapses.length
end end
def user_name def user_name
self.user.name user.name
end end
def user_image def user_image
self.user.image.url user.image.url
end end
def contributor_count def contributor_count
self.contributors.length contributors.length
end end
def screenshot_url def screenshot_url
self.screenshot.url(:thumb) screenshot.url(:thumb)
end end
def created_at_str def created_at_str
self.created_at.strftime("%m/%d/%Y") created_at.strftime("%m/%d/%Y")
end end
def updated_at_str def updated_at_str
self.updated_at.strftime("%m/%d/%Y") updated_at.strftime("%m/%d/%Y")
end end
def as_json(options={}) def as_json(options={})
json = super(:methods =>[:user_name, :user_image, :topic_count, :synapse_count, :contributor_count, :screenshot_url], :except => [:screenshot_content_type, :screenshot_file_size, :screenshot_file_name, :screenshot_updated_at]) json = super(:methods =>[:user_name, :user_image, :topic_count, :synapse_count, :contributor_count, :screenshot_url], :except => [:screenshot_content_type, :screenshot_file_size, :screenshot_file_name, :screenshot_updated_at])
json[:created_at_clean] = self.created_at_str json[:created_at_clean] = created_at_str
json[:updated_at_clean] = self.updated_at_str json[:updated_at_clean] = updated_at_str
json json
end end
##### PERMISSIONS ######
def authorize_to_delete(user)
if (self.user != user)
return false
end
return self
end
# returns false if user not allowed to 'show' Topic, Synapse, or Map
def authorize_to_show(user)
if (self.permission == "private" && self.user != user)
return false
end
return self
end
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
def authorize_to_edit(user)
if !user
return false
elsif (self.permission == "private" && self.user != user)
return false
elsif (self.permission == "public" && self.user != user)
return false
end
return self
end
def decode_base64(imgBase64) def decode_base64(imgBase64)
decoded_data = Base64.decode64(imgBase64) decoded_data = Base64.decode64(imgBase64)
data = StringIO.new(decoded_data) data = StringIO.new(decoded_data)
data.class_eval do data.class_eval do
attr_accessor :content_type, :original_filename attr_accessor :content_type, :original_filename

View file

@ -4,10 +4,15 @@ class Mapping < ActiveRecord::Base
scope :synapsemapping, -> { where(mappable_type: :Synapse) } scope :synapsemapping, -> { where(mappable_type: :Synapse) }
belongs_to :mappable, polymorphic: true belongs_to :mappable, polymorphic: true
belongs_to :map, :class_name => "Map", :foreign_key => "map_id", touch: true
belongs_to :map, :class_name => "Map", :foreign_key => "map_id"
belongs_to :user belongs_to :user
validates :xloc, presence: true,
unless: Proc.new { |m| m.mappable_type == 'Synapse' }
validates :yloc, presence: true,
unless: Proc.new { |m| m.mappable_type == 'Synapse' }
validates :map, presence: true
validates :mappable, presence: true
def user_name def user_name
self.user.name self.user.name
@ -20,5 +25,5 @@ class Mapping < ActiveRecord::Base
def as_json(options={}) def as_json(options={})
super(:methods =>[:user_name, :user_image]) super(:methods =>[:user_name, :user_image])
end end
end end

19
app/models/message.rb Normal file
View file

@ -0,0 +1,19 @@
class Message < ActiveRecord::Base
belongs_to :user
belongs_to :resource, polymorphic: true
def user_name
self.user.name
end
def user_image
self.user.image.url
end
def as_json(options={})
json = super(:methods =>[:user_name, :user_image])
json
end
end

View file

@ -1,16 +1,63 @@
class Metacode < ActiveRecord::Base class Metacode < ActiveRecord::Base
has_many :in_metacode_sets has_many :in_metacode_sets
has_many :metacode_sets, :through => :in_metacode_sets has_many :metacode_sets, :through => :in_metacode_sets
has_many :topics has_many :topics
# This method associates the attribute ":aws_icon" with a file attachment
has_attached_file :aws_icon, :styles => {
:ninetysix => ['96x96#', :png],
},
:default_url => 'https://s3.amazonaws.com/metamaps-assets/metacodes/generics/96px/gen_wildcard.png'
# Validate the attached icon is image/jpg, image/png, etc
validates_attachment_content_type :aws_icon, :content_type => /\Aimage\/.*\Z/
validate :aws_xor_manual_icon
validate :manual_icon_https
before_create do
self.manual_icon = nil if self.manual_icon == ""
end
def icon(*args)
if manual_icon.present?
manual_icon
else
aws_icon(*args)
end
end
def as_json(options={})
default = super(options)
default[:icon] = icon
default.except('aws_icon_file_name', 'aws_icon_content_type', 'aws_icon_file_size', 'aws_icon_updated_at', 'manual_icon')
end
def hasSelected(user) def hasSelected(user)
return true if user.settings.metacodes.include? self.id.to_s return true if user.settings.metacodes.include? self.id.to_s
return false return false
end end
def inMetacodeSet(metacode_set) def inMetacodeSet(metacode_set)
return true if self.metacode_sets.include? metacode_set return true if self.metacode_sets.include? metacode_set
return false return false
end end
private
def aws_xor_manual_icon
if aws_icon.blank? && manual_icon.blank?
errors.add(:base, "Either aws_icon or manual_icon is required")
end
if aws_icon.present? && manual_icon.present?
errors.add(:base, "Specify aws_icon or manual_icon, not both")
end
end
def manual_icon_https
if manual_icon.present?
unless manual_icon.starts_with? 'https'
errors.add(:base, "Manual icon must begin with https")
end
end
end
end end

View file

@ -0,0 +1,33 @@
class PermittedParams < Struct.new(:params)
%w[map synapse topic mapping token].each do |kind|
define_method(kind) do
permitted_attributes = self.send("#{kind}_attributes")
params.require(kind).permit(*permitted_attributes)
end
alias_method :"api_#{kind}", kind.to_sym
end
alias :read_attribute_for_serialization :send
def token_attributes
[:description]
end
def map_attributes
[:name, :desc, :permission, :arranged]
end
def synapse_attributes
[:desc, :category, :weight, :permission, :node1_id, :node2_id]
end
def topic_attributes
[:name, :desc, :link, :permission, :metacode_id]
end
def mapping_attributes
[:xloc, :yloc, :map_id, :mappable_type, :mappable_id]
end
end

View file

@ -1,5 +1,4 @@
class Synapse < ActiveRecord::Base class Synapse < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :topic1, :class_name => "Topic", :foreign_key => "node1_id" belongs_to :topic1, :class_name => "Topic", :foreign_key => "node1_id"
@ -11,44 +10,32 @@ class Synapse < ActiveRecord::Base
validates :desc, length: { minimum: 0, allow_nil: false } validates :desc, length: { minimum: 0, allow_nil: false }
validates :permission, presence: true validates :permission, presence: true
validates :node1_id, presence: true
validates :node2_id, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) } validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
validates :category, inclusion: { in: ['from-to', 'both'], allow_nil: true }
scope :for_topic, ->(topic_id = nil) {
where("node1_id = ? OR node2_id = ?", topic_id, topic_id)
}
# :nocov:
def user_name def user_name
self.user.name user.name
end end
# :nocov:
# :nocov:
def user_image def user_image
self.user.image.url user.image.url
end end
# :nocov:
# :nocov:
def as_json(options={}) def as_json(options={})
super(:methods =>[:user_name, :user_image]) super(:methods =>[:user_name, :user_image])
end end
# :nocov:
##### PERMISSIONS ######
# returns false if user not allowed to 'show' Topic, Synapse, or Map
def authorize_to_show(user)
if (self.permission == "private" && self.user != user)
return false
end
return self
end
# returns false if user not allowed to 'edit' Topic, Synapse, or Map
def authorize_to_edit(user)
if (self.permission == "private" && self.user != user)
return false
elsif (self.permission == "public" && self.user != user)
return false
end
return self
end
def authorize_to_delete(user)
if (self.user == user || user.admin)
return self
end
return false
end
end end

22
app/models/token.rb Normal file
View file

@ -0,0 +1,22 @@
class Token < ActiveRecord::Base
belongs_to :user
before_create :assign_token
CHARS = 32
private
def assign_token
self.token = generate_token
end
def generate_token
loop do
candidate = SecureRandom.base64(CHARS).gsub(/\W/, '')
if candidate.size >= CHARS
return candidate[0...CHARS]
end
end
end
end

View file

@ -1,117 +1,123 @@
class Topic < ActiveRecord::Base class Topic < ActiveRecord::Base
include TopicsHelper include TopicsHelper
belongs_to :user belongs_to :user
has_many :synapses1, :class_name => 'Synapse', :foreign_key => 'node1_id', dependent: :destroy has_many :synapses1, :class_name => 'Synapse', :foreign_key => 'node1_id', dependent: :destroy
has_many :synapses2, :class_name => 'Synapse', :foreign_key => 'node2_id', dependent: :destroy has_many :synapses2, :class_name => 'Synapse', :foreign_key => 'node2_id', dependent: :destroy
has_many :topics1, :through => :synapses2, :source => :topic1 has_many :topics1, :through => :synapses2, source: :topic1
has_many :topics2, :through => :synapses1, :source => :topic2 has_many :topics2, :through => :synapses1, source: :topic2
has_many :mappings, as: :mappable, dependent: :destroy has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, :through => :mappings has_many :maps, :through => :mappings
validates :permission, presence: true validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) } validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
# This method associates the attribute ":image" with a file attachment # This method associates the attribute ":image" with a file attachment
has_attached_file :image has_attached_file :image
#, styles: { #, styles: {
# thumb: '100x100>', # thumb: '100x100>',
# square: '200x200#', # square: '200x200#',
# medium: '300x300>' # medium: '300x300>'
#} #}
# Validate the attached image is image/jpg, image/png, etc # Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/ validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
# This method associates the attribute ":image" with a file attachment # This method associates the attribute ":image" with a file attachment
has_attached_file :audio has_attached_file :audio
# Validate the attached audio is audio/wav, audio/mp3, etc # Validate the attached audio is audio/wav, audio/mp3, etc
validates_attachment_content_type :audio, :content_type => /\Aaudio\/.*\Z/ validates_attachment_content_type :audio, :content_type => /\Aaudio\/.*\Z/
def synapses def synapses
synapses1 + synapses2 synapses1 + synapses2
end end
def relatives def relatives
topics1 + topics2 topics1 + topics2
end end
belongs_to :metacode belongs_to :metacode
def user_name scope :relatives1, ->(topic_id = nil) {
user.name includes(:topics1)
end .where('synapses.node1_id = ?', topic_id)
.references(:synapses)
def user_image }
user.image.url
end scope :relatives2, ->(topic_id = nil) {
includes(:topics2)
def map_count .where('synapses.node2_id = ?', topic_id)
maps.count .references(:synapses)
end }
def synapse_count def user_name
synapses.count user.name
end end
def inmaps def user_image
maps.map(&:name) user.image.url
end end
def inmapsLinks def map_count
maps.map(&:id) maps.count
end end
def as_json(options={}) def synapse_count
super(:methods =>[:user_name, :user_image, :map_count, :synapse_count, :inmaps, :inmapsLinks]) synapses.count
end end
def topic_autocomplete_method def inmaps
"Get: #{self.name}" maps.map(&:name)
end end
def mk_permission def inmapsLinks
Perm.short(permission) maps.map(&:id)
end end
# has no viewable synapses helper function def as_json(options={})
def has_viewable_synapses(current) super(:methods =>[:user_name, :user_image, :map_count, :synapse_count, :inmaps, :inmapsLinks])
result = false end
synapses.each do |synapse|
if synapse.authorize_to_show(current) # TODO move to a decorator?
result = true def synapses_csv(output_format = 'array')
end output = []
end synapses.each do |synapse|
result if synapse.category == 'from-to'
end if synapse.node1_id == id
output << synapse.node1_id.to_s + '->' + synapse.node2_id.to_s
##### PERMISSIONS ###### elsif synapse.node2_id == id
output << synapse.node2_id.to_s + '<-' + synapse.node1_id.to_s
# returns false if user not allowed to 'show' Topic, Synapse, or Map else
def authorize_to_show(user) fail 'invalid synapse on topic in synapse_csv'
if (self.permission == "private" && self.user != user) end
return false elsif synapse.category == 'both'
end if synapse.node1_id == id
return self output << synapse.node1_id.to_s + '<->' + synapse.node2_id.to_s
end elsif synapse.node2_id == id
output << synapse.node2_id.to_s + '<->' + synapse.node1_id.to_s
# returns false if user not allowed to 'edit' Topic, Synapse, or Map else
def authorize_to_edit(user) fail 'invalid synapse on topic in synapse_csv'
if (self.permission == "private" && self.user != user) end
return false end
elsif (self.permission == "public" && self.user != user) end
return false if output_format == 'array'
end return output
return self elsif output_format == 'text'
end return output.join('; ')
else
def authorize_to_delete(user) fail 'invalid argument to synapses_csv'
if (self.user == user || user.admin) end
return self output
end end
return false
end def topic_autocomplete_method
end "Get: #{self.name}"
end
def mk_permission
Perm.short(permission)
end
end

View file

@ -6,13 +6,14 @@ class User < ActiveRecord::Base
has_many :synapses has_many :synapses
has_many :maps has_many :maps
has_many :mappings has_many :mappings
has_many :tokens
after_create :generate_code after_create :generate_code
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :registerable devise :database_authenticatable, :recoverable, :rememberable, :trackable, :registerable
serialize :settings, UserPreference serialize :settings, UserPreference
validates :password, :presence => true, validates :password, :presence => true,
:length => { :within => 8..40 }, :length => { :within => 8..40 },
:on => :create :on => :create
@ -27,7 +28,7 @@ class User < ActiveRecord::Base
validates_uniqueness_of :email # done by devise validates_uniqueness_of :email # done by devise
validates :joinedwithcode, :presence => true, :inclusion => { :in => $codes, :message => "%{value} is not valid" }, :on => :create validates :joinedwithcode, :presence => true, :inclusion => { :in => $codes, :message => "%{value} is not valid" }, :on => :create
# This method associates the attribute ":image" with a file attachment # This method associates the attribute ":image" with a file attachment
has_attached_file :image, :styles => { has_attached_file :image, :styles => {
:thirtytwo => ['32x32#', :png], :thirtytwo => ['32x32#', :png],
@ -36,7 +37,7 @@ class User < ActiveRecord::Base
:onetwentyeight => ['128x128#', :png] :onetwentyeight => ['128x128#', :png]
}, },
:default_url => 'https://s3.amazonaws.com/metamaps-assets/site/user.png' :default_url => 'https://s3.amazonaws.com/metamaps-assets/site/user.png'
# Validate the attached image is image/jpg, image/png, etc # Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/ validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
@ -61,7 +62,7 @@ class User < ActiveRecord::Base
json['rtype'] = "mapper" json['rtype'] = "mapper"
json json
end end
#generate a random 8 letter/digit code that they can use to invite people #generate a random 8 letter/digit code that they can use to invite people
def generate_code def generate_code
self.code ||= rand(36**8).to_s(36) self.code ||= rand(36**8).to_s(36)
@ -76,7 +77,7 @@ class User < ActiveRecord::Base
update(generation: User.find_by_code(joinedwithcode).generation + 1) update(generation: User.find_by_code(joinedwithcode).generation + 1)
end end
end end
def settings def settings
# make sure we always return a UserPreference instance # make sure we always return a UserPreference instance
if read_attribute(:settings).nil? if read_attribute(:settings).nil?
@ -84,7 +85,7 @@ class User < ActiveRecord::Base
end end
read_attribute :settings read_attribute :settings
end end
def settings=(val) def settings=(val)
write_attribute :settings, val write_attribute :settings, val
end end

View file

@ -1,11 +1,11 @@
class UserPreference class UserPreference
attr_accessor :metacodes attr_accessor :metacodes
def initialize def initialize
array = [] array = []
Metacode.all.each do |m| Metacode.all.each do |m|
array.push(m.id.to_s) array.push(m.id.to_s)
end end
@metacodes = array @metacodes = array
end end
end end

13
app/models/webhook.rb Normal file
View file

@ -0,0 +1,13 @@
class Webhook < ActiveRecord::Base
belongs_to :hookable, polymorphic: true
validates :uri, presence: true
validates :hookable, presence: true
validates_inclusion_of :kind, in: %w[slack]
validates :event_types, length: { minimum: 1 }
def headers
{}
end
end

View file

@ -0,0 +1,72 @@
Webhooks::Slack::Base = Struct.new(:event) do
include Routing
def username
"Metamaps Bot"
end
def icon_url
"https://pbs.twimg.com/profile_images/539300245029392385/dJ1bwnw7.jpeg"
end
def text
"something"
end
def attachments
[{
title: attachment_title,
text: attachment_text,
fields: attachment_fields,
fallback: attachment_fallback
}]
end
alias :read_attribute_for_serialization :send
private
#def motion_vote_field
# {
# title: "Vote on this proposal",
# value: "#{proposal_link(eventable, "yes")} · " +
# "#{proposal_link(eventable, "abstain")} · " +
# "#{proposal_link(eventable, "no")} · " +
# "#{proposal_link(eventable, "block")}"
# }
#end
def view_map_on_metamaps(text = nil)
"<#{map_url(eventable.map)}|#{text || eventable.map.name}>"
end
#def view_discussion_on_loomio(params = {})
# { value: discussion_link(I18n.t(:"webhooks.slack.view_it_on_loomio"), params) }
#end
#def proposal_link(proposal, position = nil)
# discussion_link position || proposal.name, { proposal: proposal.key, position: position }
#end
#def discussion_link(text = nil, params = {})
# "<#{discussion_url(eventable.map, params)}|#{text || eventable.discussion.title}>"
#end
def eventable
@eventable ||= event.eventable
end
def author
@author ||= eventable.author
end
end
#webhooks:
# slack:
# motion_closed: "*%{name}* has closed"
# motion_closing_soon: "*%{name}* has a proposal closing in 24 hours"
# motion_outcome_created: "*%{author}* published an outcome in *%{name}*"
# motion_outcome_updated: "*%{author}* updated the outcome for *%{name}*"
# new_motion: "*%{author}* started a new proposal in *%{name}*"
# view_it_on_loomio: "View it on Loomio"

View file

@ -0,0 +1,26 @@
class Webhooks::Slack::SynapseAddedToMap < Webhooks::Slack::Base
def text
"\"*#{eventable.mappable.topic1.name}* #{eventable.mappable.desc || '->'} *#{eventable.mappable.topic2.name}*\" was added as a connection to the map *#{view_map_on_metamaps()}*"
end
def attachment_fallback
"" #{}"*#{eventable.name}*\n#{eventable.description}\n"
end
def attachment_title
"" #proposal_link(eventable)
end
def attachment_text
"" # "#{eventable.description}\n"
end
def attachment_fields
[{
title: "nothing",
value: "nothing"
}] #[motion_vote_field]
end
end

View file

@ -0,0 +1,27 @@
class Webhooks::Slack::TopicAddedToMap < Webhooks::Slack::Base
def text
"New #{eventable.mappable.metacode.name} topic *#{eventable.mappable.name}* was added to the map *#{view_map_on_metamaps()}*"
end
# todo: it would be sweet if it sends it with the metacode as the icon_url
def attachment_fallback
"" #{}"*#{eventable.name}*\n#{eventable.description}\n"
end
def attachment_title
"" #proposal_link(eventable)
end
def attachment_text
"" # "#{eventable.description}\n"
end
def attachment_fields
[{
title: "nothing",
value: "nothing"
}] #[motion_vote_field]
end
end

View file

@ -0,0 +1,61 @@
class ApplicationPolicy
attr_reader :user, :record
def initialize(user, record)
@user = user
@record = record
end
def index?
false
end
def show?
scope.where(:id => record.id).exists?
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
# TODO update this function to enable some flag in the interface
# so that admins usually can't do super admin stuff unless they
# explicitly say they want to (E.g. seeing/editing/deleting private
# maps - they should be able to, but not by accident)
def admin_override
user && user.admin
end
def scope
Pundit.policy_scope!(user, record.class)
end
class Scope
attr_reader :user, :scope
def initialize(user, scope)
@user = user
@scope = scope
end
def resolve
scope
end
end
end

View file

@ -0,0 +1,26 @@
class MainPolicy < ApplicationPolicy
def initialize(user, record)
@user = user
@record = nil
end
def home?
true
end
def searchtopics?
true
end
def searchmaps?
true
end
def searchmappers?
true
end
def searchsynapses?
true
end
end

View file

@ -0,0 +1,57 @@
class MapPolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = ['public', 'commons']
permission = 'maps.permission IN (?)'
if user
scope.where(permission + ' OR maps.user_id = ?', visible, user.id)
else
scope.where(permission, visible)
end
end
end
def activemaps?
user.blank? # redirect to root url if authenticated for some reason
end
def featuredmaps?
true
end
def mymaps?
user.present?
end
def usermaps?
true
end
def show?
record.permission == 'commons' || record.permission == 'public' || record.user == user
end
def export?
show?
end
def contains?
show?
end
def create?
user.present?
end
def update?
user.present? && (record.permission == 'commons' || record.user == user)
end
def screenshot?
update?
end
def destroy?
record.user == user || admin_override
end
end

View file

@ -0,0 +1,43 @@
class MappingPolicy < ApplicationPolicy
class Scope < Scope
def resolve
# TODO base this on the map policy
# it would be nice if we could also base this on the mappable, but that
# gets really complicated. Devin thinks it's OK to SHOW a mapping for
# a private topic, since you can't see the private topic anyways
visible = ['public', 'commons']
permission = 'maps.permission IN (?)'
if user
scope.joins(:maps).where(permission + ' OR maps.user_id = ?', visible, user.id)
else
scope.where(permission, visible)
end
end
end
def show?
map_policy.show? && mappable_policy.show?
end
def create?
record.map.present? && map_policy.update?
end
def update?
record.mappable_type == 'Topic' && map_policy.update?
end
def destroy?
map_policy.update? || admin_override
end
# Helpers
def map_policy
@map_policy ||= Pundit.policy(user, record.map)
end
def mappable_policy
@mappable_policy ||= Pundit.policy(user, record.mappable)
end
end

View file

@ -0,0 +1,36 @@
class MessagePolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = ['public', 'commons']
permission = 'maps.permission IN (?)'
if user
scope.joins(:maps).where(permission + ' OR maps.user_id = ?', visible, user.id)
else
scope.where(permission, visible)
end
end
end
def show?
resource_policy.show?
end
def create?
record.resource.present? && resource_policy.update?
end
def update?
record.user == user
end
def destroy?
record.user == user || admin_override
end
# Helpers
def resource_policy
@resource_policy ||= Pundit.policy(user, record.resource)
end
end

View file

@ -0,0 +1,30 @@
class SynapsePolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = ['public', 'commons']
permission = 'synapses.permission IN (?)'
if user
scope.where(permission + ' OR synapses.user_id = ?', visible, user.id)
else
scope.where(permission, visible)
end
end
end
def create?
user.present?
# todo add validation against whether you can see both topics
end
def show?
record.permission == 'commons' || record.permission == 'public' || record.user == user
end
def update?
user.present? && (record.permission == 'commons' || record.user == user)
end
def destroy?
record.user == user || admin_override
end
end

View file

@ -0,0 +1,24 @@
class TokenPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user
scope.where('tokens.user_id = ?', user.id)
else
where(:id => nil).where("id IS NOT ?", nil) # to just return none
end
end
end
def create?
user.present?
end
def my_tokens?
user.present?
end
def destroy?
user.present? && record.user == user
end
end

View file

@ -0,0 +1,45 @@
class TopicPolicy < ApplicationPolicy
class Scope < Scope
def resolve
visible = ['public', 'commons']
permission = 'topics.permission IN (?)'
if user
scope.where(permission + ' OR topics.user_id = ?', visible, user.id)
else
scope.where(permission, visible)
end
end
end
def create?
user.present?
end
def show?
record.permission == 'commons' || record.permission == 'public' || record.user == user
end
def update?
user.present? && (record.permission == 'commons' || record.user == user)
end
def destroy?
record.user == user || admin_override
end
def autocomplete_topic?
user.present?
end
def network?
show?
end
def relative_numbers?
show?
end
def relatives?
show?
end
end

View file

@ -0,0 +1,15 @@
class EventSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :id, :sequence_id, :kind, :map_id, :created_at
has_one :actor, serializer: NewUserSerializer, root: 'users'
has_one :map, serializer: NewMapSerializer
def actor
object.user || object.eventable.try(:user)
end
def map
object.eventable.try(:map) || object.eventable.map
end
end

View file

@ -0,0 +1,16 @@
class NewMapSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :id,
:name,
:desc,
:permission,
:screenshot,
:created_at,
:updated_at
has_many :topics, serializer: NewTopicSerializer
has_many :synapses, serializer: NewSynapseSerializer
has_many :mappings, serializer: NewMappingSerializer
has_many :contributors, root: :users, serializer: NewUserSerializer
end

View file

@ -0,0 +1,19 @@
class NewMappingSerializer < ActiveModel::Serializer
embed :ids, include: true
attributes :id,
:xloc,
:yloc,
:created_at,
:updated_at,
:mappable_id,
:mappable_type
has_one :user, serializer: NewUserSerializer
has_one :map, serializer: NewMapSerializer
def filter(keys)
keys.delete(:xloc) unless object.mappable_type == "Topic"
keys.delete(:yloc) unless object.mappable_type == "Topic"
keys
end
end

View file

@ -0,0 +1,7 @@
class NewMetacodeSerializer < ActiveModel::Serializer
attributes :id,
:name,
:manual_icon,
:color,
:aws_icon
end

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