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 fbba487b83
193 changed files with 47993 additions and 30125 deletions

3
.gitignore vendored
View file

@ -7,6 +7,7 @@
#assety stuff
realtime/node_modules
public/assets
public/metamaps_mobile
vendor/
#secrets and config
@ -19,6 +20,8 @@ vendor/
log/*.log
tmp
coverage
.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 'redis'
gem 'pg'
gem 'cancancan'
gem 'pundit'
gem 'pundit_extra'
gem 'doorkeeper'
gem 'formula'
gem 'formtastic'
gem 'json'
@ -15,6 +17,11 @@ gem 'best_in_place' #in-place editing
gem 'kaminari' # pagination
gem 'uservoice-ruby'
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 'aws-sdk', '< 2.0'
@ -42,6 +49,8 @@ group :test do
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'shoulda-matchers'
gem 'simplecov', require: false
gem 'json-schema'
end
group :production do #this is used on heroku

View file

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

View file

@ -1 +1,3 @@
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)
![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
@ -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.
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].
@ -52,7 +52,7 @@ We haven't figured out Vagrant for Windows yet, but we have a set of manual inst
## 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

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 postgresql -y
sudo apt-get install libpq-dev -y
sudo apt-get install redis-server -y
# get imagemagick
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
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require ./orderedLibraries/underscore
//= require ./orderedLibraries/backbone
//= require_directory ./lib
//= require ./src/Metamaps.GlobalUI
//= require ./src/Metamaps.Router
//= require ./src/Metamaps.Backbone
//= require ./src/Metamaps.Views
//= require ./src/JIT
//= require ./src/Metamaps
//= require ./src/Metamaps.JIT
//= require_directory ./shims
//= require_directory ./require
//= require_directory ./famous
// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
// GO AFTER THE REQUIRES BELOW.
//
//= require jquery
//= require jquery-ui
//= require jquery_ujs
//= require ./orderedLibraries/underscore
//= require ./orderedLibraries/backbone
//= require_directory ./lib
//= require ./src/Metamaps.GlobalUI
//= require ./src/Metamaps.Router
//= require ./src/Metamaps.Backbone
//= require ./src/Metamaps.Views
//= require ./src/views/chatView
//= require ./src/views/videoView
//= require ./src/views/room
//= require ./src/JIT
//= require ./src/Metamaps
//= 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
// (c) 2011 by R Cecco. <http://www.professorcloud.com>
// MIT License
//
// Reflection code based on plugin by Christophe Beyls <http://www.digitalia.be>
//
// Please retain this copyright header in all versions of the software
//////////////////////////////////////////////////////////////////////////////////
var matched, browser;
jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
matched = jQuery.uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
jQuery.browser = browser;
(function($) {
// START Reflection object.
// Creates a reflection for underneath an image.
// 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.
function Reflection(img, reflHeight, opacity) {
var reflection, cntx, imageWidth = img.width, imageHeight = img.width, gradient, parent;
parent = $(img.parentNode);
this.element = reflection = parent.append("<canvas class='reflection' style='position:absolute'/>").find(':last')[0];
if ( !reflection.getContext && $.browser.msie) {
this.element = reflection = parent.append("<img class='reflection' style='position:absolute'/>").find(':last')[0];
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) + ")";
} else {
cntx = reflection.getContext("2d");
try {
$(reflection).attr({width: imageWidth, height: reflHeight});
cntx.save();
cntx.translate(0, imageHeight-1);
cntx.scale(1, -1);
cntx.drawImage(img, 0, 0, imageWidth, imageHeight);
cntx.restore();
cntx.globalCompositeOperation = "destination-out";
gradient = cntx.createLinearGradient(0, 0, 0, reflHeight);
gradient.addColorStop(0, "rgba(255, 255, 255, " + (1 - opacity) + ")");
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
cntx.fillStyle = gradient;
cntx.fillRect(0, 0, imageWidth, reflHeight);
} catch(e) {
return;
}
}
// Store a copy of the alt and title attrs into the reflection
$(reflection).attr({ 'alt': $(img).attr('alt'), title: $(img).attr('title')} );
} //END Reflection object
// START Item object.
// A wrapper object for items within the carousel.
var Item = function(imgIn, options)
{
this.orgWidth = imgIn.width;
this.orgHeight = imgIn.height;
this.image = imgIn;
this.reflection = null;
this.alt = imgIn.alt;
this.title = imgIn.title;
this.imageOK = false;
this.options = options;
this.imageOK = true;
if (this.options.reflHeight > 0)
{
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!
};// END Item object
// Controller object.
// This handles moving all the items, dealing with mouse clicks etc.
var Controller = function(container, images, options)
{
var items = [], funcSin = Math.sin, funcCos = Math.cos, ctx=this;
this.controlTimer = 0;
this.stopped = false;
//this.imagesLoaded = 0;
this.container = container;
this.xRadius = options.xRadius;
this.yRadius = options.yRadius;
this.showFrontTextTimer = 0;
this.autoRotateTimer = 0;
if (options.xRadius === 0)
{
this.xRadius = ($(container).width()/2.3);
}
if (options.yRadius === 0)
{
this.yRadius = ($(container).height()/6);
}
this.xCentre = options.xPos;
this.yCentre = options.yPos;
this.frontIndex = 0; // Index of the item at the front
// Start with the first item at the front.
this.rotation = this.destRotation = Math.PI/2;
this.timeDelay = 1000/options.FPS;
// Turn on the infoBox
if(options.altBox !== null)
{
$(options.altBox).css('display','block');
$(options.titleBox).css('display','block');
}
// Turn on relative position for container to allow absolutely positioned elements
// within it to work.
$(container).css({ position:'relative', overflow:'hidden'} );
$(options.buttonLeft).css('display','inline');
$(options.buttonRight).css('display','inline');
// Setup the buttons.
$(options.buttonLeft).bind('mouseup',this,function(event){
event.data.rotate(-1);
return false;
});
$(options.buttonRight).bind('mouseup',this,function(event){
event.data.rotate(1);
return false;
});
// Add code that makes tab and shift+tab scroll through metacodes
$('.new_topic').bind('keydown',this,function(event){
if (event.keyCode == 9 && event.shiftKey) {
event.data.rotate(-1);
event.preventDefault();
event.stopPropagation();
} else if (event.keyCode == 9) {
event.data.rotate(1);
event.preventDefault();
event.stopPropagation();
}
});
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
if (options.mouseWheel)
{
// START METAMAPS CODE
$('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) {
event.data.rotate(delta);
return false;
}
});
// END METAMAPS CODE
/* ORIGINAL CODE
$(container).bind('mousewheel',this,function(event, delta) {
event.data.rotate(delta);
return false;
});
*/
}
$(container).bind('mouseover click',this,function(event){
clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over.
var text = $(event.target).attr('alt');
// If we have moved over a carousel item, then show the alt and title text.
if ( text !== undefined && text !== null )
{
clearTimeout(event.data.showFrontTextTimer);
$(options.altBox).html( ($(event.target).attr('alt') ));
//$(options.titleBox).html( ($(event.target).attr('title') ));
if ( options.bringToFront && event.type == 'click' )
{
$(options.titleBox).html( ($(event.target).attr('title') ));
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
// NOT METAMAPS CODE
var idx = $(event.target).data('itemIndex');
var frontIndex = event.data.frontIndex;
//var diff = idx - frontIndex;
var diff = (idx - frontIndex) % images.length;
if (Math.abs(diff) > images.length / 2) {
diff += (diff > 0 ? -images.length : images.length);
}
event.data.rotate(-diff);
}
}
});
// If we have moved out of a carousel item (or the container itself),
// restore the text of the front item in 1 second.
$(container).bind('mouseout',this,function(event){
var context = event.data;
clearTimeout(context.showFrontTextTimer);
context.showFrontTextTimer = setTimeout( function(){context.showFrontText();},1000);
context.autoRotate(); // Start auto rotation.
});
// Prevent items from being selected as mouse is moved and clicked in the container.
$(container).bind('mousedown',this,function(event){
event.data.container.focus();
return false;
});
container.onselectstart = function () { return false; }; // For IE.
this.innerWrapper = $(container).wrapInner('<div style="position:absolute;width:100%;height:100%;"/>').children()[0];
// Shows the text from the front most item.
this.showFrontText = function()
{
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('data-id');
//$('img.cloudcarousel').css({"background":"none", "width":"","height":""});
//$(items[this.frontIndex].image).css({"width":"45px","height":"45px"});
// NOT METAMAPS CODE
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
};
this.go = function()
{
if(this.controlTimer !== 0) { return; }
var context = this;
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
};
this.stop = function()
{
clearTimeout(this.controlTimer);
this.controlTimer = 0;
};
// Starts the rotation of the carousel. Direction is the number (+-) of carousel items to rotate by.
this.rotate = function(direction)
{
this.frontIndex -= direction;
if (this.frontIndex == -1) this.frontIndex = items.length - 1;
this.frontIndex %= items.length;
this.destRotation += ( Math.PI / items.length ) * ( 2*direction );
this.showFrontText();
this.go();
};
this.autoRotate = function()
{
if ( options.autoRotate !== 'no' )
{
var dir = (options.autoRotate === 'right')? 1 : -1;
this.autoRotateTimer = setInterval( function(){ctx.rotate(dir); }, options.autoRotateDelay );
}
};
// This is the main loop function that moves everything.
this.updateAll = function()
{
var minScale = options.minScale; // This is the smallest scale applied to the furthest item.
var smallRange = (1-minScale) * 0.5;
var w,h,x,y,scale,item,sinVal;
var change = (this.destRotation - this.rotation);
var absChange = Math.abs(change);
this.rotation += change * options.speed;
if ( absChange < 0.001 ) { this.rotation = this.destRotation; }
var itemsLen = items.length;
var spacing = (Math.PI / itemsLen) * 2;
//var wrapStyle = null;
var radians = this.rotation;
var isMSIE = $.browser.msie;
// 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
this.innerWrapper.style.display = 'none';
var style;
var px = 'px', reflHeight;
var context = this;
for (var i = 0; i<itemsLen ;i++)
{
item = items[i];
sinVal = funcSin(radians);
scale = ((sinVal+1) * smallRange) + minScale;
x = this.xCentre + (( (funcCos(radians) * this.xRadius) - (item.orgWidth*0.5)) * scale);
y = this.yCentre + (( (sinVal * this.yRadius) ) * scale);
if (item.imageOK)
{
var img = item.image;
img.style.zIndex = "" + (scale * 100)>>0; // >>0 = Math.foor(). Firefox doesn't like fractional decimals in z-index.
w = img.width = item.orgWidth * scale;
h = img.height = item.orgHeight * scale;
img.style.left = x + px ;
img.style.top = y + px;
if (item.reflection !== null)
{
reflHeight = options.reflHeight * scale;
style = item.reflection.element.style;
style.left = x + px;
style.top = y + h + options.reflGap * scale + px;
style.width = w + px;
if (isMSIE)
{
style.filter.finishy = (reflHeight / h * 100);
}else
{
style.height = reflHeight + px;
}
}
}
radians += spacing;
}
// Turn display back on.
this.innerWrapper.style.display = 'block';
// If we have a preceptable change in rotation then loop again next frame.
if ( absChange >= 0.001 )
{
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
}else
{
// Otherwise just stop completely.
this.stop();
}
}; // END updateAll
// Create an Item object for each image
// func = function(){return;ctx.updateAll();} ;
// Check if images have loaded. We need valid widths and heights for the reflections.
this.checkImagesLoaded = function()
{
var i;
for(i=0;i<images.length;i++) {
if ( (images[i].width === undefined) || ( (images[i].complete !== undefined) && (!images[i].complete) ))
{
return;
}
}
for(i=0;i<images.length;i++) {
items.push( new Item( images[i], options ) );
$(images[i]).data('itemIndex',i);
}
// If all images have valid widths and heights, we can stop checking.
clearInterval(this.tt);
this.showFrontText();
this.autoRotate();
this.updateAll();
};
this.tt = setInterval( function(){ctx.checkImagesLoaded();},50);
}; // END Controller object
// The jQuery plugin part. Iterates through items specified in selector and inits a Controller class for each one.
$.fn.CloudCarousel = function(options) {
this.each( function() {
options = $.extend({}, {
reflHeight:0,
reflOpacity:0.5,
reflGap:0,
minScale:0.5,
xPos:0,
yPos:0,
xRadius:0,
yRadius:0,
altBox:null,
titleBox:null,
FPS: 30,
autoRotate: 'no',
autoRotateDelay: 1500,
speed:0.2,
mouseWheel: false,
bringToFront: false
},options );
// Create a Controller for each carousel.
$(this).data('cloudcarousel', new Controller( this, $('.cloudcarousel',$(this)), options) );
});
return this;
};
//////////////////////////////////////////////////////////////////////////////////
// CloudCarousel V1.0.5
// (c) 2011 by R Cecco. <http://www.professorcloud.com>
// MIT License
//
// Reflection code based on plugin by Christophe Beyls <http://www.digitalia.be>
//
// Please retain this copyright header in all versions of the software
//////////////////////////////////////////////////////////////////////////////////
var matched, browser;
jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
matched = jQuery.uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
jQuery.browser = browser;
(function($) {
// START Reflection object.
// Creates a reflection for underneath an image.
// 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.
function Reflection(img, reflHeight, opacity) {
var reflection, cntx, imageWidth = img.width, imageHeight = img.width, gradient, parent;
parent = $(img.parentNode);
this.element = reflection = parent.append("<canvas class='reflection' style='position:absolute'/>").find(':last')[0];
if ( !reflection.getContext && $.browser.msie) {
this.element = reflection = parent.append("<img class='reflection' style='position:absolute'/>").find(':last')[0];
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) + ")";
} else {
cntx = reflection.getContext("2d");
try {
$(reflection).attr({width: imageWidth, height: reflHeight});
cntx.save();
cntx.translate(0, imageHeight-1);
cntx.scale(1, -1);
cntx.drawImage(img, 0, 0, imageWidth, imageHeight);
cntx.restore();
cntx.globalCompositeOperation = "destination-out";
gradient = cntx.createLinearGradient(0, 0, 0, reflHeight);
gradient.addColorStop(0, "rgba(255, 255, 255, " + (1 - opacity) + ")");
gradient.addColorStop(1, "rgba(255, 255, 255, 1.0)");
cntx.fillStyle = gradient;
cntx.fillRect(0, 0, imageWidth, reflHeight);
} catch(e) {
return;
}
}
// Store a copy of the alt and title attrs into the reflection
$(reflection).attr({ 'alt': $(img).attr('alt'), title: $(img).attr('title')} );
} //END Reflection object
// START Item object.
// A wrapper object for items within the carousel.
var Item = function(imgIn, options)
{
this.orgWidth = imgIn.width;
this.orgHeight = imgIn.height;
this.image = imgIn;
this.reflection = null;
this.alt = imgIn.alt;
this.title = imgIn.title;
this.imageOK = false;
this.options = options;
this.imageOK = true;
if (this.options.reflHeight > 0)
{
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!
};// END Item object
// Controller object.
// This handles moving all the items, dealing with mouse clicks etc.
var Controller = function(container, images, options)
{
var items = [], funcSin = Math.sin, funcCos = Math.cos, ctx=this;
this.controlTimer = 0;
this.stopped = false;
//this.imagesLoaded = 0;
this.container = container;
this.xRadius = options.xRadius;
this.yRadius = options.yRadius;
this.showFrontTextTimer = 0;
this.autoRotateTimer = 0;
if (options.xRadius === 0)
{
this.xRadius = ($(container).width()/2.3);
}
if (options.yRadius === 0)
{
this.yRadius = ($(container).height()/6);
}
this.xCentre = options.xPos;
this.yCentre = options.yPos;
this.frontIndex = 0; // Index of the item at the front
// Start with the first item at the front.
this.rotation = this.destRotation = Math.PI/2;
this.timeDelay = 1000/options.FPS;
// Turn on the infoBox
if(options.altBox !== null)
{
$(options.altBox).css('display','block');
$(options.titleBox).css('display','block');
}
// Turn on relative position for container to allow absolutely positioned elements
// within it to work.
$(container).css({ position:'relative', overflow:'hidden'} );
$(options.buttonLeft).css('display','inline');
$(options.buttonRight).css('display','inline');
// Setup the buttons.
$(options.buttonLeft).bind('mouseup',this,function(event){
event.data.rotate(-1);
return false;
});
$(options.buttonRight).bind('mouseup',this,function(event){
event.data.rotate(1);
return false;
});
// Add code that makes tab and shift+tab scroll through metacodes
$('.new_topic').bind('keydown',this,function(event){
if (event.keyCode == 9 && event.shiftKey) {
event.data.rotate(-1);
event.preventDefault();
event.stopPropagation();
} else if (event.keyCode == 9) {
event.data.rotate(1);
event.preventDefault();
event.stopPropagation();
}
});
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
if (options.mouseWheel)
{
// START METAMAPS CODE
$('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) {
event.data.rotate(delta);
return false;
}
});
// END METAMAPS CODE
/* ORIGINAL CODE
$(container).bind('mousewheel',this,function(event, delta) {
event.data.rotate(delta);
return false;
});
*/
}
$(container).bind('mouseover click',this,function(event){
clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over.
var text = $(event.target).attr('alt');
// If we have moved over a carousel item, then show the alt and title text.
if ( text !== undefined && text !== null )
{
clearTimeout(event.data.showFrontTextTimer);
$(options.altBox).html( ($(event.target).attr('alt') ));
//$(options.titleBox).html( ($(event.target).attr('title') ));
if ( options.bringToFront && event.type == 'click' )
{
$(options.titleBox).html( ($(event.target).attr('title') ));
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
// NOT METAMAPS CODE
var idx = $(event.target).data('itemIndex');
var frontIndex = event.data.frontIndex;
//var diff = idx - frontIndex;
var diff = (idx - frontIndex) % images.length;
if (Math.abs(diff) > images.length / 2) {
diff += (diff > 0 ? -images.length : images.length);
}
event.data.rotate(-diff);
}
}
});
// If we have moved out of a carousel item (or the container itself),
// restore the text of the front item in 1 second.
$(container).bind('mouseout',this,function(event){
var context = event.data;
clearTimeout(context.showFrontTextTimer);
context.showFrontTextTimer = setTimeout( function(){context.showFrontText();},1000);
context.autoRotate(); // Start auto rotation.
});
// Prevent items from being selected as mouse is moved and clicked in the container.
$(container).bind('mousedown',this,function(event){
event.data.container.focus();
return false;
});
container.onselectstart = function () { return false; }; // For IE.
this.innerWrapper = $(container).wrapInner('<div style="position:absolute;width:100%;height:100%;"/>').children()[0];
// Shows the text from the front most item.
this.showFrontText = function()
{
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('data-id');
//$('img.cloudcarousel').css({"background":"none", "width":"","height":""});
//$(items[this.frontIndex].image).css({"width":"45px","height":"45px"});
// NOT METAMAPS CODE
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
};
this.go = function()
{
if(this.controlTimer !== 0) { return; }
var context = this;
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
};
this.stop = function()
{
clearTimeout(this.controlTimer);
this.controlTimer = 0;
};
// Starts the rotation of the carousel. Direction is the number (+-) of carousel items to rotate by.
this.rotate = function(direction)
{
this.frontIndex -= direction;
if (this.frontIndex == -1) this.frontIndex = items.length - 1;
this.frontIndex %= items.length;
this.destRotation += ( Math.PI / items.length ) * ( 2*direction );
this.showFrontText();
this.go();
};
this.autoRotate = function()
{
if ( options.autoRotate !== 'no' )
{
var dir = (options.autoRotate === 'right')? 1 : -1;
this.autoRotateTimer = setInterval( function(){ctx.rotate(dir); }, options.autoRotateDelay );
}
};
// This is the main loop function that moves everything.
this.updateAll = function()
{
var minScale = options.minScale; // This is the smallest scale applied to the furthest item.
var smallRange = (1-minScale) * 0.5;
var w,h,x,y,scale,item,sinVal;
var change = (this.destRotation - this.rotation);
var absChange = Math.abs(change);
this.rotation += change * options.speed;
if ( absChange < 0.001 ) { this.rotation = this.destRotation; }
var itemsLen = items.length;
var spacing = (Math.PI / itemsLen) * 2;
//var wrapStyle = null;
var radians = this.rotation;
var isMSIE = $.browser.msie;
// 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
this.innerWrapper.style.display = 'none';
var style;
var px = 'px', reflHeight;
var context = this;
for (var i = 0; i<itemsLen ;i++)
{
item = items[i];
sinVal = funcSin(radians);
scale = ((sinVal+1) * smallRange) + minScale;
x = this.xCentre + (( (funcCos(radians) * this.xRadius) - (item.orgWidth*0.5)) * scale);
y = this.yCentre + (( (sinVal * this.yRadius) ) * scale);
if (item.imageOK)
{
var img = item.image;
img.style.zIndex = "" + (scale * 100)>>0; // >>0 = Math.foor(). Firefox doesn't like fractional decimals in z-index.
w = img.width = item.orgWidth * scale;
h = img.height = item.orgHeight * scale;
img.style.left = x + px ;
img.style.top = y + px;
if (item.reflection !== null)
{
reflHeight = options.reflHeight * scale;
style = item.reflection.element.style;
style.left = x + px;
style.top = y + h + options.reflGap * scale + px;
style.width = w + px;
if (isMSIE)
{
style.filter.finishy = (reflHeight / h * 100);
}else
{
style.height = reflHeight + px;
}
}
}
radians += spacing;
}
// Turn display back on.
this.innerWrapper.style.display = 'block';
// If we have a preceptable change in rotation then loop again next frame.
if ( absChange >= 0.001 )
{
this.controlTimer = setTimeout( function(){context.updateAll();},this.timeDelay);
}else
{
// Otherwise just stop completely.
this.stop();
}
}; // END updateAll
// Create an Item object for each image
// func = function(){return;ctx.updateAll();} ;
// Check if images have loaded. We need valid widths and heights for the reflections.
this.checkImagesLoaded = function()
{
var i;
for(i=0;i<images.length;i++) {
if ( (images[i].width === undefined) || ( (images[i].complete !== undefined) && (!images[i].complete) ))
{
return;
}
}
for(i=0;i<images.length;i++) {
items.push( new Item( images[i], options ) );
$(images[i]).data('itemIndex',i);
}
// If all images have valid widths and heights, we can stop checking.
clearInterval(this.tt);
this.showFrontText();
this.autoRotate();
this.updateAll();
};
this.tt = setInterval( function(){ctx.checkImagesLoaded();},50);
}; // END Controller object
// The jQuery plugin part. Iterates through items specified in selector and inits a Controller class for each one.
$.fn.CloudCarousel = function(options) {
this.each( function() {
options = $.extend({}, {
reflHeight:0,
reflOpacity:0.5,
reflGap:0,
minScale:0.5,
xPos:0,
yPos:0,
xRadius:0,
yRadius:0,
altBox:null,
titleBox:null,
FPS: 30,
autoRotate: 'no',
autoRotateDelay: 1500,
speed:0.2,
mouseWheel: false,
bringToFront: false
},options );
// Create a Controller for each carousel.
$(this).data('cloudcarousel', new Controller( this, $('.cloudcarousel',$(this)), options) );
});
return this;
};
})(jQuery);

File diff suppressed because it is too large Load diff

View file

@ -1,180 +1,180 @@
/**
* jquery.purr.js
* Copyright (c) 2008 Net Perspective (net-perspective.com)
* Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
*
* @author R.A. Ray
* @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
* @version 0.1.0
*
* @requires jquery.js (tested with 1.2.6)
*
* @param fadeInSpeed int - Duration of fade in animation in miliseconds
* default: 500
* @param fadeOutSpeed int - Duration of fade out animationin miliseconds
default: 500
* @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
default: 4000
* @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed
default: false
* @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling
default: false
*/
( function( $ ) {
$.purr = function ( notice, options )
{
// Convert notice to a jQuery object
notice = $( notice );
// Add a class to denote the notice as not sticky
if ( !options.isSticky )
{
notice.addClass( 'not-sticky' );
};
// Get the container element from the page
var cont = document.getElementById( 'purr-container' );
// If the container doesn't yet exist, we need to create it
if ( !cont )
{
cont = '<div id="purr-container"></div>';
}
// Convert cont to a jQuery object
cont = $( cont );
// Add the container to the page
$( 'body' ).append( cont );
notify();
function notify ()
{
// Set up the close button
var close = document.createElement( 'a' );
$( close ).attr(
{
className: 'close',
href: '#close',
innerHTML: 'Close'
}
)
.appendTo( notice )
.click( function ()
{
removeNotice();
return false;
}
);
// Add the notice to the page and keep it hidden initially
notice.appendTo( cont )
.hide();
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
// notice style, we'll just skip the fading in.
notice.show();
}
else
{
//Fade in the notice we just added
notice.fadeIn( options.fadeInSpeed );
}
// Set up the removal interval for the added notice if that notice is not a sticky
if ( !options.isSticky )
{
var topSpotInt = setInterval( function ()
{
// Check to see if our notice is the first non-sticky notice in the list
if ( notice.prevAll( '.not-sticky' ).length == 0 )
{
// Stop checking once the condition is met
clearInterval( topSpotInt );
// Call the close action after the timeout set in options
setTimeout( function ()
{
removeNotice();
}, options.removeTimer
);
}
}, 200 );
}
}
function removeNotice ()
{
// 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.
if ( jQuery.browser.msie && options.usingTransparentPNG )
{
notice.css( { opacity: 0 } )
.animate(
{
height: '0px'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.remove();
}
}
);
}
else
{
// Fade the object out before reducing its height to produce the sliding effect
notice.animate(
{
opacity: '0'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.animate(
{
height: '0px'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.remove();
}
}
);
}
}
);
}
};
};
$.fn.purr = function ( options )
{
options = options || {};
options.fadeInSpeed = options.fadeInSpeed || 500;
options.fadeOutSpeed = options.fadeOutSpeed || 500;
options.removeTimer = options.removeTimer || 4000;
options.isSticky = options.isSticky || false;
options.usingTransparentPNG = options.usingTransparentPNG || false;
this.each( function()
{
new $.purr( this, options );
}
);
return this;
};
})( jQuery );
/**
* jquery.purr.js
* Copyright (c) 2008 Net Perspective (net-perspective.com)
* Licensed under the MIT License (http://www.opensource.org/licenses/mit-license.php)
*
* @author R.A. Ray
* @projectDescription jQuery plugin for dynamically displaying unobtrusive messages in the browser. Mimics the behavior of the MacOS program "Growl."
* @version 0.1.0
*
* @requires jquery.js (tested with 1.2.6)
*
* @param fadeInSpeed int - Duration of fade in animation in miliseconds
* default: 500
* @param fadeOutSpeed int - Duration of fade out animationin miliseconds
default: 500
* @param removeTimer int - Timeout, in miliseconds, before notice is removed once it is the top non-sticky notice in the list
default: 4000
* @param isSticky bool - Whether the notice should fade out on its own or wait to be manually closed
default: false
* @param usingTransparentPNG bool - Whether or not the notice is using transparent .png images in its styling
default: false
*/
( function( $ ) {
$.purr = function ( notice, options )
{
// Convert notice to a jQuery object
notice = $( notice );
// Add a class to denote the notice as not sticky
if ( !options.isSticky )
{
notice.addClass( 'not-sticky' );
};
// Get the container element from the page
var cont = document.getElementById( 'purr-container' );
// If the container doesn't yet exist, we need to create it
if ( !cont )
{
cont = '<div id="purr-container"></div>';
}
// Convert cont to a jQuery object
cont = $( cont );
// Add the container to the page
$( 'body' ).append( cont );
notify();
function notify ()
{
// Set up the close button
var close = document.createElement( 'a' );
$( close ).attr(
{
className: 'close',
href: '#close',
innerHTML: 'Close'
}
)
.appendTo( notice )
.click( function ()
{
removeNotice();
return false;
}
);
// Add the notice to the page and keep it hidden initially
notice.appendTo( cont )
.hide();
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
// notice style, we'll just skip the fading in.
notice.show();
}
else
{
//Fade in the notice we just added
notice.fadeIn( options.fadeInSpeed );
}
// Set up the removal interval for the added notice if that notice is not a sticky
if ( !options.isSticky )
{
var topSpotInt = setInterval( function ()
{
// Check to see if our notice is the first non-sticky notice in the list
if ( notice.prevAll( '.not-sticky' ).length == 0 )
{
// Stop checking once the condition is met
clearInterval( topSpotInt );
// Call the close action after the timeout set in options
setTimeout( function ()
{
removeNotice();
}, options.removeTimer
);
}
}, 200 );
}
}
function removeNotice ()
{
// 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.
if ( jQuery.browser.msie && options.usingTransparentPNG )
{
notice.css( { opacity: 0 } )
.animate(
{
height: '0px'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.remove();
}
}
);
}
else
{
// Fade the object out before reducing its height to produce the sliding effect
notice.animate(
{
opacity: '0'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.animate(
{
height: '0px'
},
{
duration: options.fadeOutSpeed,
complete: function ()
{
notice.remove();
}
}
);
}
}
);
}
};
};
$.fn.purr = function ( options )
{
options = options || {};
options.fadeInSpeed = options.fadeInSpeed || 500;
options.fadeOutSpeed = options.fadeOutSpeed || 500;
options.removeTimer = options.removeTimer || 4000;
options.isSticky = options.isSticky || false;
options.usingTransparentPNG = options.usingTransparentPNG || false;
this.each( function()
{
new $.purr( this, options );
}
);
return this;
};
})( 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.Map = Backbone.Model.extend({
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'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist);
},
save: function (key, val, options) {
var attrs;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
var newOptions = options || {};
var s = newOptions.success;
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt);
model.trigger('saved');
};
return Backbone.Model.prototype.save.call(this, attrs, newOptions);
},
initialize: function () {
this.on('changeByOther', this.updateView);
this.on('saved', this.savedEvent);
},
savedEvent: function() {
Metamaps.Realtime.sendMapChange(this);
},
authorizeToEdit: function (mapper) {
if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true;
else return false;
},
authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) return true;
else return false;
},
getUser: function () {
return Metamaps.Mapper.get(this.get('user_id'));
},
fetchContained: function () {
var bb = Metamaps.Backbone;
var that = this;
var start = function (data) {
that.set('mappers', new bb.MapperCollection(data.mappers));
that.set('topics', new bb.TopicCollection(data.topics));
that.set('synapses', new bb.SynapseCollection(data.synapses));
that.set('mappings', new bb.MappingCollection(data.mappings));
};
var e = $.ajax({
url: "/maps/" + this.id + "/contains.json",
success: start,
error: errorFunc,
async: false
});
},
getTopics: function () {
if (!this.get('topics')) {
this.fetchContained();
}
return this.get('topics');
},
getSynapses: function () {
if (!this.get('synapses')) {
this.fetchContained();
}
return this.get('synapses');
},
getMappings: function () {
if (!this.get('mappings')) {
this.fetchContained();
}
return this.get('mappings');
},
getMappers: function () {
if (!this.get('mappers')) {
this.fetchContained();
}
return this.get('mappers');
},
attrForCards: function () {
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var n = this.get('name');
var d = this.get('desc');
var maxNameLength = 32;
var maxDescLength = 118;
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + "..." : n) : "";
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + "..." : d) : "";
var obj = {
id: this.id,
name: truncatedName,
fullName: n,
desc: truncatedDesc,
permission: this.get("permission") ? capitalize(this.get("permission")) : "Commons",
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
contributor_count_string: this.get('contributor_count') == 1 ? ' contributor' : ' contributors',
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
topic_count_string: this.get('topic_count') == 1 ? ' topic' : ' topics',
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
synapse_count_string: this.get('synapse_count') == 1 ? ' synapse' : ' synapses',
screenshot: '<img src="' + this.get('screenshot_url') + '" />'
};
return obj;
},
updateView: function() {
var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) {
Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'));
this.updateMapWrapper();
}
},
updateMapWrapper: function() {
var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) {
$('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap);
}
}
});
Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Map,
initialize: function(models, options) {
this.id = options.id;
this.sortBy = options.sortBy;
if (options.mapperId) {
this.mapperId = options.mapperId;
}
// this.page represents the NEXT page to fetch
this.page = models.length > 0 ? (models.length < 20 ? "loadedAll" : 2) : 1;
},
url: function() {
if (!this.mapperId) {
return '/explore/' + this.id + '.json';
}
else {
return '/explore/mapper/' + this.mapperId + '.json';
}
},
comparator: function (a, b) {
a = a.get(this.sortBy);
b = b.get(this.sortBy);
var temp;
if (this.sortBy === 'name') {
a = a ? a.toLowerCase() : "";
b = b ? b.toLowerCase() : "";
}
else {
// this is for updated_at and created_at
temp = a;
a = b;
b = temp;
a = (new Date(a)).getTime();
b = (new Date(b)).getTime();
}
return a > b ? 1 : a < b ? -1 : 0;
},
getMaps: function (cb) {
var self = this;
Metamaps.Loading.show();
if (this.page != "loadedAll") {
var numBefore = this.length;
this.fetch({
remove: false,
silent: true,
data: { page: this.page },
success: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
if (collection.length - numBefore < 20) {
self.page = "loadedAll";
}
else self.page += 1;
self.trigger('successOnFetch', cb);
},
error: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
self.trigger('errorOnFetch');
}
});
}
else {
self.trigger('successOnFetch', cb);
}
}
});
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'
});
Metamaps.Backbone = {};
Metamaps.Backbone.Map = Backbone.Model.extend({
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'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist);
},
save: function (key, val, options) {
var attrs;
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key;
options = val;
} else {
(attrs = {})[key] = val;
}
var newOptions = options || {};
var s = newOptions.success;
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt);
model.trigger('saved');
};
return Backbone.Model.prototype.save.call(this, attrs, newOptions);
},
initialize: function () {
this.on('changeByOther', this.updateView);
this.on('saved', this.savedEvent);
},
savedEvent: function() {
Metamaps.Realtime.sendMapChange(this);
},
authorizeToEdit: function (mapper) {
if (mapper && (this.get('permission') === "commons" || this.get('user_id') === mapper.get('id'))) return true;
else return false;
},
authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) return true;
else return false;
},
getUser: function () {
return Metamaps.Mapper.get(this.get('user_id'));
},
fetchContained: function () {
var bb = Metamaps.Backbone;
var that = this;
var start = function (data) {
that.set('mappers', new bb.MapperCollection(data.mappers));
that.set('topics', new bb.TopicCollection(data.topics));
that.set('synapses', new bb.SynapseCollection(data.synapses));
that.set('mappings', new bb.MappingCollection(data.mappings));
};
var e = $.ajax({
url: "/maps/" + this.id + "/contains.json",
success: start,
error: errorFunc,
async: false
});
},
getTopics: function () {
if (!this.get('topics')) {
this.fetchContained();
}
return this.get('topics');
},
getSynapses: function () {
if (!this.get('synapses')) {
this.fetchContained();
}
return this.get('synapses');
},
getMappings: function () {
if (!this.get('mappings')) {
this.fetchContained();
}
return this.get('mappings');
},
getMappers: function () {
if (!this.get('mappers')) {
this.fetchContained();
}
return this.get('mappers');
},
attrForCards: function () {
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
var n = this.get('name');
var d = this.get('desc');
var maxNameLength = 32;
var maxDescLength = 118;
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + "..." : n) : "";
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + "..." : d) : "";
var obj = {
id: this.id,
name: truncatedName,
fullName: n,
desc: truncatedDesc,
permission: this.get("permission") ? capitalize(this.get("permission")) : "Commons",
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
contributor_count_string: this.get('contributor_count') == 1 ? ' contributor' : ' contributors',
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
topic_count_string: this.get('topic_count') == 1 ? ' topic' : ' topics',
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
synapse_count_string: this.get('synapse_count') == 1 ? ' synapse' : ' synapses',
screenshot: '<img src="' + this.get('screenshot_url') + '" />'
};
return obj;
},
updateView: function() {
var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) {
Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'));
this.updateMapWrapper();
}
},
updateMapWrapper: function() {
var map = Metamaps.Active.Map;
var isActiveMap = this.id === map.id;
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : '';
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : '';
if (isActiveMap) {
$('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap);
}
}
});
Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Map,
initialize: function(models, options) {
this.id = options.id;
this.sortBy = options.sortBy;
if (options.mapperId) {
this.mapperId = options.mapperId;
}
// this.page represents the NEXT page to fetch
this.page = models.length > 0 ? (models.length < 20 ? "loadedAll" : 2) : 1;
},
url: function() {
if (!this.mapperId) {
return '/explore/' + this.id + '.json';
}
else {
return '/explore/mapper/' + this.mapperId + '.json';
}
},
comparator: function (a, b) {
a = a.get(this.sortBy);
b = b.get(this.sortBy);
var temp;
if (this.sortBy === 'name') {
a = a ? a.toLowerCase() : "";
b = b ? b.toLowerCase() : "";
}
else {
// this is for updated_at and created_at
temp = a;
a = b;
b = temp;
a = (new Date(a)).getTime();
b = (new Date(b)).getTime();
}
return a > b ? 1 : a < b ? -1 : 0;
},
getMaps: function (cb) {
var self = this;
Metamaps.Loading.show();
if (this.page != "loadedAll") {
var numBefore = this.length;
this.fetch({
remove: false,
silent: true,
data: { page: this.page },
success: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
if (collection.length - numBefore < 20) {
self.page = "loadedAll";
}
else self.page += 1;
self.trigger('successOnFetch', cb);
},
error: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
self.trigger('errorOnFetch');
}
});
}
else {
self.trigger('successOnFetch', cb);
}
}
});
Metamaps.Backbone.Message = Backbone.Model.extend({
urlRoot: '/messages',
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.MessageCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Message,
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 () {
Metamaps.currentPage = "";
var Router = Backbone.Router.extend({
routes: {
"": "home", // #home
"explore/:section": "explore", // #explore/active
"explore/:section/:id": "explore", // #explore/mapper/1234
"maps/:id": "maps" // #maps/7
},
home: function () {
clearTimeout(Metamaps.routerTimeoutId);
if (Metamaps.Active.Mapper) document.title = 'Explore Active Maps | Metamaps';
else document.title = 'Home | Metamaps';
Metamaps.currentSection = "";
Metamaps.currentPage = "";
$('.wrapper').removeClass('mapPage topicPage');
var classes = Metamaps.Active.Mapper ? "homePage explorePage" : "homePage";
$('.wrapper').addClass(classes);
var navigate = function() {
Metamaps.routerTimeoutId = setTimeout(function() {
Metamaps.Router.navigate("");
}, 300);
};
// all this only for the logged in home page
if (Metamaps.Active.Mapper) {
Metamaps.Famous.yield.hide();
Metamaps.Famous.explore.set('active');
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.explore.show();
Metamaps.Famous.maps.show();
Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock();
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active );
if (Metamaps.Maps.Active.length === 0) {
Metamaps.Maps.Active.getMaps(navigate); // this will trigger an explore maps render
}
else {
Metamaps.Views.exploreMaps.render(navigate);
}
}
// logged out home page
else {
Metamaps.Famous.yield.show();
Metamaps.Famous.explore.hide();
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Famous.maps.hide();
Metamaps.routerTimeoutId = setTimeout(navigate, 500);
}
Metamaps.Famous.viz.hide();
Metamaps.Map.end();
Metamaps.Topic.end();
Metamaps.Active.Map = null;
Metamaps.Active.Topic = null;
},
explore: function (section, id) {
clearTimeout(Metamaps.routerTimeoutId);
// just capitalize the variable section
// either 'featured', 'mapper', or 'active'
var capitalize = section.charAt(0).toUpperCase() + section.slice(1);
if (section === "featured" || section === "active") {
document.title = 'Explore ' + capitalize + ' Maps | Metamaps';
}
else if (section === "mapper") {
$.ajax({
url: "/users/" + id + ".json",
success: function (response) {
document.title = response.name + ' | Metamaps';
},
error: function () {
}
});
}
else if (section === "mine") {
document.title = 'Explore My Maps | Metamaps';
}
$('.wrapper').removeClass('homePage mapPage topicPage');
$('.wrapper').addClass('explorePage');
Metamaps.currentSection = "explore";
Metamaps.currentPage = section;
// this will mean it's a mapper page being loaded
if (id) {
if (Metamaps.Maps.Mapper.mapperId !== id) {
// empty the collection if we are trying to load the maps
// collection of a different mapper than we had previously
Metamaps.Maps.Mapper.reset();
Metamaps.Maps.Mapper.page = 1;
}
Metamaps.Maps.Mapper.mapperId = id;
}
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] );
var navigate = function(){
var path = "/explore/" + Metamaps.currentPage;
// alter url if for mapper profile page
if (Metamaps.currentPage == "mapper") {
path += "/" + Metamaps.Maps.Mapper.mapperId;
}
Metamaps.Router.navigate(path);
};
var navigateTimeout = function() {
Metamaps.routerTimeoutId = setTimeout(navigate, 300);
};
if (Metamaps.Maps[capitalize].length === 0) {
Metamaps.Loading.show();
setTimeout(function(){
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
}
else {
if (id) {
Metamaps.Views.exploreMaps.fetchUserThenRender(navigateTimeout);
}
else {
Metamaps.Views.exploreMaps.render(navigateTimeout);
}
}
Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock();
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.maps.show();
Metamaps.Famous.explore.set(section, id);
Metamaps.Famous.explore.show();
Metamaps.Famous.viz.hide();
Metamaps.Map.end();
Metamaps.Topic.end();
Metamaps.Active.Map = null;
Metamaps.Active.Topic = null;
},
maps: function (id) {
clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Map ' + id + ' | Metamaps';
Metamaps.currentSection = "map";
Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage topicPage');
$('.wrapper').addClass('mapPage');
// another class will be added to wrapper if you
// can edit this map '.canEditMap'
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
}
Metamaps.Famous.viz.show();
Metamaps.Topic.end();
Metamaps.Active.Topic = null;
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Loading.show();
Metamaps.Map.end();
Metamaps.Map.launch(id);
},
topics: function (id) {
clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Topic ' + id + ' | Metamaps';
Metamaps.currentSection = "topic";
Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage mapPage');
$('.wrapper').addClass('topicPage');
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
}
Metamaps.Famous.viz.show();
Metamaps.Map.end();
Metamaps.Active.Map = null;
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Topic.end();
Metamaps.Topic.launch(id);
}
});
Metamaps.Router = new Router();
Metamaps.Router.intercept = function (evt) {
var segments;
var href = {
prop: $(this).prop("href"),
attr: $(this).attr("href")
};
var root = location.protocol + "//" + location.host + Backbone.history.options.root;
if (href.prop && href.prop === root) href.attr = "";
if (href.prop && href.prop.slice(0, root.length) === root) {
evt.preventDefault();
segments = href.attr.split('/');
segments.splice(0,1); // pop off the element created by the first /
if (href.attr === "") Metamaps.Router.home();
else {
Metamaps.Router[segments[0]](segments[1], segments[2]);
}
}
};
Metamaps.Router.init = function () {
Backbone.history.start({
silent: true,
pushState: true,
root: '/'
});
$(document).on("click", "a:not([data-bypass])", Metamaps.Router.intercept);
};
})();
(function () {
Metamaps.currentPage = "";
var Router = Backbone.Router.extend({
routes: {
"": "home", // #home
"explore/:section": "explore", // #explore/active
"explore/:section/:id": "explore", // #explore/mapper/1234
"maps/:id": "maps" // #maps/7
},
home: function () {
clearTimeout(Metamaps.routerTimeoutId);
if (Metamaps.Active.Mapper) document.title = 'Explore Active Maps | Metamaps';
else document.title = 'Home | Metamaps';
Metamaps.currentSection = "";
Metamaps.currentPage = "";
$('.wrapper').removeClass('mapPage topicPage');
var classes = Metamaps.Active.Mapper ? "homePage explorePage" : "homePage";
$('.wrapper').addClass(classes);
var navigate = function() {
Metamaps.routerTimeoutId = setTimeout(function() {
Metamaps.Router.navigate("");
}, 300);
};
// all this only for the logged in home page
if (Metamaps.Active.Mapper) {
Metamaps.Famous.yield.hide();
Metamaps.Famous.explore.set('active');
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.explore.show();
Metamaps.Famous.maps.show();
Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock();
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Active );
if (Metamaps.Maps.Active.length === 0) {
Metamaps.Maps.Active.getMaps(navigate); // this will trigger an explore maps render
}
else {
Metamaps.Views.exploreMaps.render(navigate);
}
}
// logged out home page
else {
Metamaps.Famous.yield.show();
Metamaps.Famous.explore.hide();
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Famous.maps.hide();
Metamaps.routerTimeoutId = setTimeout(navigate, 500);
}
Metamaps.Famous.viz.hide();
Metamaps.Map.end();
Metamaps.Topic.end();
Metamaps.Active.Map = null;
Metamaps.Active.Topic = null;
},
explore: function (section, id) {
clearTimeout(Metamaps.routerTimeoutId);
// just capitalize the variable section
// either 'featured', 'mapper', or 'active'
var capitalize = section.charAt(0).toUpperCase() + section.slice(1);
if (section === "featured" || section === "active") {
document.title = 'Explore ' + capitalize + ' Maps | Metamaps';
}
else if (section === "mapper") {
$.ajax({
url: "/users/" + id + ".json",
success: function (response) {
document.title = response.name + ' | Metamaps';
},
error: function () {
}
});
}
else if (section === "mine") {
document.title = 'Explore My Maps | Metamaps';
}
$('.wrapper').removeClass('homePage mapPage topicPage');
$('.wrapper').addClass('explorePage');
Metamaps.currentSection = "explore";
Metamaps.currentPage = section;
// this will mean it's a mapper page being loaded
if (id) {
if (Metamaps.Maps.Mapper.mapperId !== id) {
// empty the collection if we are trying to load the maps
// collection of a different mapper than we had previously
Metamaps.Maps.Mapper.reset();
Metamaps.Maps.Mapper.page = 1;
}
Metamaps.Maps.Mapper.mapperId = id;
}
Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] );
var navigate = function(){
var path = "/explore/" + Metamaps.currentPage;
// alter url if for mapper profile page
if (Metamaps.currentPage == "mapper") {
path += "/" + Metamaps.Maps.Mapper.mapperId;
}
Metamaps.Router.navigate(path);
};
var navigateTimeout = function() {
Metamaps.routerTimeoutId = setTimeout(navigate, 300);
};
if (Metamaps.Maps[capitalize].length === 0) {
Metamaps.Loading.show();
setTimeout(function(){
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
}
else {
if (id) {
Metamaps.Views.exploreMaps.fetchUserThenRender(navigateTimeout);
}
else {
Metamaps.Views.exploreMaps.render(navigateTimeout);
}
}
Metamaps.GlobalUI.Search.open();
Metamaps.GlobalUI.Search.lock();
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.resetScroll(); // sets the scroll back to the top
Metamaps.Famous.maps.show();
Metamaps.Famous.explore.set(section, id);
Metamaps.Famous.explore.show();
Metamaps.Famous.viz.hide();
Metamaps.Map.end();
Metamaps.Topic.end();
Metamaps.Active.Map = null;
Metamaps.Active.Topic = null;
},
maps: function (id) {
clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Map ' + id + ' | Metamaps';
Metamaps.currentSection = "map";
Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage topicPage');
$('.wrapper').addClass('mapPage');
// another class will be added to wrapper if you
// can edit this map '.canEditMap'
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
}
Metamaps.Famous.viz.show();
Metamaps.Topic.end();
Metamaps.Active.Topic = null;
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Loading.show();
Metamaps.Map.end();
Metamaps.Map.launch(id);
},
topics: function (id) {
clearTimeout(Metamaps.routerTimeoutId);
document.title = 'Topic ' + id + ' | Metamaps';
Metamaps.currentSection = "topic";
Metamaps.currentPage = id;
$('.wrapper').removeClass('homePage explorePage mapPage');
$('.wrapper').addClass('topicPage');
Metamaps.Famous.yield.hide();
Metamaps.Famous.maps.hide();
Metamaps.Famous.explore.hide();
// clear the visualization, if there was one, before showing its div again
if (Metamaps.Visualize.mGraph) {
Metamaps.Visualize.mGraph.graph.empty();
Metamaps.Visualize.mGraph.plot();
Metamaps.JIT.centerMap(Metamaps.Visualize.mGraph.canvas);
}
Metamaps.Famous.viz.show();
Metamaps.Map.end();
Metamaps.Active.Map = null;
Metamaps.GlobalUI.Search.unlock();
Metamaps.GlobalUI.Search.close(0, true);
Metamaps.Topic.end();
Metamaps.Topic.launch(id);
}
});
Metamaps.Router = new Router();
Metamaps.Router.intercept = function (evt) {
var segments;
var href = {
prop: $(this).prop("href"),
attr: $(this).attr("href")
};
var root = location.protocol + "//" + location.host + Backbone.history.options.root;
if (href.prop && href.prop === root) href.attr = "";
if (href.prop && href.prop.slice(0, root.length) === root) {
evt.preventDefault();
segments = href.attr.split('/');
segments.splice(0,1); // pop off the element created by the first /
if (href.attr === "") Metamaps.Router.home();
else {
Metamaps.Router[segments[0]](segments[1], segments[2]);
}
}
};
Metamaps.Router.init = function () {
Backbone.history.start({
silent: true,
pushState: true,
root: '/'
});
$(document).on("click", "a:not([data-bypass])", Metamaps.Router.intercept);
};
})();

View file

@ -1,133 +1,133 @@
(function () {
Metamaps.Views = {};
var initialized = false;
Metamaps.Views.init = function () {
Metamaps.Views.MapperCard = Backbone.View.extend({
template: Hogan.compile( $('#mapperCardTemplate').html() ),
tagNamea: "div",
className: "mapper",
render: function () {
this.$el.html( this.template.render(this.model) );
return this;
}
});
Metamaps.Views.MapCard = Backbone.View.extend({
template: Hogan.compile( $('#mapCardTemplate').html() ),
tagName: "div",
className: "map",
id: function() {
return this.model.id;
},
initialize: function () {
this.listenTo(this.model, "change", this.render);
},
render: function () {
this.$el.html( this.template.render(this.model.attrForCards()) );
return this;
}
});
var mapsWrapper = Backbone.View.extend({
initialize: function (opts) {
},
setCollection: function (collection) {
if (this.collection) this.stopListening(this.collection);
this.collection = collection;
this.listenTo(this.collection, 'add', this.render);
this.listenTo(this.collection, 'successOnFetch', this.handleSuccess);
this.listenTo(this.collection, 'errorOnFetch', this.handleError);
},
render: function (mapperObj, cb) {
var that = this;
if (typeof mapperObj === "function") {
var cb = mapperObj;
mapperObj = null;
}
this.el.innerHTML = "";
// in case it is a page where we have to display the mapper card
if (mapperObj) {
var view = new Metamaps.Views.MapperCard({ model: mapperObj });
that.el.appendChild( view.render().el );
}
this.collection.each(function (map) {
var view = new Metamaps.Views.MapCard({ model: map });
that.el.appendChild( view.render().el );
});
this.$el.append('<div class="clearfloat"></div>');
var m = Metamaps.Famous.maps.surf;
m.setContent(this.el);
var updateHeight = function(){
var height = $(that.el).height() + 32 + 56;
m.setSize([undefined, height]);
Metamaps.Famous.maps.lock = false;
if (cb) cb();
};
if (!initialized) {
m.deploy(m._currTarget);
initialized = true;
setTimeout(updateHeight, 100);
} else {
setTimeout(updateHeight, 100);
}
Metamaps.Loading.hide();
},
handleSuccess: function (cb) {
var that = this;
if (this.collection && this.collection.id === "mapper") {
this.fetchUserThenRender(cb);
}
else {
this.render(cb);
}
},
handleError: function () {
console.log('error loading maps!'); //TODO
},
fetchUserThenRender: function (cb) {
var that = this;
// first load the mapper object and then call the render function
$.ajax({
url: "/users/" + this.collection.mapperId + "/details.json",
success: function (response) {
that.render(response, cb);
},
error: function () {
that.render(cb);
}
});
}
});
Metamaps.Views.exploreMaps = new mapsWrapper();
};
})();
(function () {
Metamaps.Views = {};
var initialized = false;
Metamaps.Views.init = function () {
Metamaps.Views.MapperCard = Backbone.View.extend({
template: Hogan.compile( $('#mapperCardTemplate').html() ),
tagNamea: "div",
className: "mapper",
render: function () {
this.$el.html( this.template.render(this.model) );
return this;
}
});
Metamaps.Views.MapCard = Backbone.View.extend({
template: Hogan.compile( $('#mapCardTemplate').html() ),
tagName: "div",
className: "map",
id: function() {
return this.model.id;
},
initialize: function () {
this.listenTo(this.model, "change", this.render);
},
render: function () {
this.$el.html( this.template.render(this.model.attrForCards()) );
return this;
}
});
var mapsWrapper = Backbone.View.extend({
initialize: function (opts) {
},
setCollection: function (collection) {
if (this.collection) this.stopListening(this.collection);
this.collection = collection;
this.listenTo(this.collection, 'add', this.render);
this.listenTo(this.collection, 'successOnFetch', this.handleSuccess);
this.listenTo(this.collection, 'errorOnFetch', this.handleError);
},
render: function (mapperObj, cb) {
var that = this;
if (typeof mapperObj === "function") {
var cb = mapperObj;
mapperObj = null;
}
this.el.innerHTML = "";
// in case it is a page where we have to display the mapper card
if (mapperObj) {
var view = new Metamaps.Views.MapperCard({ model: mapperObj });
that.el.appendChild( view.render().el );
}
this.collection.each(function (map) {
var view = new Metamaps.Views.MapCard({ model: map });
that.el.appendChild( view.render().el );
});
this.$el.append('<div class="clearfloat"></div>');
var m = Metamaps.Famous.maps.surf;
m.setContent(this.el);
var updateHeight = function(){
var height = $(that.el).height() + 32 + 56;
m.setSize([undefined, height]);
Metamaps.Famous.maps.lock = false;
if (cb) cb();
};
if (!initialized) {
m.deploy(m._currTarget);
initialized = true;
setTimeout(updateHeight, 100);
} else {
setTimeout(updateHeight, 100);
}
Metamaps.Loading.hide();
},
handleSuccess: function (cb) {
var that = this;
if (this.collection && this.collection.id === "mapper") {
this.fetchUserThenRender(cb);
}
else {
this.render(cb);
}
},
handleError: function () {
console.log('error loading maps!'); //TODO
},
fetchUserThenRender: function (cb) {
var that = this;
// first load the mapper object and then call the render function
$.ajax({
url: "/users/" + this.collection.mapperId + "/details.json",
success: function (response) {
that.render(response, cb);
},
error: function () {
that.render(cb);
}
});
}
});
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 {
position:fixed;
position:absolute;
top: 0;
width: 100%;
height: 100%;
@ -116,7 +116,7 @@
/* upperLeftUI */
.upperLeftUI {
position: fixed;
position: absolute;
top: 10px;
left: 24px;
z-index:3;
@ -155,7 +155,7 @@
/* upperRightUI */
.upperRightUI {
position: fixed;
position: absolute;
top: 10px;
right: 24px;
z-index:4;
@ -166,9 +166,9 @@
}
.upperRightBox {
position: fixed;
top:52px;
right:24px;
position: absolute;
top:42px;
right:0;
background-color: #E0E0E0;
border-radius: 2px;
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 {
position: relative;
top: -42px; /* puts it just offscreen */
}
.mapPage .upperRightMapButtons, .topicPage .upperRightMapButtons {
top: 0;
}
.topicPage .sidebarCollaborate {
display: none;
}
.upperRightIcon {
width: 32px;
height: 32px;
@ -205,20 +200,6 @@
background-repeat: no-repeat;
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 {
background-position: -64px 0;
}
@ -384,7 +365,7 @@
}
.infoAndHelp {
position: fixed;
position: absolute;
bottom: 20px;
right: 20px;
z-index: 3;
@ -424,14 +405,14 @@
/* mapControls */
.mapControls {
position: fixed;
position: absolute;
bottom: 24px;
right:-32px; /* puts it just offscreen */
width:32px;
z-index: 3;
}
.mapPage .mapControls, .topicPage .mapControls {
right: 24px;
right: 24px;
}
.topicPage .zoomExtents {
@ -474,14 +455,13 @@
background-position: -32px 0;
}
.zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .takeScreenshot:hover .tooltips, .sidebarCollaborateIcon:hover .tooltipsUnder,
.sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder,
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove {
.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,
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips {
display: block;
}
.hide {
display: none !important;
display: none !important;
}
.tooltips {
@ -532,10 +512,6 @@
font-style: normal;
}
.sidebarCollaborateIcon .tooltipsUnder {
margin-left: -3px;
}
.sidebarFilterIcon .tooltipsUnder {
margin-left: -4px;
}
@ -560,16 +536,20 @@
left: -11px;
}
.chat-button .tooltips {
top: 10px;
}
.openCheatsheet .tooltipsAbove {
left: -4px;
}
.sidebarAccountIcon .tooltipsUnder {
margin-left: -8px;
margin-left: -12px;
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: '';
position: absolute;
top: 57%;
@ -582,21 +562,20 @@
border-bottom: 5px solid transparent;
}
.sidebarCollaborateIcon div:after, .sidebarFilterIcon div:after, .sidebarAccountIcon .tooltipsUnder:after {
left: 38%;
}
.sidebarCollaborateIcon div:after, .sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
.sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
content: '';
position: absolute;
top: 129%;
margin-top: -30px;
right: 40%;
margin-top: -7px;
width: 0;
height: 0;
border-bottom: 4px solid #000000;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
}
.sidebarFilterIcon div:after {
right: 37% !important;
}
.mapInfoIcon div:after, .openCheatsheet div:after {
content: '';
@ -735,7 +714,7 @@
color: #F5F5F5;
padding: 16px;
border-radius: 2px;
z-index: 1 !important; /* important necessary for firefox */
z-index: 4 !important; /* important necessary for firefox */
font-size: 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 {
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
* 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
* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */
/* Layout helpers
----------------------------------*/
.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-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:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.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-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
.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-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}
/* workarounds */
* 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, .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 */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.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-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-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*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 { 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-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; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
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 .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-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left: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-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 select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.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 th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.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 .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.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.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-3 .ui-datepicker-group { width:33.3%; }
.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-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.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-prev:hover { right: 1px; left: 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 button { float: left; }
.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-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; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}
.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-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 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-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 .ui-dialog-buttonset { float: right; }
.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-draggable .ui-dialog-titlebar { cursor: move; }
.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-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-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-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 a { cursor: default; }
/* icon support */
.ui-menu-icons { position: relative; }
.ui-menu-icons .ui-menu-topic a { position: relative; padding-left: 2em; }
/* left-aligned */
.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
/* right-aligned */
.ui-menu .ui-menu-icon { position: static; float: right; }
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
.ui-resizable { position: relative;}
.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-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-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-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-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-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
.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-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 .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.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-max { right: 0; }
.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-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 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-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 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-up { top: 0; }
.ui-spinner-down { bottom: 0; }
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
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 .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 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 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-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-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 */
* html .ui-tooltip {
background-image: none;
}
body .ui-tooltip { border-width: 2px; }
/* Component containers
----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
.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-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-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}*/; }
/* 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 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 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 a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
/* 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 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 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-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-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 */
/* Icons
----------------------------------*/
/* states and images */
.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-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-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-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}*/; }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -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-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -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-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -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 { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* 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-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-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 */
.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}*/; }
/*! jQuery UI - v1.9.2 - 2012-11-23
* 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
* Copyright 2012 jQuery Foundation and other contributors; Licensed MIT */
/* Layout helpers
----------------------------------*/
.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-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:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
/* Interaction Cues
----------------------------------*/
.ui-state-disabled { cursor: default !important; }
/* Icons
----------------------------------*/
/* states and images */
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
/* Misc visuals
----------------------------------*/
/* Overlays */
.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-icons { padding-left: 2.2em; }
.ui-accordion .ui-accordion-noicons { padding-left: .7em; }
.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-content { padding: 1em 2.2em; border-top: 0; overflow: auto; zoom: 1; }
.ui-autocomplete {
position: absolute;
top: 0;
left: 0;
cursor: default;
}
/* workarounds */
* 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, .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 */
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
.ui-button-icons-only { width: 3.4em; }
button.ui-button-icons-only { width: 3.7em; }
/*button text element */
.ui-button .ui-button-text { display: block; line-height: 1.4; }
.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-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-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
/* no icon support for input elements, provide padding by default */
input.ui-button { padding: .4em 1em; }
/*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 { 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-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; }
/*button sets*/
.ui-buttonset { margin-right: 7px; }
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
/* workarounds */
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 .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-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
.ui-datepicker .ui-datepicker-prev { left:2px; }
.ui-datepicker .ui-datepicker-next { right:2px; }
.ui-datepicker .ui-datepicker-prev-hover { left: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-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 select.ui-datepicker-month-year {width: 100%;}
.ui-datepicker select.ui-datepicker-month,
.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 th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
.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 .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.ui-datepicker-current { float:left; }
/* with multiple calendars */
.ui-datepicker.ui-datepicker-multi { width:auto; }
.ui-datepicker-multi .ui-datepicker-group { float:left; }
.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-3 .ui-datepicker-group { width:33.3%; }
.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-middle .ui-datepicker-header { border-left-width:0; }
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
/* RTL support */
.ui-datepicker-rtl { direction: rtl; }
.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-prev:hover { right: 1px; left: 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 button { float: left; }
.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-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; }
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
.ui-datepicker-cover {
position: absolute; /*must have*/
z-index: -1; /*must have*/
filter: mask(); /*must have*/
top: -4px; /*must have*/
left: -4px; /*must have*/
width: 200px; /*must have*/
height: 200px; /*must have*/
}
.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-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 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-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 .ui-dialog-buttonset { float: right; }
.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-draggable .ui-dialog-titlebar { cursor: move; }
.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-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-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-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 a { cursor: default; }
/* icon support */
.ui-menu-icons { position: relative; }
.ui-menu-icons .ui-menu-topic a { position: relative; padding-left: 2em; }
/* left-aligned */
.ui-menu .ui-icon { position: absolute; top: .2em; left: .2em; }
/* right-aligned */
.ui-menu .ui-menu-icon { position: static; float: right; }
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
.ui-resizable { position: relative;}
.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-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-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-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-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-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
.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-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 .ui-slider-handle { top: -.3em; margin-left: -.6em; }
.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-max { right: 0; }
.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-range { left: 0; width: 100%; }
.ui-slider-vertical .ui-slider-range-min { bottom: 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-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 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-up { top: 0; }
.ui-spinner-down { bottom: 0; }
/* TR overrides */
.ui-spinner .ui-icon-triangle-1-s {
/* need to fix icons sprite */
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 .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 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 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-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
.ui-tooltip {
padding: 8px;
position: absolute;
z-index: 9999;
max-width: 300px;
-webkit-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 */
* html .ui-tooltip {
background-image: none;
}
body .ui-tooltip { border-width: 2px; }
/* Component containers
----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
.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-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-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}*/; }
/* 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 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 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 a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
/* 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 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 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-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-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 */
/* Icons
----------------------------------*/
/* states and images */
.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-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-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-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}*/; }
/* positioning */
.ui-icon-carat-1-n { background-position: 0 0; }
.ui-icon-carat-1-ne { background-position: -16px 0; }
.ui-icon-carat-1-e { background-position: -32px 0; }
.ui-icon-carat-1-se { background-position: -48px 0; }
.ui-icon-carat-1-s { background-position: -64px 0; }
.ui-icon-carat-1-sw { background-position: -80px 0; }
.ui-icon-carat-1-w { background-position: -96px 0; }
.ui-icon-carat-1-nw { background-position: -112px 0; }
.ui-icon-carat-2-n-s { background-position: -128px 0; }
.ui-icon-carat-2-e-w { background-position: -144px 0; }
.ui-icon-triangle-1-n { background-position: 0 -16px; }
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
.ui-icon-triangle-1-e { background-position: -32px -16px; }
.ui-icon-triangle-1-se { background-position: -48px -16px; }
.ui-icon-triangle-1-s { background-position: -64px -16px; }
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
.ui-icon-triangle-1-w { background-position: -96px -16px; }
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
.ui-icon-arrow-1-n { background-position: 0 -32px; }
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
.ui-icon-arrow-1-e { background-position: -32px -32px; }
.ui-icon-arrow-1-se { background-position: -48px -32px; }
.ui-icon-arrow-1-s { background-position: -64px -32px; }
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
.ui-icon-arrow-1-w { background-position: -96px -32px; }
.ui-icon-arrow-1-nw { background-position: -112px -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-e-w { background-position: -160px -32px; }
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
.ui-icon-arrowthick-1-nw { background-position: -112px -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-e-w { background-position: -160px -48px; }
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
.ui-icon-arrow-4 { background-position: 0 -80px; }
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
.ui-icon-extlink { background-position: -32px -80px; }
.ui-icon-newwin { background-position: -48px -80px; }
.ui-icon-refresh { background-position: -64px -80px; }
.ui-icon-shuffle { background-position: -80px -80px; }
.ui-icon-transfer-e-w { background-position: -96px -80px; }
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
.ui-icon-folder-collapsed { background-position: 0 -96px; }
.ui-icon-folder-open { background-position: -16px -96px; }
.ui-icon-document { background-position: -32px -96px; }
.ui-icon-document-b { background-position: -48px -96px; }
.ui-icon-note { background-position: -64px -96px; }
.ui-icon-mail-closed { background-position: -80px -96px; }
.ui-icon-mail-open { background-position: -96px -96px; }
.ui-icon-suitcase { background-position: -112px -96px; }
.ui-icon-comment { background-position: -128px -96px; }
.ui-icon-person { background-position: -144px -96px; }
.ui-icon-print { background-position: -160px -96px; }
.ui-icon-trash { background-position: -176px -96px; }
.ui-icon-locked { background-position: -192px -96px; }
.ui-icon-unlocked { background-position: -208px -96px; }
.ui-icon-bookmark { background-position: -224px -96px; }
.ui-icon-tag { background-position: -240px -96px; }
.ui-icon-home { background-position: 0 -112px; }
.ui-icon-flag { background-position: -16px -112px; }
.ui-icon-calendar { background-position: -32px -112px; }
.ui-icon-cart { background-position: -48px -112px; }
.ui-icon-pencil { background-position: -64px -112px; }
.ui-icon-clock { background-position: -80px -112px; }
.ui-icon-disk { background-position: -96px -112px; }
.ui-icon-calculator { background-position: -112px -112px; }
.ui-icon-zoomin { background-position: -128px -112px; }
.ui-icon-zoomout { background-position: -144px -112px; }
.ui-icon-search { background-position: -160px -112px; }
.ui-icon-wrench { background-position: -176px -112px; }
.ui-icon-gear { background-position: -192px -112px; }
.ui-icon-heart { background-position: -208px -112px; }
.ui-icon-star { background-position: -224px -112px; }
.ui-icon-link { background-position: -240px -112px; }
.ui-icon-cancel { background-position: 0 -128px; }
.ui-icon-plus { background-position: -16px -128px; }
.ui-icon-plusthick { background-position: -32px -128px; }
.ui-icon-minus { background-position: -48px -128px; }
.ui-icon-minusthick { background-position: -64px -128px; }
.ui-icon-close { background-position: -80px -128px; }
.ui-icon-closethick { background-position: -96px -128px; }
.ui-icon-key { background-position: -112px -128px; }
.ui-icon-lightbulb { background-position: -128px -128px; }
.ui-icon-scissors { background-position: -144px -128px; }
.ui-icon-clipboard { background-position: -160px -128px; }
.ui-icon-copy { background-position: -176px -128px; }
.ui-icon-contact { background-position: -192px -128px; }
.ui-icon-image { background-position: -208px -128px; }
.ui-icon-video { background-position: -224px -128px; }
.ui-icon-script { background-position: -240px -128px; }
.ui-icon-alert { background-position: 0 -144px; }
.ui-icon-info { background-position: -16px -144px; }
.ui-icon-notice { background-position: -32px -144px; }
.ui-icon-help { background-position: -48px -144px; }
.ui-icon-check { background-position: -64px -144px; }
.ui-icon-bullet { background-position: -80px -144px; }
.ui-icon-radio-on { background-position: -96px -144px; }
.ui-icon-radio-off { background-position: -112px -144px; }
.ui-icon-pin-w { background-position: -128px -144px; }
.ui-icon-pin-s { background-position: -144px -144px; }
.ui-icon-play { background-position: 0 -160px; }
.ui-icon-pause { background-position: -16px -160px; }
.ui-icon-seek-next { background-position: -32px -160px; }
.ui-icon-seek-prev { background-position: -48px -160px; }
.ui-icon-seek-end { background-position: -64px -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 { background-position: -80px -160px; }
.ui-icon-stop { background-position: -96px -160px; }
.ui-icon-eject { background-position: -112px -160px; }
.ui-icon-volume-off { background-position: -128px -160px; }
.ui-icon-volume-on { background-position: -144px -160px; }
.ui-icon-power { background-position: 0 -176px; }
.ui-icon-signal-diag { background-position: -16px -176px; }
.ui-icon-signal { background-position: -32px -176px; }
.ui-icon-battery-0 { background-position: -48px -176px; }
.ui-icon-battery-1 { background-position: -64px -176px; }
.ui-icon-battery-2 { background-position: -80px -176px; }
.ui-icon-battery-3 { background-position: -96px -176px; }
.ui-icon-circle-plus { background-position: 0 -192px; }
.ui-icon-circle-minus { background-position: -16px -192px; }
.ui-icon-circle-close { background-position: -32px -192px; }
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
.ui-icon-circle-zoomin { background-position: -176px -192px; }
.ui-icon-circle-zoomout { background-position: -192px -192px; }
.ui-icon-circle-check { background-position: -208px -192px; }
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
.ui-icon-circlesmall-close { background-position: -32px -208px; }
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
.ui-icon-squaresmall-close { background-position: -80px -208px; }
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
/* Misc visuals
----------------------------------*/
/* 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-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-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 */
.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}*/; }

View file

@ -1,473 +1,473 @@
/* basic scrollbar styling */
/* vertical scrollbar */
.mCSB_container{
width:auto;
margin-right:30px;
overflow:hidden;
}
.mCSB_container.mCS_no_scrollbar{
margin-right:0;
}
.mCS_disabled>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar{
margin-right:30px;
}
.mCustomScrollBox>.mCSB_scrollTools{
width:16px;
height:100%;
top:0;
right:0;
}
.mCSB_scrollTools .mCSB_draggerContainer{
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
height:auto;
}
.mCSB_scrollTools a+.mCSB_draggerContainer{
margin:20px 0;
}
.mCSB_scrollTools .mCSB_draggerRail{
width:2px;
height:100%;
margin:0 auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_scrollTools .mCSB_dragger{
cursor:pointer;
width:100%;
height:30px;
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
height:100%;
margin:0 auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
text-align:center;
}
.mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown{
display:block;
position:relative;
height:20px;
overflow:hidden;
margin:0 auto;
cursor:pointer;
}
.mCSB_scrollTools .mCSB_buttonDown{
top:100%;
margin-top:-40px;
}
/* horizontal scrollbar */
.mCSB_horizontal>.mCSB_container{
height:auto;
margin-right:0;
margin-bottom:30px;
overflow:hidden;
}
.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-bottom:0;
}
.mCS_disabled>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-right:0;
margin-bottom:30px;
}
.mCSB_horizontal.mCustomScrollBox>.mCSB_scrollTools{
width:100%;
height:16px;
top:auto;
right:auto;
bottom:0;
left:0;
overflow:hidden;
}
.mCSB_horizontal>.mCSB_scrollTools a+.mCSB_draggerContainer{
margin:0 20px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:2px;
margin:7px 0;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger{
width:30px;
height:100%;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
display:block;
position:relative;
width:20px;
height:100%;
overflow:hidden;
margin:0 auto;
cursor:pointer;
float:left;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
margin-left:-40px;
float:right;
}
.mCustomScrollBox{
-ms-touch-action:none; /*MSPointer events - direct all pointer events to js*/
}
/* default scrollbar colors and backgrounds (default theme) */
.mCustomScrollBox>.mCSB_scrollTools{
opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCustomScrollBox:hover>.mCSB_scrollTools{
opacity:1;
filter:"alpha(opacity=100)"; -ms-filter:"alpha(opacity=100)"; /* old ie */
}
.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.4);
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(255,255,255,0.85);
filter:"alpha(opacity=85)"; -ms-filter:"alpha(opacity=85)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown,
.mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_scrollTools .mCSB_buttonRight{
background-repeat:no-repeat;
opacity:0.4;
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonDown{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonLeft{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonRight{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonUp:hover,
.mCSB_scrollTools .mCSB_buttonDown:hover,
.mCSB_scrollTools .mCSB_buttonLeft:hover,
.mCSB_scrollTools .mCSB_buttonRight:hover{
opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp:active,
.mCSB_scrollTools .mCSB_buttonDown:active,
.mCSB_scrollTools .mCSB_buttonLeft:active,
.mCSB_scrollTools .mCSB_buttonRight:active{
opacity:0.9;
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
}
/*scrollbar themes*/
/*dark (dark colored scrollbar)*/
.mCS-dark>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-80px -56px;
}
/*light-2*/
.mCS-light-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-32px 0;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-32px -20px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-40px -40px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-40px -56px;
}
/*dark-2*/
.mCS-dark-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-112px 0;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-112px -20px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-120px -40px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-120px -56px;
}
/*light-thick*/
.mCS-light-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:6px;
margin:5px auto;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-16px 0;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-16px -20px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-20px -40px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-20px -56px;
}
/*dark-thick*/
.mCS-dark-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:6px;
margin:5px auto;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-96px 0;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-96px -20px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-100px -40px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-100px -56px;
}
/*light-thin*/
.mCS-light-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
}
.mCS-light-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px;
}
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
}
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:2px;
margin:7px auto;
}
/*dark-thin*/
.mCS-dark-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15);
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
}
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
}
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:2px;
margin:7px auto;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-80px -56px;
}
/* basic scrollbar styling */
/* vertical scrollbar */
.mCSB_container{
width:auto;
margin-right:30px;
overflow:hidden;
}
.mCSB_container.mCS_no_scrollbar{
margin-right:0;
}
.mCS_disabled>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCustomScrollBox>.mCSB_container.mCS_no_scrollbar{
margin-right:30px;
}
.mCustomScrollBox>.mCSB_scrollTools{
width:16px;
height:100%;
top:0;
right:0;
}
.mCSB_scrollTools .mCSB_draggerContainer{
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
height:auto;
}
.mCSB_scrollTools a+.mCSB_draggerContainer{
margin:20px 0;
}
.mCSB_scrollTools .mCSB_draggerRail{
width:2px;
height:100%;
margin:0 auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_scrollTools .mCSB_dragger{
cursor:pointer;
width:100%;
height:30px;
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
height:100%;
margin:0 auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
text-align:center;
}
.mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown{
display:block;
position:relative;
height:20px;
overflow:hidden;
margin:0 auto;
cursor:pointer;
}
.mCSB_scrollTools .mCSB_buttonDown{
top:100%;
margin-top:-40px;
}
/* horizontal scrollbar */
.mCSB_horizontal>.mCSB_container{
height:auto;
margin-right:0;
margin-bottom:30px;
overflow:hidden;
}
.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-bottom:0;
}
.mCS_disabled>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar,
.mCS_destroyed>.mCSB_horizontal>.mCSB_container.mCS_no_scrollbar{
margin-right:0;
margin-bottom:30px;
}
.mCSB_horizontal.mCustomScrollBox>.mCSB_scrollTools{
width:100%;
height:16px;
top:auto;
right:auto;
bottom:0;
left:0;
overflow:hidden;
}
.mCSB_horizontal>.mCSB_scrollTools a+.mCSB_draggerContainer{
margin:0 20px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:2px;
margin:7px 0;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger{
width:30px;
height:100%;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
-webkit-border-radius:10px;
-moz-border-radius:10px;
border-radius:10px;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
display:block;
position:relative;
width:20px;
height:100%;
overflow:hidden;
margin:0 auto;
cursor:pointer;
float:left;
}
.mCSB_horizontal>.mCSB_scrollTools .mCSB_buttonRight{
margin-left:-40px;
float:right;
}
.mCustomScrollBox{
-ms-touch-action:none; /*MSPointer events - direct all pointer events to js*/
}
/* default scrollbar colors and backgrounds (default theme) */
.mCustomScrollBox>.mCSB_scrollTools{
opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCustomScrollBox:hover>.mCSB_scrollTools{
opacity:1;
filter:"alpha(opacity=100)"; -ms-filter:"alpha(opacity=100)"; /* old ie */
}
.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.4);
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(255,255,255,0.85);
filter:"alpha(opacity=85)"; -ms-filter:"alpha(opacity=85)"; /* old ie */
}
.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp,
.mCSB_scrollTools .mCSB_buttonDown,
.mCSB_scrollTools .mCSB_buttonLeft,
.mCSB_scrollTools .mCSB_buttonRight{
background-repeat:no-repeat;
opacity:0.4;
filter:"alpha(opacity=40)"; -ms-filter:"alpha(opacity=40)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonDown{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonLeft{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonRight{
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)
*/
}
.mCSB_scrollTools .mCSB_buttonUp:hover,
.mCSB_scrollTools .mCSB_buttonDown:hover,
.mCSB_scrollTools .mCSB_buttonLeft:hover,
.mCSB_scrollTools .mCSB_buttonRight:hover{
opacity:0.75;
filter:"alpha(opacity=75)"; -ms-filter:"alpha(opacity=75)"; /* old ie */
}
.mCSB_scrollTools .mCSB_buttonUp:active,
.mCSB_scrollTools .mCSB_buttonDown:active,
.mCSB_scrollTools .mCSB_buttonLeft:active,
.mCSB_scrollTools .mCSB_buttonRight:active{
opacity:0.9;
filter:"alpha(opacity=90)"; -ms-filter:"alpha(opacity=90)"; /* old ie */
}
/*scrollbar themes*/
/*dark (dark colored scrollbar)*/
.mCS-dark>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
background:rgba(0,0,0,0.85);
}
.mCS-dark>.mCSB_scrollTools .mCSB_dragger:active .mCSB_dragger_bar,
.mCS-dark>.mCSB_scrollTools .mCSB_dragger.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px;
}
.mCS-dark>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-80px -56px;
}
/*light-2*/
.mCS-light-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-light-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-32px 0;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-32px -20px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-40px -40px;
}
.mCS-light-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-40px -56px;
}
/*dark-2*/
.mCS-dark-2>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
-webkit-border-radius:1px;
-moz-border-radius:1px;
border-radius:1px;
}
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-dark-2.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:4px;
margin:6px auto;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-112px 0;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-112px -20px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-120px -40px;
}
.mCS-dark-2>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-120px -56px;
}
/*light-thick*/
.mCS-light-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px;
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.75);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-light-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:6px;
margin:5px auto;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(255,255,255,0.9);
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-16px 0;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-16px -20px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-20px -40px;
}
.mCS-light-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-20px -56px;
}
/*dark-thick*/
.mCS-dark-thick>.mCSB_scrollTools .mCSB_draggerRail{
width:4px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.1);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:6px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
-webkit-border-radius:2px;
-moz-border-radius:2px;
border-radius:2px;
}
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
height:4px;
margin:6px 0;
}
.mCS-dark-thick.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:6px;
margin:5px auto;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-96px 0;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-96px -20px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-100px -40px;
}
.mCS-dark-thick>.mCSB_scrollTools .mCSB_buttonRight{
background-position:-100px -56px;
}
/*light-thin*/
.mCS-light-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#fff; /* rgba fallback */
background:rgba(255,255,255,0.1);
}
.mCS-light-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px;
}
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
}
.mCS-light-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:2px;
margin:7px auto;
}
/*dark-thin*/
.mCS-dark-thin>.mCSB_scrollTools .mCSB_draggerRail{
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.15);
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:2px;
background:#000; /* rgba fallback */
background:rgba(0,0,0,0.75);
}
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_draggerRail{
width:100%;
}
.mCS-dark-thin.mCSB_horizontal>.mCSB_scrollTools .mCSB_dragger .mCSB_dragger_bar{
width:100%;
height:2px;
margin:7px auto;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_dragger:hover .mCSB_dragger_bar{
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.mCSB_dragger_onDrag .mCSB_dragger_bar{
background:rgba(0,0,0,0.9);
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonUp{
background-position:-80px 0;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonDown{
background-position:-80px -20px;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonLeft{
background-position:-80px -40px;
}
.mCS-dark-thin>.mCSB_scrollTools .mCSB_buttonRight{
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
include ApplicationHelper
include Pundit
include PunditExtra
rescue_from Pundit::NotAuthorizedError, with: :handle_unauthorized
protect_from_forgery
before_filter :get_invite_link
after_action :allow_embedding
def default_serializer_options
{ root: false }
end
# this is for global login
include ContentHelper
helper_method :user
helper_method :authenticated?
helper_method :admin?
def after_sign_in_path_for(resource)
unsafe_uri = request.env["REQUEST_URI"]
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)
sign_in_url = url_for(:action => 'new', :controller => 'sessions', :only_path => false, :protocol => 'https')
if request.referer == sign_in_url
super
@ -27,7 +29,11 @@ class ApplicationController < ActionController::Base
stored_location_for(resource) || request.referer || root_path
end
end
def handle_unauthorized
head :forbidden # TODO make this better
end
private
def require_no_user
@ -36,37 +42,37 @@ private
return false
end
end
def require_user
unless authenticated?
redirect_to new_user_session_path, notice: "You must be logged in."
return false
end
end
def require_admin
unless authenticated? && admin?
redirect_to root_url, notice: "You need to be an admin for that."
return false
end
end
def user
current_user
end
def authenticated?
current_user
end
def admin?
authenticated? && current_user.admin
end
def get_invite_link
unsafe_uri = request.env["REQUEST_URI"] || 'https://metamaps.cc'
valid_url = /^https?:\/\/([\w\.-]+)(:\d{1,5})?\/?$/
safe_uri = (unsafe_uri.match(valid_url)) ? unsafe_uri : '//metamaps.cc/'
@invite_link = "#{safe_uri}join" + (current_user ? "?code=#{current_user.code}" : "")
def allow_embedding
#allow all
response.headers.except! 'X-Frame-Options'
# or allow a whitelist
# response.headers['X-Frame-Options'] = 'ALLOW-FROM http://blog.metamaps.cc'
end
end

View file

@ -3,20 +3,20 @@ class MainController < ApplicationController
include MapsHelper
include UsersHelper
include SynapsesHelper
after_action :verify_policy_scoped
respond_to :html, :json
# home page
def home
@current = current_user
@maps = policy_scope(Map).order("updated_at DESC").page(1).per(20)
respond_to do |format|
format.html {
if authenticated?
@maps = Map.where("maps.permission != ?", "private").order("updated_at DESC").page(1).per(20)
respond_with(@maps, @current)
if not authenticated?
render 'main/home'
else
respond_with(@current)
render 'maps/activemaps'
end
}
end
@ -59,69 +59,35 @@ class MainController < ApplicationController
filterByMetacode = m
end
end
search = '%' + term.downcase + '%'
builder = policy_scope(Topic)
if filterByMetacode
if term == ""
@topics = []
builder = builder.none
else
search = term.downcase + '%'
if user
@topics = Set.new(Topic.where('LOWER("name") like ?', search).where('metacode_id = ? AND user_id = ?', filterByMetacode.id, user).order('"name"'))
@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
builder = builder.where('LOWER("name") like ? OR
LOWER("desc") like ? OR
LOWER("link") like ?', search, search, search)
builder = builder.where(metacode_id: filterByMetacode.id)
end
elsif desc
search = '%' + term.downcase + '%'
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
builder = builder.where('LOWER("desc") like ?', search)
elsif link
search = '%' + term.downcase + '%'
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
builder = builder.where('LOWER("link") like ?', search)
else #regular case, just search the name
search = term.downcase + '%'
if !user
@topics = Topic.where('LOWER("name") like ?', search).order('"name"')
@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
builder = builder.where('LOWER("name") like ? OR
LOWER("desc") like ? OR
LOWER("link") like ?', search, search, search)
end
builder = builder.where(user: user) if user
@topics = builder.order(:name)
else
@topics = []
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)
end
@ -141,21 +107,21 @@ class MainController < ApplicationController
term = term[5..-1]
desc = true
end
search = '%' + term.downcase + '%'
query = desc ? 'LOWER("desc") like ?' : 'LOWER("name") like ?'
if !user
# !connor why is the limit 5 done here and not above? also, why not limit after sorting alphabetically?
@maps = Map.where(query, search).limit(5).order('"name"')
elsif user
@maps = Map.where(query, search).where('user_id = ?', user).order('"name"')
builder = policy_scope(Map)
if desc
builder = builder.where('LOWER("desc") like ?', search)
else
builder = builder.where('LOWER("name") like ?', search)
end
builder = builder.where(user: user) if user
@maps = builder.order(:name)
else
@maps = []
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)
end
@ -166,7 +132,10 @@ class MainController < ApplicationController
#remove "mapper:" if appended at beginning
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
@mappers = []
end
@ -181,7 +150,7 @@ class MainController < ApplicationController
topic2id = params[:topic2id]
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
# leading or trailing whitespaces
@ -195,23 +164,18 @@ class MainController < ApplicationController
boolean = true
end
}
#limit to 5 results
@synapses = @synapses.slice(0,5)
elsif topic1id && !topic1id.empty?
@one = Synapse.where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
@two = Synapse.where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
@one = policy_scope(Synapse).where('node1_id = ? AND node2_id = ?', topic1id, topic2id)
@two = policy_scope(Synapse).where('node2_id = ? AND node1_id = ?', topic1id, topic2id)
@synapses = @one + @two
@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
@synapses = []
end
#limit to 5 results
@synapses = @synapses.slice(0,5)
render json: autocomplete_synapse_array_json(@synapses)
end
end

View file

@ -1,12 +1,15 @@
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
# GET /mappings/1.json
def show
@mapping = Mapping.find(params[:id])
authorize @mapping
render json: @mapping
end
@ -14,11 +17,12 @@ class MappingsController < ApplicationController
# POST /mappings.json
def create
@mapping = Mapping.new(mapping_params)
@mapping.map.touch(:updated_at)
authorize @mapping
@mapping.user = current_user
if @mapping.save
render json: @mapping, status: :created
Events::NewMapping.publish!(@mapping, current_user)
else
render json: @mapping.errors, status: :unprocessable_entity
end
@ -27,8 +31,7 @@ class MappingsController < ApplicationController
# PUT /mappings/1.json
def update
@mapping = Mapping.find(params[:id])
@mapping.map.touch(:updated_at)
authorize @mapping
if @mapping.update_attributes(mapping_params)
head :no_content
@ -40,18 +43,16 @@ class MappingsController < ApplicationController
# DELETE /mappings/1.json
def destroy
@mapping = Mapping.find(params[:id])
@map = @mapping.map
authorize @mapping
@mapping.destroy
@map.touch(:updated_at)
head :no_content
end
private
# Never trust parameters from the scary internet, only allow the white list through.
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

View file

@ -1,106 +1,119 @@
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]
# GET /explore/active
# GET /explore/featured
# GET /explore/mapper/:id
def index
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
def activemaps
page = params[:page].present? ? params[:page] : 1
@maps = policy_scope(Map).order("updated_at DESC")
.page(page).per(20)
respond_to do |format|
format.html {
if @request == "active" && authenticated?
redirect_to root_url and return
end
respond_with(@maps, @request, @user)
# root url => main/home. main/home renders maps/activemaps view.
redirect_to root_url and return if authenticated?
respond_with(@maps, @user)
}
format.json { render json: @maps }
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
def show
@current = current_user
@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
@map = Map.find(params[:id])
authorize @map
respond_to do |format|
format.html {
format.html {
@allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.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_user.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m|
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.csv { redirect_to action: :export, format: :csv }
format.xls { redirect_to action: :export, format: :xls }
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
def contains
@current = current_user
@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
@map = Map.find(params[:id])
authorize @map
@allmappers = @map.contributors
@alltopics = @map.topics.to_a.delete_if {|t| t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)) }
@allsynapses = @map.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.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_user.id != s.user_id)) }
@allmappings = @map.mappings.to_a.delete_if {|m|
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()
@ -109,6 +122,7 @@ class MapsController < ApplicationController
@json['synapses'] = @allsynapses
@json['mappings'] = @allmappings
@json['mappers'] = @allmappers
@json['messages'] = @map.messages.sort_by(&:created_at)
respond_to do |format|
format.json { render json: @json }
@ -117,60 +131,66 @@ class MapsController < ApplicationController
# POST maps
def create
@user = current_user
@map = Map.new()
@map.name = params[:name]
@map.desc = params[:desc]
@map.permission = params[:permission]
@map.user = @user
@map.arranged = false
@map.save
@map.arranged = false
if params[:topicsToMap]
@all = params[:topicsToMap]
@all = @all.split(',')
@all.each do |topic|
topic = topic.split('/')
@mapping = Mapping.new()
@mapping.user = @user
@mapping.map = @map
@mapping.mappable = Topic.find(topic[0])
@mapping.xloc = topic[1]
@mapping.yloc = topic[2]
@mapping.save
mapping = Mapping.new()
mapping.user = @user
mapping.mappable = Topic.find(topic[0])
mapping.xloc = topic[1]
mapping.yloc = topic[2]
@map.topicmappings << mapping
authorize mapping, :create
mapping.save
end
if params[:synapsesToMap]
@synAll = params[:synapsesToMap]
@synAll = @synAll.split(',')
@synAll.each do |synapse_id|
@mapping = Mapping.new()
@mapping.user = @user
@mapping.map = @map
@mapping.mappable = Synapse.find(synapse_id)
@mapping.save
mapping = Mapping.new()
mapping.user = @user
mapping.map = @map
mapping.mappable = Synapse.find(synapse_id)
@map.synapsemappings << mapping
authorize mapping, :create
mapping.save
end
end
@map.arranged = true
@map.save
end
respond_to do |format|
authorize @map
if @map.save
respond_to do |format|
format.json { render :json => @map }
end
else
respond_to do |format|
format.json { render :json => "invalid params" }
end
end
end
# PUT maps/:id
def update
@current = current_user
@map = Map.find(params[:id]).authorize_to_edit(@current)
@map = Map.find(params[:id])
authorize @map
respond_to do |format|
if !@map
format.json { render json: "unauthorized" }
elsif @map.update_attributes(map_params)
if @map.update_attributes(map_params)
format.json { head :no_content }
else
format.json { render json: @map.errors, status: :unprocessable_entity }
@ -180,51 +200,42 @@ class MapsController < ApplicationController
# POST maps/:id/upload_screenshot
def screenshot
@current = current_user
@map = Map.find(params[:id]).authorize_to_edit(@current)
@map = Map.find(params[:id])
authorize @map
if @map
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
StringIO.open(png) do |data|
data.class.class_eval { attr_accessor :original_filename, :content_type }
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
data.content_type = "image/png"
@map.screenshot = data
end
png = Base64.decode64(params[:encoded_image]['data:image/png;base64,'.length .. -1])
StringIO.open(png) do |data|
data.class.class_eval { attr_accessor :original_filename, :content_type }
data.original_filename = "map-" + @map.id.to_s + "-screenshot.png"
data.content_type = "image/png"
@map.screenshot = data
end
if @map.save
render :json => {:message => "Successfully uploaded the map screenshot."}
else
render :json => {:message => "Failed to upload image."}
end
else
render :json => {:message => "Unauthorized to set map screenshot."}
end
if @map.save
render :json => {:message => "Successfully uploaded the map screenshot."}
else
render :json => {:message => "Failed to upload image."}
end
end
# DELETE maps/:id
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 {
if @map
render json: "success"
else
render json: "unauthorized"
end
}
respond_to do |format|
format.json do
head :no_content
end
end
end
private
# Never trust parameters from the scary internet, only allow the white list through.
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

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
before_filter :require_admin
before_action :require_admin
# GET /metacode_sets
# GET /metacode_sets.json

View file

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

View file

@ -1,20 +1,17 @@
class SynapsesController < ApplicationController
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
# GET /synapses/1.json
def show
@synapse = Synapse.find(params[:id])
authorize @synapse
#.authorize_to_show(@current)
#if not @synapse
# redirect_to root_url and return
#end
render json: @synapse
end
@ -22,7 +19,8 @@ class SynapsesController < ApplicationController
# POST /synapses.json
def create
@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|
if @synapse.save
@ -37,7 +35,8 @@ class SynapsesController < ApplicationController
# PUT /synapses/1.json
def update
@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|
if @synapse.update_attributes(synapse_params)
@ -50,8 +49,9 @@ class SynapsesController < ApplicationController
# DELETE synapses/:id
def destroy
@synapse = Synapse.find(params[:id]).authorize_to_delete(current_user)
@synapse.delete if @synapse
@synapse = Synapse.find(params[:id])
authorize @synapse
@synapse.delete
respond_to do |format|
format.json { head :no_content }

View file

@ -1,215 +1,164 @@
class TopicsController < ApplicationController
include TopicsHelper
before_filter :require_user, only: [:create, :update, :destroy]
respond_to :html, :js, :json
# GET /topics/autocomplete_topic
def autocomplete_topic
@current = current_user
term = params[:term]
if term && !term.empty?
@topics = Topic.where('LOWER("name") like ?', term.downcase + '%').order('"name"')
#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.id != t.user_id)) }
else
@topics = []
end
render json: autocomplete_array_json(@topics)
end
# GET topics/:id
def show
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_show(@current)
if not @topic
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
respond_to do |format|
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
@allsynapses = @topic.synapses.to_a.delete_if {|s| s.permission == "private" && (!authenticated? || (authenticated? && @current.id != s.user_id)) }
@allcreators = []
@alltopics.each do |t|
if @allcreators.index(t.user) == nil
@allcreators.push(t.user)
end
end
@allsynapses.each do |s|
if @allcreators.index(s.user) == nil
@allcreators.push(s.user)
end
end
respond_with(@allsynapses, @alltopics, @allcreators, @topic)
}
format.json { render json: @topic }
end
end
# GET topics/:id/network
def network
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_show(@current)
if not @topic
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
@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)) }
@allcreators = []
@allcreators.push(@topic.user)
@alltopics.each do |t|
if @allcreators.index(t.user) == nil
@allcreators.push(t.user)
end
end
@allsynapses.each do |s|
if @allcreators.index(s.user) == nil
@allcreators.push(s.user)
end
end
@json = Hash.new()
@json['topic'] = @topic
@json['creators'] = @allcreators
@json['relatives'] = @alltopics
@json['synapses'] = @allsynapses
respond_to do |format|
format.json { render json: @json }
end
end
# GET topics/:id/relative_numbers
def relative_numbers
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_show(@current)
if not @topic
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
@alltopics = @topic.relatives.to_a.delete_if {|t|
@topicsAlreadyHas.index(t.id.to_s) != nil ||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
}
@alltopics.uniq!
@json = Hash.new()
@alltopics.each do |t|
if @json[t.metacode.id]
@json[t.metacode.id] += 1
else
@json[t.metacode.id] = 1
end
end
respond_to do |format|
format.json { render json: @json }
end
end
# GET topics/:id/relatives
def relatives
@current = current_user
@topic = Topic.find(params[:id]).authorize_to_show(@current)
if not @topic
redirect_to root_url, notice: "Access denied. That topic is private." and return
end
@topicsAlreadyHas = params[:network] ? params[:network].split(',') : []
@alltopics = @topic.relatives.to_a.delete_if {|t|
@topicsAlreadyHas.index(t.id.to_s) != nil ||
(params[:metacode] && t.metacode_id.to_s != params[:metacode]) ||
(t.permission == "private" && (!authenticated? || (authenticated? && @current.id != t.user_id)))
}
@alltopics.uniq!
@allsynapses = @topic.synapses.to_a.delete_if {|s|
(s.topic1 == @topic && @alltopics.index(s.topic2) == nil) ||
(s.topic2 == @topic && @alltopics.index(s.topic1) == nil)
}
@creatorsAlreadyHas = params[:creators] ? params[:creators].split(',') : []
@allcreators = []
@alltopics.each do |t|
if @allcreators.index(t.user) == nil && @creatorsAlreadyHas.index(t.user_id.to_s) == nil
@allcreators.push(t.user)
end
end
@allsynapses.each do |s|
if @allcreators.index(s.user) == nil && @creatorsAlreadyHas.index(s.user_id.to_s) == nil
@allcreators.push(s.user)
end
end
@json = Hash.new()
@json['topics'] = @alltopics
@json['synapses'] = @allsynapses
@json['creators'] = @allcreators
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
class TopicsController < ApplicationController
include TopicsHelper
before_action :require_user, only: [:create, :update, :destroy]
after_action :verify_authorized, except: :autocomplete_topic
respond_to :html, :js, :json
# GET /topics/autocomplete_topic
def autocomplete_topic
term = params[:term]
if term && !term.empty?
@topics = policy_scope(Topic.where('LOWER("name") like ?', term.downcase + '%')).order('"name"')
else
@topics = []
end
render json: autocomplete_array_json(@topics)
end
# GET topics/:id
def show
@topic = Topic.find(params[:id])
authorize @topic
respond_to do |format|
format.html {
@alltopics = [@topic].concat(policy_scope(Topic.relatives1(@topic.id)).to_a).concat(policy_scope(Topic.relatives2(@topic.id)).to_a)
@allsynapses = policy_scope(Synapse.for_topic(@topic.id)).to_a
puts @alltopics.length
puts @allsynapses.length
@allcreators = @alltopics.map(&:user).uniq
@allcreators += @allsynapses.map(&:user).uniq
respond_with(@allsynapses, @alltopics, @allcreators, @topic)
}
format.json { render json: @topic }
end
end
# GET topics/:id/network
def network
@topic = Topic.find(params[:id])
authorize @topic
@alltopics = [@topic].concat(policy_scope(Topic.relatives1(@topic.id)).to_a).concat(policy_scope(Topic.relatives2(@topic.id)).to_a)
@allsynapses = policy_scope(Synapse.for_topic(@topic.id))
@allcreators = @alltopics.map(&:user).uniq
@allcreators += @allsynapses.map(&:user).uniq
@json = Hash.new()
@json['topic'] = @topic
@json['creators'] = @allcreators
@json['relatives'] = @alltopics
@json['synapses'] = @allsynapses
respond_to do |format|
format.json { render json: @json }
end
end
# GET topics/:id/relative_numbers
def relative_numbers
@topic = Topic.find(params[:id])
authorize @topic
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
@alltopics = policy_scope(Topic.relatives1(@topic.id)).to_a.concat(policy_scope(Topic.relatives2(@topic.id)).to_a).uniq
@alltopics.delete_if do |topic|
topicsAlreadyHas.index(topic.id) != nil
end
@json = Hash.new(0)
@alltopics.each do |t|
@json[t.metacode.id] += 1
end
respond_to do |format|
format.json { render json: @json }
end
end
# GET topics/:id/relatives
def relatives
@topic = Topic.find(params[:id])
authorize @topic
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
alltopics = policy_scope(Topic.relatives1(@topic.id)).to_a.concat(policy_scope(Topic.relatives2(@topic.id)).to_a).uniq
alltopics.delete_if do |topic|
topicsAlreadyHas.index(topic.id.to_s) != nil
end
#find synapses between topics in alltopics array
allsynapses = policy_scope(Synapse.for_topic(@topic.id)).to_a
synapse_ids = (allsynapses.map(&:node1_id) + allsynapses.map(&:node2_id)).uniq
allsynapses.delete_if do |synapse|
synapse_ids.index(synapse.id) != nil
end
creatorsAlreadyHas = params[:creators] ? params[:creators].split(',').map(&:to_i) : []
allcreators = (alltopics.map(&:user) + allsynapses.map(&:user)).uniq.delete_if do |user|
creatorsAlreadyHas.index(user.id) != nil
end
@json = Hash.new()
@json['topics'] = alltopics
@json['synapses'] = allsynapses
@json['creators'] = allcreators
respond_to do |format|
format.json { render json: @json }
end
end
# POST /topics
# POST /topics.json
def create
@topic = Topic.new(topic_params)
authorize @topic
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])
authorize @topic
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
@topic = Topic.find(params[:id])
authorize @topic
@topic.delete
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
before_filter :configure_sign_up_params, only: [:create]
before_filter :configure_account_update_params, only: [:update]
before_action :configure_sign_up_params, only: [:create]
before_action :configure_account_update_params, only: [:update]
protected
def after_sign_up_path_for(resource)

View file

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

View file

@ -1,12 +1,12 @@
module ApplicationHelper
module ApplicationHelper
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
return set
end
def user_metacodes
@m = user.settings.metacodes
@m = current_user.settings.metacodes
set = get_metacodeset
if set
@metacodes = set.metacodes.to_a
@ -15,4 +15,8 @@ module ApplicationHelper
end
@metacodes.sort! {|m1,m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
end
def determine_invite_link
"#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : "")
end
end

View file

@ -8,7 +8,7 @@ module TopicsHelper
topic['id'] = t.id
topic['label'] = 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['typeImageURL'] = t.metacode.icon
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 :topics, through: :topicmappings, source: :mappable, source_type: "Topic"
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
has_attached_file :screenshot, :styles => {
@ -13,15 +17,16 @@ class Map < ActiveRecord::Base
#:full => ['940x630#', :png]
},
:default_url => 'https://s3.amazonaws.com/metamaps-assets/site/missing-map.png'
validates :name, presence: true
validates :arranged, inclusion: { in: [true, false] }
validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :screenshot, :content_type => /\Aimage\/.*\Z/
def mappings
def mappings
topicmappings + synapsemappings
end
@ -32,85 +37,56 @@ class Map < ActiveRecord::Base
#return an array of the contributors to the map
def contributors
contributors = []
self.mappings.each do |m|
contributors.push(m.user) if !contributors.include?(m.user)
end
return contributors
end
def topic_count
self.topics.length
topics.length
end
def synapse_count
self.synapses.length
synapses.length
end
def user_name
self.user.name
user.name
end
def user_image
self.user.image.url
user.image.url
end
def contributor_count
self.contributors.length
contributors.length
end
def screenshot_url
self.screenshot.url(:thumb)
screenshot.url(:thumb)
end
def created_at_str
self.created_at.strftime("%m/%d/%Y")
created_at.strftime("%m/%d/%Y")
end
def updated_at_str
self.updated_at.strftime("%m/%d/%Y")
updated_at.strftime("%m/%d/%Y")
end
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[:created_at_clean] = self.created_at_str
json[:updated_at_clean] = self.updated_at_str
json[:created_at_clean] = created_at_str
json[:updated_at_clean] = updated_at_str
json
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)
decoded_data = Base64.decode64(imgBase64)
data = StringIO.new(decoded_data)
data.class_eval do
attr_accessor :content_type, :original_filename

View file

@ -4,10 +4,15 @@ class Mapping < ActiveRecord::Base
scope :synapsemapping, -> { where(mappable_type: :Synapse) }
belongs_to :mappable, polymorphic: true
belongs_to :map, :class_name => "Map", :foreign_key => "map_id"
belongs_to :map, :class_name => "Map", :foreign_key => "map_id", touch: true
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
self.user.name
@ -20,5 +25,5 @@ class Mapping < ActiveRecord::Base
def as_json(options={})
super(:methods =>[:user_name, :user_image])
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
has_many :in_metacode_sets
has_many :metacode_sets, :through => :in_metacode_sets
has_many :metacode_sets, :through => :in_metacode_sets
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)
return true if user.settings.metacodes.include? self.id.to_s
return false
end
def inMetacodeSet(metacode_set)
return true if self.metacode_sets.include? metacode_set
return false
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

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
belongs_to :user
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 :permission, presence: true
validates :node1_id, presence: true
validates :node2_id, presence: true
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
self.user.name
user.name
end
# :nocov:
# :nocov:
def user_image
self.user.image.url
user.image.url
end
# :nocov:
# :nocov:
def as_json(options={})
super(:methods =>[:user_name, :user_image])
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

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
include TopicsHelper
belongs_to :user
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 :topics1, :through => :synapses2, :source => :topic1
has_many :topics2, :through => :synapses1, :source => :topic2
has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, :through => :mappings
validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
# This method associates the attribute ":image" with a file attachment
has_attached_file :image
#, styles: {
# thumb: '100x100>',
# square: '200x200#',
# medium: '300x300>'
#}
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
# This method associates the attribute ":image" with a file attachment
has_attached_file :audio
# Validate the attached audio is audio/wav, audio/mp3, etc
validates_attachment_content_type :audio, :content_type => /\Aaudio\/.*\Z/
def synapses
synapses1 + synapses2
end
def relatives
topics1 + topics2
end
belongs_to :metacode
def user_name
user.name
end
def user_image
user.image.url
end
def map_count
maps.count
end
def synapse_count
synapses.count
end
def inmaps
maps.map(&:name)
end
def inmapsLinks
maps.map(&:id)
end
def as_json(options={})
super(:methods =>[:user_name, :user_image, :map_count, :synapse_count, :inmaps, :inmapsLinks])
end
def topic_autocomplete_method
"Get: #{self.name}"
end
def mk_permission
Perm.short(permission)
end
# has no viewable synapses helper function
def has_viewable_synapses(current)
result = false
synapses.each do |synapse|
if synapse.authorize_to_show(current)
result = true
end
end
result
end
##### 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
class Topic < ActiveRecord::Base
include TopicsHelper
belongs_to :user
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 :topics1, :through => :synapses2, source: :topic1
has_many :topics2, :through => :synapses1, source: :topic2
has_many :mappings, as: :mappable, dependent: :destroy
has_many :maps, :through => :mappings
validates :permission, presence: true
validates :permission, inclusion: { in: Perm::ISSIONS.map(&:to_s) }
# This method associates the attribute ":image" with a file attachment
has_attached_file :image
#, styles: {
# thumb: '100x100>',
# square: '200x200#',
# medium: '300x300>'
#}
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
# This method associates the attribute ":image" with a file attachment
has_attached_file :audio
# Validate the attached audio is audio/wav, audio/mp3, etc
validates_attachment_content_type :audio, :content_type => /\Aaudio\/.*\Z/
def synapses
synapses1 + synapses2
end
def relatives
topics1 + topics2
end
belongs_to :metacode
scope :relatives1, ->(topic_id = nil) {
includes(:topics1)
.where('synapses.node1_id = ?', topic_id)
.references(:synapses)
}
scope :relatives2, ->(topic_id = nil) {
includes(:topics2)
.where('synapses.node2_id = ?', topic_id)
.references(:synapses)
}
def user_name
user.name
end
def user_image
user.image.url
end
def map_count
maps.count
end
def synapse_count
synapses.count
end
def inmaps
maps.map(&:name)
end
def inmapsLinks
maps.map(&:id)
end
def as_json(options={})
super(:methods =>[:user_name, :user_image, :map_count, :synapse_count, :inmaps, :inmapsLinks])
end
# TODO move to a decorator?
def synapses_csv(output_format = 'array')
output = []
synapses.each do |synapse|
if synapse.category == 'from-to'
if synapse.node1_id == id
output << synapse.node1_id.to_s + '->' + synapse.node2_id.to_s
elsif synapse.node2_id == id
output << synapse.node2_id.to_s + '<-' + synapse.node1_id.to_s
else
fail 'invalid synapse on topic in synapse_csv'
end
elsif synapse.category == 'both'
if synapse.node1_id == id
output << synapse.node1_id.to_s + '<->' + synapse.node2_id.to_s
elsif synapse.node2_id == id
output << synapse.node2_id.to_s + '<->' + synapse.node1_id.to_s
else
fail 'invalid synapse on topic in synapse_csv'
end
end
end
if output_format == 'array'
return output
elsif output_format == 'text'
return output.join('; ')
else
fail 'invalid argument to synapses_csv'
end
output
end
def topic_autocomplete_method
"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 :maps
has_many :mappings
has_many :tokens
after_create :generate_code
devise :database_authenticatable, :recoverable, :rememberable, :trackable, :registerable
serialize :settings, UserPreference
validates :password, :presence => true,
:length => { :within => 8..40 },
:on => :create
@ -27,7 +28,7 @@ class User < ActiveRecord::Base
validates_uniqueness_of :email # done by devise
validates :joinedwithcode, :presence => true, :inclusion => { :in => $codes, :message => "%{value} is not valid" }, :on => :create
# This method associates the attribute ":image" with a file attachment
has_attached_file :image, :styles => {
:thirtytwo => ['32x32#', :png],
@ -36,7 +37,7 @@ class User < ActiveRecord::Base
:onetwentyeight => ['128x128#', :png]
},
:default_url => 'https://s3.amazonaws.com/metamaps-assets/site/user.png'
# Validate the attached image is image/jpg, image/png, etc
validates_attachment_content_type :image, :content_type => /\Aimage\/.*\Z/
@ -61,7 +62,7 @@ class User < ActiveRecord::Base
json['rtype'] = "mapper"
json
end
#generate a random 8 letter/digit code that they can use to invite people
def generate_code
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)
end
end
def settings
# make sure we always return a UserPreference instance
if read_attribute(:settings).nil?
@ -84,7 +85,7 @@ class User < ActiveRecord::Base
end
read_attribute :settings
end
def settings=(val)
write_attribute :settings, val
end

View file

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