Compare commits
1 commit
develop
...
feature/im
Author | SHA1 | Date | |
---|---|---|---|
|
7635498f14 |
|
@ -1 +0,0 @@
|
||||||
app/assets/javascripts/metamaps.secret.bundle.js
|
|
1
.babelrc
|
@ -4,7 +4,6 @@
|
||||||
"es2015"
|
"es2015"
|
||||||
],
|
],
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"lodash",
|
|
||||||
"transform-class-properties"
|
"transform-class-properties"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,23 +5,17 @@ engines:
|
||||||
bundler-audit:
|
bundler-audit:
|
||||||
enabled: true
|
enabled: true
|
||||||
duplication:
|
duplication:
|
||||||
enabled: true
|
enabled: false
|
||||||
config:
|
config:
|
||||||
languages:
|
languages:
|
||||||
count_threshold: 3 # rule of three
|
- ruby
|
||||||
ruby:
|
- javascript
|
||||||
mass_threshold: 36 # default: 18
|
|
||||||
javascript:
|
|
||||||
mass_threshold: 80 # default: 40
|
|
||||||
eslint:
|
eslint:
|
||||||
enabled: true
|
enabled: true
|
||||||
channel: "eslint-3"
|
|
||||||
fixme:
|
fixme:
|
||||||
enabled: true
|
enabled: true
|
||||||
rubocop:
|
rubocop:
|
||||||
enabled: true
|
enabled: true
|
||||||
exclude_fingerprints:
|
|
||||||
- 74f18007b920e8d81148d2f6a2756534
|
|
||||||
ratings:
|
ratings:
|
||||||
paths:
|
paths:
|
||||||
- 'Gemfile.lock'
|
- 'Gemfile.lock'
|
||||||
|
|
25
.eslintrc.js
|
@ -1,26 +1,9 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"sourceType": "module",
|
"sourceType": "module",
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"parserOptions": {
|
|
||||||
"ecmaFeatures": {
|
|
||||||
"jsx": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"extends": "standard",
|
"extends": "standard",
|
||||||
"installedESLint": true,
|
"installedESLint": true,
|
||||||
"env": {
|
|
||||||
"es6": true,
|
|
||||||
"node": true
|
|
||||||
},
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
"promise",
|
"standard"
|
||||||
"standard",
|
]
|
||||||
"react"
|
};
|
||||||
],
|
|
||||||
"rules": {
|
|
||||||
"react/jsx-uses-react": [2],
|
|
||||||
"react/jsx-uses-vars": [2],
|
|
||||||
"space-before-function-paren": [2, "never"],
|
|
||||||
"yoda": [2, "never", { "exceptRange": true }]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
10
.example-env
|
@ -1,14 +1,10 @@
|
||||||
# Node JS env
|
|
||||||
export NODE_REALTIME_PORT='5000' # should match REALTIME_SERVER, below
|
|
||||||
|
|
||||||
# Rails env
|
|
||||||
export DB_USERNAME='postgres'
|
export DB_USERNAME='postgres'
|
||||||
export DB_PASSWORD='3112'
|
export DB_PASSWORD='3112'
|
||||||
export DB_HOST='localhost'
|
export DB_HOST='localhost'
|
||||||
export DB_PORT='5432'
|
export DB_PORT='5432'
|
||||||
export DB_NAME='metamaps'
|
export DB_NAME='metamap002'
|
||||||
|
|
||||||
export REALTIME_SERVER='http://localhost:5000'
|
export REALTIME_SERVER='http://localhost:5001'
|
||||||
export MAILER_DEFAULT_URL='localhost:3000'
|
export MAILER_DEFAULT_URL='localhost:3000'
|
||||||
export DEVISE_MAILER_SENDER='team@metamaps.cc'
|
export DEVISE_MAILER_SENDER='team@metamaps.cc'
|
||||||
|
|
||||||
|
@ -18,10 +14,10 @@ export SECRET_KEY_BASE='267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c800
|
||||||
# # you can safely leave these blank, unless you're deploying an instance, in
|
# # you can safely leave these blank, unless you're deploying an instance, in
|
||||||
# # which case you'll need to set them up
|
# # which case you'll need to set them up
|
||||||
#
|
#
|
||||||
# export S3_REGION
|
|
||||||
# export S3_BUCKET_NAME
|
# export S3_BUCKET_NAME
|
||||||
# export AWS_ACCESS_KEY_ID
|
# export AWS_ACCESS_KEY_ID
|
||||||
# export AWS_SECRET_ACCESS_KEY
|
# export AWS_SECRET_ACCESS_KEY
|
||||||
|
# export SSO_KEY
|
||||||
#
|
#
|
||||||
# export SMTP_DOMAIN
|
# export SMTP_DOMAIN
|
||||||
# export SMTP_PASSWORD
|
# export SMTP_PASSWORD
|
||||||
|
|
5
.gitignore
vendored
|
@ -7,7 +7,6 @@
|
||||||
#assety stuff
|
#assety stuff
|
||||||
public/assets
|
public/assets
|
||||||
public/metamaps_mobile
|
public/metamaps_mobile
|
||||||
public/api/index.html
|
|
||||||
vendor/
|
vendor/
|
||||||
node_modules
|
node_modules
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
@ -15,7 +14,6 @@ app/assets/javascripts/webpacked
|
||||||
|
|
||||||
#secrets and config
|
#secrets and config
|
||||||
.env
|
.env
|
||||||
*.swp
|
|
||||||
|
|
||||||
# Ignore bundler config
|
# Ignore bundler config
|
||||||
.bundle
|
.bundle
|
||||||
|
@ -23,7 +21,6 @@ app/assets/javascripts/webpacked
|
||||||
# Ignore all logfiles and tempfiles.
|
# Ignore all logfiles and tempfiles.
|
||||||
log/*.log
|
log/*.log
|
||||||
tmp
|
tmp
|
||||||
.tmp
|
|
||||||
|
|
||||||
coverage
|
coverage
|
||||||
|
|
||||||
|
@ -31,5 +28,3 @@ coverage
|
||||||
*/.DS_Store
|
*/.DS_Store
|
||||||
.DS_Store?
|
.DS_Store?
|
||||||
.vagrant
|
.vagrant
|
||||||
gentle/
|
|
||||||
startserver.sh
|
|
||||||
|
|
10
.rubocop.yml
|
@ -12,18 +12,10 @@ Rails:
|
||||||
Enabled: true
|
Enabled: true
|
||||||
|
|
||||||
Metrics/LineLength:
|
Metrics/LineLength:
|
||||||
Max: 120
|
Max: 100
|
||||||
|
|
||||||
Metrics/AbcSize:
|
Metrics/AbcSize:
|
||||||
Max: 16
|
Max: 16
|
||||||
|
|
||||||
Style/Documentation:
|
Style/Documentation:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Style/EmptyMethod:
|
|
||||||
EnforcedStyle: expanded
|
|
||||||
|
|
||||||
# I like this cop, but occasionally code is more readable without a guard clause,
|
|
||||||
# and I don't want to write rubocop:disable comments every time that happens
|
|
||||||
Style/GuardClause:
|
|
||||||
Enabled: false
|
|
||||||
|
|
|
@ -1,7 +1,3 @@
|
||||||
if ENV['COVERAGE'] == 'on'
|
if ENV['COVERAGE'] == 'on'
|
||||||
SimpleCov.start 'rails' do
|
SimpleCov.start 'rails'
|
||||||
add_group 'Policies', 'app/policies'
|
|
||||||
add_group 'Services', 'app/services'
|
|
||||||
add_group 'Serializers', 'app/serializers'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,10 +16,9 @@ before_script:
|
||||||
- . $HOME/.nvm/nvm.sh
|
- . $HOME/.nvm/nvm.sh
|
||||||
- nvm install stable
|
- nvm install stable
|
||||||
- nvm use stable
|
- nvm use stable
|
||||||
- npm install --no-optional
|
- npm install
|
||||||
script:
|
script:
|
||||||
- bundle exec rspec && bundle exec brakeman -q -z && npm test
|
- bundle exec rspec && bundle exec brakeman -q -z && npm test
|
||||||
addons:
|
addons:
|
||||||
code_climate:
|
code_climate:
|
||||||
repo_token: 479d3bf56798fbc7fff3fc8151a5ed09e8ac368fd5af332c437b9e07dbebb44e
|
repo_token: 479d3bf56798fbc7fff3fc8151a5ed09e8ac368fd5af332c437b9e07dbebb44e
|
||||||
postgresql: "9.4"
|
|
||||||
|
|
39
Gemfile
|
@ -1,57 +1,62 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://rubygems.org'
|
source 'https://rubygems.org'
|
||||||
ruby '2.3.0'
|
ruby '2.3.0'
|
||||||
|
|
||||||
gem 'rails', '~> 5.0.0'
|
gem 'rails', '~> 5.0.0'
|
||||||
|
|
||||||
gem 'active_model_serializers'
|
gem 'active_model_serializers'
|
||||||
gem 'aws-sdk', '~> 2.7.0'
|
gem 'aws-sdk', '< 2.0'
|
||||||
gem 'best_in_place'
|
gem 'best_in_place'
|
||||||
gem 'delayed_job'
|
gem 'delayed_job'
|
||||||
gem 'delayed_job_active_record'
|
gem 'delayed_job_active_record'
|
||||||
gem 'devise'
|
gem 'devise'
|
||||||
gem 'doorkeeper'
|
gem 'doorkeeper', '~> 4.0.0.rc4'
|
||||||
gem 'dotenv-rails'
|
gem 'dotenv-rails'
|
||||||
gem 'exception_notification'
|
gem 'exception_notification'
|
||||||
|
gem 'formtastic'
|
||||||
|
gem 'formula'
|
||||||
gem 'httparty'
|
gem 'httparty'
|
||||||
gem 'json'
|
gem 'json'
|
||||||
gem 'kaminari'
|
gem 'kaminari'
|
||||||
gem 'mailboxer'
|
gem 'paperclip', '~> 4.3.6'
|
||||||
gem 'paperclip'
|
|
||||||
gem 'pg'
|
gem 'pg'
|
||||||
gem 'puma'
|
|
||||||
gem 'pundit'
|
gem 'pundit'
|
||||||
gem 'pundit_extra'
|
gem 'pundit_extra'
|
||||||
gem 'rack-attack'
|
|
||||||
gem 'rack-cors'
|
gem 'rack-cors'
|
||||||
gem 'redis', '~> 3.3.3'
|
gem 'redis'
|
||||||
gem 'slack-notifier'
|
gem 'slack-notifier'
|
||||||
gem 'snorlax'
|
gem 'snorlax'
|
||||||
gem 'sucker_punch'
|
gem 'uservoice-ruby'
|
||||||
|
|
||||||
# asset stuff
|
|
||||||
gem 'jquery-rails'
|
gem 'jquery-rails'
|
||||||
gem 'jquery-ui-rails'
|
gem 'jquery-ui-rails'
|
||||||
gem 'sass-rails'
|
gem 'jbuilder'
|
||||||
gem 'uglifier'
|
gem 'rails3-jquery-autocomplete'
|
||||||
|
|
||||||
|
group :assets do
|
||||||
|
gem 'coffee-rails'
|
||||||
|
gem 'sass-rails'
|
||||||
|
gem 'uglifier'
|
||||||
|
end
|
||||||
|
|
||||||
|
group :production do
|
||||||
|
gem 'rails_12factor'
|
||||||
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'brakeman', require: false
|
gem 'factory_girl_rails'
|
||||||
gem 'factory_bot_rails'
|
|
||||||
gem 'json-schema'
|
gem 'json-schema'
|
||||||
gem 'rspec-rails'
|
gem 'rspec-rails'
|
||||||
gem 'shoulda-matchers'
|
gem 'shoulda-matchers'
|
||||||
gem 'simplecov', require: false
|
gem 'simplecov', require: false
|
||||||
|
gem 'brakeman', require: false
|
||||||
end
|
end
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'better_errors'
|
gem 'better_errors'
|
||||||
gem 'binding_of_caller'
|
gem 'binding_of_caller'
|
||||||
gem 'faker'
|
|
||||||
gem 'pry-byebug'
|
gem 'pry-byebug'
|
||||||
gem 'pry-rails'
|
gem 'pry-rails'
|
||||||
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758
|
|
||||||
gem 'timecop'
|
|
||||||
gem 'tunemygc'
|
gem 'tunemygc'
|
||||||
|
gem 'rubocop'
|
||||||
end
|
end
|
||||||
|
|
391
Gemfile.lock
|
@ -1,297 +1,285 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://rubygems.org/
|
remote: https://rubygems.org/
|
||||||
specs:
|
specs:
|
||||||
actioncable (5.0.5)
|
actioncable (5.0.0.1)
|
||||||
actionpack (= 5.0.5)
|
actionpack (= 5.0.0.1)
|
||||||
nio4r (>= 1.2, < 3.0)
|
nio4r (~> 1.2)
|
||||||
websocket-driver (~> 0.6.1)
|
websocket-driver (~> 0.6.1)
|
||||||
actionmailer (5.0.5)
|
actionmailer (5.0.0.1)
|
||||||
actionpack (= 5.0.5)
|
actionpack (= 5.0.0.1)
|
||||||
actionview (= 5.0.5)
|
actionview (= 5.0.0.1)
|
||||||
activejob (= 5.0.5)
|
activejob (= 5.0.0.1)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (5.0.5)
|
actionpack (5.0.0.1)
|
||||||
actionview (= 5.0.5)
|
actionview (= 5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
rack (~> 2.0)
|
rack (~> 2.0)
|
||||||
rack-test (~> 0.6.3)
|
rack-test (~> 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
actionview (5.0.5)
|
actionview (5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubis (~> 2.7.0)
|
erubis (~> 2.7.0)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||||
active_model_serializers (0.10.6)
|
active_model_serializers (0.10.2)
|
||||||
actionpack (>= 4.1, < 6)
|
actionpack (>= 4.1, < 6)
|
||||||
activemodel (>= 4.1, < 6)
|
activemodel (>= 4.1, < 6)
|
||||||
case_transform (>= 0.2)
|
jsonapi (~> 0.1.1.beta2)
|
||||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
|
railties (>= 4.1, < 6)
|
||||||
activejob (5.0.5)
|
activejob (5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (5.0.5)
|
activemodel (5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
activerecord (5.0.5)
|
activerecord (5.0.0.1)
|
||||||
activemodel (= 5.0.5)
|
activemodel (= 5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
arel (~> 7.0)
|
arel (~> 7.0)
|
||||||
activesupport (5.0.5)
|
activesupport (5.0.0.1)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (~> 0.7)
|
i18n (~> 0.7)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 1.1)
|
||||||
addressable (2.5.2)
|
addressable (2.3.8)
|
||||||
public_suffix (>= 2.0.2, < 4.0)
|
arel (7.1.2)
|
||||||
arel (7.1.4)
|
|
||||||
ast (2.3.0)
|
ast (2.3.0)
|
||||||
aws-sdk (2.7.0)
|
aws-sdk (1.66.0)
|
||||||
aws-sdk-resources (= 2.7.0)
|
aws-sdk-v1 (= 1.66.0)
|
||||||
aws-sdk-core (2.7.0)
|
aws-sdk-v1 (1.66.0)
|
||||||
aws-sigv4 (~> 1.0)
|
json (~> 1.4)
|
||||||
jmespath (~> 1.0)
|
nokogiri (>= 1.4.4)
|
||||||
aws-sdk-resources (2.7.0)
|
|
||||||
aws-sdk-core (= 2.7.0)
|
|
||||||
aws-sigv4 (1.0.2)
|
|
||||||
bcrypt (3.1.11)
|
bcrypt (3.1.11)
|
||||||
best_in_place (3.1.1)
|
best_in_place (3.1.0)
|
||||||
actionpack (>= 3.2)
|
actionpack (>= 3.2)
|
||||||
railties (>= 3.2)
|
railties (>= 3.2)
|
||||||
better_errors (2.3.0)
|
better_errors (2.1.1)
|
||||||
coderay (>= 1.0.0)
|
coderay (>= 1.0.0)
|
||||||
erubi (>= 1.0.0)
|
erubis (>= 2.6.6)
|
||||||
rack (>= 0.9.0)
|
rack (>= 0.9.0)
|
||||||
binding_of_caller (0.7.2)
|
binding_of_caller (0.7.2)
|
||||||
debug_inspector (>= 0.0.1)
|
debug_inspector (>= 0.0.1)
|
||||||
brakeman (3.7.2)
|
brakeman (3.4.0)
|
||||||
builder (3.2.3)
|
builder (3.2.2)
|
||||||
byebug (9.1.0)
|
byebug (9.0.5)
|
||||||
carrierwave (1.1.0)
|
climate_control (0.0.3)
|
||||||
activemodel (>= 4.0.0)
|
activesupport (>= 3.0)
|
||||||
activesupport (>= 4.0.0)
|
|
||||||
mime-types (>= 1.16)
|
|
||||||
case_transform (0.2)
|
|
||||||
activesupport
|
|
||||||
climate_control (0.2.0)
|
|
||||||
cocaine (0.5.8)
|
cocaine (0.5.8)
|
||||||
climate_control (>= 0.0.3, < 1.0)
|
climate_control (>= 0.0.3, < 1.0)
|
||||||
coderay (1.1.2)
|
coderay (1.1.1)
|
||||||
concurrent-ruby (1.0.5)
|
coffee-rails (4.2.1)
|
||||||
debug_inspector (0.0.3)
|
coffee-script (>= 2.2.0)
|
||||||
delayed_job (4.1.3)
|
railties (>= 4.0.0, < 5.2.x)
|
||||||
activesupport (>= 3.0, < 5.2)
|
coffee-script (2.4.1)
|
||||||
delayed_job_active_record (4.1.2)
|
coffee-script-source
|
||||||
activerecord (>= 3.0, < 5.2)
|
execjs
|
||||||
|
coffee-script-source (1.10.0)
|
||||||
|
concurrent-ruby (1.0.2)
|
||||||
|
debug_inspector (0.0.2)
|
||||||
|
delayed_job (4.1.2)
|
||||||
|
activesupport (>= 3.0, < 5.1)
|
||||||
|
delayed_job_active_record (4.1.1)
|
||||||
|
activerecord (>= 3.0, < 5.1)
|
||||||
delayed_job (>= 3.0, < 5)
|
delayed_job (>= 3.0, < 5)
|
||||||
devise (4.3.0)
|
devise (4.2.0)
|
||||||
bcrypt (~> 3.0)
|
bcrypt (~> 3.0)
|
||||||
orm_adapter (~> 0.1)
|
orm_adapter (~> 0.1)
|
||||||
railties (>= 4.1.0, < 5.2)
|
railties (>= 4.1.0, < 5.1)
|
||||||
responders
|
responders
|
||||||
warden (~> 1.2.3)
|
warden (~> 1.2.3)
|
||||||
diff-lcs (1.3)
|
diff-lcs (1.2.5)
|
||||||
docile (1.1.5)
|
docile (1.1.5)
|
||||||
doorkeeper (4.2.6)
|
doorkeeper (4.0.0)
|
||||||
railties (>= 4.2)
|
railties (>= 4.2)
|
||||||
dotenv (2.2.1)
|
dotenv (2.1.1)
|
||||||
dotenv-rails (2.2.1)
|
dotenv-rails (2.1.1)
|
||||||
dotenv (= 2.2.1)
|
dotenv (= 2.1.1)
|
||||||
railties (>= 3.2, < 5.2)
|
railties (>= 4.0, < 5.1)
|
||||||
erubi (1.6.1)
|
|
||||||
erubis (2.7.0)
|
erubis (2.7.0)
|
||||||
exception_notification (4.2.2)
|
exception_notification (4.2.1)
|
||||||
actionmailer (>= 4.0, < 6)
|
actionmailer (>= 4.0, < 6)
|
||||||
activesupport (>= 4.0, < 6)
|
activesupport (>= 4.0, < 6)
|
||||||
execjs (2.7.0)
|
execjs (2.7.0)
|
||||||
factory_bot (4.8.2)
|
ezcrypto (0.7.2)
|
||||||
|
factory_girl (4.7.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
factory_bot_rails (4.8.2)
|
factory_girl_rails (4.7.0)
|
||||||
factory_bot (~> 4.8.2)
|
factory_girl (~> 4.7.0)
|
||||||
railties (>= 3.0.0)
|
railties (>= 3.0.0)
|
||||||
faker (1.8.4)
|
formtastic (3.1.4)
|
||||||
i18n (~> 0.5)
|
actionpack (>= 3.2.13)
|
||||||
ffi (1.9.18)
|
formula (1.1.1)
|
||||||
globalid (0.4.0)
|
rails (> 3.0.0)
|
||||||
activesupport (>= 4.2.0)
|
globalid (0.3.7)
|
||||||
httparty (0.15.6)
|
activesupport (>= 4.1.0)
|
||||||
|
httparty (0.14.0)
|
||||||
multi_xml (>= 0.5.2)
|
multi_xml (>= 0.5.2)
|
||||||
i18n (0.9.3)
|
i18n (0.7.0)
|
||||||
concurrent-ruby (~> 1.0)
|
jbuilder (2.6.0)
|
||||||
jmespath (1.3.1)
|
activesupport (>= 3.0.0, < 5.1)
|
||||||
jquery-rails (4.3.1)
|
multi_json (~> 1.2)
|
||||||
|
jquery-rails (4.2.1)
|
||||||
rails-dom-testing (>= 1, < 3)
|
rails-dom-testing (>= 1, < 3)
|
||||||
railties (>= 4.2.0)
|
railties (>= 4.2.0)
|
||||||
thor (>= 0.14, < 2.0)
|
thor (>= 0.14, < 2.0)
|
||||||
jquery-ui-rails (6.0.1)
|
jquery-ui-rails (5.0.5)
|
||||||
railties (>= 3.2.16)
|
railties (>= 3.2.16)
|
||||||
json (2.1.0)
|
json (1.8.3)
|
||||||
json-schema (2.8.0)
|
json-schema (2.6.2)
|
||||||
addressable (>= 2.4)
|
addressable (~> 2.3.8)
|
||||||
jsonapi-renderer (0.1.3)
|
jsonapi (0.1.1.beta2)
|
||||||
kaminari (1.0.1)
|
json (~> 1.8)
|
||||||
activesupport (>= 4.1.0)
|
kaminari (0.17.0)
|
||||||
kaminari-actionview (= 1.0.1)
|
actionpack (>= 3.0.0)
|
||||||
kaminari-activerecord (= 1.0.1)
|
activesupport (>= 3.0.0)
|
||||||
kaminari-core (= 1.0.1)
|
|
||||||
kaminari-actionview (1.0.1)
|
|
||||||
actionview
|
|
||||||
kaminari-core (= 1.0.1)
|
|
||||||
kaminari-activerecord (1.0.1)
|
|
||||||
activerecord
|
|
||||||
kaminari-core (= 1.0.1)
|
|
||||||
kaminari-core (1.0.1)
|
|
||||||
loofah (2.0.3)
|
loofah (2.0.3)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.6.6)
|
mail (2.6.4)
|
||||||
mime-types (>= 1.16, < 4)
|
mime-types (>= 1.16, < 4)
|
||||||
mailboxer (0.15.1)
|
|
||||||
carrierwave (>= 0.5.8)
|
|
||||||
rails (>= 5.0.0)
|
|
||||||
method_source (0.8.2)
|
method_source (0.8.2)
|
||||||
mime-types (3.1)
|
mime-types (3.1)
|
||||||
mime-types-data (~> 3.2015)
|
mime-types-data (~> 3.2015)
|
||||||
mime-types-data (3.2016.0521)
|
mime-types-data (3.2016.0521)
|
||||||
mimemagic (0.3.2)
|
mimemagic (0.3.0)
|
||||||
mini_portile2 (2.3.0)
|
mini_portile2 (2.1.0)
|
||||||
minitest (5.11.1)
|
minitest (5.9.0)
|
||||||
multi_xml (0.6.0)
|
multi_json (1.12.1)
|
||||||
nio4r (2.1.0)
|
multi_xml (0.5.5)
|
||||||
nokogiri (1.8.1)
|
nio4r (1.2.1)
|
||||||
mini_portile2 (~> 2.3.0)
|
nokogiri (1.6.8)
|
||||||
|
mini_portile2 (~> 2.1.0)
|
||||||
|
pkg-config (~> 1.1.7)
|
||||||
|
oauth (0.5.1)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
paperclip (5.2.0)
|
paperclip (4.3.7)
|
||||||
activemodel (>= 4.2.0)
|
activemodel (>= 3.2.0)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 3.2.0)
|
||||||
cocaine (~> 0.5.5)
|
cocaine (~> 0.5.5)
|
||||||
mime-types
|
mime-types
|
||||||
mimemagic (~> 0.3.0)
|
mimemagic (= 0.3.0)
|
||||||
parser (2.4.0.2)
|
parser (2.3.1.4)
|
||||||
ast (~> 2.3)
|
ast (~> 2.2)
|
||||||
pg (0.21.0)
|
pg (0.19.0)
|
||||||
|
pkg-config (1.1.7)
|
||||||
powerpack (0.1.1)
|
powerpack (0.1.1)
|
||||||
pry (0.10.4)
|
pry (0.10.4)
|
||||||
coderay (~> 1.1.0)
|
coderay (~> 1.1.0)
|
||||||
method_source (~> 0.8.1)
|
method_source (~> 0.8.1)
|
||||||
slop (~> 3.4)
|
slop (~> 3.4)
|
||||||
pry-byebug (3.5.0)
|
pry-byebug (3.4.0)
|
||||||
byebug (~> 9.1)
|
byebug (~> 9.0)
|
||||||
pry (~> 0.10)
|
pry (~> 0.10)
|
||||||
pry-rails (0.3.6)
|
pry-rails (0.3.4)
|
||||||
pry (>= 0.10.4)
|
pry (>= 0.9.10)
|
||||||
public_suffix (3.0.0)
|
|
||||||
puma (3.10.0)
|
|
||||||
pundit (1.1.0)
|
pundit (1.1.0)
|
||||||
activesupport (>= 3.0.0)
|
activesupport (>= 3.0.0)
|
||||||
pundit_extra (0.3.0)
|
pundit_extra (0.3.0)
|
||||||
rack (2.0.3)
|
rack (2.0.1)
|
||||||
rack-attack (5.0.1)
|
rack-cors (0.4.0)
|
||||||
rack
|
|
||||||
rack-cors (1.0.1)
|
|
||||||
rack-test (0.6.3)
|
rack-test (0.6.3)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
rails (5.0.5)
|
rails (5.0.0.1)
|
||||||
actioncable (= 5.0.5)
|
actioncable (= 5.0.0.1)
|
||||||
actionmailer (= 5.0.5)
|
actionmailer (= 5.0.0.1)
|
||||||
actionpack (= 5.0.5)
|
actionpack (= 5.0.0.1)
|
||||||
actionview (= 5.0.5)
|
actionview (= 5.0.0.1)
|
||||||
activejob (= 5.0.5)
|
activejob (= 5.0.0.1)
|
||||||
activemodel (= 5.0.5)
|
activemodel (= 5.0.0.1)
|
||||||
activerecord (= 5.0.5)
|
activerecord (= 5.0.0.1)
|
||||||
activesupport (= 5.0.5)
|
activesupport (= 5.0.0.1)
|
||||||
bundler (>= 1.3.0)
|
bundler (>= 1.3.0, < 2.0)
|
||||||
railties (= 5.0.5)
|
railties (= 5.0.0.1)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.1)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0, < 6.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (~> 1.6.0)
|
||||||
rails-html-sanitizer (1.0.3)
|
rails-html-sanitizer (1.0.3)
|
||||||
loofah (~> 2.0)
|
loofah (~> 2.0)
|
||||||
railties (5.0.5)
|
rails3-jquery-autocomplete (1.0.15)
|
||||||
actionpack (= 5.0.5)
|
rails (>= 3.2)
|
||||||
activesupport (= 5.0.5)
|
rails_12factor (0.0.3)
|
||||||
|
rails_serve_static_assets
|
||||||
|
rails_stdout_logging
|
||||||
|
rails_serve_static_assets (0.0.5)
|
||||||
|
rails_stdout_logging (0.0.5)
|
||||||
|
railties (5.0.0.1)
|
||||||
|
actionpack (= 5.0.0.1)
|
||||||
|
activesupport (= 5.0.0.1)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 0.8.7)
|
rake (>= 0.8.7)
|
||||||
thor (>= 0.18.1, < 2.0)
|
thor (>= 0.18.1, < 2.0)
|
||||||
rainbow (2.2.2)
|
rainbow (2.1.0)
|
||||||
rake
|
rake (11.3.0)
|
||||||
rake (12.3.0)
|
redis (3.3.1)
|
||||||
rb-fsevent (0.10.2)
|
responders (2.3.0)
|
||||||
rb-inotify (0.9.10)
|
railties (>= 4.2.0, < 5.1)
|
||||||
ffi (>= 0.5.0, < 2)
|
rspec-core (3.5.3)
|
||||||
redis (3.3.3)
|
rspec-support (~> 3.5.0)
|
||||||
responders (2.4.0)
|
rspec-expectations (3.5.0)
|
||||||
actionpack (>= 4.2.0, < 5.3)
|
|
||||||
railties (>= 4.2.0, < 5.3)
|
|
||||||
rspec-core (3.6.0)
|
|
||||||
rspec-support (~> 3.6.0)
|
|
||||||
rspec-expectations (3.6.0)
|
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.6.0)
|
rspec-support (~> 3.5.0)
|
||||||
rspec-mocks (3.6.0)
|
rspec-mocks (3.5.0)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.6.0)
|
rspec-support (~> 3.5.0)
|
||||||
rspec-rails (3.6.1)
|
rspec-rails (3.5.2)
|
||||||
actionpack (>= 3.0)
|
actionpack (>= 3.0)
|
||||||
activesupport (>= 3.0)
|
activesupport (>= 3.0)
|
||||||
railties (>= 3.0)
|
railties (>= 3.0)
|
||||||
rspec-core (~> 3.6.0)
|
rspec-core (~> 3.5.0)
|
||||||
rspec-expectations (~> 3.6.0)
|
rspec-expectations (~> 3.5.0)
|
||||||
rspec-mocks (~> 3.6.0)
|
rspec-mocks (~> 3.5.0)
|
||||||
rspec-support (~> 3.6.0)
|
rspec-support (~> 3.5.0)
|
||||||
rspec-support (3.6.0)
|
rspec-support (3.5.0)
|
||||||
rubocop (0.48.1)
|
rubocop (0.43.0)
|
||||||
parser (>= 2.3.3.1, < 3.0)
|
parser (>= 2.3.1.1, < 3.0)
|
||||||
powerpack (~> 0.1)
|
powerpack (~> 0.1)
|
||||||
rainbow (>= 1.99.1, < 3.0)
|
rainbow (>= 1.99.1, < 3.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||||
ruby-progressbar (1.9.0)
|
ruby-progressbar (1.8.1)
|
||||||
sass (3.5.1)
|
sass (3.4.22)
|
||||||
sass-listen (~> 4.0.0)
|
|
||||||
sass-listen (4.0.0)
|
|
||||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
||||||
rb-inotify (~> 0.9, >= 0.9.7)
|
|
||||||
sass-rails (5.0.6)
|
sass-rails (5.0.6)
|
||||||
railties (>= 4.0.0, < 6)
|
railties (>= 4.0.0, < 6)
|
||||||
sass (~> 3.1)
|
sass (~> 3.1)
|
||||||
sprockets (>= 2.8, < 4.0)
|
sprockets (>= 2.8, < 4.0)
|
||||||
sprockets-rails (>= 2.0, < 4.0)
|
sprockets-rails (>= 2.0, < 4.0)
|
||||||
tilt (>= 1.1, < 3)
|
tilt (>= 1.1, < 3)
|
||||||
shoulda-matchers (3.1.2)
|
shoulda-matchers (3.1.1)
|
||||||
activesupport (>= 4.0.0)
|
activesupport (>= 4.0.0)
|
||||||
simplecov (0.15.0)
|
simplecov (0.12.0)
|
||||||
docile (~> 1.1.0)
|
docile (~> 1.1.0)
|
||||||
json (>= 1.8, < 3)
|
json (>= 1.8, < 3)
|
||||||
simplecov-html (~> 0.10.0)
|
simplecov-html (~> 0.10.0)
|
||||||
simplecov-html (0.10.2)
|
simplecov-html (0.10.0)
|
||||||
slack-notifier (2.3.1)
|
slack-notifier (1.5.1)
|
||||||
slop (3.6.0)
|
slop (3.6.0)
|
||||||
snorlax (0.1.6)
|
snorlax (0.1.6)
|
||||||
rails (> 4.1)
|
rails (> 4.1)
|
||||||
sprockets (3.7.1)
|
sprockets (3.7.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
rack (> 1, < 3)
|
rack (> 1, < 3)
|
||||||
sprockets-rails (3.2.1)
|
sprockets-rails (3.2.0)
|
||||||
actionpack (>= 4.0)
|
actionpack (>= 4.0)
|
||||||
activesupport (>= 4.0)
|
activesupport (>= 4.0)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
sucker_punch (2.0.3)
|
thor (0.19.1)
|
||||||
concurrent-ruby (~> 1.0.0)
|
thread_safe (0.3.5)
|
||||||
thor (0.20.0)
|
tilt (2.0.5)
|
||||||
thread_safe (0.3.6)
|
tunemygc (1.0.68)
|
||||||
tilt (2.0.8)
|
tzinfo (1.2.2)
|
||||||
timecop (0.9.1)
|
|
||||||
tunemygc (1.0.69)
|
|
||||||
tzinfo (1.2.4)
|
|
||||||
thread_safe (~> 0.1)
|
thread_safe (~> 0.1)
|
||||||
uglifier (3.2.0)
|
uglifier (3.0.2)
|
||||||
execjs (>= 0.3.0, < 3)
|
execjs (>= 0.3.0, < 3)
|
||||||
unicode-display_width (1.3.0)
|
unicode-display_width (1.1.1)
|
||||||
warden (1.2.7)
|
uservoice-ruby (0.0.11)
|
||||||
|
ezcrypto (>= 0.7.2)
|
||||||
|
json (>= 1.7.5)
|
||||||
|
oauth (>= 0.4.7)
|
||||||
|
warden (1.2.6)
|
||||||
rack (>= 1.0)
|
rack (>= 1.0)
|
||||||
websocket-driver (0.6.5)
|
websocket-driver (0.6.4)
|
||||||
websocket-extensions (>= 0.1.0)
|
websocket-extensions (>= 0.1.0)
|
||||||
websocket-extensions (0.1.2)
|
websocket-extensions (0.1.2)
|
||||||
|
|
||||||
|
@ -300,51 +288,52 @@ PLATFORMS
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
active_model_serializers
|
active_model_serializers
|
||||||
aws-sdk (~> 2.7.0)
|
aws-sdk (< 2.0)
|
||||||
best_in_place
|
best_in_place
|
||||||
better_errors
|
better_errors
|
||||||
binding_of_caller
|
binding_of_caller
|
||||||
brakeman
|
brakeman
|
||||||
|
coffee-rails
|
||||||
delayed_job
|
delayed_job
|
||||||
delayed_job_active_record
|
delayed_job_active_record
|
||||||
devise
|
devise
|
||||||
doorkeeper
|
doorkeeper (~> 4.0.0.rc4)
|
||||||
dotenv-rails
|
dotenv-rails
|
||||||
exception_notification
|
exception_notification
|
||||||
factory_bot_rails
|
factory_girl_rails
|
||||||
faker
|
formtastic
|
||||||
|
formula
|
||||||
httparty
|
httparty
|
||||||
|
jbuilder
|
||||||
jquery-rails
|
jquery-rails
|
||||||
jquery-ui-rails
|
jquery-ui-rails
|
||||||
json
|
json
|
||||||
json-schema
|
json-schema
|
||||||
kaminari
|
kaminari
|
||||||
mailboxer
|
paperclip (~> 4.3.6)
|
||||||
paperclip
|
|
||||||
pg
|
pg
|
||||||
pry-byebug
|
pry-byebug
|
||||||
pry-rails
|
pry-rails
|
||||||
puma
|
|
||||||
pundit
|
pundit
|
||||||
pundit_extra
|
pundit_extra
|
||||||
rack-attack
|
|
||||||
rack-cors
|
rack-cors
|
||||||
rails (~> 5.0.0)
|
rails (~> 5.0.0)
|
||||||
redis (~> 3.3.3)
|
rails3-jquery-autocomplete
|
||||||
|
rails_12factor
|
||||||
|
redis
|
||||||
rspec-rails
|
rspec-rails
|
||||||
rubocop (~> 0.48.1)
|
rubocop
|
||||||
sass-rails
|
sass-rails
|
||||||
shoulda-matchers
|
shoulda-matchers
|
||||||
simplecov
|
simplecov
|
||||||
slack-notifier
|
slack-notifier
|
||||||
snorlax
|
snorlax
|
||||||
sucker_punch
|
|
||||||
timecop
|
|
||||||
tunemygc
|
tunemygc
|
||||||
uglifier
|
uglifier
|
||||||
|
uservoice-ruby
|
||||||
|
|
||||||
RUBY VERSION
|
RUBY VERSION
|
||||||
ruby 2.3.0p0
|
ruby 2.3.0p0
|
||||||
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
1.16.1
|
1.12.5
|
||||||
|
|
2
Procfile
|
@ -1,3 +1,3 @@
|
||||||
web: bundle exec puma -p $PORT
|
web: bundle exec rails server -p $PORT
|
||||||
worker: bundle exec rake jobs:work
|
worker: bundle exec rake jobs:work
|
||||||
|
|
||||||
|
|
69
README.md
|
@ -2,45 +2,58 @@ Metamaps
|
||||||
=======
|
=======
|
||||||
|
|
||||||
[![Build Status](https://travis-ci.org/metamaps/metamaps.svg?branch=develop)](https://travis-ci.org/metamaps/metamaps)
|
[![Build Status](https://travis-ci.org/metamaps/metamaps.svg?branch=develop)](https://travis-ci.org/metamaps/metamaps)
|
||||||
[![Code Climate](https://codeclimate.com/github/metamaps/metamaps/badges/gpa.svg)](https://codeclimate.com/github/metamaps/metamaps)
|
|
||||||
|
|
||||||
## What is Metamaps?
|
## What is Metamaps?
|
||||||
|
|
||||||
Metamaps is a free and open-source technology for changemakers, innovators, educators and students. It enables individuals and communities to build and visualize their shared knowledge and unlock their collective intelligence.
|
Metamaps is a free and open source technology for changemakers, innovators, educators and students. It enables individuals and communities to build and visualize their shared knowledge and unlock their collective intelligence.
|
||||||
|
|
||||||
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in an open beta.
|
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in a private beta.
|
||||||
|
|
||||||
Metamaps is developed and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch by using whichever of these channels you prefer:
|
Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch by using whichever of these channels you prefer:
|
||||||
|
|
||||||
## How do I learn more?
|
## Community
|
||||||
|
|
||||||
- Contact: [team@metamaps.cc](mailto:team@metamaps.cc) or [@metamapps](https://twitter.com/metamapps) on Twitter
|
|
||||||
- User Documentation: [docs.metamaps.cc](https://docs.metamaps.cc)
|
|
||||||
- User Community: [hylo.com/c/metamaps](https://www.hylo.com/c/metamaps)
|
|
||||||
- To see what we're developing, or to weigh in on what you'd like to see developed, see our [Metamaps Feedback and Features](https://trello.com/b/uFOA6a2x/metamaps-feedback-feature-ideas-requests) board on trello
|
|
||||||
- To follow along with, or contribute,to our design process, see our [Metamaps Design](https://trello.com/b/8HlCikOX/metamaps-design) board on trello
|
|
||||||
- To follow along with, or contribute to, our development process, see our [Github Issues and Pull Requests](https://github.com/metamaps/metamaps/issues)
|
|
||||||
- Request an invite to the open beta [here](https://metamaps.cc/request)
|
|
||||||
|
|
||||||
<!-- markdown hack to split two lists -->
|
- To send us a personal message or request an invite to the open beta, get in touch with us at team@metamaps.cc or @metamapps on Twitter.
|
||||||
|
|
||||||
- To send us a personal message get in touch with us via email, Twitter, or Hylo
|
|
||||||
- If you would like to report a bug, please check the [issues][contributing-issues] section in our [contributing instructions][contributing].
|
- If you would like to report a bug, please check the [issues][contributing-issues] section in our [contributing instructions][contributing].
|
||||||
- If you would like to get set up as a developer, that's great! Read on for help getting your development environment set up.
|
- If you would like to get set up as a developer, that's great! Read on for help getting your development environment set up.
|
||||||
|
|
||||||
## Installation for local use or development of Metamaps
|
## Installation
|
||||||
|
|
||||||
First off is getting the code downloaded to your computer. You can download a zip file from github, but if you've got `git` you can just run `git clone https://github.com/metamaps/metamaps` in your terminal.
|
If you are on Mac or Ubuntu you can use the following instructions to quickly get a local copy of metamaps up and running using a Vagrant virtualbox. Don't be intimidated, it's easy!
|
||||||
|
```
|
||||||
|
git clone git@github.com:metamaps/metamaps.git
|
||||||
|
```
|
||||||
|
Now ensure you have VirtualBox and Vagrant installed on your computer
|
||||||
|
```
|
||||||
|
cd metamaps
|
||||||
|
./bin/configure.sh
|
||||||
|
```
|
||||||
|
This will do all the setup steps to make Metamaps work with a bit of behind the scenes ninja magick.
|
||||||
|
|
||||||
There are instructions for setup on various platforms, with particular support for Mac and Ubuntu, which can be found here:
|
To start servers which will run metamaps you can then run:
|
||||||
- [Mac Install Walkthrough][mac-installation]
|
```
|
||||||
- [Ubuntu Install Walkthrough][ubuntu-installation]
|
./bin/start
|
||||||
|
```
|
||||||
|
To stop them:
|
||||||
|
```
|
||||||
|
./bin/stop
|
||||||
|
```
|
||||||
|
With your webservers running, open a web browser and go to `http://localhost:3000`
|
||||||
|
|
||||||
If you prefer to isolate your install in a virtual machine, you may find it simpler to setup using Vagrant:
|
You can sign in with the default account
|
||||||
- [Vagrant installation][vagrant-installation]
|
email: `user@user.com`
|
||||||
|
password: `toolsplusconsciousness`
|
||||||
|
OR create a new account at `/join`, and use access code `qwertyui`
|
||||||
|
|
||||||
We don't promise support for Windows, but at one point we had it running and we've kept those docs available for reference
|
Start mapping and programming!
|
||||||
- [Outdated Windows Walkthrough][windows-installation]
|
|
||||||
|
We haven't set up instructions for using Vagrant on Windows, but there are instructions for a manual setup here:
|
||||||
|
|
||||||
|
- [For Windows][windows-installation]
|
||||||
|
|
||||||
|
## Contributing guidelines
|
||||||
|
|
||||||
|
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
|
||||||
|
|
||||||
## Licensing information
|
## Licensing information
|
||||||
|
|
||||||
|
@ -50,13 +63,11 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||||
|
|
||||||
The license can be read [here][license].
|
The license can be read [here][license].
|
||||||
|
|
||||||
Copyright (c) 2017 Connor Turland
|
Copyright (c) 2016 Connor Turland
|
||||||
|
|
||||||
|
[site-blog]: http://blog.metamaps.cc
|
||||||
[site-beta]: http://metamaps.cc
|
[site-beta]: http://metamaps.cc
|
||||||
[license]: https://github.com/metamaps/metamaps/blob/develop/LICENSE
|
[license]: https://github.com/metamaps/metamaps/blob/develop/LICENSE
|
||||||
[contributing]: https://github.com/metamaps/metamaps/blob/develop/doc/CONTRIBUTING.md
|
[contributing]: https://github.com/metamaps/metamaps/blob/develop/doc/CONTRIBUTING.md
|
||||||
[contributing-issues]: https://github.com/metamaps/metamaps/blob/develop/doc/CONTRIBUTING.md#reporting-bugs-and-other-issues
|
[contributing-issues]: https://github.com/metamaps/metamaps/blob/develop/doc/CONTRIBUTING.md#reporting-bugs-and-other-issues
|
||||||
[mac-installation]: https://github.com/metamaps/metamaps/blob/develop/doc/MacInstallation.md
|
|
||||||
[ubuntu-installation]: https://github.com/metamaps/metamaps/blob/develop/doc/UbuntuInstallation.md
|
|
||||||
[vagrant-installation]: https://github.com/metamaps/metamaps/blob/develop/doc/VagrantInstallation.md
|
|
||||||
[windows-installation]: https://github.com/metamaps/metamaps/blob/develop/doc/WindowsInstallation.md
|
[windows-installation]: https://github.com/metamaps/metamaps/blob/develop/doc/WindowsInstallation.md
|
||||||
|
|
1
Rakefile
Executable file → Normal file
|
@ -1,6 +1,5 @@
|
||||||
#!/usr/bin/env rake
|
#!/usr/bin/env rake
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||||
|
|
||||||
|
|
2
Vagrantfile
vendored
|
@ -37,7 +37,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
||||||
config.vm.box = 'trusty64'
|
config.vm.box = 'trusty64'
|
||||||
config.vm.box_url = 'http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box'
|
config.vm.box_url = 'http://cloud-images.ubuntu.com/vagrant/trusty/current/trusty-server-cloudimg-amd64-vagrant-disk1.box'
|
||||||
config.vm.network :forwarded_port, guest: 3000, host: 3000
|
config.vm.network :forwarded_port, guest: 3000, host: 3000
|
||||||
config.vm.network :forwarded_port, guest: 5000, host: 5000
|
config.vm.network :forwarded_port, guest: 5001, host: 5001
|
||||||
config.vm.network 'private_network', ip: '10.0.1.11'
|
config.vm.network 'private_network', ip: '10.0.1.11'
|
||||||
config.vm.synced_folder '.', '/vagrant', nfs: true
|
config.vm.synced_folder '.', '/vagrant', nfs: true
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
// eslint-disable spaced-comment
|
|
||||||
// JS and CSS bundles
|
// JS and CSS bundles
|
||||||
//= link_directory ../javascripts .js
|
//= link_directory ../javascripts .js
|
||||||
//= link_directory ../stylesheets .css
|
//= link_directory ../stylesheets .css
|
||||||
|
|
BIN
app/assets/images/.DS_Store
vendored
Normal file
BIN
app/assets/images/arrowperms_sprite.png
Normal file
After Width: | Height: | Size: 543 B |
Before Width: | Height: | Size: 44 KiB |
Before Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 7.2 KiB |
BIN
app/assets/images/user_sprite.png
Normal file → Executable file
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 421 B |
|
@ -1,21 +0,0 @@
|
||||||
/* global Metamaps */
|
|
||||||
|
|
||||||
/* erb variables from rails */
|
|
||||||
Metamaps.ServerData = Metamaps.ServerData || {}
|
|
||||||
Metamaps.ServerData['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
|
|
||||||
Metamaps.ServerData['user.png'] = '<%= asset_path('user.png') %>'
|
|
||||||
Metamaps.ServerData['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
|
|
||||||
Metamaps.ServerData['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
|
|
||||||
Metamaps.ServerData['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
|
|
||||||
Metamaps.ServerData['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
|
|
||||||
Metamaps.ServerData['sounds/MM_sounds.mp3'] = '<%= asset_path 'sounds/MM_sounds.mp3' %>'
|
|
||||||
Metamaps.ServerData['sounds/MM_sounds.ogg'] = '<%= asset_path 'sounds/MM_sounds.ogg' %>'
|
|
||||||
Metamaps.ServerData['exploremaps_sprite.png'] = '<%= asset_path 'exploremaps_sprite.png' %>'
|
|
||||||
Metamaps.ServerData['map_control_sprite.png'] = '<%= asset_path 'map_control_sprite.png' %>'
|
|
||||||
Metamaps.ServerData['user_sprite.png'] = '<%= asset_path 'user_sprite.png' %>'
|
|
||||||
Metamaps.ServerData.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %>
|
|
||||||
Metamaps.ServerData.REALTIME_SERVER = '<%= ENV['REALTIME_SERVER'] %>'
|
|
||||||
Metamaps.ServerData.RAILS_ENV = '<%= ENV['RAILS_ENV'] %>'
|
|
||||||
Metamaps.ServerData.VERSION = '<%= METAMAPS_VERSION %>'
|
|
||||||
Metamaps.ServerData.BUILD = '<%= METAMAPS_BUILD %>'
|
|
||||||
Metamaps.ServerData.LAST_UPDATED = '<%= METAMAPS_LAST_UPDATED %>'
|
|
|
@ -1,23 +0,0 @@
|
||||||
// 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.
|
|
||||||
//
|
|
||||||
/* eslint-disable spaced-comment */
|
|
||||||
//= require jquery
|
|
||||||
//= require jquery-ui
|
|
||||||
//= require jquery_ujs
|
|
||||||
//= require action_cable
|
|
||||||
//= require_directory ./lib
|
|
||||||
//= require ./cloudcarousel-secret
|
|
||||||
//= require ./metamaps.secret.bundle
|
|
||||||
//= require ./Metamaps.ServerData
|
|
||||||
//= require homepageVimeoFallback
|
|
||||||
/* eslint-enable spaced-comment */
|
|
|
@ -9,14 +9,11 @@
|
||||||
//
|
//
|
||||||
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
// WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
|
||||||
// GO AFTER THE REQUIRES BELOW.
|
// GO AFTER THE REQUIRES BELOW.
|
||||||
//
|
//
|
||||||
/* eslint-disable spaced-comment */
|
|
||||||
//= require jquery
|
//= require jquery
|
||||||
//= require jquery-ui
|
//= require jquery-ui
|
||||||
//= require jquery_ujs
|
//= require jquery_ujs
|
||||||
//= require action_cable
|
|
||||||
//= require_directory ./lib
|
//= require_directory ./lib
|
||||||
|
//= require ./src/Metamaps.Erb
|
||||||
//= require ./webpacked/metamaps.bundle
|
//= require ./webpacked/metamaps.bundle
|
||||||
//= require ./Metamaps.ServerData
|
//= require ./src/check-canvas-support
|
||||||
//= require homepageVimeoFallback
|
|
||||||
/* eslint-enable spaced-comment */
|
|
||||||
|
|
|
@ -1,438 +0,0 @@
|
||||||
//////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// 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;
|
|
||||||
});
|
|
||||||
|
|
||||||
// START METAMAPS CODE
|
|
||||||
// Add code that makes tab and shift+tab scroll through metacodes
|
|
||||||
$('.new_topic').bind('keydown',this,function(event){
|
|
||||||
if (event.keyCode == 9 && event.shiftKey) {
|
|
||||||
$(container).show()
|
|
||||||
event.data.rotate(-1);
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
} else if (event.keyCode == 9) {
|
|
||||||
$(container).show()
|
|
||||||
event.data.rotate(1);
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// END METAMAPS CODE
|
|
||||||
|
|
||||||
// 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 &&
|
|
||||||
!Metamaps.Create.newTopic.pinned) {
|
|
||||||
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).unbind('mouseover click').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') ));
|
|
||||||
// START METAMAPS CODE
|
|
||||||
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
|
|
||||||
// END 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// START METAMAPS CODE - initialize newTopic.metacode
|
|
||||||
var first = $(this.container).find('img').get(0)
|
|
||||||
Metamaps.Create.newTopic.metacode = $(first).data('id')
|
|
||||||
// END METAMAPS CODE
|
|
||||||
|
|
||||||
// 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.setMetacode($(items[this.frontIndex].image).attr('data-id'))
|
|
||||||
// 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;
|
|
||||||
// METAMAPS CODE
|
|
||||||
$(container).hide()
|
|
||||||
// END METAMAPS CODE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
// METAMAPS COMMENT 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);
|
|
|
@ -1,29 +0,0 @@
|
||||||
/* global $ */
|
|
||||||
|
|
||||||
$(document).ready(function() {
|
|
||||||
if (window.location.pathname === '/') {
|
|
||||||
$.ajax({
|
|
||||||
type: 'GET',
|
|
||||||
url: 'https://i.vimeocdn.com/video/',
|
|
||||||
error: function(e) {
|
|
||||||
$('.homeVideo').hide()
|
|
||||||
$('.homeVideo').replaceWith($('<video/>', {
|
|
||||||
poster: '<%= asset_path('metamaps-intro-poster.webp') %>',
|
|
||||||
width: '560',
|
|
||||||
height: '315',
|
|
||||||
class: 'homeVideo',
|
|
||||||
controls: ''
|
|
||||||
}))
|
|
||||||
$('.homeVideo').append($('<source/>', {
|
|
||||||
src: 'https://metamaps.cc/videos/metamaps-intro.mp4',
|
|
||||||
type: 'video/mp4'
|
|
||||||
}))
|
|
||||||
$('.homeVideo').append(
|
|
||||||
'<p>You can watch our instruction video at ' +
|
|
||||||
'<a href="https://metamaps.cc/videos/metamaps-intro.mp4">' +
|
|
||||||
'https://metamaps.cc/videos/metamaps-intro.mp4</a>.'
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}// if
|
|
||||||
})
|
|
BIN
app/assets/javascripts/lib/WebSocketMain.swf
Normal file
BIN
app/assets/javascripts/lib/WebSocketMainInsecure.swf
Normal file
|
@ -1,161 +0,0 @@
|
||||||
// AjaxQ jQuery Plugin
|
|
||||||
// Copyright (c) 2012 Foliotek Inc.
|
|
||||||
// MIT License
|
|
||||||
// https://github.com/Foliotek/ajaxq
|
|
||||||
// Uses CommonJS, AMD or browser globals to create a jQuery plugin.
|
|
||||||
|
|
||||||
(function (factory) {
|
|
||||||
if (typeof define === 'function' && define.amd) {
|
|
||||||
// AMD. Register as an anonymous module.
|
|
||||||
define(['jquery'], factory);
|
|
||||||
} else if (typeof module === 'object' && module.exports) {
|
|
||||||
// Node/CommonJS
|
|
||||||
module.exports = factory(require('jquery'));
|
|
||||||
} else {
|
|
||||||
// Browser globals
|
|
||||||
factory(jQuery);
|
|
||||||
}
|
|
||||||
}(function ($) {
|
|
||||||
var queues = {};
|
|
||||||
var activeReqs = {};
|
|
||||||
|
|
||||||
// Register an $.ajaxq function, which follows the $.ajax interface, but allows a queue name which will force only one request per queue to fire.
|
|
||||||
// opts can be the regular $.ajax settings plainObject, or a callback returning the settings object, to be evaluated just prior to the actual call to $.ajax.
|
|
||||||
$.ajaxq = function(qname, opts) {
|
|
||||||
|
|
||||||
if (typeof opts === "undefined") {
|
|
||||||
throw ("AjaxQ: queue name is not provided");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Will return a Deferred promise object extended with success/error/callback, so that this function matches the interface of $.ajax
|
|
||||||
var deferred = $.Deferred(),
|
|
||||||
promise = deferred.promise();
|
|
||||||
|
|
||||||
promise.success = promise.done;
|
|
||||||
promise.error = promise.fail;
|
|
||||||
promise.complete = promise.always;
|
|
||||||
|
|
||||||
// Check whether options are to be evaluated at call time or not.
|
|
||||||
var deferredOpts = typeof opts === 'function';
|
|
||||||
// Create a deep copy of the arguments, and enqueue this request.
|
|
||||||
var clonedOptions = !deferredOpts ? $.extend(true, {}, opts) : null;
|
|
||||||
enqueue(function() {
|
|
||||||
// Send off the ajax request now that the item has been removed from the queue
|
|
||||||
var jqXHR = $.ajax.apply(window, [deferredOpts ? opts() : clonedOptions]);
|
|
||||||
|
|
||||||
// Notify the returned deferred object with the correct context when the jqXHR is done or fails
|
|
||||||
// Note that 'always' will automatically be fired once one of these are called: http://api.jquery.com/category/deferred-object/.
|
|
||||||
jqXHR.done(function() {
|
|
||||||
deferred.resolve.apply(this, arguments);
|
|
||||||
});
|
|
||||||
jqXHR.fail(function() {
|
|
||||||
deferred.reject.apply(this, arguments);
|
|
||||||
});
|
|
||||||
|
|
||||||
jqXHR.always(dequeue); // make sure to dequeue the next request AFTER the done and fail callbacks are fired
|
|
||||||
|
|
||||||
return jqXHR;
|
|
||||||
});
|
|
||||||
|
|
||||||
return promise;
|
|
||||||
|
|
||||||
|
|
||||||
// If there is no queue, create an empty one and instantly process this item.
|
|
||||||
// Otherwise, just add this item onto it for later processing.
|
|
||||||
function enqueue(cb) {
|
|
||||||
if (!queues[qname]) {
|
|
||||||
queues[qname] = [];
|
|
||||||
var xhr = cb();
|
|
||||||
activeReqs[qname] = xhr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
queues[qname].push(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove the next callback from the queue and fire it off.
|
|
||||||
// If the queue was empty (this was the last item), delete it from memory so the next one can be instantly processed.
|
|
||||||
function dequeue() {
|
|
||||||
if (!queues[qname]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var nextCallback = queues[qname].shift();
|
|
||||||
if (nextCallback) {
|
|
||||||
var xhr = nextCallback();
|
|
||||||
activeReqs[qname] = xhr;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
delete queues[qname];
|
|
||||||
delete activeReqs[qname];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Register a $.postq and $.getq method to provide shortcuts for $.get and $.post
|
|
||||||
// Copied from jQuery source to make sure the functions share the same defaults as $.get and $.post.
|
|
||||||
$.each( [ "getq", "postq" ], function( i, method ) {
|
|
||||||
$[ method ] = function( qname, url, data, callback, type ) {
|
|
||||||
|
|
||||||
if ( $.isFunction( data ) ) {
|
|
||||||
type = type || callback;
|
|
||||||
callback = data;
|
|
||||||
data = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $.ajaxq(qname, {
|
|
||||||
type: method === "postq" ? "post" : "get",
|
|
||||||
url: url,
|
|
||||||
data: data,
|
|
||||||
success: callback,
|
|
||||||
dataType: type
|
|
||||||
});
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
var isQueueRunning = function(qname) {
|
|
||||||
return (queues.hasOwnProperty(qname) && queues[qname].length > 0) || activeReqs.hasOwnProperty(qname);
|
|
||||||
};
|
|
||||||
|
|
||||||
var isAnyQueueRunning = function() {
|
|
||||||
for (var i in queues) {
|
|
||||||
if (isQueueRunning(i)) return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajaxq.isRunning = function(qname) {
|
|
||||||
if (qname) return isQueueRunning(qname);
|
|
||||||
else return isAnyQueueRunning();
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajaxq.getActiveRequest = function(qname) {
|
|
||||||
if (!qname) throw ("AjaxQ: queue name is required");
|
|
||||||
|
|
||||||
return activeReqs[qname];
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajaxq.abort = function(qname) {
|
|
||||||
if (!qname) throw ("AjaxQ: queue name is required");
|
|
||||||
|
|
||||||
var current = $.ajaxq.getActiveRequest(qname);
|
|
||||||
delete queues[qname];
|
|
||||||
delete activeReqs[qname];
|
|
||||||
if (current) current.abort();
|
|
||||||
};
|
|
||||||
|
|
||||||
$.ajaxq.clear = function(qname) {
|
|
||||||
if (!qname) {
|
|
||||||
for (var i in queues) {
|
|
||||||
if (queues.hasOwnProperty(i)) {
|
|
||||||
queues[i] = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (queues[qname]) {
|
|
||||||
queues[qname] = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}));
|
|
39
app/assets/javascripts/lib/attachMediaStream.js
Normal 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;
|
||||||
|
};
|
|
@ -1,685 +0,0 @@
|
||||||
/*
|
|
||||||
* BestInPlace (for jQuery)
|
|
||||||
* version: 3.0.0.alpha (2014)
|
|
||||||
*
|
|
||||||
* By Bernat Farrero based on the work of Jan Varwig.
|
|
||||||
* Examples at http://bernatfarrero.com
|
|
||||||
*
|
|
||||||
* Licensed under the MIT:
|
|
||||||
* http://www.opensource.org/licenses/mit-license.php
|
|
||||||
*
|
|
||||||
* @requires jQuery
|
|
||||||
*
|
|
||||||
* Usage:
|
|
||||||
*
|
|
||||||
* Attention.
|
|
||||||
* The format of the JSON object given to the select inputs is the following:
|
|
||||||
* [["key", "value"],["key", "value"]]
|
|
||||||
* The format of the JSON object given to the checkbox inputs is the following:
|
|
||||||
* ["falseValue", "trueValue"]
|
|
||||||
|
|
||||||
*/
|
|
||||||
//= require jquery.autosize
|
|
||||||
|
|
||||||
function BestInPlaceEditor(e) {
|
|
||||||
'use strict';
|
|
||||||
this.element = e;
|
|
||||||
this.initOptions();
|
|
||||||
this.bindForm();
|
|
||||||
this.initPlaceHolder();
|
|
||||||
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
BestInPlaceEditor.prototype = {
|
|
||||||
// Public Interface Functions //////////////////////////////////////////////
|
|
||||||
|
|
||||||
activate: function () {
|
|
||||||
'use strict';
|
|
||||||
var to_display;
|
|
||||||
if (this.isPlaceHolder()) {
|
|
||||||
to_display = "";
|
|
||||||
} else if (this.original_content) {
|
|
||||||
to_display = this.original_content;
|
|
||||||
} else {
|
|
||||||
switch (this.formType) {
|
|
||||||
case 'input':
|
|
||||||
case 'textarea':
|
|
||||||
if (this.display_raw) {
|
|
||||||
to_display = this.element.html().replace(/&/gi, '&');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var value = this.element.data('bipValue');
|
|
||||||
if (typeof value === 'undefined') {
|
|
||||||
to_display = '';
|
|
||||||
} else if (typeof value === 'string') {
|
|
||||||
to_display = this.element.data('bipValue').replace(/&/gi, '&');
|
|
||||||
} else {
|
|
||||||
to_display = this.element.data('bipValue');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'select':
|
|
||||||
to_display = this.element.html();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.oldValue = this.isPlaceHolder() ? "" : this.element.html();
|
|
||||||
this.display_value = to_display;
|
|
||||||
jQuery(this.activator).unbind("click", this.clickHandler);
|
|
||||||
this.activateForm();
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:activate"));
|
|
||||||
},
|
|
||||||
|
|
||||||
abort: function () {
|
|
||||||
'use strict';
|
|
||||||
this.activateText(this.oldValue);
|
|
||||||
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:abort"));
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
|
||||||
},
|
|
||||||
|
|
||||||
abortIfConfirm: function () {
|
|
||||||
'use strict';
|
|
||||||
if (!this.useConfirm) {
|
|
||||||
this.abort();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (confirm(BestInPlaceEditor.defaults.locales[''].confirmMessage)) {
|
|
||||||
this.abort();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
update: function () {
|
|
||||||
'use strict';
|
|
||||||
var editor = this,
|
|
||||||
value = this.getValue();
|
|
||||||
|
|
||||||
// Avoid request if no change is made
|
|
||||||
if (this.formType in {"input": 1, "textarea": 1} && value === this.oldValue) {
|
|
||||||
this.abort();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.ajax({
|
|
||||||
"type": this.requestMethod(),
|
|
||||||
"dataType": BestInPlaceEditor.defaults.ajaxDataType,
|
|
||||||
"data": editor.requestData(),
|
|
||||||
"success": function (data, status, xhr) {
|
|
||||||
editor.loadSuccessCallback(data, status, xhr);
|
|
||||||
},
|
|
||||||
"error": function (request, error) {
|
|
||||||
editor.loadErrorCallback(request, error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
switch (this.formType) {
|
|
||||||
case "select":
|
|
||||||
this.previousCollectionValue = value;
|
|
||||||
|
|
||||||
// search for the text for the span
|
|
||||||
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
case "checkbox":
|
|
||||||
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (value !== "") {
|
|
||||||
if (this.display_raw) {
|
|
||||||
editor.element.html(value);
|
|
||||||
} else {
|
|
||||||
editor.element.text(value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
editor.element.html(this.placeHolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editor.element.data('bipValue', value);
|
|
||||||
editor.element.attr('data-bip-value', value);
|
|
||||||
|
|
||||||
editor.element.trigger(jQuery.Event("best_in_place:update"));
|
|
||||||
|
|
||||||
|
|
||||||
},
|
|
||||||
|
|
||||||
activateForm: function () {
|
|
||||||
'use strict';
|
|
||||||
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
|
|
||||||
},
|
|
||||||
|
|
||||||
activateText: function (value) {
|
|
||||||
'use strict';
|
|
||||||
this.element.html(value);
|
|
||||||
if (this.isPlaceHolder()) {
|
|
||||||
this.element.html(this.placeHolder);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Helper Functions ////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
initOptions: function () {
|
|
||||||
// Try parent supplied info
|
|
||||||
'use strict';
|
|
||||||
var self = this;
|
|
||||||
self.element.parents().each(function () {
|
|
||||||
var $parent = jQuery(this);
|
|
||||||
self.url = self.url || $parent.data("bipUrl");
|
|
||||||
self.activator = self.activator || $parent.data("bipActivator");
|
|
||||||
self.okButton = self.okButton || $parent.data("bipOkButton");
|
|
||||||
self.okButtonClass = self.okButtonClass || $parent.data("bipOkButtonClass");
|
|
||||||
self.cancelButton = self.cancelButton || $parent.data("bipCancelButton");
|
|
||||||
self.cancelButtonClass = self.cancelButtonClass || $parent.data("bipCancelButtonClass");
|
|
||||||
self.skipBlur = self.skipBlur || $parent.data("bipSkipBlur");
|
|
||||||
});
|
|
||||||
|
|
||||||
// Load own attributes (overrides all others)
|
|
||||||
self.url = self.element.data("bipUrl") || self.url || document.location.pathname;
|
|
||||||
self.collection = self.element.data("bipCollection") || self.collection;
|
|
||||||
self.formType = self.element.data("bipType") || "input";
|
|
||||||
self.objectName = self.element.data("bipObject") || self.objectName;
|
|
||||||
self.attributeName = self.element.data("bipAttribute") || self.attributeName;
|
|
||||||
self.activator = self.element.data("bipActivator") || self.element;
|
|
||||||
self.okButton = self.element.data("bipOkButton") || self.okButton;
|
|
||||||
self.okButtonClass = self.element.data("bipOkButtonClass") || self.okButtonClass || BestInPlaceEditor.defaults.okButtonClass;
|
|
||||||
self.cancelButton = self.element.data("bipCancelButton") || self.cancelButton;
|
|
||||||
self.cancelButtonClass = self.element.data("bipCancelButtonClass") || self.cancelButtonClass || BestInPlaceEditor.defaults.cancelButtonClass;
|
|
||||||
self.skipBlur = self.element.data("bipSkipBlur") || self.skipBlur || BestInPlaceEditor.defaults.skipBlur;
|
|
||||||
self.isNewObject = self.element.data("bipNewObject");
|
|
||||||
self.dataExtraPayload = self.element.data("bipExtraPayload");
|
|
||||||
|
|
||||||
// Fix for default values of 0
|
|
||||||
if (self.element.data("bipPlaceholder") == null) {
|
|
||||||
self.placeHolder = BestInPlaceEditor.defaults.locales[''].placeHolder;
|
|
||||||
} else {
|
|
||||||
self.placeHolder = self.element.data("bipPlaceholder");
|
|
||||||
}
|
|
||||||
|
|
||||||
self.inner_class = self.element.data("bipInnerClass");
|
|
||||||
self.html_attrs = self.element.data("bipHtmlAttrs");
|
|
||||||
self.original_content = self.element.data("bipOriginalContent") || self.original_content;
|
|
||||||
|
|
||||||
// if set the input won't be satinized
|
|
||||||
self.display_raw = self.element.data("bip-raw");
|
|
||||||
|
|
||||||
self.useConfirm = self.element.data("bip-confirm");
|
|
||||||
|
|
||||||
if (self.formType === "select" || self.formType === "checkbox") {
|
|
||||||
self.values = self.collection;
|
|
||||||
self.collectionValue = self.element.data("bipValue") || self.collectionValue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
bindForm: function () {
|
|
||||||
'use strict';
|
|
||||||
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
|
|
||||||
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
initPlaceHolder: function () {
|
|
||||||
'use strict';
|
|
||||||
// TODO add placeholder for select and checkbox
|
|
||||||
if (this.element.html() === "") {
|
|
||||||
this.element.addClass('bip-placeholder');
|
|
||||||
this.element.html(this.placeHolder);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
isPlaceHolder: function () {
|
|
||||||
'use strict';
|
|
||||||
// TODO: It only work when form is deactivated.
|
|
||||||
// Condition will fail when form is activated
|
|
||||||
return this.element.html() === "" || this.element.html() === this.placeHolder;
|
|
||||||
},
|
|
||||||
|
|
||||||
getValue: function () {
|
|
||||||
'use strict';
|
|
||||||
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Trim and Strips HTML from text
|
|
||||||
sanitizeValue: function (s) {
|
|
||||||
'use strict';
|
|
||||||
return jQuery.trim(s);
|
|
||||||
},
|
|
||||||
|
|
||||||
requestMethod: function() {
|
|
||||||
'use strict';
|
|
||||||
return this.isNewObject ? 'post' : BestInPlaceEditor.defaults.ajaxMethod;
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Generate the data sent in the POST request */
|
|
||||||
requestData: function () {
|
|
||||||
'use strict';
|
|
||||||
// To prevent xss attacks, a csrf token must be defined as a meta attribute
|
|
||||||
var csrf_token = jQuery('meta[name=csrf-token]').attr('content'),
|
|
||||||
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
|
|
||||||
|
|
||||||
var data = {}
|
|
||||||
data['_method'] = this.requestMethod()
|
|
||||||
|
|
||||||
data[this.objectName] = this.dataExtraPayload || {}
|
|
||||||
|
|
||||||
data[this.objectName][this.attributeName] = this.getValue()
|
|
||||||
|
|
||||||
if (csrf_param !== undefined && csrf_token !== undefined) {
|
|
||||||
data[csrf_param] = csrf_token
|
|
||||||
}
|
|
||||||
return jQuery.param(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
ajax: function (options) {
|
|
||||||
'use strict';
|
|
||||||
options.url = this.url;
|
|
||||||
options.beforeSend = function (xhr) {
|
|
||||||
xhr.setRequestHeader("Accept", "application/json");
|
|
||||||
};
|
|
||||||
return jQuery.ajax(options);
|
|
||||||
},
|
|
||||||
|
|
||||||
// Handlers ////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
loadSuccessCallback: function (data, status, xhr) {
|
|
||||||
'use strict';
|
|
||||||
data = jQuery.trim(data);
|
|
||||||
//Update original content with current text.
|
|
||||||
if (this.display_raw) {
|
|
||||||
this.original_content = this.element.html();
|
|
||||||
} else {
|
|
||||||
this.original_content = this.element.text();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data && data !== "") {
|
|
||||||
var response = jQuery.parseJSON(data);
|
|
||||||
if (response !== null && response.hasOwnProperty("display_as")) {
|
|
||||||
this.element.data('bip-original-content', this.element.text());
|
|
||||||
this.element.html(response.display_as);
|
|
||||||
}
|
|
||||||
if (this.isNewObject && response && response[this.objectName]) {
|
|
||||||
if (response[this.objectName]["id"]) {
|
|
||||||
this.isNewObject = false
|
|
||||||
this.url += "/" + response[this.objectName]["id"] // in REST a POST /thing url should become PUT /thing/123
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.element.toggleClass('bip-placeholder', this.isPlaceHolder());
|
|
||||||
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:success"), [data, status, xhr]);
|
|
||||||
this.element.trigger(jQuery.Event("ajax:success"), [data, status, xhr]);
|
|
||||||
|
|
||||||
// Binding back after being clicked
|
|
||||||
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
|
||||||
|
|
||||||
if (this.collectionValue !== null && this.formType === "select") {
|
|
||||||
this.collectionValue = this.previousCollectionValue;
|
|
||||||
this.previousCollectionValue = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
loadErrorCallback: function (request, error) {
|
|
||||||
'use strict';
|
|
||||||
this.activateText(this.oldValue);
|
|
||||||
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
|
|
||||||
this.element.trigger(jQuery.Event("ajax:error"), request, error);
|
|
||||||
|
|
||||||
// Binding back after being clicked
|
|
||||||
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
|
||||||
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
|
||||||
},
|
|
||||||
|
|
||||||
clickHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.preventDefault();
|
|
||||||
event.data.editor.activate();
|
|
||||||
},
|
|
||||||
|
|
||||||
setHtmlAttributes: function () {
|
|
||||||
'use strict';
|
|
||||||
var formField = this.element.find(this.formType);
|
|
||||||
|
|
||||||
if (this.html_attrs) {
|
|
||||||
var attrs = this.html_attrs;
|
|
||||||
$.each(attrs, function (key, val) {
|
|
||||||
formField.attr(key, val);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
placeButtons: function (output, field) {
|
|
||||||
'use strict';
|
|
||||||
if (field.okButton) {
|
|
||||||
output.append(
|
|
||||||
jQuery(document.createElement('input'))
|
|
||||||
.attr('type', 'submit')
|
|
||||||
.attr('class', field.okButtonClass)
|
|
||||||
.attr('value', field.okButton)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (field.cancelButton) {
|
|
||||||
output.append(
|
|
||||||
jQuery(document.createElement('input'))
|
|
||||||
.attr('type', 'button')
|
|
||||||
.attr('class', field.cancelButtonClass)
|
|
||||||
.attr('value', field.cancelButton)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Button cases:
|
|
||||||
// If no buttons, then blur saves, ESC cancels
|
|
||||||
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
|
|
||||||
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
|
|
||||||
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
|
|
||||||
BestInPlaceEditor.forms = {
|
|
||||||
"input": {
|
|
||||||
activateForm: function () {
|
|
||||||
'use strict';
|
|
||||||
var output = jQuery(document.createElement('form'))
|
|
||||||
.addClass('form_in_place')
|
|
||||||
.attr('action', 'javascript:void(0);')
|
|
||||||
.attr('style', 'display:inline');
|
|
||||||
var input_elt = jQuery(document.createElement('input'))
|
|
||||||
.attr('type', 'text')
|
|
||||||
.attr('name', this.attributeName)
|
|
||||||
.val(this.display_value);
|
|
||||||
|
|
||||||
// Add class to form input
|
|
||||||
if (this.inner_class) {
|
|
||||||
input_elt.addClass(this.inner_class);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.append(input_elt);
|
|
||||||
this.placeButtons(output, this);
|
|
||||||
|
|
||||||
this.element.html(output);
|
|
||||||
this.setHtmlAttributes();
|
|
||||||
|
|
||||||
this.element.find("input[type='text']")[0].select();
|
|
||||||
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
|
|
||||||
if (this.cancelButton) {
|
|
||||||
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
|
|
||||||
}
|
|
||||||
if (!this.okButton) {
|
|
||||||
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
|
|
||||||
}
|
|
||||||
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
|
|
||||||
this.blurTimer = null;
|
|
||||||
this.userClicked = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
getValue: function () {
|
|
||||||
'use strict';
|
|
||||||
return this.sanitizeValue(this.element.find("input").val());
|
|
||||||
},
|
|
||||||
|
|
||||||
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
|
||||||
inputBlurHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
if (event.data.editor.okButton) {
|
|
||||||
event.data.editor.blurTimer = setTimeout(function () {
|
|
||||||
if (!event.data.editor.userClicked) {
|
|
||||||
event.data.editor.abort();
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
if (event.data.editor.cancelButton) {
|
|
||||||
event.data.editor.blurTimer = setTimeout(function () {
|
|
||||||
if (!event.data.editor.userClicked) {
|
|
||||||
event.data.editor.update();
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
event.data.editor.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
submitHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.data.editor.userClicked = true;
|
|
||||||
clearTimeout(event.data.editor.blurTimer);
|
|
||||||
event.data.editor.update();
|
|
||||||
},
|
|
||||||
|
|
||||||
cancelButtonHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.data.editor.userClicked = true;
|
|
||||||
clearTimeout(event.data.editor.blurTimer);
|
|
||||||
event.data.editor.abort();
|
|
||||||
event.stopPropagation(); // Without this, click isn't handled
|
|
||||||
},
|
|
||||||
|
|
||||||
keyupHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
if (event.keyCode === 27) {
|
|
||||||
event.data.editor.abort();
|
|
||||||
event.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"select": {
|
|
||||||
activateForm: function () {
|
|
||||||
'use strict';
|
|
||||||
var output = jQuery(document.createElement('form'))
|
|
||||||
.attr('action', 'javascript:void(0)')
|
|
||||||
.attr('style', 'display:inline'),
|
|
||||||
selected = '',
|
|
||||||
select_elt = jQuery(document.createElement('select'))
|
|
||||||
.attr('class', this.inner_class !== null ? this.inner_class : ''),
|
|
||||||
currentCollectionValue = this.collectionValue,
|
|
||||||
key, value,
|
|
||||||
a = this.values;
|
|
||||||
|
|
||||||
$.each(a, function(index, arr){
|
|
||||||
key = arr[0];
|
|
||||||
value = arr[1];
|
|
||||||
var option_elt = jQuery(document.createElement('option'))
|
|
||||||
.val(key)
|
|
||||||
.html(value);
|
|
||||||
|
|
||||||
if (currentCollectionValue) {
|
|
||||||
if (String(key) === String(currentCollectionValue)) option_elt.attr('selected', 'selected');
|
|
||||||
}
|
|
||||||
select_elt.append(option_elt);
|
|
||||||
});
|
|
||||||
output.append(select_elt);
|
|
||||||
|
|
||||||
this.element.html(output);
|
|
||||||
this.setHtmlAttributes();
|
|
||||||
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
|
||||||
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
|
||||||
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
|
|
||||||
this.element.find("select")[0].focus();
|
|
||||||
|
|
||||||
// automatically click on the select so you
|
|
||||||
// don't have to click twice
|
|
||||||
try {
|
|
||||||
var e = document.createEvent("MouseEvents");
|
|
||||||
e.initMouseEvent("mousedown", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
|
|
||||||
this.element.find("select")[0].dispatchEvent(e);
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
// browser doesn't support this, e.g. IE8
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
getValue: function () {
|
|
||||||
'use strict';
|
|
||||||
return this.sanitizeValue(this.element.find("select").val());
|
|
||||||
},
|
|
||||||
|
|
||||||
blurHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.data.editor.update();
|
|
||||||
},
|
|
||||||
|
|
||||||
keyupHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
if (event.keyCode === 27) {
|
|
||||||
event.data.editor.abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"checkbox": {
|
|
||||||
activateForm: function () {
|
|
||||||
'use strict';
|
|
||||||
this.collectionValue = !this.getValue();
|
|
||||||
this.setHtmlAttributes();
|
|
||||||
this.update();
|
|
||||||
},
|
|
||||||
|
|
||||||
getValue: function () {
|
|
||||||
'use strict';
|
|
||||||
return this.collectionValue;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
"textarea": {
|
|
||||||
activateForm: function () {
|
|
||||||
'use strict';
|
|
||||||
// grab width and height of text
|
|
||||||
var width = this.element.css('width');
|
|
||||||
var height = this.element.css('height');
|
|
||||||
|
|
||||||
// construct form
|
|
||||||
var output = jQuery(document.createElement('form'))
|
|
||||||
.addClass('form_in_place')
|
|
||||||
.attr('action', 'javascript:void(0);')
|
|
||||||
.attr('style', 'display:inline');
|
|
||||||
var textarea_elt = jQuery(document.createElement('textarea'))
|
|
||||||
.attr('name', this.attributeName)
|
|
||||||
.val(this.sanitizeValue(this.display_value));
|
|
||||||
|
|
||||||
if (this.inner_class !== null) {
|
|
||||||
textarea_elt.addClass(this.inner_class);
|
|
||||||
}
|
|
||||||
|
|
||||||
output.append(textarea_elt);
|
|
||||||
|
|
||||||
this.placeButtons(output, this);
|
|
||||||
|
|
||||||
this.element.html(output);
|
|
||||||
this.setHtmlAttributes();
|
|
||||||
|
|
||||||
// set width and height of textarea
|
|
||||||
jQuery(this.element.find("textarea")[0]).css({'min-width': width, 'min-height': height});
|
|
||||||
jQuery(this.element.find("textarea")[0]).autosize();
|
|
||||||
|
|
||||||
this.element.find("textarea")[0].focus();
|
|
||||||
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
|
|
||||||
|
|
||||||
if (this.cancelButton) {
|
|
||||||
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.skipBlur) {
|
|
||||||
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
|
|
||||||
}
|
|
||||||
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
|
|
||||||
this.blurTimer = null;
|
|
||||||
this.userClicked = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
getValue: function () {
|
|
||||||
'use strict';
|
|
||||||
return this.sanitizeValue(this.element.find("textarea").val());
|
|
||||||
},
|
|
||||||
|
|
||||||
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
|
||||||
blurHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
if (event.data.editor.okButton) {
|
|
||||||
event.data.editor.blurTimer = setTimeout(function () {
|
|
||||||
if (!event.data.editor.userClicked) {
|
|
||||||
event.data.editor.abortIfConfirm();
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
if (event.data.editor.cancelButton) {
|
|
||||||
event.data.editor.blurTimer = setTimeout(function () {
|
|
||||||
if (!event.data.editor.userClicked) {
|
|
||||||
event.data.editor.update();
|
|
||||||
}
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
event.data.editor.update();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
submitHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.data.editor.userClicked = true;
|
|
||||||
clearTimeout(event.data.editor.blurTimer);
|
|
||||||
event.data.editor.update();
|
|
||||||
},
|
|
||||||
|
|
||||||
cancelButtonHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
event.data.editor.userClicked = true;
|
|
||||||
clearTimeout(event.data.editor.blurTimer);
|
|
||||||
event.data.editor.abortIfConfirm();
|
|
||||||
event.stopPropagation(); // Without this, click isn't handled
|
|
||||||
},
|
|
||||||
|
|
||||||
keyupHandler: function (event) {
|
|
||||||
'use strict';
|
|
||||||
if (event.keyCode === 27) {
|
|
||||||
event.data.editor.abortIfConfirm();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
BestInPlaceEditor.defaults = {
|
|
||||||
locales: {},
|
|
||||||
ajaxMethod: "put", //TODO Change to patch when support to 3.2 is dropped
|
|
||||||
ajaxDataType: 'text',
|
|
||||||
okButtonClass: '',
|
|
||||||
cancelButtonClass: '',
|
|
||||||
skipBlur: false
|
|
||||||
};
|
|
||||||
|
|
||||||
// Default locale
|
|
||||||
BestInPlaceEditor.defaults.locales[''] = {
|
|
||||||
confirmMessage: "Are you sure you want to discard your changes?",
|
|
||||||
uninitializedForm: "The form was not properly initialized. getValue is unbound",
|
|
||||||
placeHolder: '-'
|
|
||||||
};
|
|
||||||
|
|
||||||
jQuery.fn.best_in_place = function () {
|
|
||||||
'use strict';
|
|
||||||
function setBestInPlace(element) {
|
|
||||||
if (!element.data('bestInPlaceEditor')) {
|
|
||||||
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
jQuery(this.context).delegate(this.selector, 'click', function () {
|
|
||||||
var el = jQuery(this);
|
|
||||||
if (setBestInPlace(el)) {
|
|
||||||
el.click();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.each(function () {
|
|
||||||
setBestInPlace(jQuery(this));
|
|
||||||
});
|
|
||||||
|
|
||||||
return this;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
780
app/assets/javascripts/lib/bip.js
Normal file
|
@ -0,0 +1,780 @@
|
||||||
|
/*
|
||||||
|
BestInPlace (for jQuery)
|
||||||
|
version: 0.1.0 (01/01/2011)
|
||||||
|
@requires jQuery >= v1.4
|
||||||
|
@requires jQuery.purr to display pop-up windows
|
||||||
|
|
||||||
|
By Bernat Farrero based on the work of Jan Varwig.
|
||||||
|
Examples at http://bernatfarrero.com
|
||||||
|
|
||||||
|
Licensed under the MIT:
|
||||||
|
http://www.opensource.org/licenses/mit-license.php
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
Attention.
|
||||||
|
The format of the JSON object given to the select inputs is the following:
|
||||||
|
[["key", "value"],["key", "value"]]
|
||||||
|
The format of the JSON object given to the checkbox inputs is the following:
|
||||||
|
["falseValue", "trueValue"]
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
function BestInPlaceEditor(e) {
|
||||||
|
this.element = e;
|
||||||
|
this.initOptions();
|
||||||
|
this.bindForm();
|
||||||
|
this.initNil();
|
||||||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
BestInPlaceEditor.prototype = {
|
||||||
|
// Public Interface Functions //////////////////////////////////////////////
|
||||||
|
|
||||||
|
activate : function() {
|
||||||
|
var to_display = "";
|
||||||
|
if (this.isNil()) {
|
||||||
|
to_display = "";
|
||||||
|
}
|
||||||
|
else if (this.original_content) {
|
||||||
|
to_display = this.original_content;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (this.sanitize) {
|
||||||
|
to_display = this.element.text();
|
||||||
|
} else {
|
||||||
|
to_display = this.element.html();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oldValue = this.isNil() ? "" : this.element.html();
|
||||||
|
this.display_value = to_display;
|
||||||
|
jQuery(this.activator).unbind("click", this.clickHandler);
|
||||||
|
this.activateForm();
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:activate"));
|
||||||
|
},
|
||||||
|
|
||||||
|
abort : function() {
|
||||||
|
this.activateText(this.oldValue);
|
||||||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:abort"));
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||||||
|
},
|
||||||
|
|
||||||
|
abortIfConfirm : function () {
|
||||||
|
if (!this.useConfirm) {
|
||||||
|
this.abort();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (confirm("Are you sure you want to discard your changes?")) {
|
||||||
|
this.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
update : function() {
|
||||||
|
var editor = this;
|
||||||
|
if (this.formType in {"input":1, "textarea":1} && this.getValue() == this.oldValue)
|
||||||
|
{ // Avoid request if no change is made
|
||||||
|
this.abort();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
editor.ajax({
|
||||||
|
"type" : "post",
|
||||||
|
"dataType" : "text",
|
||||||
|
"data" : editor.requestData(),
|
||||||
|
"success" : function(data){ editor.loadSuccessCallback(data); },
|
||||||
|
"error" : function(request, error){ editor.loadErrorCallback(request, error); }
|
||||||
|
});
|
||||||
|
if (this.formType == "select") {
|
||||||
|
var value = this.getValue();
|
||||||
|
this.previousCollectionValue = value;
|
||||||
|
|
||||||
|
jQuery.each(this.values, function(i, v) {
|
||||||
|
if (value == v[0]) {
|
||||||
|
editor.element.html(v[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (this.formType == "checkbox") {
|
||||||
|
editor.element.html(this.getValue() ? this.values[1] : this.values[0]);
|
||||||
|
} else {
|
||||||
|
if (this.getValue() !== "") {
|
||||||
|
editor.element.text(this.getValue());
|
||||||
|
} else {
|
||||||
|
editor.element.html(this.nil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
editor.element.trigger(jQuery.Event("best_in_place:update"));
|
||||||
|
},
|
||||||
|
|
||||||
|
activateForm : function() {
|
||||||
|
alert("The form was not properly initialized. activateForm is unbound");
|
||||||
|
},
|
||||||
|
|
||||||
|
activateText : function(value){
|
||||||
|
this.element.html(value);
|
||||||
|
if(this.isNil()) this.element.html(this.nil);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Helper Functions ////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
initOptions : function() {
|
||||||
|
// Try parent supplied info
|
||||||
|
var self = this;
|
||||||
|
self.element.parents().each(function(){
|
||||||
|
$parent = jQuery(this);
|
||||||
|
self.url = self.url || $parent.attr("data-url");
|
||||||
|
self.collection = self.collection || $parent.attr("data-collection");
|
||||||
|
self.formType = self.formType || $parent.attr("data-type");
|
||||||
|
self.objectName = self.objectName || $parent.attr("data-object");
|
||||||
|
self.attributeName = self.attributeName || $parent.attr("data-attribute");
|
||||||
|
self.activator = self.activator || $parent.attr("data-activator");
|
||||||
|
self.okButton = self.okButton || $parent.attr("data-ok-button");
|
||||||
|
self.okButtonClass = self.okButtonClass || $parent.attr("data-ok-button-class");
|
||||||
|
self.cancelButton = self.cancelButton || $parent.attr("data-cancel-button");
|
||||||
|
self.cancelButtonClass = self.cancelButtonClass || $parent.attr("data-cancel-button-class");
|
||||||
|
self.nil = self.nil || $parent.attr("data-nil");
|
||||||
|
self.inner_class = self.inner_class || $parent.attr("data-inner-class");
|
||||||
|
self.html_attrs = self.html_attrs || $parent.attr("data-html-attrs");
|
||||||
|
self.original_content = self.original_content || $parent.attr("data-original-content");
|
||||||
|
self.collectionValue = self.collectionValue || $parent.attr("data-value");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Try Rails-id based if parents did not explicitly supply something
|
||||||
|
self.element.parents().each(function(){
|
||||||
|
var res = this.id.match(/^(\w+)_(\d+)$/i);
|
||||||
|
if (res) {
|
||||||
|
self.objectName = self.objectName || res[1];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Load own attributes (overrides all others)
|
||||||
|
self.url = self.element.attr("data-url") || self.url || document.location.pathname;
|
||||||
|
self.collection = self.element.attr("data-collection") || self.collection;
|
||||||
|
self.formType = self.element.attr("data-type") || self.formtype || "input";
|
||||||
|
self.objectName = self.element.attr("data-object") || self.objectName;
|
||||||
|
self.attributeName = self.element.attr("data-attribute") || self.attributeName;
|
||||||
|
self.activator = self.element.attr("data-activator") || self.element;
|
||||||
|
self.okButton = self.element.attr("data-ok-button") || self.okButton;
|
||||||
|
self.okButtonClass = self.element.attr("data-ok-button-class") || self.okButtonClass || "";
|
||||||
|
self.cancelButton = self.element.attr("data-cancel-button") || self.cancelButton;
|
||||||
|
self.cancelButtonClass = self.element.attr("data-cancel-button-class") || self.cancelButtonClass || "";
|
||||||
|
self.nil = self.element.attr("data-nil") || self.nil || "—";
|
||||||
|
self.inner_class = self.element.attr("data-inner-class") || self.inner_class || null;
|
||||||
|
self.html_attrs = self.element.attr("data-html-attrs") || self.html_attrs;
|
||||||
|
self.original_content = self.element.attr("data-original-content") || self.original_content;
|
||||||
|
self.collectionValue = self.element.attr("data-value") || self.collectionValue;
|
||||||
|
|
||||||
|
if (!self.element.attr("data-sanitize")) {
|
||||||
|
self.sanitize = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
self.sanitize = (self.element.attr("data-sanitize") == "true");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!self.element.attr("data-use-confirm")) {
|
||||||
|
self.useConfirm = true;
|
||||||
|
} else {
|
||||||
|
self.useConfirm = (self.element.attr("data-use-confirm") != "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((self.formType == "select" || self.formType == "checkbox") && self.collection !== null)
|
||||||
|
{
|
||||||
|
self.values = jQuery.parseJSON(self.collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
bindForm : function() {
|
||||||
|
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
|
||||||
|
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
|
||||||
|
},
|
||||||
|
|
||||||
|
initNil: function() {
|
||||||
|
if (this.element.html() === "")
|
||||||
|
{
|
||||||
|
this.element.html(this.nil);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
isNil: function() {
|
||||||
|
// TODO: It only work when form is deactivated.
|
||||||
|
// Condition will fail when form is activated
|
||||||
|
return this.element.html() === "" || this.element.html() === this.nil;
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
alert("The form was not properly initialized. getValue is unbound");
|
||||||
|
},
|
||||||
|
|
||||||
|
// Trim and Strips HTML from text
|
||||||
|
sanitizeValue : function(s) {
|
||||||
|
return jQuery.trim(s);
|
||||||
|
},
|
||||||
|
|
||||||
|
/* Generate the data sent in the POST request */
|
||||||
|
requestData : function() {
|
||||||
|
// To prevent xss attacks, a csrf token must be defined as a meta attribute
|
||||||
|
csrf_token = jQuery('meta[name=csrf-token]').attr('content');
|
||||||
|
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
|
||||||
|
|
||||||
|
var data = "_method=put";
|
||||||
|
data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
|
||||||
|
|
||||||
|
if (csrf_param !== undefined && csrf_token !== undefined) {
|
||||||
|
data += "&" + csrf_param + "=" + encodeURIComponent(csrf_token);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
},
|
||||||
|
|
||||||
|
ajax : function(options) {
|
||||||
|
options.url = this.url;
|
||||||
|
options.beforeSend = function(xhr){ xhr.setRequestHeader("Accept", "application/json"); };
|
||||||
|
return jQuery.ajax(options);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Handlers ////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
loadSuccessCallback : function(data) {
|
||||||
|
data = jQuery.trim(data);
|
||||||
|
|
||||||
|
if(data && data!=""){
|
||||||
|
var response = jQuery.parseJSON(jQuery.trim(data));
|
||||||
|
if (response !== null && response.hasOwnProperty("display_as")) {
|
||||||
|
this.element.attr("data-original-content", this.element.text());
|
||||||
|
this.original_content = this.element.text();
|
||||||
|
this.element.html(response["display_as"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:success"), data);
|
||||||
|
this.element.trigger(jQuery.Event("ajax:success"), data);
|
||||||
|
} else {
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:success"));
|
||||||
|
this.element.trigger(jQuery.Event("ajax:success"));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binding back after being clicked
|
||||||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||||||
|
|
||||||
|
if (this.collectionValue !== null && this.formType == "select") {
|
||||||
|
this.collectionValue = this.previousCollectionValue;
|
||||||
|
this.previousCollectionValue = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
loadErrorCallback : function(request, error) {
|
||||||
|
this.activateText(this.oldValue);
|
||||||
|
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
|
||||||
|
this.element.trigger(jQuery.Event("ajax:error"), request, error);
|
||||||
|
|
||||||
|
// Binding back after being clicked
|
||||||
|
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
|
||||||
|
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
|
||||||
|
},
|
||||||
|
|
||||||
|
clickHandler : function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.data.editor.activate();
|
||||||
|
},
|
||||||
|
|
||||||
|
setHtmlAttributes : function() {
|
||||||
|
var formField = this.element.find(this.formType);
|
||||||
|
|
||||||
|
if(this.html_attrs){
|
||||||
|
var attrs = jQuery.parseJSON(this.html_attrs);
|
||||||
|
for(var key in attrs){
|
||||||
|
formField.attr(key, attrs[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Button cases:
|
||||||
|
// If no buttons, then blur saves, ESC cancels
|
||||||
|
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
|
||||||
|
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
|
||||||
|
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
|
||||||
|
BestInPlaceEditor.forms = {
|
||||||
|
"input" : {
|
||||||
|
activateForm : function() {
|
||||||
|
var output = jQuery(document.createElement('form'))
|
||||||
|
.addClass('form_in_place')
|
||||||
|
.attr('action', 'javascript:void(0);')
|
||||||
|
.attr('style', 'display:inline');
|
||||||
|
var input_elt = jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'text')
|
||||||
|
.attr('name', this.attributeName)
|
||||||
|
.val(this.display_value);
|
||||||
|
if(this.inner_class !== null) {
|
||||||
|
input_elt.addClass(this.inner_class);
|
||||||
|
}
|
||||||
|
output.append(input_elt);
|
||||||
|
if(this.okButton) {
|
||||||
|
output.append(
|
||||||
|
jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'submit')
|
||||||
|
.attr('class', this.okButtonClass)
|
||||||
|
.attr('value', this.okButton)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if(this.cancelButton) {
|
||||||
|
output.append(
|
||||||
|
jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'button')
|
||||||
|
.attr('class', this.cancelButtonClass)
|
||||||
|
.attr('value', this.cancelButton)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.html(output);
|
||||||
|
this.setHtmlAttributes();
|
||||||
|
// START METAMAPS CODE
|
||||||
|
//this.element.find("input[type='text']")[0].select();
|
||||||
|
this.element.find("input[type='text']")[0].focus();
|
||||||
|
// END METAMAPS CODE
|
||||||
|
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
|
||||||
|
if (this.cancelButton) {
|
||||||
|
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
|
||||||
|
}
|
||||||
|
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
|
||||||
|
// START METAMAPS CODE
|
||||||
|
this.element.find("input[type='text']").bind('keydown', {editor: this}, BestInPlaceEditor.forms.input.keydownHandler);
|
||||||
|
// END METAMAPS CODE
|
||||||
|
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
|
||||||
|
this.blurTimer = null;
|
||||||
|
this.userClicked = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
return this.sanitizeValue(this.element.find("input").val());
|
||||||
|
},
|
||||||
|
|
||||||
|
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
||||||
|
inputBlurHandler : function(event) {
|
||||||
|
if (event.data.editor.okButton) {
|
||||||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||||||
|
if (!event.data.editor.userClicked) {
|
||||||
|
event.data.editor.abort();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
if (event.data.editor.cancelButton) {
|
||||||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||||||
|
if (!event.data.editor.userClicked) {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
submitHandler : function(event) {
|
||||||
|
event.data.editor.userClicked = true;
|
||||||
|
clearTimeout(event.data.editor.blurTimer);
|
||||||
|
event.data.editor.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelButtonHandler : function(event) {
|
||||||
|
event.data.editor.userClicked = true;
|
||||||
|
clearTimeout(event.data.editor.blurTimer);
|
||||||
|
event.data.editor.abort();
|
||||||
|
event.stopPropagation(); // Without this, click isn't handled
|
||||||
|
},
|
||||||
|
|
||||||
|
keyupHandler : function(event) {
|
||||||
|
if (event.keyCode == 27) {
|
||||||
|
event.data.editor.abort();
|
||||||
|
}
|
||||||
|
// START METAMAPS CODE
|
||||||
|
else if (event.keyCode == 13 && !event.shiftKey) {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
// END METAMAPS CODE
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"date" : {
|
||||||
|
activateForm : function() {
|
||||||
|
var that = this,
|
||||||
|
output = jQuery(document.createElement('form'))
|
||||||
|
.addClass('form_in_place')
|
||||||
|
.attr('action', 'javascript:void(0);')
|
||||||
|
.attr('style', 'display:inline'),
|
||||||
|
input_elt = jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'text')
|
||||||
|
.attr('name', this.attributeName)
|
||||||
|
.attr('value', this.sanitizeValue(this.display_value));
|
||||||
|
if(this.inner_class !== null) {
|
||||||
|
input_elt.addClass(this.inner_class);
|
||||||
|
}
|
||||||
|
output.append(input_elt)
|
||||||
|
|
||||||
|
this.element.html(output);
|
||||||
|
this.setHtmlAttributes();
|
||||||
|
this.element.find('input')[0].select();
|
||||||
|
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
|
||||||
|
this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
|
||||||
|
|
||||||
|
this.element.find('input')
|
||||||
|
.datepicker({
|
||||||
|
onClose: function() {
|
||||||
|
that.update();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.datepicker('show');
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
return this.sanitizeValue(this.element.find("input").val());
|
||||||
|
},
|
||||||
|
|
||||||
|
submitHandler : function(event) {
|
||||||
|
event.data.editor.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
// START METAMAPS CODE
|
||||||
|
keydownHandler : function(event) {
|
||||||
|
if (event.keyCode == 13 && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// END METAMAPS CODE
|
||||||
|
|
||||||
|
keyupHandler : function(event) {
|
||||||
|
if (event.keyCode == 27) {
|
||||||
|
event.data.editor.abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"select" : {
|
||||||
|
activateForm : function() {
|
||||||
|
var output = jQuery(document.createElement('form'))
|
||||||
|
.attr('action', 'javascript:void(0)')
|
||||||
|
.attr('style', 'display:inline');
|
||||||
|
selected = '',
|
||||||
|
oldValue = this.oldValue,
|
||||||
|
select_elt = jQuery(document.createElement('select'))
|
||||||
|
.attr('class', this.inned_class !== null ? this.inner_class : '' ),
|
||||||
|
currentCollectionValue = this.collectionValue;
|
||||||
|
|
||||||
|
jQuery.each(this.values, function (index, value) {
|
||||||
|
var option_elt = jQuery(document.createElement('option'))
|
||||||
|
// .attr('value', value[0])
|
||||||
|
.val(value[0])
|
||||||
|
.html(value[1]);
|
||||||
|
if(value[0] == currentCollectionValue) {
|
||||||
|
option_elt.attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
select_elt.append(option_elt);
|
||||||
|
});
|
||||||
|
output.append(select_elt);
|
||||||
|
|
||||||
|
this.element.html(output);
|
||||||
|
this.setHtmlAttributes();
|
||||||
|
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
||||||
|
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
|
||||||
|
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
|
||||||
|
this.element.find("select")[0].focus();
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
return this.sanitizeValue(this.element.find("select").val());
|
||||||
|
// return this.element.find("select").val();
|
||||||
|
},
|
||||||
|
|
||||||
|
blurHandler : function(event) {
|
||||||
|
event.data.editor.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
keyupHandler : function(event) {
|
||||||
|
if (event.keyCode == 27) event.data.editor.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"checkbox" : {
|
||||||
|
activateForm : function() {
|
||||||
|
this.collectionValue = !this.getValue();
|
||||||
|
this.setHtmlAttributes();
|
||||||
|
this.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
return this.collectionValue;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"textarea" : {
|
||||||
|
activateForm : function() {
|
||||||
|
// grab width and height of text
|
||||||
|
width = this.element.css('width');
|
||||||
|
height = this.element.css('height');
|
||||||
|
|
||||||
|
// construct form
|
||||||
|
var output = jQuery(document.createElement('form'))
|
||||||
|
.attr('action', 'javascript:void(0)')
|
||||||
|
.attr('style', 'display:inline')
|
||||||
|
.append(jQuery(document.createElement('textarea'))
|
||||||
|
.val(this.sanitizeValue(this.display_value)));
|
||||||
|
if(this.okButton) {
|
||||||
|
output.append(
|
||||||
|
jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'submit')
|
||||||
|
.attr('value', this.okButton)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if(this.cancelButton) {
|
||||||
|
output.append(
|
||||||
|
jQuery(document.createElement('input'))
|
||||||
|
.attr('type', 'button')
|
||||||
|
.attr('value', this.cancelButton)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.html(output);
|
||||||
|
this.setHtmlAttributes();
|
||||||
|
|
||||||
|
// set width and height of textarea
|
||||||
|
jQuery(this.element.find("textarea")[0]).css({ 'min-width': width, 'min-height': height });
|
||||||
|
jQuery(this.element.find("textarea")[0]).elastic();
|
||||||
|
|
||||||
|
this.element.find("textarea")[0].focus();
|
||||||
|
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
|
||||||
|
if (this.cancelButton) {
|
||||||
|
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
|
||||||
|
}
|
||||||
|
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
|
||||||
|
// START METAMAPS CODE
|
||||||
|
this.element.find("textarea").bind('keydown', {editor: this}, BestInPlaceEditor.forms.textarea.keydownHandler);
|
||||||
|
// END METAMAPS CODE
|
||||||
|
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
|
||||||
|
this.blurTimer = null;
|
||||||
|
this.userClicked = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getValue : function() {
|
||||||
|
return this.sanitizeValue(this.element.find("textarea").val());
|
||||||
|
},
|
||||||
|
|
||||||
|
// When buttons are present, use a timer on the blur event to give precedence to clicks
|
||||||
|
blurHandler : function(event) {
|
||||||
|
if (event.data.editor.okButton) {
|
||||||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||||||
|
if (!event.data.editor.userClicked) {
|
||||||
|
event.data.editor.abortIfConfirm();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
if (event.data.editor.cancelButton) {
|
||||||
|
event.data.editor.blurTimer = setTimeout(function () {
|
||||||
|
if (!event.data.editor.userClicked) {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
} else {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
submitHandler : function(event) {
|
||||||
|
event.data.editor.userClicked = true;
|
||||||
|
clearTimeout(event.data.editor.blurTimer);
|
||||||
|
event.data.editor.update();
|
||||||
|
},
|
||||||
|
|
||||||
|
cancelButtonHandler : function(event) {
|
||||||
|
event.data.editor.userClicked = true;
|
||||||
|
clearTimeout(event.data.editor.blurTimer);
|
||||||
|
event.data.editor.abortIfConfirm();
|
||||||
|
event.stopPropagation(); // Without this, click isn't handled
|
||||||
|
},
|
||||||
|
|
||||||
|
// START METAMAPS CODE
|
||||||
|
keydownHandler : function(event) {
|
||||||
|
if (event.keyCode == 13 && !event.shiftKey) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// END METAMAPS CODE
|
||||||
|
|
||||||
|
keyupHandler : function(event) {
|
||||||
|
if (event.keyCode == 27) {
|
||||||
|
event.data.editor.abortIfConfirm();
|
||||||
|
}
|
||||||
|
// START METAMAPS CODE
|
||||||
|
else if (event.keyCode == 13 && !event.shiftKey) {
|
||||||
|
event.data.editor.update();
|
||||||
|
}
|
||||||
|
// END METAMAPS CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery.fn.best_in_place = function() {
|
||||||
|
|
||||||
|
function setBestInPlace(element) {
|
||||||
|
if (!element.data('bestInPlaceEditor')) {
|
||||||
|
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
jQuery(this.context).delegate(this.selector, 'click', function () {
|
||||||
|
var el = jQuery(this);
|
||||||
|
if (setBestInPlace(el))
|
||||||
|
el.click();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.each(function () {
|
||||||
|
setBestInPlace(jQuery(this));
|
||||||
|
});
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name Elastic
|
||||||
|
* @descripton Elastic is Jquery plugin that grow and shrink your textareas automaticliy
|
||||||
|
* @version 1.6.5
|
||||||
|
* @requires Jquery 1.2.6+
|
||||||
|
*
|
||||||
|
* @author Jan Jarfalk
|
||||||
|
* @author-email jan.jarfalk@unwrongest.com
|
||||||
|
* @author-website http://www.unwrongest.com
|
||||||
|
*
|
||||||
|
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function(jQuery){
|
||||||
|
if (typeof jQuery.fn.elastic !== 'undefined') return;
|
||||||
|
|
||||||
|
jQuery.fn.extend({
|
||||||
|
elastic: function() {
|
||||||
|
// We will create a div clone of the textarea
|
||||||
|
// by copying these attributes from the textarea to the div.
|
||||||
|
var mimics = [
|
||||||
|
'paddingTop',
|
||||||
|
'paddingRight',
|
||||||
|
'paddingBottom',
|
||||||
|
'paddingLeft',
|
||||||
|
'fontSize',
|
||||||
|
'lineHeight',
|
||||||
|
'fontFamily',
|
||||||
|
'width',
|
||||||
|
'fontWeight'];
|
||||||
|
|
||||||
|
return this.each( function() {
|
||||||
|
|
||||||
|
// Elastic only works on textareas
|
||||||
|
if ( this.type != 'textarea' ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var $textarea = jQuery(this),
|
||||||
|
$twin = jQuery('<div />').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
|
||||||
|
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
|
||||||
|
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
|
||||||
|
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
|
||||||
|
goalheight = 0,
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
// Opera returns max-height of -1 if not set
|
||||||
|
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
|
||||||
|
|
||||||
|
// Append the twin to the DOM
|
||||||
|
// We are going to meassure the height of this, not the textarea.
|
||||||
|
$twin.appendTo($textarea.parent());
|
||||||
|
|
||||||
|
// Copy the essential styles (mimics) from the textarea to the twin
|
||||||
|
i = mimics.length;
|
||||||
|
while(i--){
|
||||||
|
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sets a given height and overflow state on the textarea
|
||||||
|
function setHeightAndOverflow(height, overflow){
|
||||||
|
curratedHeight = Math.floor(parseInt(height,10));
|
||||||
|
if($textarea.height() != curratedHeight){
|
||||||
|
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// This function will update the height of the textarea if necessary
|
||||||
|
function update() {
|
||||||
|
|
||||||
|
// Get curated content from the textarea.
|
||||||
|
var textareaContent = $textarea.val().replace(/&/g,'&').replace(/ /g, ' ').replace(/<|>/g, '>').replace(/\n/g, '<br />');
|
||||||
|
|
||||||
|
// Compare curated content with curated twin.
|
||||||
|
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
|
||||||
|
|
||||||
|
if(textareaContent+' ' != twinContent){
|
||||||
|
|
||||||
|
// Add an extra white space so new rows are added when you are at the end of a row.
|
||||||
|
$twin.html(textareaContent+' ');
|
||||||
|
|
||||||
|
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
|
||||||
|
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
|
||||||
|
|
||||||
|
var goalheight = $twin.height()+lineHeight;
|
||||||
|
if(goalheight >= maxheight) {
|
||||||
|
setHeightAndOverflow(maxheight,'auto');
|
||||||
|
} else if(goalheight <= minheight) {
|
||||||
|
setHeightAndOverflow(minheight,'hidden');
|
||||||
|
} else {
|
||||||
|
setHeightAndOverflow(goalheight,'hidden');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide scrollbars
|
||||||
|
$textarea.css({'overflow':'hidden'});
|
||||||
|
|
||||||
|
// Update textarea size on keyup, change, cut and paste
|
||||||
|
$textarea.bind('keyup change cut paste', function(){
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Compact textarea on blur
|
||||||
|
// Lets animate this....
|
||||||
|
$textarea.bind('blur',function(){
|
||||||
|
if($twin.height() < maxheight){
|
||||||
|
if($twin.height() > minheight) {
|
||||||
|
$textarea.height($twin.height());
|
||||||
|
} else {
|
||||||
|
$textarea.height(minheight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// And this line is to catch the browser paste event
|
||||||
|
$textarea.on("input paste", function(e){ setTimeout( update, 250); });
|
||||||
|
|
||||||
|
// Run update once when elastic is initialized
|
||||||
|
update();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})(jQuery);
|
|
@ -1,2 +0,0 @@
|
||||||
!function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,b,c,d,B,f;if(e=t.match(a),!e)throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),b=l?atob(u):decodeURIComponent(u),c=new ArrayBuffer(b.length),d=new Uint8Array(c),B=0;B<b.length;B+=1)d[B]=b.charCodeAt(B);return o?new Blob([n?d:c],{type:i}):(f=new r,f.append(c),f.getBlob(i))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,o,n){t(n&&e.toDataURL&&i?i(this.toDataURL(o,n)):this.mozGetAsFile("blob",o))}:e.toDataURL&&i&&(e.toBlob=function(t,e,o){t(i(this.toDataURL(e,o)))})),"function"==typeof define&&define.amd?define(function(){return i}):"object"==typeof module&&module.exports?module.exports=i:t.dataURLtoBlob=i}(window);
|
|
||||||
//# sourceMappingURL=canvas-to-blob.min.js.map
|
|
|
@ -156,48 +156,45 @@ jQuery.browser = browser;
|
||||||
event.data.rotate(-1);
|
event.data.rotate(-1);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
$(options.buttonRight).bind('mouseup',this,function(event){
|
$(options.buttonRight).bind('mouseup',this,function(event){
|
||||||
event.data.rotate(1);
|
event.data.rotate(1);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
// START METAMAPS CODE
|
|
||||||
// Add code that makes tab and shift+tab scroll through metacodes
|
// Add code that makes tab and shift+tab scroll through metacodes
|
||||||
$('.new_topic').bind('keydown',this,function(event){
|
$('.new_topic').bind('keydown',this,function(event){
|
||||||
if (event.keyCode == 9) {
|
if (event.keyCode == 9 && event.shiftKey) {
|
||||||
if (event.shiftKey) {
|
event.data.rotate(-1);
|
||||||
event.data.rotate(-1)
|
event.preventDefault();
|
||||||
} else {
|
event.stopPropagation();
|
||||||
event.data.rotate(1)
|
} else if (event.keyCode == 9) {
|
||||||
}
|
event.data.rotate(1);
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
Metamaps.Create.newTopic.metacode = $(items[event.data.frontIndex].image).attr('data-id');
|
}
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// END METAMAPS CODE
|
|
||||||
|
|
||||||
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
|
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
|
||||||
if (options.mouseWheel)
|
if (options.mouseWheel)
|
||||||
{
|
{
|
||||||
// START METAMAPS CODE
|
// START METAMAPS CODE
|
||||||
$('body').bind('mousewheel',this,function(event, delta) {
|
$('body').bind('mousewheel',this,function(event, delta) {
|
||||||
if (Metamaps.Create.newTopic.beingCreated &&
|
if (Metamaps.Create.newTopic.beingCreated &&
|
||||||
!Metamaps.Create.isSwitchingSet &&
|
!Metamaps.Create.isSwitchingSet &&
|
||||||
!Metamaps.Create.newTopic.pinned) {
|
!Metamaps.Create.newTopic.pinned) {
|
||||||
event.data.rotate(delta);
|
event.data.rotate(delta);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// END METAMAPS CODE
|
// END METAMAPS CODE
|
||||||
// ORIGINAL CODE
|
/* ORIGINAL CODE
|
||||||
// $(container).bind('mousewheel',this,function(event, delta) {
|
$(container).bind('mousewheel',this,function(event, delta) {
|
||||||
// event.data.rotate(delta);
|
event.data.rotate(delta);
|
||||||
// return false;
|
return false;
|
||||||
// });
|
});
|
||||||
//
|
*/
|
||||||
}
|
}
|
||||||
$(container).unbind('mouseover click').bind('mouseover click',this,function(event){
|
$(container).bind('mouseover click',this,function(event){
|
||||||
|
|
||||||
clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over.
|
clearInterval(event.data.autoRotateTimer); // Stop auto rotation if mouse over.
|
||||||
var text = $(event.target).attr('alt');
|
var text = $(event.target).attr('alt');
|
||||||
|
@ -211,27 +208,22 @@ jQuery.browser = browser;
|
||||||
//$(options.titleBox).html( ($(event.target).attr('title') ));
|
//$(options.titleBox).html( ($(event.target).attr('title') ));
|
||||||
if ( options.bringToFront && event.type == 'click' )
|
if ( options.bringToFront && event.type == 'click' )
|
||||||
{
|
{
|
||||||
$(options.titleBox).html( ($(event.target).attr('title') ));
|
$(options.titleBox).html( ($(event.target).attr('title') ));
|
||||||
// START METAMAPS CODE
|
// METAMAPS CODE
|
||||||
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
|
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
|
||||||
// END METAMAPS CODE
|
// NOT METAMAPS CODE
|
||||||
var idx = $(event.target).data('itemIndex');
|
var idx = $(event.target).data('itemIndex');
|
||||||
var frontIndex = event.data.frontIndex;
|
var frontIndex = event.data.frontIndex;
|
||||||
//var diff = idx - frontIndex;
|
//var diff = idx - frontIndex;
|
||||||
var diff = (idx - frontIndex) % images.length;
|
var diff = (idx - frontIndex) % images.length;
|
||||||
if (Math.abs(diff) > images.length / 2) {
|
if (Math.abs(diff) > images.length / 2) {
|
||||||
diff += (diff > 0 ? -images.length : images.length);
|
diff += (diff > 0 ? -images.length : images.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
event.data.rotate(-diff);
|
event.data.rotate(-diff);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
// START METAMAPS CODE - initialize newTopic.metacode
|
|
||||||
var first = $(this.container).find('img').get(0)
|
|
||||||
Metamaps.Create.newTopic.metacode = $(first).data('id')
|
|
||||||
// END METAMAPS CODE
|
|
||||||
|
|
||||||
// If we have moved out of a carousel item (or the container itself),
|
// If we have moved out of a carousel item (or the container itself),
|
||||||
// restore the text of the front item in 1 second.
|
// restore the text of the front item in 1 second.
|
||||||
$(container).bind('mouseout',this,function(event){
|
$(container).bind('mouseout',this,function(event){
|
||||||
|
@ -255,6 +247,11 @@ jQuery.browser = browser;
|
||||||
this.showFrontText = function()
|
this.showFrontText = function()
|
||||||
{
|
{
|
||||||
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
|
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
|
||||||
|
// METAMAPS CODE
|
||||||
|
Metamaps.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.titleBox).html( $(items[this.frontIndex].image).attr('title'));
|
||||||
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
|
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
|
||||||
};
|
};
|
||||||
|
@ -428,4 +425,4 @@ jQuery.browser = browser;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
})(jQuery);
|
})(jQuery);
|
1353
app/assets/javascripts/lib/howler.js
Normal file
180
app/assets/javascripts/lib/jquery.purr.js
Normal file
|
@ -0,0 +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 );
|
||||||
|
|
9808
app/assets/javascripts/lib/simplewebrtc.bundle.js
Normal file
3871
app/assets/javascripts/lib/socket.io.js
Normal file
23
app/assets/javascripts/lib/socketIoConnection.js
Normal 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();
|
||||||
|
};
|
41
app/assets/javascripts/lib/uservoice.js
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
var USERVOICE;
|
||||||
|
if(USERVOICE == undefined) {
|
||||||
|
USERVOICE = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
USERVOICE.load = function (name, id, email, sso_token) {
|
||||||
|
// Include the UserVoice JavaScript SDK (only needed once on a page)
|
||||||
|
UserVoice=window.UserVoice||[];(function(){var uv=document.createElement('script');uv.type='text/javascript';uv.async=true;uv.src='//widget.uservoice.com/wybK0nSMNuhlWkIKzTyWg.js';var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(uv,s)})();
|
||||||
|
|
||||||
|
//
|
||||||
|
// UserVoice Javascript SDK developer documentation:
|
||||||
|
// https://www.uservoice.com/o/javascript-sdk
|
||||||
|
//
|
||||||
|
|
||||||
|
// Set colors
|
||||||
|
UserVoice.push(['set', {
|
||||||
|
accent_color: '#448dd6',
|
||||||
|
trigger_color: 'white',
|
||||||
|
trigger_background_color: 'rgba(46, 49, 51, 0.6)'
|
||||||
|
}]);
|
||||||
|
|
||||||
|
// Identify the user and pass traits
|
||||||
|
// To enable, replace sample data with actual user traits and uncomment the line
|
||||||
|
if (name) {
|
||||||
|
UserVoice.push(['setSSO', sso_token]);
|
||||||
|
UserVoice.push(['identify', {
|
||||||
|
'email': email, // User’s email address
|
||||||
|
'name': name, // User’s real name
|
||||||
|
'id': id, // Optional: Unique id of the user
|
||||||
|
}]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add default trigger to the bottom-left corner of the window:
|
||||||
|
UserVoice.push(['addTrigger', { mode: 'contact', trigger_position: 'bottom-left' }]);
|
||||||
|
|
||||||
|
// Or, use your own custom trigger:
|
||||||
|
//UserVoice.push(['addTrigger', '#barometer_tab', { mode: 'contact' }]);
|
||||||
|
|
||||||
|
// Autoprompt for Satisfaction and SmartVote (only displayed under certain conditions)
|
||||||
|
UserVoice.push(['autoprompt', {}]);
|
||||||
|
};
|
7
app/assets/javascripts/lib/xls.core.min.js
vendored
Normal file
13
app/assets/javascripts/lib/xlsx.core.min.js
vendored
Normal file
20
app/assets/javascripts/src/Metamaps.Erb.js.erb
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/* global Metamaps */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Metamaps.Erb.js.erb
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* erb variables from rails */
|
||||||
|
window.Metamaps = window.Metamaps || {}
|
||||||
|
Metamaps.Erb = {}
|
||||||
|
Metamaps.Erb['REALTIME_SERVER'] = '<%= ENV['REALTIME_SERVER'] %>'
|
||||||
|
Metamaps.Erb['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
|
||||||
|
Metamaps.Erb['user.png'] = '<%= asset_path('user.png') %>'
|
||||||
|
Metamaps.Erb['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
|
||||||
|
Metamaps.Erb['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
|
||||||
|
Metamaps.Erb['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
|
||||||
|
Metamaps.Erb['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
|
||||||
|
Metamaps.Erb['sounds/MM_sounds.mp3'] = '<%= asset_path 'sounds/MM_sounds.mp3' %>'
|
||||||
|
Metamaps.Erb['sounds/MM_sounds.ogg'] = '<%= asset_path 'sounds/MM_sounds.ogg' %>'
|
||||||
|
Metamaps.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %>
|
||||||
|
Metamaps.VERSION = '<%= METAMAPS_VERSION %>'
|
15
app/assets/javascripts/src/check-canvas-support.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
// TODO document this user agent function
|
||||||
|
var labelType, useGradients, nativeTextSupport, animate
|
||||||
|
;(function () {
|
||||||
|
var ua = navigator.userAgent,
|
||||||
|
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
|
||||||
|
typeOfCanvas = typeof HTMLCanvasElement,
|
||||||
|
nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
|
||||||
|
textSupport = nativeCanvasSupport && (typeof document.createElement('canvas').getContext('2d').fillText == 'function')
|
||||||
|
// I'm setting this based on the fact that ExCanvas provides text support for IE
|
||||||
|
// and that as of today iPhone/iPad current text support is lame
|
||||||
|
labelType = (!nativeCanvasSupport || (textSupport && !iStuff)) ? 'Native' : 'HTML'
|
||||||
|
nativeTextSupport = labelType == 'Native'
|
||||||
|
useGradients = nativeCanvasSupport
|
||||||
|
animate = !(iStuff || !nativeCanvasSupport)
|
||||||
|
})()
|
|
@ -1,12 +0,0 @@
|
||||||
/*
|
|
||||||
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
|
||||||
* listed below.
|
|
||||||
*
|
|
||||||
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
|
||||||
* or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
|
|
||||||
*
|
|
||||||
* You're free to add application-wide styles to this file and they'll appear at the top of the
|
|
||||||
* compiled file, but it's generally better to create a new file per style scope.
|
|
||||||
*
|
|
||||||
*= require ./special
|
|
||||||
*/
|
|
|
@ -1,109 +0,0 @@
|
||||||
#metacodeSelector {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.metacodeSelect {
|
|
||||||
border-top: 1px solid #DDD;
|
|
||||||
padding: 0;
|
|
||||||
background: #FFF;
|
|
||||||
|
|
||||||
.metacodeFilterInput {
|
|
||||||
width: 100px;
|
|
||||||
outline: none;
|
|
||||||
border: 0;
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 14px;
|
|
||||||
color: #424242;
|
|
||||||
font-family: 'din-medium', helvetica, sans-serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.metacodeList {
|
|
||||||
list-style: none;
|
|
||||||
background: #FFF;
|
|
||||||
|
|
||||||
li {
|
|
||||||
padding: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
&:hover, &.keySelect {
|
|
||||||
background: #4CAF50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
padding-right: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.selectedMetacode {
|
|
||||||
float: left;
|
|
||||||
background: #FFF;
|
|
||||||
border-top-left-radius: 2px;
|
|
||||||
border-bottom-left-radius: 2px;
|
|
||||||
padding: 5px 10px 5px 6px;
|
|
||||||
vertical-align: top;
|
|
||||||
border-right: 1px solid #DDD;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.selectedMetacode:hover, .selectedMetacode.isBeingSelected {
|
|
||||||
background: #EDEDED;
|
|
||||||
}
|
|
||||||
.selectedMetacode img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.selectedMetacode span {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.selectedMetacode .downArrow {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-style: solid;
|
|
||||||
border-width: 8px 6px 0 6px;
|
|
||||||
border-color: #777 transparent transparent transparent;
|
|
||||||
margin-left: 2px;
|
|
||||||
margin-top: 4px;
|
|
||||||
}
|
|
||||||
.new_topic {
|
|
||||||
margin: 0;
|
|
||||||
margin-top: -17px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
#new_topic .twitter-typeahead {
|
|
||||||
position: relative !important;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
.new_topic #topic_name,
|
|
||||||
.new_topic .tt-hint {
|
|
||||||
border-radius: none;
|
|
||||||
border-top-right-radius: 2px;
|
|
||||||
border-bottom-right-radius: 2px;
|
|
||||||
}
|
|
||||||
.openMetacodeSwitcher {
|
|
||||||
top: -16px;
|
|
||||||
left: -16px;
|
|
||||||
}
|
|
||||||
#metacodeImg {
|
|
||||||
height: 120px;
|
|
||||||
width: 380px;
|
|
||||||
display: none;
|
|
||||||
position: absolute !important;
|
|
||||||
top: -30px;
|
|
||||||
z-index: -1;
|
|
||||||
}
|
|
||||||
#metacodeImgTitle {
|
|
||||||
display: none;
|
|
||||||
float: left;
|
|
||||||
width: 120px;
|
|
||||||
text-align: center;
|
|
||||||
margin-left: 110px;
|
|
||||||
}
|
|
|
@ -56,15 +56,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
li.toggledOff {
|
li.toggledOff {
|
||||||
opacity: 0.6;
|
opacity: 0.4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerContent {
|
.blackBox {
|
||||||
width: 760px;
|
width: 760px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 80px 0 60px 20px;
|
padding: 80px 0 60px 20px;
|
||||||
background: rgba(125, 125, 125, 0.4);
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
color: white;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
|
@ -84,10 +85,10 @@
|
||||||
display: table-row;
|
display: table-row;
|
||||||
}
|
}
|
||||||
tr:nth-child(odd) {
|
tr:nth-child(odd) {
|
||||||
background: rgba(125, 125, 125, 0.2);
|
background: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
tr:nth-child(even) {
|
tr:nth-child(even) {
|
||||||
background: rgba(125, 125, 125, 0.3);
|
background: rgba(0, 0, 0, 0.3);
|
||||||
}
|
}
|
||||||
th,
|
th,
|
||||||
td {
|
td {
|
||||||
|
|
|
@ -78,18 +78,11 @@ html {
|
||||||
|
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
background: #d8d9da url(<%= asset_path('shattered_@2X.png') %>);
|
background: #d8d9da url(<%= asset_data_uri('shattered_@2X.png') %>);
|
||||||
font-family: 'din-medium', helvetica, sans-serif;
|
font-family: 'din-medium', helvetica, sans-serif;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
|
|
||||||
&.controller-main,
|
|
||||||
&.controller-maps,
|
|
||||||
&.controller-topics,
|
|
||||||
&.controller-explore {
|
|
||||||
overflow-y: hidden;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
h1,
|
h1,
|
||||||
h2,
|
h2,
|
||||||
|
@ -149,7 +142,6 @@ button.button.btn-no:hover {
|
||||||
.toast .toast-button {
|
.toast .toast-button {
|
||||||
margin-top: -10px;
|
margin-top: -10px;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
margin-bottom: -10px;
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* Utility
|
* Utility
|
||||||
|
@ -193,6 +185,10 @@ button.button.btn-no:hover {
|
||||||
display: block;
|
display: block;
|
||||||
width: 830px;
|
width: 830px;
|
||||||
}
|
}
|
||||||
|
.requestInvite {
|
||||||
|
display: block;
|
||||||
|
margin: -720px auto 0;
|
||||||
|
}
|
||||||
.new_session,
|
.new_session,
|
||||||
.new_user,
|
.new_user,
|
||||||
.edit_user,
|
.edit_user,
|
||||||
|
@ -527,12 +523,10 @@ button.button.btn-no:hover {
|
||||||
left: -1000px;
|
left: -1000px;
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
width: 340px;
|
||||||
margin: -40px 0 0 -35px;
|
margin: -40px 0 0 -35px;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
body:not(.action-conversation) .new_topic {
|
|
||||||
width: 340px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#new_topic .twitter-typeahead {
|
#new_topic .twitter-typeahead {
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
|
@ -668,21 +662,9 @@ label {
|
||||||
position: relative;
|
position: relative;
|
||||||
/*overflow:hidden; */
|
/*overflow:hidden; */
|
||||||
}
|
}
|
||||||
.compressed {
|
.main.compressed {
|
||||||
.upperRightUI {
|
width: calc(100% - 300px);
|
||||||
right: 324px;
|
|
||||||
}
|
|
||||||
.upperRightMapButtons {
|
|
||||||
right: 434px;
|
|
||||||
}
|
|
||||||
.mapControls {
|
|
||||||
right: 324px;
|
|
||||||
}
|
|
||||||
.infoAndHelp {
|
|
||||||
right: 370px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#infovis-canvas {
|
#infovis-canvas {
|
||||||
-webkit-touch-callout: none;
|
-webkit-touch-callout: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
|
@ -783,9 +765,9 @@ label {
|
||||||
}
|
}
|
||||||
.sidebarAccountIcon img {
|
.sidebarAccountIcon img {
|
||||||
border-radius: 16px;
|
border-radius: 16px;
|
||||||
width: 32px;
|
|
||||||
}
|
}
|
||||||
.sidebarAccountBox {
|
.sidebarAccountBox {
|
||||||
|
display: none;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.authenticated .sidebarAccountBox {
|
.authenticated .sidebarAccountBox {
|
||||||
|
@ -826,7 +808,6 @@ label {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
color: #757575;
|
color: #757575;
|
||||||
cursor: pointer;
|
|
||||||
}
|
}
|
||||||
.accountListItem:hover {
|
.accountListItem:hover {
|
||||||
color: #424242;
|
color: #424242;
|
||||||
|
@ -837,7 +818,7 @@ label {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
pointer-events:none;
|
pointer-events:none;
|
||||||
background-repeat:no-repeat;
|
background-repeat:no-repeat;
|
||||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('user_sprite.png') %>);
|
||||||
}
|
}
|
||||||
.accountSettings .accountIcon {
|
.accountSettings .accountIcon {
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
|
@ -845,9 +826,6 @@ label {
|
||||||
.accountAdmin .accountIcon {
|
.accountAdmin .accountIcon {
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
}
|
}
|
||||||
.accountApps .accountIcon {
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
|
||||||
.accountInvite .accountIcon {
|
.accountInvite .accountIcon {
|
||||||
background-position: 0 -64px;
|
background-position: 0 -64px;
|
||||||
}
|
}
|
||||||
|
@ -1048,6 +1026,7 @@ label[for="user_remember_me"] {
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarFilterBox {
|
.sidebarFilterBox {
|
||||||
|
display:none;
|
||||||
width: 319px;
|
width: 319px;
|
||||||
padding: 16px 0;
|
padding: 16px 0;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
@ -1258,7 +1237,7 @@ h3.filterBox {
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.12), 0 3px 3px rgba(0,0,0,0.24);
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.12), 0 3px 3px rgba(0,0,0,0.24);
|
||||||
}
|
}
|
||||||
.rightclickmenu .rc-permission:hover > ul,
|
.rightclickmenu .rc-permission:hover > ul,
|
||||||
.rightclickmenu .rc-metacode:hover #metacodeOptions > ul,
|
.rightclickmenu .rc-metacode:hover > ul,
|
||||||
.rightclickmenu .rc-siblings:hover > ul {
|
.rightclickmenu .rc-siblings:hover > ul {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
@ -1287,7 +1266,7 @@ h3.filterBox {
|
||||||
.rightclickmenu li.toPrivate .rc-perm-icon {
|
.rightclickmenu li.toPrivate .rc-perm-icon {
|
||||||
background-position: -24px 0;
|
background-position: -24px 0;
|
||||||
}
|
}
|
||||||
.rightclickmenu .rc-metacode #metacodeOptions > ul > li,
|
.rightclickmenu .rc-metacode > ul > li,
|
||||||
.rightclickmenu .rc-siblings > ul > li {
|
.rightclickmenu .rc-siblings > ul > li {
|
||||||
padding: 6px 24px 6px 8px;
|
padding: 6px 24px 6px 8px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
|
@ -1546,8 +1525,9 @@ h3.filterBox {
|
||||||
background-image: url(<%= asset_data_uri('permissions32_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('permissions32_sprite.png') %>);
|
||||||
}
|
}
|
||||||
/* map info box */
|
/* map info box */
|
||||||
|
/* map info box */
|
||||||
|
|
||||||
.wrapper .mapInfoBox {
|
.wrapper div.mapInfoBox {
|
||||||
display: none;
|
display: none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 40px;
|
bottom: 40px;
|
||||||
|
@ -1555,41 +1535,12 @@ h3.filterBox {
|
||||||
background-color: #424242;
|
background-color: #424242;
|
||||||
color: #F5F5F5;
|
color: #F5F5F5;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0px 3px 3px rgba(0,0,0,0.16);
|
|
||||||
text-align: center;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
.import-dialog{
|
|
||||||
button {
|
|
||||||
margin: 1em 0.5em;
|
|
||||||
}
|
|
||||||
.import-blue-button {
|
|
||||||
display: inline-block;
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0.75em;
|
|
||||||
padding: 0.75em;
|
|
||||||
padding-top: 0.85em;
|
|
||||||
height: 3em;
|
|
||||||
background-color: #AAB0FB;
|
|
||||||
border-radius: 0.3em;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
.fileupload {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0.75em;
|
|
||||||
padding: 0.75em;
|
|
||||||
height: 3em;
|
|
||||||
border: 3px dashed #AAB0FB;
|
|
||||||
width: 75%;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.wrapper .mapInfoBox {
|
|
||||||
width: 360px;
|
width: 360px;
|
||||||
min-height: 300px;
|
min-height: 300px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
font-style: normal;
|
||||||
|
text-align: center;
|
||||||
|
box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0px 3px 3px rgba(0,0,0,0.16);
|
||||||
}
|
}
|
||||||
.requestTitle {
|
.requestTitle {
|
||||||
display: none;
|
display: none;
|
||||||
|
@ -1915,10 +1866,14 @@ input.collaboratorSearchField {
|
||||||
background-position: -32px 0;
|
background-position: -32px 0;
|
||||||
}
|
}
|
||||||
.yourMap .mapPermission:hover {
|
.yourMap .mapPermission:hover {
|
||||||
|
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-position: -32px 0;
|
||||||
}
|
}
|
||||||
.yourMap .mapPermission.minimize {
|
.yourMap .mapPermission.minimize {
|
||||||
|
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
.mapInfoBox .mapPermission .permissionSelect {
|
.mapInfoBox .mapPermission .permissionSelect {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
@ -2019,7 +1974,6 @@ input.collaboratorSearchField {
|
||||||
position: relative;
|
position: relative;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: none;
|
display: none;
|
||||||
padding: 0 2px;
|
|
||||||
}
|
}
|
||||||
.mapInfoShareIcon {
|
.mapInfoShareIcon {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
|
@ -2059,43 +2013,6 @@ and it won't be important on password protected instances */
|
||||||
.yourMap .mapInfoDelete {
|
.yourMap .mapInfoDelete {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapInfoButtonsWrapper .mapInfoThumbnail {
|
|
||||||
display: block;
|
|
||||||
background-image: url(<%= asset_path('screenshot_sprite.png') %>);
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
|
|
||||||
& > span {
|
|
||||||
bottom: -8px;
|
|
||||||
right: 2px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #e0e0e0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-position: -32px 0;
|
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
bottom: 30px;
|
|
||||||
background: black;
|
|
||||||
color: white;
|
|
||||||
border-radius: 2px;
|
|
||||||
padding: 3px 5px 2px 5px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapInfoButtonsWrapper span {
|
.mapInfoButtonsWrapper span {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -2110,17 +2027,17 @@ and it won't be important on password protected instances */
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: absolute;
|
position: fixed;
|
||||||
z-index: 1000000;
|
z-index: 1000000;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#lightbox_main {
|
#lightbox_main {
|
||||||
width: 800px;
|
width: 800px;
|
||||||
|
height: auto;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 5vh;
|
top: 50%;
|
||||||
height: 90vh;
|
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
@ -2159,10 +2076,8 @@ and it won't be important on password protected instances */
|
||||||
background-position: center center;
|
background-position: center center;
|
||||||
}
|
}
|
||||||
#lightbox_content {
|
#lightbox_content {
|
||||||
width: 800px;
|
width: 552px;
|
||||||
max-height: 90vh;
|
height: 434px;
|
||||||
box-sizing: border-box;
|
|
||||||
overflow-y: auto;
|
|
||||||
background-color: #e0e0e0;
|
background-color: #e0e0e0;
|
||||||
padding: 64px 124px 64px 124px;
|
padding: 64px 124px 64px 124px;
|
||||||
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);
|
||||||
|
@ -2244,34 +2159,41 @@ and it won't be important on password protected instances */
|
||||||
color: #00bcd4;
|
color: #00bcd4;
|
||||||
}
|
}
|
||||||
.lightbox_links .lightboxAboutIcon {
|
.lightbox_links .lightboxAboutIcon {
|
||||||
|
background-image: url(<%= asset_data_uri('about_sprite.png') %>);
|
||||||
|
background-repeat: no-repeat;
|
||||||
width:32px;
|
width:32px;
|
||||||
height:32px;
|
height:32px;
|
||||||
margin:10px auto;
|
margin:10px auto;
|
||||||
}
|
}
|
||||||
.icon_twitter .lightboxAboutIcon,
|
#lightbox_metamapps .lightboxAboutIcon {
|
||||||
.icon_source_code .lightboxAboutIcon,
|
|
||||||
.icon_terms .lightboxAboutIcon {
|
|
||||||
background-image: url(<%= asset_data_uri('about_sprite.png') %>);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
.icon_twitter .lightboxAboutIcon {
|
#lightbox_community .lightboxAboutIcon {
|
||||||
background-position: 0 0;
|
background-position: -32px 0;
|
||||||
&:hover {
|
}
|
||||||
|
#lightbox_source .lightboxAboutIcon {
|
||||||
|
background-position: -64px 0;
|
||||||
|
}
|
||||||
|
#lightbox_blog .lightboxAboutIcon {
|
||||||
|
background-position: -96px 0;
|
||||||
|
}
|
||||||
|
#lightbox_term .lightboxAboutIcon {
|
||||||
|
background-position: -128px 0;
|
||||||
|
}
|
||||||
|
#lightbox_metamapps:hover .lightboxAboutIcon {
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.icon_source_code .lightboxAboutIcon {
|
#lightbox_community:hover .lightboxAboutIcon {
|
||||||
background-position: -64px 0;
|
background-position: -32px -32px;
|
||||||
&:hover {
|
}
|
||||||
|
#lightbox_source:hover .lightboxAboutIcon {
|
||||||
background-position: -64px -32px;
|
background-position: -64px -32px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.icon_terms .lightboxAboutIcon {
|
#lightbox_blog:hover .lightboxAboutIcon {
|
||||||
background-position: -128px 0;
|
background-position: -96px -32px;
|
||||||
&:hover {
|
}
|
||||||
|
#lightbox_term:hover .lightboxAboutIcon {
|
||||||
background-position: -128px -32px;
|
background-position: -128px -32px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* jquery ui tabs */
|
/* jquery ui tabs */
|
||||||
|
@ -2315,9 +2237,6 @@ and it won't be important on password protected instances */
|
||||||
}
|
}
|
||||||
/* switch metacode set */
|
/* switch metacode set */
|
||||||
|
|
||||||
#switchMetacodes > p {
|
|
||||||
margin: 16px 0 16px 0;
|
|
||||||
}
|
|
||||||
#metacodeSwitchTabs {
|
#metacodeSwitchTabs {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
@ -2325,43 +2244,28 @@ and it won't be important on password protected instances */
|
||||||
border: none;
|
border: none;
|
||||||
background: none;
|
background: none;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
}
|
||||||
.setDesc,
|
#metacodeSwitchTabs .setDesc {
|
||||||
.selectAll,
|
margin-bottom: 5px;
|
||||||
.selectNone {
|
font-family: 'din-medium', helvetica, sans-serif;
|
||||||
margin-bottom: 5px;
|
color: #424242;
|
||||||
font-family: 'din-medium', helvetica, sans-serif;
|
font-size: 14px;
|
||||||
color: #424242;
|
text-align: justify;
|
||||||
font-size: 14px;
|
padding-right: 16px;
|
||||||
text-align: justify;
|
}
|
||||||
padding-right: 16px;
|
#switchMetacodes > p {
|
||||||
display: inline-block;
|
margin: 16px 0 16px 0;
|
||||||
}
|
}
|
||||||
|
#metacodeSwitchTabs > ul {
|
||||||
.selectAll,
|
width: 130px;
|
||||||
.selectNone {
|
}
|
||||||
float: right;
|
#metacodeSwitchTabs > ul li {
|
||||||
cursor: pointer;
|
font-size: 14px;
|
||||||
|
text-transform: uppercase;
|
||||||
&:hover,
|
}
|
||||||
&.selected {
|
#metacodeSwitchTabs li.ui-state-active a {
|
||||||
color: #00bcd4;
|
color: #00BCD4;
|
||||||
}
|
cursor: pointer;
|
||||||
}
|
|
||||||
|
|
||||||
& > ul {
|
|
||||||
width: 130px;
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: 14px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li.ui-state-active a {
|
|
||||||
color: #00BCD4;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.metacodeSwitchTab {
|
.metacodeSwitchTab {
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
|
@ -2930,18 +2834,146 @@ and it won't be important on password protected instances */
|
||||||
color: #424242;
|
color: #424242;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Admin Pages */
|
||||||
|
|
||||||
|
.blackBox {
|
||||||
|
width: 760px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px 0 60px 20px;
|
||||||
|
background: rgba(0, 0, 0, 0.4);
|
||||||
|
color: white;
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.blackBox .metacodeSetsDescription {
|
||||||
|
width: 314px;
|
||||||
|
}
|
||||||
|
.blackBox td.metacodeSetDesc {
|
||||||
|
width: 314px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.blackBox .metacodeSetImage {
|
||||||
|
width: 36px;
|
||||||
|
height: 36px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
.blackBox tr {
|
||||||
|
display: table-row;
|
||||||
|
}
|
||||||
|
.blackBox tr:nth-child(odd) {
|
||||||
|
background: rgba(0, 0, 0, 0.2);
|
||||||
|
}
|
||||||
|
.blackBox tr:nth-child(even) {
|
||||||
|
background: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
.blackBox th,
|
||||||
|
.blackBox td {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
.blackBox td.iconURL {
|
||||||
|
max-width: 415px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.blackBox td.iconColor {
|
||||||
|
|
||||||
|
}
|
||||||
|
.blackBox .field {
|
||||||
|
margin: 15px 0 5px;
|
||||||
|
}
|
||||||
|
.blackBox label {
|
||||||
|
float: left;
|
||||||
|
width: 100px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
.blackBox 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;
|
||||||
|
}
|
||||||
|
.blackBox input[type="text"]:hover,
|
||||||
|
.blackBox textarea: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);
|
||||||
|
}
|
||||||
|
.blackBox 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;
|
||||||
|
}
|
||||||
|
.blackBox .allMetacodes {
|
||||||
|
padding: 5px 0;
|
||||||
|
}
|
||||||
|
.blackBox a.button {
|
||||||
|
margin-right: 20px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
.blackBox a.button,
|
||||||
|
.blackBox input.add {
|
||||||
|
float: left;
|
||||||
|
margin-top: 5px;
|
||||||
|
height: 40px;
|
||||||
|
font-size: 17px;
|
||||||
|
width: auto;
|
||||||
|
padding: 0 30px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
.blackBox a.button:hover,
|
||||||
|
.blackBox input.add:hover {
|
||||||
|
-webkit-box-shadow: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* request */
|
/* request */
|
||||||
|
|
||||||
.requestInvite {
|
#wrapper .requestInvite {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 0 60px 0;
|
||||||
background: #FFFFFF;
|
background: #FFFFFF;
|
||||||
color: white;
|
color: white;
|
||||||
height: calc(100% - 52px);
|
height: 100%;
|
||||||
z-index: 1;
|
overflow: hidden;
|
||||||
position: relative;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -350px;
|
|
||||||
margin-top: 52px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.home_bg {
|
.home_bg {
|
||||||
|
@ -3011,21 +3043,3 @@ script.data-gratipay-username {
|
||||||
display: inline;
|
display: inline;
|
||||||
float: left;
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.inline {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.topicFollow {
|
|
||||||
height: 24px;
|
|
||||||
line-height: 24px;
|
|
||||||
cursor: pointer;
|
|
||||||
font-family: helvetica, sans-serif;
|
|
||||||
float: left;
|
|
||||||
width: 72px;
|
|
||||||
text-align: right;
|
|
||||||
padding: 12px 0;
|
|
||||||
color: #4fb5c0;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
|
@ -1,14 +1,17 @@
|
||||||
.centerContent {
|
.centerContent {
|
||||||
position: relative;
|
position: relative;
|
||||||
margin: 0 auto;
|
margin: 92px auto 0 auto;
|
||||||
width: auto;
|
padding: 20px 0 60px 20px;
|
||||||
max-width: 800px;
|
width: 760px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-shadow: 0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);
|
box-shadow: 0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-sizing: border-box;
|
-webkit-border-radius: 3px;
|
||||||
|
-moz-border-radius: 3px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid #dcdcdc;
|
||||||
|
margin-bottom: 10px;
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
font-family: 'din-regular', sans-serif;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerContent .page-header {
|
.centerContent .page-header {
|
||||||
|
@ -126,9 +129,3 @@
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerContent.withPadding {
|
|
||||||
margin-top: 1em;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,11 @@
|
||||||
$mid-gray: #8A8A8A;
|
|
||||||
$mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
|
||||||
|
|
||||||
.nameCounter {
|
.nameCounter {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 1px;
|
bottom: 1px;
|
||||||
right: 2px;
|
right: 2px;
|
||||||
font-size: 11px;
|
font-size: 11px;
|
||||||
font-family: helvetica, sans-serif;
|
font-family: helvetica;
|
||||||
color: #727272;
|
color: #727272;
|
||||||
line-height: 11px;
|
line-height: 11px;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.riek-editing + .nameCounter {
|
|
||||||
display: block;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nameCounter.forMap {
|
.nameCounter.forMap {
|
||||||
|
@ -22,20 +14,22 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.nameCounter.forTopic {
|
.nameCounter.forTopic {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#center-container {
|
#center-container {
|
||||||
position:relative;
|
position:relative;
|
||||||
height:100%;
|
height:100%;
|
||||||
width:100%;
|
width:100%;
|
||||||
|
|
||||||
/* background-color:#031924; */
|
/* background-color:#031924; */
|
||||||
color:#444;
|
color:#444;
|
||||||
}
|
}
|
||||||
|
|
||||||
.showcard {
|
.showcard {
|
||||||
position:absolute;
|
position:absolute;
|
||||||
|
display:none;
|
||||||
top:100px;
|
top:100px;
|
||||||
left:100px;
|
left:100px;
|
||||||
width:300px;
|
width:300px;
|
||||||
|
@ -45,7 +39,7 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
z-index:2;
|
z-index:2;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
border-radius:2px;
|
border-radius:2px;
|
||||||
box-shadow: 2px 3px 3px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
.text {
|
.text {
|
||||||
|
@ -56,6 +50,7 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
width:100%;
|
width:100%;
|
||||||
height:100%;
|
height:100%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.showcard .permission {
|
.showcard .permission {
|
||||||
|
@ -67,6 +62,7 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
display:block;
|
display:block;
|
||||||
position:relative;
|
position:relative;
|
||||||
width:100%;
|
width:100%;
|
||||||
|
min-height:360px;
|
||||||
z-index: 25;
|
z-index: 25;
|
||||||
}
|
}
|
||||||
.CardOnGraph.hasAttachment {
|
.CardOnGraph.hasAttachment {
|
||||||
|
@ -74,11 +70,11 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .title {
|
.CardOnGraph .title {
|
||||||
word-break: break-word;
|
font-size: 18px;
|
||||||
font-size: 20px;
|
line-height: 22px;
|
||||||
line-height: 24px;
|
|
||||||
display: table;
|
display: table;
|
||||||
padding: 20px 0;
|
padding: 8px 0 16px;
|
||||||
|
height: 80px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-family: 'din-regular', sans-serif;
|
font-family: 'din-regular', sans-serif;
|
||||||
width: 300px;
|
width: 300px;
|
||||||
|
@ -97,11 +93,12 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
.showcard .title .riek-editing {
|
.showcard .best_in_place_name textarea, .showcard .best_in_place_name input {
|
||||||
font-family: 'din-regular', sans-serif;
|
font-family: 'din-regular', sans-serif;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
font-size: 20px;
|
font-size: 18px;
|
||||||
line-height: 24px;
|
line-height: 22px;
|
||||||
|
height: 15px;
|
||||||
padding: 5px 0;
|
padding: 5px 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -115,76 +112,44 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
.CardOnGraph .scroll {
|
.CardOnGraph .scroll {
|
||||||
display:block;
|
display:block;
|
||||||
padding: 8px 0 8px 16px;
|
padding: 8px 0 8px 16px;
|
||||||
|
height: 152px;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height:15px;
|
line-height:15px;
|
||||||
font-family: helvetica, sans-serif;
|
font-family: helvetica, sans-serif;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
|
||||||
p.emptyDesc {
|
|
||||||
color: $mid-gray-opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.mdSupport {
|
|
||||||
color: #4fb5c0;
|
|
||||||
font-size: 11px;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.riek-editing + .mdSupport {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.CardOnGraph.hasAttachment .scroll {
|
.CardOnGraph.hasAttachment .scroll {
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .desc .riek-editing {
|
.CardOnGraph .best_in_place_desc textarea {
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
line-height:15px;
|
line-height:15px;
|
||||||
font-family: helvetica, sans-serif;
|
font-family: helvetica, sans-serif;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
width: 258px;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
font-size: 12px;
|
||||||
|
line-height: 15px;
|
||||||
background: none;
|
background: none;
|
||||||
overflow-y: scroll;
|
resize: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
.CardOnGraph .desc h3 {
|
||||||
* Styling for Markdown in topic cards
|
font-style:normal;
|
||||||
*/
|
margin-top:5px;
|
||||||
|
|
||||||
.CardOnGraph .desc {
|
|
||||||
p, ol, ul {
|
|
||||||
padding: 0.15em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5, h6 {
|
|
||||||
font-style: normal;
|
|
||||||
padding: 0.25em 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
|
||||||
ul {
|
|
||||||
margin-left: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
opacity: 0.9;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
.CardOnGraph .best_in_place_desc {
|
||||||
* End Markdown styling
|
|
||||||
*/
|
|
||||||
|
|
||||||
.CardOnGraph .riek_desc {
|
|
||||||
display:block;
|
display:block;
|
||||||
padding-right: 26px;
|
margin-top:2px;
|
||||||
|
padding-right: 18px;
|
||||||
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
.canEdit .CardOnGraph .riek_desc:not(.riek-editing):hover {
|
.canEdit .CardOnGraph .best_in_place_desc:hover {
|
||||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||||
background-position: top right;
|
background-position: top right;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
@ -196,215 +161,155 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .links {
|
.CardOnGraph .links {
|
||||||
position: relative;
|
position:relative;
|
||||||
z-index: 2;
|
border-bottom: 1px solid #BDBDBD;
|
||||||
|
border-top: 1px solid #BDBDBD;
|
||||||
.linkItem {
|
background-color: #e0e0e0;
|
||||||
float: left;
|
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
color: #424242;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 14px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #424242;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
padding: 0;
|
|
||||||
height: 48px;
|
|
||||||
margin-right: 10px;
|
|
||||||
|
|
||||||
.metacodeImage {
|
|
||||||
cursor: move;
|
|
||||||
position: absolute;
|
|
||||||
left: -18px;
|
|
||||||
top: 6px;
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
background-size:36px 36px;
|
|
||||||
background-position:0 0;
|
|
||||||
background-repeat:no-repeat;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .info {
|
.linkItem {
|
||||||
|
float:left;
|
||||||
|
height:46px;
|
||||||
|
z-index: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
color: #424242;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height:14px;
|
||||||
|
height:12px;
|
||||||
|
padding:17px 0;
|
||||||
|
}
|
||||||
|
.linkItem a {
|
||||||
|
color: #424242;
|
||||||
|
}
|
||||||
|
|
||||||
.linkItem {
|
.CardOnGraph .icon {
|
||||||
float: left;
|
position:absolute;
|
||||||
z-index: 1;
|
width:100%;
|
||||||
position: relative;
|
z-index:1;
|
||||||
color: $mid-gray-opacity;
|
padding: 0;
|
||||||
font-size: 14px;
|
height: 48px;
|
||||||
line-height: 14px;
|
}
|
||||||
|
.linkItem.contributor {
|
||||||
|
margin-left:40px;
|
||||||
|
z-index:1;
|
||||||
|
padding:17px 16px 17px 30px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.contributor .contributorIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 0;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
a {
|
.contributor:hover .contributorName {
|
||||||
color: $mid-gray-opacity;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.contributor {
|
.contributorName {
|
||||||
bottom: 7px;
|
display: none;
|
||||||
margin-left: 16px;
|
position: absolute;
|
||||||
|
background: black;
|
||||||
|
text-align: center;
|
||||||
|
color: white;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-family: din-regular;
|
||||||
|
line-height: 15px;
|
||||||
|
font-size: 12px;
|
||||||
|
padding: 3px 5px 2px;
|
||||||
|
white-space: nowrap;
|
||||||
|
margin-top: 36px;
|
||||||
|
margin-left: -32px;
|
||||||
|
}
|
||||||
|
|
||||||
.contributorIcon {
|
.contributor div:before {
|
||||||
position: relative;
|
content: '';
|
||||||
display: inline-block;
|
position: absolute;
|
||||||
vertical-align: middle;
|
top: 128%;
|
||||||
border-radius: 16px;
|
left: 13px;
|
||||||
margin: 5px 5px 5px 0;
|
margin-top: -30px;
|
||||||
top: 11px;
|
width: 0;
|
||||||
left: 0;
|
height: 0;
|
||||||
}
|
border-bottom: 4px solid #000000;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
span {
|
.linkItem.mapCount {
|
||||||
font-family: 'din-regular', sans-serif;
|
margin-left: 12px;
|
||||||
font-size: 14px;
|
width: 24px;
|
||||||
}
|
padding:17px 0 17px 36px;
|
||||||
|
}
|
||||||
|
.linkItem.mapCount .mapCountIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 0;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-image: url(<%= asset_data_uri('map32_sprite.png') %>);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.linkItem.mapCount:hover .mapCountIcon {
|
||||||
|
background-position: 0 -32px;
|
||||||
|
}
|
||||||
|
|
||||||
.contributorName {
|
.linkItem.mapCount:hover .hoverTip {
|
||||||
font-family: din-regular;
|
display: block;
|
||||||
margin-top: 20px;
|
}
|
||||||
display: inline-block;
|
.CardOnGraph .mapCount .tip, .CardonGraph .mapCount .hoverTip {
|
||||||
vertical-align: middle;
|
top: 44px;
|
||||||
width: 97px;
|
left: 0px;
|
||||||
padding: 0 8px 0 4px;
|
font-size: 12px !important;
|
||||||
white-space: nowrap;
|
}
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapCount {
|
.hoverTip {
|
||||||
padding:17px 38px 17px 0;
|
white-space: nowrap;
|
||||||
width: 22px;
|
font-family: 'din-regular';
|
||||||
text-align: right;
|
top: 44px;
|
||||||
|
left: 0px;
|
||||||
|
font-size: 12px !important;
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
background: black;
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 17px;
|
||||||
|
padding: 3px 5px 2px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
.mapCountIcon {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 0;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
background-image: url(<%= asset_data_uri('map32_sprite.png') %>);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .mapCountIcon {
|
.CardOnGraph .mapCount .tip:before, .CardOnGraph .mapCount .hoverTip:before {
|
||||||
background-position: 0 -32px;
|
content: '';
|
||||||
}
|
position: absolute;
|
||||||
|
top: 26px;
|
||||||
|
left: 10px;
|
||||||
|
margin-top: -30px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-bottom: 4px solid #000000;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
.tip, .hoverTip {
|
.CardOnGraph .mapCount .tip li {
|
||||||
top: 44px;
|
list-style-type: none;
|
||||||
right: 0px;
|
white-space: nowrap;
|
||||||
font-size: 12px !important;
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
padding: 6px 10px;
|
||||||
|
display: block;
|
||||||
|
height: 14px;
|
||||||
|
font-family: 'din-regular', helvetica, sans-serif;
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 14px;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
&:before {
|
.CardOnGraph .mapCount li.hideExtra {
|
||||||
content: '';
|
display: none;
|
||||||
position: absolute;
|
|
||||||
top: 26px;
|
|
||||||
right: 10px;
|
|
||||||
margin-top: -30px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-bottom: 4px solid $mid-gray;
|
|
||||||
border-left: 5px solid transparent;
|
|
||||||
border-right: 5px solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.hoverTip {
|
|
||||||
white-space: nowrap;
|
|
||||||
font-family: 'din-regular';
|
|
||||||
top: 44px;
|
|
||||||
font-size: 12px !important;
|
|
||||||
position: absolute;
|
|
||||||
background: $mid-gray;
|
|
||||||
color: white;
|
|
||||||
border-radius: 4px;
|
|
||||||
line-height: 17px;
|
|
||||||
padding: 3px 5px 2px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip a {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip a:hover {
|
|
||||||
color: #757575;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip li {
|
|
||||||
list-style-type: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
padding: 6px 10px;
|
|
||||||
display: block;
|
|
||||||
height: 14px;
|
|
||||||
font-family: 'din-regular', helvetica, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 14px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.synapseCount {
|
|
||||||
width: 22px;
|
|
||||||
padding:17px 38px 17px 0;
|
|
||||||
text-align: right;
|
|
||||||
margin-right: 4px;
|
|
||||||
|
|
||||||
.synapseCountIcon {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 0;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
background-image: url(<%= asset_data_uri('synapse32_sprite.png') %>);
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
|
||||||
opacity: 0.6;
|
|
||||||
}
|
|
||||||
hover .synapseCountIcon {
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
|
||||||
.tip {
|
|
||||||
position: absolute;
|
|
||||||
background: $mid-gray;
|
|
||||||
width: auto;
|
|
||||||
top: 44px;
|
|
||||||
right: 0px;
|
|
||||||
color: white;
|
|
||||||
white-space: nowrap;
|
|
||||||
border-radius: 2px;
|
|
||||||
font-size: 12px !important;
|
|
||||||
font-family: 'din-regular';
|
|
||||||
line-height: 12px;
|
|
||||||
padding: 4px 4px 4px;
|
|
||||||
z-index: 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tip:before {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
margin-top: -8px;
|
|
||||||
right: 12px;
|
|
||||||
width: 0;
|
|
||||||
height: 0;
|
|
||||||
border-bottom: 4px solid $mid-gray;
|
|
||||||
border-left: 5px solid transparent;
|
|
||||||
border-right: 5px solid transparent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.showMore {
|
.showMore {
|
||||||
|
@ -412,10 +317,66 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
color: #4FC059;
|
color: #4FC059;
|
||||||
}
|
}
|
||||||
|
|
||||||
.linkItem.mapPerm {
|
.mapCount .tip a {
|
||||||
margin-right: 8px;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mapCount .tip a:hover {
|
||||||
|
color: #757575;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.linkItem.synapseCount {
|
||||||
|
margin-left: 2px;
|
||||||
|
width: 24px;
|
||||||
|
padding:17px 0 17px 32px;
|
||||||
|
}
|
||||||
|
.linkItem.synapseCount .synapseCountIcon {
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 0;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-image: url(<%= asset_data_uri('synapse32_sprite.png') %>);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 0;
|
||||||
|
}
|
||||||
|
.linkItem.synapseCount:hover .synapseCountIcon {
|
||||||
|
background-position: 0 -32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CardOnGraph .synapseCount .tip {
|
||||||
|
position: absolute;
|
||||||
|
background: black;
|
||||||
|
width: auto;
|
||||||
|
top: 44px;
|
||||||
|
color: white;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-family: 'din-regular';
|
||||||
|
line-height: 12px;
|
||||||
|
padding: 4px 4px 4px;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CardOnGraph .synapseCount:hover .tip {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.CardOnGraph .synapseCount .tip:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
margin-top: -8px;
|
||||||
|
margin-left: 6px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-bottom: 4px solid black;
|
||||||
|
border-left: 5px solid transparent;
|
||||||
|
border-right: 5px solid transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.mapPerm {
|
.mapPerm {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -437,10 +398,14 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.yourTopic .mapPerm:hover, .yourEdge .mapPerm:hover {
|
.yourTopic .mapPerm:hover, .yourEdge .mapPerm:hover {
|
||||||
|
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||||
|
background-position: -32px 0;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
.yourTopic .mapPerm.minimize, .yourEdge .mapPerm.minimize {
|
.yourTopic .mapPerm.minimize, .yourEdge .mapPerm.minimize {
|
||||||
cursor: pointer;
|
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||||
|
background-position: 0 0;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.mapPerm .permissionSelect {
|
.mapPerm .permissionSelect {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
|
@ -476,55 +441,63 @@ $mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .metacodeTitle {
|
.CardOnGraph .metacodeTitle {
|
||||||
font-family: 'din-regular';
|
font-style: italic;
|
||||||
|
font-family: 'vinyl';
|
||||||
|
text-transform: uppercase;
|
||||||
|
position: absolute;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
height: 26px;
|
height:24px;
|
||||||
font-size: 18px;
|
font-size: 24px;
|
||||||
padding: 13px 24px 9px 24px;
|
display: none;
|
||||||
|
width: 90%;
|
||||||
|
padding: 13px 0 9px 10%;
|
||||||
|
background-color: #E0E0E0;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
width: 120px;
|
|
||||||
max-width: 120px;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
}
|
||||||
.permission.canEdit .metacodeTitle {
|
.permission.canEdit .metacodeTitle {
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.permission.canEdit .expandMetacodeSelect {
|
.permission.canEdit .expandMetacodeSelect {
|
||||||
position: relative;
|
position: absolute;
|
||||||
top: 2px;
|
top: 16px;
|
||||||
left: 4px;
|
right: 16px;
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
background-image: url(<%= asset_data_uri('arrowright_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('arrowright_sprite.png') %>);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
display: inline-block;
|
|
||||||
-webkit-transform: rotate(90deg);
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
}
|
||||||
.permission.canEdit .minimize .expandMetacodeSelect {
|
.permission.canEdit .minimize .expandMetacodeSelect {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .metacodeName {
|
.CardOnGraph .metacodeImage {
|
||||||
display: inline-block;
|
cursor:move;
|
||||||
|
width:46px;
|
||||||
|
height:46px;
|
||||||
|
position:absolute;
|
||||||
|
left:-23px;
|
||||||
|
top:0;
|
||||||
|
background-size:46px 46px;
|
||||||
|
background-position:0 0;
|
||||||
|
background-repeat:no-repeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#metacodeOptions {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
.CardOnGraph .metacodeSelect {
|
.CardOnGraph .metacodeSelect {
|
||||||
display:none;
|
display:none;
|
||||||
width:auto;
|
width:auto;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
background: #EAEAEA;
|
|
||||||
white-space: nowrap;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 48px;
|
background: #EAEAEA;
|
||||||
box-shadow: 2px 2px 2px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
left: 300px;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
.CardOnGraph .metacodeSelect ul {
|
.CardOnGraph .metacodeSelect ul {
|
||||||
position: relative;
|
position: relative;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
font-family: helvetica, sans-serif;
|
font-family: helvetica, sans-serif;
|
||||||
|
@ -609,14 +582,15 @@ background-color: #E0E0E0;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .hoverForTip:hover .tip, #mapContribs:hover .tip {
|
.CardOnGraph .hoverForTip:hover .tip, .mapCard .hoverForTip:hover .tip, #mapContribs:hover .tip {
|
||||||
display:block;
|
display:block;
|
||||||
}
|
}
|
||||||
.CardOnGraph .tip {
|
.CardOnGraph .tip, .mapCard .tip {
|
||||||
|
display:none;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background: $mid-gray;
|
background: black;
|
||||||
top: 35px;
|
top: 35px;
|
||||||
right: 0;
|
left: 0;
|
||||||
color: white;
|
color: white;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
font-size:15px !important;
|
font-size:15px !important;
|
||||||
|
@ -625,23 +599,26 @@ background-color: #E0E0E0;
|
||||||
z-index:100;
|
z-index:100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#embedlyLink {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
#embedlyLinkLoader {
|
#embedlyLinkLoader {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.CardOnGraph .link-adder {
|
.CardOnGraph .attachments {
|
||||||
|
border-top: 1px solid #BDBDBD;
|
||||||
width:100%;
|
width:100%;
|
||||||
height:47px;
|
height:47px;
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.link-adder a {
|
.attachments a {
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: 40px;
|
margin-left: 40px;
|
||||||
padding-top:9px;
|
padding-top:9px;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
|
@ -651,7 +628,7 @@ background-color: #E0E0E0;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 102px;
|
width: 102px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 18px 0 18px 48px;
|
padding: 18px 0 18px 48px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #9e9e9e;
|
color: #9e9e9e;
|
||||||
|
@ -695,9 +672,9 @@ background-color: #E0E0E0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#addLinkInput input{
|
#addLinkInput input{
|
||||||
padding: 9px 27px 9px 31px;
|
padding: 9px 7px 9px 31px;
|
||||||
height: 12px;
|
height: 12px;
|
||||||
width: 210px;
|
width: 198px;
|
||||||
margin: 0 0 0 0;
|
margin: 0 0 0 0;
|
||||||
border: none;
|
border: none;
|
||||||
outline: none;
|
outline: none;
|
||||||
|
@ -751,6 +728,7 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
-moz-border-radius-bottomright: 8px;
|
-moz-border-radius-bottomright: 8px;
|
||||||
-webkit-border-bottom-right-radius: 8px;
|
-webkit-border-bottom-right-radius: 8px;
|
||||||
border-bottom-right-radius: 8px;
|
border-bottom-right-radius: 8px;
|
||||||
|
display: none;
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -837,10 +815,10 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.canEdit span.titleWrapper:hover {
|
.canEdit #edit_synapse_desc:hover {
|
||||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 95% 95%;
|
background-position: 164px center;
|
||||||
cursor: text;
|
cursor: text;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -948,11 +926,11 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
}
|
}
|
||||||
#edit_synapse_right {
|
#edit_synapse_right {
|
||||||
background-image: url(<%= asset_data_uri('synapsedirectionright_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('synapsedirectionright_sprite.png') %>);
|
||||||
right: 16px;
|
right: 16px;
|
||||||
}
|
}
|
||||||
#edit_synapse_left {
|
#edit_synapse_left {
|
||||||
background-image: url(<%= asset_data_uri('synapsedirectionleft_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('synapsedirectionleft_sprite.png') %>);
|
||||||
right: 56px;
|
right: 56px;
|
||||||
}
|
}
|
||||||
#edit_synapse_left.checked, #edit_synapse_right.checked {
|
#edit_synapse_left.checked, #edit_synapse_right.checked {
|
||||||
background-position: 0 -48px;
|
background-position: 0 -48px;
|
||||||
|
@ -964,14 +942,160 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
background-position: 0 -24px;
|
background-position: 0 -24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Map Cards */
|
||||||
|
|
||||||
|
.map {
|
||||||
|
display:inline-block;
|
||||||
|
width:220px;
|
||||||
|
height:340px;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: left;
|
||||||
|
overflow: visible;
|
||||||
|
background: #e8e8e8;
|
||||||
|
border-radius:2px;
|
||||||
|
margin:16px 16px 16px 19px;
|
||||||
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||||
|
}
|
||||||
|
.map:hover {
|
||||||
|
background: #dcdcdc;
|
||||||
|
}
|
||||||
|
.map.newMap {
|
||||||
|
float: left;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.map.newMap a {
|
||||||
|
height: 340px;
|
||||||
|
display: block;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
.newMap .newMapImage {
|
||||||
|
display: block;
|
||||||
|
width: 72px;
|
||||||
|
height: 72px;
|
||||||
|
background-image: url("<%= asset_data_uri('newmap_sprite.png') %>");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: 0 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -36px;
|
||||||
|
top: 50%;
|
||||||
|
margin-top: -36px;
|
||||||
|
}
|
||||||
|
.map:hover .newMapImage {
|
||||||
|
background-position: 0 -72px;
|
||||||
|
}
|
||||||
|
.newMap span {
|
||||||
|
font-family: 'din-regular', sans-serif;
|
||||||
|
font-size: 18px;
|
||||||
|
line-height: 22px;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
padding-top: 220px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard {
|
||||||
|
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||||
|
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
|
||||||
|
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||||
|
display: -webkit-flex; /* NEW - Chrome */
|
||||||
|
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-moz-box-orient: vertical;
|
||||||
|
-webkit-box-direction: normal;
|
||||||
|
-moz-box-direction: normal;
|
||||||
|
-ms-flex-direction: column;
|
||||||
|
-webkit-flex-direction: column;
|
||||||
|
flex-direction: column;
|
||||||
|
position:relative;
|
||||||
|
width:100%;
|
||||||
|
height:308px;
|
||||||
|
padding: 16px 0;
|
||||||
|
color: #424242;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .title {
|
||||||
|
word-wrap: break-word;
|
||||||
|
font-size:18px;
|
||||||
|
line-height:22px;
|
||||||
|
height: 44px;
|
||||||
|
display:block;
|
||||||
|
padding: 0 16px;
|
||||||
|
text-align: center;
|
||||||
|
-webkit-box-flex: none; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||||
|
-moz-box-flex: none; /* OLD - Firefox 19- */
|
||||||
|
-webkit-flex: none; /* Chrome */
|
||||||
|
-ms-flex: none; /* IE 10 */
|
||||||
|
flex: none; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||||
|
font-family: 'din-regular', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .mapScreenshot {
|
||||||
|
width: 188px;
|
||||||
|
height: 126px;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
.mapCard .mapScreenshot img {
|
||||||
|
width: 188px;
|
||||||
|
height: 126px;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .scroll {
|
||||||
|
display:block;
|
||||||
|
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||||
|
-moz-box-flex: 1; /* OLD - Firefox 19- */
|
||||||
|
-webkit-flex: 1; /* Chrome */
|
||||||
|
-ms-flex: 1; /* IE 10 */
|
||||||
|
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||||
|
padding:0 16px 8px;
|
||||||
|
font-family: helvetica, sans-serif;
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 12px;
|
||||||
|
word-wrap: break-word;
|
||||||
|
}
|
||||||
|
.mCS_no_scrollbar {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .mapMetadata {
|
||||||
|
font-family: 'din-regular', sans-serif;
|
||||||
|
font-size: 12px;
|
||||||
|
position:relative;
|
||||||
|
border-top: 1px solid #BDBDBD;
|
||||||
|
-webkit-box-flex: none; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||||
|
-moz-box-flex: none; /* OLD - Firefox 19- */
|
||||||
|
-webkit-flex: none; /* Chrome */
|
||||||
|
-ms-flex: none; /* IE 10 */
|
||||||
|
flex: none; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .metadataSection {
|
||||||
|
padding: 8px 16px 0 16px;
|
||||||
|
width: 78px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapPermission {
|
||||||
|
font-family: 'din-medium', sans-serif;
|
||||||
|
}
|
||||||
|
.cCountColor {
|
||||||
|
font-family: 'din-medium', sans-serif;
|
||||||
|
color: #DB5D5D;
|
||||||
|
}
|
||||||
|
.tCountColor {
|
||||||
|
font-family: 'din-medium', sans-serif;
|
||||||
|
color: #4FC059;
|
||||||
|
}
|
||||||
|
.sCountColor {
|
||||||
|
font-family: 'din-medium', sans-serif;
|
||||||
|
color: #DAB539;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* mapper card */
|
/* mapper card */
|
||||||
|
|
||||||
.mapper {
|
.mapper {
|
||||||
display: inline-block;
|
float: left;
|
||||||
vertical-align: bottom;
|
|
||||||
width:220px;
|
width:220px;
|
||||||
height:340px;
|
height:340px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -979,7 +1103,7 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
background: #E0E0E0;
|
background: #E0E0E0;
|
||||||
border-radius:2px;
|
border-radius:2px;
|
||||||
margin:16px;
|
margin:16px 16px 16px 19px;
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1003,10 +1127,10 @@ font-family: 'din-regular', helvetica, sans-serif;
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
padding: 0 5%;
|
padding: 0 16px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
width: 90%;
|
width: 189px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
box-sizing: border-box;
|
|
||||||
padding-top: 92px;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*.animations {
|
/*.animations {
|
||||||
|
@ -47,9 +44,23 @@
|
||||||
transition-timing-function: ease-in-out;
|
transition-timing-function: ease-in-out;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
.mapElement {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.mapPage .mapElement, .topicPage .mapElement {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.mapPage .mapElementHidden {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.topicPage .starMap {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* loading */
|
/* loading */
|
||||||
|
|
||||||
#loading {
|
#loading {
|
||||||
|
display: none;
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
|
@ -168,64 +179,43 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.upperRightMapButtons {
|
.upperRightMapButtons {
|
||||||
right: 138px;
|
top: -42px; /* puts it just offscreen */
|
||||||
padding-right: 7px;
|
|
||||||
border-right: 1px solid #747474;
|
|
||||||
}
|
}
|
||||||
.unauthenticated .upperRightMapButtons {
|
.mapPage .upperRightMapButtons, .topicPage .upperRightMapButtons {
|
||||||
right: 115px;
|
top: 0;
|
||||||
padding-right: 0;
|
|
||||||
border-right: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.upperRightIcon {
|
.upperRightIcon {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
background-image: url(<%= asset_path('topright_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('topright_sprite.png') %>);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.sidebarFilterIcon {
|
.sidebarFilterIcon {
|
||||||
background-position: -32px 0;
|
|
||||||
}
|
|
||||||
.sidebarForkIcon {
|
|
||||||
background-position: -64px 0;
|
background-position: -64px 0;
|
||||||
}
|
}
|
||||||
.addMap {
|
.sidebarForkIcon {
|
||||||
background-position: -96px 0;
|
background-position: -96px 0;
|
||||||
}
|
}
|
||||||
.notificationsIcon {
|
.addMap {
|
||||||
background-position: -128px 0;
|
background-position: -128px 0;
|
||||||
margin-right: 10px; // make it look more natural next to the account menu icon
|
margin-right:10px;
|
||||||
}
|
|
||||||
.notificationsIcon:hover {
|
|
||||||
background-position: -128px -32px;
|
|
||||||
}
|
|
||||||
.importDialog:hover {
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
}
|
||||||
.sidebarFilterIcon:hover {
|
.sidebarFilterIcon:hover {
|
||||||
background-position: -32px -32px;
|
|
||||||
}
|
|
||||||
.sidebarForkIcon:hover {
|
|
||||||
background-position: -64px -32px;
|
background-position: -64px -32px;
|
||||||
}
|
}
|
||||||
.addMap:hover {
|
.sidebarForkIcon:hover {
|
||||||
background-position: -96px -32px;
|
background-position: -96px -32px;
|
||||||
}
|
}
|
||||||
|
.addMap:hover {
|
||||||
|
background-position: -128px -32px;
|
||||||
|
margin-right:10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* end upperRightUI */
|
/* end upperRightUI */
|
||||||
|
|
||||||
/* map wrapper */
|
|
||||||
.mapWrapper {
|
|
||||||
position:absolute;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* end map wrapper */
|
|
||||||
|
|
||||||
/* yield */
|
/* yield */
|
||||||
|
|
||||||
|
@ -335,7 +325,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullWidthWrapper.withPartners {
|
.fullWidthWrapper.withPartners {
|
||||||
background: url(<%= asset_path('homepage_bg_fade.png') %>) no-repeat center -300px;
|
background: url(<%= asset_data_uri('homepage_bg_fade.png') %>) no-repeat center -300px;
|
||||||
}
|
}
|
||||||
.homeWrapper.homePartners {
|
.homeWrapper.homePartners {
|
||||||
padding: 64px 0 280px;
|
padding: 64px 0 280px;
|
||||||
|
@ -346,15 +336,22 @@
|
||||||
|
|
||||||
/* infoAndHelp */
|
/* infoAndHelp */
|
||||||
|
|
||||||
.openCheatsheet .tooltipsAbove {
|
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
|
||||||
|
right: 70px;
|
||||||
|
}
|
||||||
|
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
||||||
right: 1px;
|
right: 1px;
|
||||||
left: auto;
|
left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unauthenticated .homePage .infoAndHelp {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
.infoAndHelp {
|
.infoAndHelp {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
right: 70px;
|
right: 20px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
width: auto;
|
width: auto;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@ -367,7 +364,7 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.openCheatsheet {
|
.openCheatsheet {
|
||||||
background-image: url(<%= asset_path('help_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('help_sprite.png') %>);
|
||||||
background-repeat:no-repeat;
|
background-repeat:no-repeat;
|
||||||
}
|
}
|
||||||
.openCheatsheet:hover {
|
.openCheatsheet:hover {
|
||||||
|
@ -375,15 +372,18 @@
|
||||||
}
|
}
|
||||||
.mapInfoIcon {
|
.mapInfoIcon {
|
||||||
position: relative;
|
position: relative;
|
||||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
top: 56px; /* puts it just offscreen */
|
||||||
background-repeat:no-repeat;
|
background-image: url(<%= asset_data_uri('mapinfo_sprite.png') %>);
|
||||||
|
background-repeat:no-repeat;
|
||||||
}
|
}
|
||||||
.mapInfoIcon:hover {
|
.mapInfoIcon:hover {
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
}
|
}
|
||||||
|
.mapPage .mapInfoIcon {
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
.starMap {
|
.starMap {
|
||||||
background-image: url(<%= asset_path('starmap_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('starmap_sprite.png') %>);
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
width: 32px;
|
width: 32px;
|
||||||
|
@ -398,6 +398,9 @@
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unauthenticated .mapPage .starMap {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
/* end infoAndHelp */
|
/* end infoAndHelp */
|
||||||
|
|
||||||
|
|
||||||
|
@ -406,17 +409,24 @@
|
||||||
.mapControls {
|
.mapControls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 24px;
|
bottom: 24px;
|
||||||
right:24px;
|
right:-32px; /* puts it just offscreen */
|
||||||
width:32px;
|
width:32px;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
}
|
}
|
||||||
|
.mapPage .mapControls, .topicPage .mapControls {
|
||||||
|
right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topicPage .zoomExtents {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.mapControl {
|
.mapControl {
|
||||||
width:32px;
|
width:32px;
|
||||||
height:32px;
|
height:32px;
|
||||||
background-color: #424242;
|
background-color: #424242;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -424,18 +434,31 @@
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.takeScreenshot {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-image: url(<%= asset_data_uri 'screenshot_sprite.png' %>);
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.takeScreenshot:hover {
|
||||||
|
background-position: -32px 0;
|
||||||
|
}
|
||||||
|
.canEditMap .takeScreenshot {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.zoomExtents {
|
.zoomExtents {
|
||||||
margin-bottom:5px;
|
margin-bottom:5px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-image: url(<%= asset_path('extents_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('extents_sprite.png') %>);
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomExtents:hover {
|
.zoomExtents:hover {
|
||||||
background-position: -32px 0;
|
background-position: -32px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .notificationsIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder,
|
.zoomExtents:hover .tooltips, .zoomIn:hover .tooltips, .zoomOut:hover .tooltips, .takeScreenshot:hover .tooltips, .sidebarFilterIcon:hover .tooltipsUnder, .sidebarForkIcon:hover .tooltipsUnder, .addMap:hover .tooltipsUnder, .authenticated .sidebarAccountIcon:hover .tooltipsUnder,
|
||||||
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips, .importDialog:hover .tooltipsUnder, .starMap:hover .tooltipsAbove, .openMetacodeSwitcher:hover .tooltipsAbove, .pinCarousel:not(.isPinned):hover .tooltipsAbove.helpPin, .pinCarousel.isPinned:hover .tooltipsAbove.helpUnpin {
|
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips, .starMap:hover .tooltipsAbove, .openMetacodeSwitcher:hover .tooltipsAbove, .pinCarousel:not(.isPinned):hover .tooltipsAbove.helpPin, .pinCarousel.isPinned:hover .tooltipsAbove.helpUnpin {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -491,16 +514,9 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.importDialog .tooltipsUnder {
|
|
||||||
left: -22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebarFilterIcon .tooltipsUnder {
|
.sidebarFilterIcon .tooltipsUnder {
|
||||||
margin-left: -4px;
|
margin-left: -4px;
|
||||||
}
|
}
|
||||||
.notificationsIcon .tooltipsUnder {
|
|
||||||
left: -20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sidebarForkIcon .tooltipsUnder {
|
.sidebarForkIcon .tooltipsUnder {
|
||||||
margin-left: -34px;
|
margin-left: -34px;
|
||||||
|
@ -556,12 +572,16 @@
|
||||||
left: -8px;
|
left: -8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.openCheatsheet .tooltipsAbove {
|
||||||
|
left: -4px;
|
||||||
|
}
|
||||||
|
|
||||||
.sidebarAccountIcon .tooltipsUnder {
|
.sidebarAccountIcon .tooltipsUnder {
|
||||||
margin-left: -12px;
|
margin-left: -12px;
|
||||||
margin-top: 40px;
|
margin-top: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .chat-button div.tooltips::after {
|
.zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .takeScreenshot div:after, .chat-button div.tooltips::after {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 57%;
|
top: 57%;
|
||||||
|
@ -574,12 +594,7 @@
|
||||||
border-bottom: 5px solid transparent;
|
border-bottom: 5px solid transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
.addMap div:after,
|
.sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
|
||||||
.importDialog div:after,
|
|
||||||
.sidebarForkIcon div:after,
|
|
||||||
.sidebarFilterIcon div:after,
|
|
||||||
.notificationsIcon div:after,
|
|
||||||
.sidebarAccountIcon .tooltipsUnder:after {
|
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 40%;
|
right: 40%;
|
||||||
|
@ -590,15 +605,9 @@
|
||||||
border-left: 5px solid transparent;
|
border-left: 5px solid transparent;
|
||||||
border-right: 5px solid transparent;
|
border-right: 5px solid transparent;
|
||||||
}
|
}
|
||||||
.notificationsIcon .unread-notifications-dot:after {
|
|
||||||
content: none;
|
|
||||||
}
|
|
||||||
.sidebarFilterIcon div:after {
|
.sidebarFilterIcon div:after {
|
||||||
right: 37% !important;
|
right: 37% !important;
|
||||||
}
|
}
|
||||||
.notificationsIcon div:after {
|
|
||||||
right: 46% !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapInfoIcon div:after, .openCheatsheet div:after, .starMap div:after, .openMetacodeSwitcher div:after, .pinCarousel div:after {
|
.mapInfoIcon div:after, .openCheatsheet div:after, .starMap div:after, .openMetacodeSwitcher div:after, .pinCarousel div:after {
|
||||||
content: '';
|
content: '';
|
||||||
|
@ -614,7 +623,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.zoomIn {
|
.zoomIn {
|
||||||
background-image: url(<%= asset_path('zoom_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('zoom_sprite.png') %>);
|
||||||
background-position: 0 /…0;
|
background-position: 0 /…0;
|
||||||
border-top-left-radius: 2px;
|
border-top-left-radius: 2px;
|
||||||
border-top-right-radius: 2px;
|
border-top-right-radius: 2px;
|
||||||
|
@ -623,7 +632,7 @@
|
||||||
background-position: -32px 0;
|
background-position: -32px 0;
|
||||||
}
|
}
|
||||||
.zoomOut {
|
.zoomOut {
|
||||||
background-image: url(<%= asset_path('zoom_sprite.png') %>);
|
background-image: url(<%= asset_data_uri('zoom_sprite.png') %>);
|
||||||
background-position:0 -32px;
|
background-position:0 -32px;
|
||||||
border-bottom-left-radius: 2px;
|
border-bottom-left-radius: 2px;
|
||||||
border-bottom-right-radius: 2px;
|
border-bottom-right-radius: 2px;
|
||||||
|
@ -636,22 +645,20 @@
|
||||||
|
|
||||||
/* explore maps */
|
/* explore maps */
|
||||||
|
|
||||||
#react-app {
|
#explore {
|
||||||
position: absolute;
|
display: none;
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMaps {
|
#exploreMaps {
|
||||||
|
padding: 0 5%;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
width: 90%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMaps > div {
|
#exploreMaps > div {
|
||||||
margin: 110px auto 0 auto;
|
margin-top: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.loadMore {
|
.button.loadMore {
|
||||||
|
@ -659,28 +666,23 @@
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.requestInviteHeader {
|
.appsPage #exploreMapsHeader {
|
||||||
position: absolute;
|
display: block;
|
||||||
width: 100%;
|
|
||||||
z-index:2;
|
|
||||||
background-color:#FAFAFA;
|
|
||||||
height: 52px;
|
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#navBar {
|
#exploreMapsHeader {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarContainer {
|
.exploreMapsBar {
|
||||||
z-index:2;
|
z-index:2;
|
||||||
background-color:#FAFAFA;
|
background-color:#FAFAFA;
|
||||||
height: 42px;
|
height: 42px;
|
||||||
padding-top: 52px;
|
padding-top: 52px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarMenu {
|
.exploreMapsMenu {
|
||||||
display: block;
|
display: block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height:42px;
|
height:42px;
|
||||||
|
@ -689,29 +691,30 @@
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarCenter {
|
.exploreMapsCenter {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarButton {
|
.exploreMapsButton {
|
||||||
color: #757575;
|
color: #757575;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-family: 'din-medium';
|
font-family: 'din-medium';
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
padding: 0 8px;
|
height: 14px;
|
||||||
border-bottom: 2px solid rgba(0,0,0,0);
|
padding: 14px 8px 12px 40px;
|
||||||
|
border-bottom: 2px solid rgba(0,0,0,0);
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
position:relative;
|
position:relative;
|
||||||
}
|
}
|
||||||
.navBarButton:hover, .navBarButton.active {
|
.exploreMapsButton:hover, .exploreMapsButton.active {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: #424242;
|
color: #424242;
|
||||||
border-bottom: 2px solid #00BCD4;
|
border-bottom: 2px solid #00BCD4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.navBarButton.mapperButton {
|
.exploreMapsButton.mapperButton {
|
||||||
height: 40px;
|
height: 40px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
@ -728,71 +731,49 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.navBarButton .navBarIcon {
|
.exploreMapsButton .exploreMapsIcon {
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
width:32px;
|
width:32px;
|
||||||
height:32px;
|
height:32px;
|
||||||
margin-top:5px;
|
position:absolute;
|
||||||
margin-left:5px;
|
top:5px;
|
||||||
margin-right: 5px;
|
left:5px;
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
}
|
}
|
||||||
|
.exploreMapsCenter .myMaps .exploreMapsIcon {
|
||||||
.navBarLinkText {
|
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
|
||||||
padding: 11px 0 12px 0;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.navBarCenter .authedApps .navBarIcon {
|
|
||||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
|
||||||
.navBarCenter .myMaps .navBarIcon {
|
|
||||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
|
||||||
background-position: -32px 0;
|
background-position: -32px 0;
|
||||||
}
|
}
|
||||||
.navBarCenter .sharedMaps .navBarIcon {
|
.exploreMapsCenter .sharedMaps .exploreMapsIcon {
|
||||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
|
||||||
background-position: -128px 0;
|
background-position: -128px 0;
|
||||||
}
|
}
|
||||||
.navBarCenter .activeMaps .navBarIcon {
|
.exploreMapsCenter .activeMaps .exploreMapsIcon {
|
||||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
|
||||||
background-position: 0 0;
|
background-position: 0 0;
|
||||||
}
|
}
|
||||||
.navBarCenter .featuredMaps .navBarIcon {
|
.exploreMapsCenter .featuredMaps .exploreMapsIcon {
|
||||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
|
||||||
background-position: -96px 0;
|
background-position: -96px 0;
|
||||||
}
|
}
|
||||||
.navBarCenter .starredMaps .navBarIcon {
|
.exploreMapsCenter .starredMaps .exploreMapsIcon {
|
||||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
|
||||||
background-position: -96px 0;
|
background-position: -96px 0;
|
||||||
}
|
}
|
||||||
.navBarCenter .notificationsLink .navBarIcon {
|
.myMaps:hover .exploreMapsIcon, .myMaps.active .exploreMapsIcon {
|
||||||
background-image: url(<%= asset_path 'topright_sprite.png' %>);
|
|
||||||
background-position: -128px 0;
|
|
||||||
}
|
|
||||||
.authedApps:hover .navBarIcon, .authedApps.active .navBarIcon {
|
|
||||||
background-position-x: -32px;
|
|
||||||
}
|
|
||||||
.myMaps:hover .navBarIcon, .myMaps.active .navBarIcon {
|
|
||||||
background-position: -32px -32px;
|
background-position: -32px -32px;
|
||||||
}
|
}
|
||||||
.activeMaps:hover .navBarIcon, .activeMaps.active .navBarIcon {
|
.activeMaps:hover .exploreMapsIcon, .activeMaps.active .exploreMapsIcon {
|
||||||
background-position: 0 -32px;
|
background-position: 0 -32px;
|
||||||
}
|
}
|
||||||
.featuredMaps:hover .navBarIcon, .featuredMaps.active .navBarIcon {
|
.featuredMaps:hover .exploreMapsIcon, .featuredMaps.active .exploreMapsIcon {
|
||||||
background-position: -96px -32px;
|
background-position: -96px -32px;
|
||||||
}
|
}
|
||||||
.starredMaps:hover .navBarIcon, .starredMaps.active .navBarIcon {
|
.starredMaps:hover .exploreMapsIcon, .starredMaps.active .exploreMapsIcon {
|
||||||
background-position: -96px -32px;
|
background-position: -96px -32px;
|
||||||
}
|
}
|
||||||
.sharedMaps:hover .navBarIcon, .sharedMaps.active .navBarIcon {
|
.sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
|
||||||
background-position: -128px -32px;
|
background-position: -128px -32px;
|
||||||
}
|
}
|
||||||
.notificationsLink:hover .navBarIcon, .notificationsLink.active .navBarIcon {
|
|
||||||
background-position-y: -32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapsWrapper {
|
.mapsWrapper {
|
||||||
/*overflow-y: auto; */
|
/*overflow-y: auto; */
|
||||||
|
@ -808,6 +789,7 @@
|
||||||
height: 80px;
|
height: 80px;
|
||||||
font-family: 'din-regular', helvetica, sans-serif;
|
font-family: 'din-regular', helvetica, sans-serif;
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
|
display: none;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color: #999999;
|
color: #999999;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
|
@ -823,6 +805,7 @@
|
||||||
/* toast */
|
/* toast */
|
||||||
|
|
||||||
.toast {
|
.toast {
|
||||||
|
display: none;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
bottom: 20px;
|
bottom: 20px;
|
||||||
left: 20px;
|
left: 20px;
|
||||||
|
|
|
@ -1,263 +0,0 @@
|
||||||
.emoji-mart,
|
|
||||||
.emoji-mart * {
|
|
||||||
box-sizing: border-box;
|
|
||||||
line-height: 1.15;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart {
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
display: inline-block;
|
|
||||||
color: #222427;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
border-radius: 5px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart .emoji-mart-emoji {
|
|
||||||
padding: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-bar:first-child {
|
|
||||||
border-top-left-radius: 5px;
|
|
||||||
border-top-right-radius: 5px;
|
|
||||||
}
|
|
||||||
.emoji-mart-bar:last-child {
|
|
||||||
border-bottom-left-radius: 5px;
|
|
||||||
border-bottom-right-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchors {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0 6px;
|
|
||||||
color: #858585;
|
|
||||||
line-height: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchor {
|
|
||||||
position: relative;
|
|
||||||
flex: 1;
|
|
||||||
text-align: center;
|
|
||||||
padding: 12px 4px;
|
|
||||||
overflow: hidden;
|
|
||||||
transition: color .1s ease-out;
|
|
||||||
}
|
|
||||||
.emoji-mart-anchor:hover,
|
|
||||||
.emoji-mart-anchor-selected {
|
|
||||||
color: #464646;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchor-selected .emoji-mart-anchor-bar {
|
|
||||||
bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchor-bar {
|
|
||||||
position: absolute;
|
|
||||||
bottom: -3px; left: 0;
|
|
||||||
width: 100%; height: 3px;
|
|
||||||
background-color: #464646;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchors i {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 22px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-anchors svg {
|
|
||||||
fill: currentColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-scroll {
|
|
||||||
overflow-y: scroll;
|
|
||||||
height: 270px;
|
|
||||||
padding: 0 6px 6px 6px;
|
|
||||||
border: solid #d9d9d9;
|
|
||||||
border-width: 1px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-search {
|
|
||||||
font-size: 16px;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
padding: .2em .6em;
|
|
||||||
margin-top: 6px;
|
|
||||||
border-radius: 25px;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-category .emoji-mart-emoji span {
|
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-category .emoji-mart-emoji:hover:before {
|
|
||||||
z-index: 0;
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 0; left: 0;
|
|
||||||
width: 100%; height: 100%;
|
|
||||||
background-color: #f4f4f4;
|
|
||||||
border-radius: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-category-label {
|
|
||||||
z-index: 2;
|
|
||||||
position: relative;
|
|
||||||
position: -webkit-sticky;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-category-label span {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
font-weight: 500;
|
|
||||||
padding: 5px 6px;
|
|
||||||
background-color: #fff;
|
|
||||||
background-color: rgba(255, 255, 255, .95);
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-emoji {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
font-size: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-no-results {
|
|
||||||
font-size: 14px;
|
|
||||||
text-align: center;
|
|
||||||
padding-top: 70px;
|
|
||||||
color: #858585;
|
|
||||||
}
|
|
||||||
.emoji-mart-no-results span {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview {
|
|
||||||
position: relative;
|
|
||||||
height: 70px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-emoji,
|
|
||||||
.emoji-mart-preview-data,
|
|
||||||
.emoji-mart-preview-skins {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-emoji {
|
|
||||||
left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-data {
|
|
||||||
left: 68px; right: 12px;
|
|
||||||
word-break: break-word;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-skins {
|
|
||||||
right: 30px;
|
|
||||||
text-align: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-name {
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-shortname {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #888;
|
|
||||||
}
|
|
||||||
.emoji-mart-preview-shortname + .emoji-mart-preview-shortname,
|
|
||||||
.emoji-mart-preview-shortname + .emoji-mart-preview-emoticon,
|
|
||||||
.emoji-mart-preview-emoticon + .emoji-mart-preview-emoticon {
|
|
||||||
margin-left: .5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-preview-emoticon {
|
|
||||||
font-size: 11px;
|
|
||||||
color: #bbb;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-title span {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-title .emoji-mart-emoji {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-title-label {
|
|
||||||
color: #999A9C;
|
|
||||||
font-size: 26px;
|
|
||||||
font-weight: 300;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatches {
|
|
||||||
font-size: 0;
|
|
||||||
padding: 2px 0;
|
|
||||||
border: 1px solid #d9d9d9;
|
|
||||||
border-radius: 12px;
|
|
||||||
background-color: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch {
|
|
||||||
width: 16px;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatches-opened .emoji-mart-skin-swatch-selected:after {
|
|
||||||
opacity: .75;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatch {
|
|
||||||
display: inline-block;
|
|
||||||
width: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
transition-property: width, padding;
|
|
||||||
transition-duration: .125s;
|
|
||||||
transition-timing-function: ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatch:nth-child(1) { transition-delay: 0 }
|
|
||||||
.emoji-mart-skin-swatch:nth-child(2) { transition-delay: .03s }
|
|
||||||
.emoji-mart-skin-swatch:nth-child(3) { transition-delay: .06s }
|
|
||||||
.emoji-mart-skin-swatch:nth-child(4) { transition-delay: .09s }
|
|
||||||
.emoji-mart-skin-swatch:nth-child(5) { transition-delay: .12s }
|
|
||||||
.emoji-mart-skin-swatch:nth-child(6) { transition-delay: .15s }
|
|
||||||
|
|
||||||
.emoji-mart-skin-swatch-selected {
|
|
||||||
position: relative;
|
|
||||||
width: 16px;
|
|
||||||
padding: 0 2px;
|
|
||||||
}
|
|
||||||
.emoji-mart-skin-swatch-selected:after {
|
|
||||||
content: "";
|
|
||||||
position: absolute;
|
|
||||||
top: 50%; left: 50%;
|
|
||||||
width: 4px; height: 4px;
|
|
||||||
margin: -2px 0 0 -2px;
|
|
||||||
background-color: #fff;
|
|
||||||
border-radius: 100%;
|
|
||||||
pointer-events: none;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity .2s ease-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%; padding-top: 100%;
|
|
||||||
max-width: 12px;
|
|
||||||
border-radius: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emoji-mart-skin-tone-1 { background-color: #ffc93a }
|
|
||||||
.emoji-mart-skin-tone-2 { background-color: #fadcbc }
|
|
||||||
.emoji-mart-skin-tone-3 { background-color: #e0bb95 }
|
|
||||||
.emoji-mart-skin-tone-4 { background-color: #bf8f68 }
|
|
||||||
.emoji-mart-skin-tone-5 { background-color: #9b643d }
|
|
||||||
.emoji-mart-skin-tone-6 { background-color: #594539 }
|
|
347
app/assets/stylesheets/junto.css.erb
Normal file
|
@ -0,0 +1,347 @@
|
||||||
|
.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: -8px 0px 16px 2px rgba(0, 0, 0, 0.23);
|
||||||
|
}
|
||||||
|
.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: 276px;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
.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: 10px;
|
||||||
|
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: 276px;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
.chat-box .chat-header .sound-toggle {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
margin-right: 10px;
|
||||||
|
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;
|
||||||
|
}
|
|
@ -1,375 +0,0 @@
|
||||||
.collaborator-video {
|
|
||||||
z-index: 1;
|
|
||||||
position: absolute;
|
|
||||||
width: 150px;
|
|
||||||
height: 150px;
|
|
||||||
cursor: default;
|
|
||||||
color: #FFF;
|
|
||||||
|
|
||||||
.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;
|
|
||||||
|
|
||||||
.video-statement {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.btn-group {
|
|
||||||
.btn-yes {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.btn-no {
|
|
||||||
background-color: #c04f4f;
|
|
||||||
&:hover {
|
|
||||||
background-color: #A54242;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.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);
|
|
||||||
|
|
||||||
video {
|
|
||||||
height: 150px;
|
|
||||||
margin-left: -25px;
|
|
||||||
}
|
|
||||||
.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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.video-audio {
|
|
||||||
position: absolute;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
top: 85%;
|
|
||||||
right: 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
background: url(<%= asset_path 'audio_sprite.png' %>) no-repeat;
|
|
||||||
}
|
|
||||||
.video-audio:hover {
|
|
||||||
background-position-x: -24px;
|
|
||||||
}
|
|
||||||
.video-audio.active {
|
|
||||||
background-position-y: -24px;
|
|
||||||
}
|
|
||||||
.video-video {
|
|
||||||
position: absolute;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
top: 85%;
|
|
||||||
left: 0px;
|
|
||||||
cursor: pointer;
|
|
||||||
background: url(<%= asset_path 'camera_sprite.png' %>) no-repeat;
|
|
||||||
}
|
|
||||||
.video-video:hover {
|
|
||||||
background-position-x: -24px;
|
|
||||||
}
|
|
||||||
.video-video.active {
|
|
||||||
background-position-y: -24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.collaborator-video.my-video {
|
|
||||||
left: 30px;
|
|
||||||
top: 72px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-box {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
z-index: 1;
|
|
||||||
height: 100%;
|
|
||||||
background: #424242;
|
|
||||||
box-shadow: -8px 0px 16px 2px rgba(0, 0, 0, 0.23);
|
|
||||||
|
|
||||||
.chat-panel {
|
|
||||||
width: 300px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.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;
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
background: url(<%= asset_path 'junto_spinner_dark.gif' %>) no-repeat 2px 8px, url(<%= asset_path 'tray_tab.png' %>) no-repeat !important;
|
|
||||||
}
|
|
||||||
.chat-unread {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.junto-header {
|
|
||||||
width: 276px;
|
|
||||||
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);
|
|
||||||
|
|
||||||
.cursor-toggle {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin-right: 8px;
|
|
||||||
margin-top: -8px;
|
|
||||||
float: right;
|
|
||||||
background: url(<%= asset_path 'cursor_sprite.png' %>) no-repeat;
|
|
||||||
}
|
|
||||||
.cursor-toggle:hover {
|
|
||||||
background-position-x: -32px;
|
|
||||||
}
|
|
||||||
.cursor-toggle.active {
|
|
||||||
background-position-y: -32px;
|
|
||||||
}
|
|
||||||
.video-toggle {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: -8px;
|
|
||||||
float: right;
|
|
||||||
background: url(<%= asset_path 'video_sprite.png' %>) no-repeat;
|
|
||||||
}
|
|
||||||
.video-toggle:hover {
|
|
||||||
background-position-x: -32px;
|
|
||||||
}
|
|
||||||
.video-toggle.active {
|
|
||||||
background-position-y: -32px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.participants {
|
|
||||||
width: 100%;
|
|
||||||
min-height: 150px;
|
|
||||||
padding: 16px 0px 16px 0px;
|
|
||||||
text-align: left;
|
|
||||||
color: #f5f5f5;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
.conversation-live {
|
|
||||||
padding: 5px 10px 5px 10px;
|
|
||||||
background: #c04f4f;
|
|
||||||
margin: 5px 10px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
.conversation-live .call-action {
|
|
||||||
float: right;
|
|
||||||
cursor: pointer;
|
|
||||||
color: #EBFF00;
|
|
||||||
}
|
|
||||||
.participant {
|
|
||||||
width: 89%;
|
|
||||||
padding: 8px 8px 2px 8px;
|
|
||||||
color: #f5f5f5;
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 14px;
|
|
||||||
|
|
||||||
.chat-participant-image {
|
|
||||||
width: 15%;
|
|
||||||
float: left;
|
|
||||||
overflow: hidden;
|
|
||||||
color: #BBB;
|
|
||||||
padding-top: 2px;
|
|
||||||
}
|
|
||||||
.chat-participant-image img {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 18px;
|
|
||||||
}
|
|
||||||
.chat-participant-name {
|
|
||||||
width: 53%;
|
|
||||||
float: left;
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: bold;
|
|
||||||
margin-top: 12px;
|
|
||||||
padding: 2px 8px 0;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
.chat-participant-invite-call,
|
|
||||||
.chat-participant-invite-join
|
|
||||||
{
|
|
||||||
float: right;
|
|
||||||
background: #4FC059 url(<%= asset_path 'invitepeer16.png' %>) no-repeat center center;
|
|
||||||
}
|
|
||||||
.chat-participant-invite-call.pending,
|
|
||||||
.chat-participant-invite-join.pending {
|
|
||||||
background: #dab539 url(<%= asset_path 'ellipsis.gif' %>) no-repeat center center;
|
|
||||||
}
|
|
||||||
.chat-participant-participating {
|
|
||||||
float: right;
|
|
||||||
margin-top: 14px;
|
|
||||||
}
|
|
||||||
.chat-participant-participating .green-dot {
|
|
||||||
background: #4fc059;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-header {
|
|
||||||
width: 276px;
|
|
||||||
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);
|
|
||||||
|
|
||||||
.sound-toggle {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
margin-right: 10px;
|
|
||||||
margin-top: -2px;
|
|
||||||
float: right;
|
|
||||||
background: url(<%= asset_path 'sound_sprite.png' %>) no-repeat;
|
|
||||||
}
|
|
||||||
.sound-toggle:hover {
|
|
||||||
background-position-x: -24px;
|
|
||||||
}
|
|
||||||
.sound-toggle.active {
|
|
||||||
background-position-y: -24px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$chat_font_size: 16px;
|
|
||||||
|
|
||||||
.chat-input {
|
|
||||||
min-height: 80px;
|
|
||||||
width: 88%;
|
|
||||||
padding: 8px 9% 8px 3%;
|
|
||||||
font-size: $chat_font_size;
|
|
||||||
outline: none;
|
|
||||||
resize: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-messages {
|
|
||||||
width: 100%;
|
|
||||||
padding: 16px 0px;
|
|
||||||
overflow-y: auto;
|
|
||||||
flex-grow: 1;
|
|
||||||
|
|
||||||
.chat-message {
|
|
||||||
width: 89%;
|
|
||||||
padding: 8px 8px 2px 8px;
|
|
||||||
color: #f5f5f5;
|
|
||||||
font-family: arial, sans-serif;
|
|
||||||
font-size: $chat_font_size;
|
|
||||||
line-height: $chat_font_size + 1px;
|
|
||||||
|
|
||||||
a:link {
|
|
||||||
color: #4fb5c0;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
a:visited {
|
|
||||||
color: #aea9fd;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
a:hover {
|
|
||||||
color: #dab539;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
.chat-message-user {
|
|
||||||
width: 12%;
|
|
||||||
float: left;
|
|
||||||
overflow: hidden;
|
|
||||||
color: #BBB;
|
|
||||||
padding-top: 2px;
|
|
||||||
}
|
|
||||||
.chat-message-user img {
|
|
||||||
border: 2px solid #424242;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
.chat-message-meta {
|
|
||||||
padding: 0 8px;
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
.chat-message-username {
|
|
||||||
color: #4fc059;
|
|
||||||
}
|
|
||||||
.chat-message-text {
|
|
||||||
width: 80%;
|
|
||||||
float: left;
|
|
||||||
padding: 2px 8px 0;
|
|
||||||
text-align: left;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
.chat-message-time {
|
|
||||||
font-size: 12px;
|
|
||||||
color: #757575;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-message-area {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.emoji-mart {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 98px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.extra-message-options {
|
|
||||||
height: 20px;
|
|
||||||
position: absolute;
|
|
||||||
right: 2px;
|
|
||||||
bottom: 74px;
|
|
||||||
|
|
||||||
.emoji-picker-button {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 20px;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,288 +0,0 @@
|
||||||
/* Map Cards */
|
|
||||||
|
|
||||||
.map {
|
|
||||||
display:inline-block;
|
|
||||||
width:220px;
|
|
||||||
height:340px;
|
|
||||||
font-size: 12px;
|
|
||||||
text-align: left;
|
|
||||||
overflow: visible;
|
|
||||||
background: #e8e8e8;
|
|
||||||
border-radius:2px;
|
|
||||||
margin:16px;
|
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
|
||||||
|
|
||||||
&.newMap {
|
|
||||||
float: left;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: #dcdcdc;
|
|
||||||
|
|
||||||
.newMapImage {
|
|
||||||
background-position: 0 -72px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
height: 340px;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.newMapImage {
|
|
||||||
display: block;
|
|
||||||
width: 72px;
|
|
||||||
height: 72px;
|
|
||||||
background-image: url("<%= asset_data_uri('newmap_sprite.png') %>");
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
background-position: 0 0;
|
|
||||||
position: absolute;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -36px;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
font-family: 'din-regular', sans-serif;
|
|
||||||
font-size: 18px;
|
|
||||||
line-height: 22px;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
padding-top: 220px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapCard {
|
|
||||||
position:relative;
|
|
||||||
width:100%;
|
|
||||||
height:308px;
|
|
||||||
padding: 0 0 16px 0;
|
|
||||||
color: #424242;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.dropdownMenu .menuToggle .circle {
|
|
||||||
background-color: #FFF;
|
|
||||||
}
|
|
||||||
.dropdownMenu .menuToggle:hover .circle {
|
|
||||||
background-color: #DDD;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainContent {
|
|
||||||
filter: blur(2px);
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapMetadata {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapHasMapper, .mapHasConversation {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: 8px;
|
|
||||||
min-width: 32px;
|
|
||||||
min-height: 32px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #FFF;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
.mapperList {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapperList {
|
|
||||||
display: none;
|
|
||||||
padding: 8px;
|
|
||||||
list-style-type: none;
|
|
||||||
|
|
||||||
li {
|
|
||||||
&.live {
|
|
||||||
height: 32px;
|
|
||||||
padding-left: 32px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 12px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
padding-left: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mapHasMapper {
|
|
||||||
background: url('<%= asset_path('junto.png') %>') no-repeat 4px 0;
|
|
||||||
}
|
|
||||||
.mapHasConversation {
|
|
||||||
background: url('<%= asset_path('junto.gif') %>') no-repeat 4px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dropdownMenu {
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
right: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.menuToggle {
|
|
||||||
width: 30px;
|
|
||||||
height: 10px;
|
|
||||||
|
|
||||||
.circle {
|
|
||||||
display: inline-block;
|
|
||||||
background-color: #454545;
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover .circle {
|
|
||||||
background-color: #222;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.menuItems {
|
|
||||||
position: absolute;
|
|
||||||
top: 18px;
|
|
||||||
right: 0px;
|
|
||||||
background: #FFF;
|
|
||||||
border-radius: 2px;
|
|
||||||
list-style-type: none;
|
|
||||||
color: #454545;
|
|
||||||
|
|
||||||
li {
|
|
||||||
white-space: nowrap;
|
|
||||||
padding: 6px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #DDD;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapScreenshot {
|
|
||||||
width: 100%;
|
|
||||||
height: 220px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mapScreenshot img {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
word-wrap: break-word;
|
|
||||||
font-size:18px;
|
|
||||||
line-height:22px;
|
|
||||||
height: 71px;
|
|
||||||
display:table;
|
|
||||||
padding: 0 16px;
|
|
||||||
font-family: 'din-regular', sans-serif;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
.innerTitle {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.creatorAndPerm {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.creatorImage {
|
|
||||||
display: inline-block;
|
|
||||||
border-radius: 16px;
|
|
||||||
vertical-align: middle;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.creatorName {
|
|
||||||
margin-left: 8px;
|
|
||||||
max-width: 162px;
|
|
||||||
display: inline-block;
|
|
||||||
overflow: hidden;
|
|
||||||
white-space: nowrap;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.creatorAndPerm.cardHasViewOnly span.creatorName {
|
|
||||||
max-width: 95px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cardViewOnly {
|
|
||||||
float: right;
|
|
||||||
line-height: 32px;
|
|
||||||
padding-right: 10px;
|
|
||||||
color: #454545;
|
|
||||||
}
|
|
||||||
|
|
||||||
.scroll {
|
|
||||||
display:block;
|
|
||||||
font-family: helvetica, sans-serif;
|
|
||||||
font-size: 12px;
|
|
||||||
word-wrap: break-word;
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.mapMetadata {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
padding: 40px 20px 0;
|
|
||||||
height: 300px;
|
|
||||||
font-family: 'din-regular', sans-serif;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #FFF;
|
|
||||||
background: -moz-linear-gradient(top, rgba(0,0,0,0.65) 0%, rgba(0,0,0,0.43) 81%, rgba(0,0,0,0) 100%);
|
|
||||||
background: -webkit-linear-gradient(top, rgba(0,0,0,0.65) 0%,rgba(0,0,0,0.43) 81%,rgba(0,0,0,0) 100%);
|
|
||||||
background: linear-gradient(to bottom, rgba(0,0,0,0.65) 0%,rgba(0,0,0,0.43) 81%,rgba(0,0,0,0) 100%);
|
|
||||||
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a6000000', endColorstr='#00000000',GradientType=0 );
|
|
||||||
}
|
|
||||||
|
|
||||||
.metadataSection {
|
|
||||||
padding: 16px 0;
|
|
||||||
width: 90px;
|
|
||||||
float: left;
|
|
||||||
font-family: 'din-medium', sans-serif;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
div {
|
|
||||||
background: url('<%= asset_path('metadata.png') %>') no-repeat;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.numTopicsIcon {
|
|
||||||
background-position: 0 -32px;
|
|
||||||
}
|
|
||||||
.numStarsIcon {
|
|
||||||
background-position: 0 0;
|
|
||||||
}
|
|
||||||
.numSynapsesIcon {
|
|
||||||
background-position: -32px -32px;
|
|
||||||
}
|
|
||||||
.numContributorsIcon {
|
|
||||||
background-position: -32px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,52 +1,17 @@
|
||||||
@media only screen and (max-width : 752px) and (min-width : 504px) {
|
#mobile_header {
|
||||||
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
display: none;
|
||||||
width: 160px !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* when this switches to two lines */
|
/* Smartphones (portrait and landscape) ----------- */
|
||||||
@media only screen and (max-width : 728px) {
|
@media only screen and (max-device-width : 480px) {
|
||||||
.controller-notifications .notificationsPage .notification .notification-read-unread a {
|
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .uv-icon, .chat-box, #exploreMapsHeader {
|
||||||
margin-top: -20px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width : 390px) {
|
|
||||||
.map .mapCard .mobileMetadata {
|
|
||||||
width: 190px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@media only screen and (min-width : 390px) {
|
|
||||||
.map .mapCard .mobileMetadata {
|
|
||||||
width: 390px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* 800 is the max-width for centerContent */
|
|
||||||
@media only screen and (max-width : 800px) {
|
|
||||||
.centerContent.withPadding {
|
|
||||||
margin-top: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Smartphones (portrait and landscape) ----------- the minimum space that two map cards can fit side by side */
|
|
||||||
@media only screen and (max-width : 504px) {
|
|
||||||
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .feedback-icon, .chat-box, #navBar {
|
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.notificationsPage .page-header {
|
#mobile_header {
|
||||||
display: none;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.controller-notifications .notificationsPage .notification .notification-read-unread {
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
.controller-notifications .notificationsPage .notification .notification-date {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.homeWrapper {
|
.homeWrapper {
|
||||||
width: 96%;
|
width: 96%;
|
||||||
padding: 0 2%;
|
padding: 0 2%;
|
||||||
|
@ -64,7 +29,7 @@
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.homeVideo {
|
.homeVideo {
|
||||||
width: 100% !important;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
.fullWidthWrapper.withPartners {
|
.fullWidthWrapper.withPartners {
|
||||||
|
@ -73,25 +38,25 @@
|
||||||
.learnMoreCTA {
|
.learnMoreCTA {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#yield {
|
#yield {
|
||||||
padding-top: 50px;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: auto;
|
top: auto;
|
||||||
left: auto;
|
left: auto;
|
||||||
width: 78%;
|
width: 78%;
|
||||||
padding: 16px 10%;
|
padding: 16px 10%;
|
||||||
margin: 0 auto;
|
margin: 50px auto 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.wrapper .mapInfoBox {
|
.wrapper div.mapInfoBox {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
|
@ -99,29 +64,16 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 360px;
|
max-width: 360px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.requestInviteHeader {
|
#wrapper .requestInvite {
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.requestInvite {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 50px);
|
padding: 0;
|
||||||
z-index: 1;
|
|
||||||
position: relative;
|
|
||||||
left: 0;
|
|
||||||
margin-left: 0px;
|
|
||||||
margin-top: 50px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#exploreMaps > div {
|
#exploreMaps > div {
|
||||||
margin-top: 70px;
|
margin-top: 70px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mapper {
|
|
||||||
width: 100%;
|
|
||||||
margin: 0 0 30px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.map.newMap {
|
.map.newMap {
|
||||||
a {
|
a {
|
||||||
height: auto;
|
height: auto;
|
||||||
|
@ -142,73 +94,35 @@
|
||||||
span {
|
span {
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.map.newMap:hover .newMapImage {
|
.map.newMap:hover .newMapImage {
|
||||||
background-position: 0 -40px;
|
background-position: 0 -40px;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Smartphones (portrait) ----------- */
|
||||||
|
@media only screen and (max-width : 400px) {
|
||||||
|
|
||||||
.map {
|
.map {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0 0 30px 0;
|
margin: 0 0 30px 0;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
|
||||||
.mapCard {
|
|
||||||
height: auto;
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
.mainContent {
|
|
||||||
filter: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mobileHasMapper, .mobileHasConversation {
|
|
||||||
.mapperList {
|
|
||||||
padding: 8px 16px;
|
|
||||||
list-style-type: none;
|
|
||||||
|
|
||||||
li {
|
|
||||||
&.live {
|
|
||||||
height: 32px;
|
|
||||||
padding-left: 32px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
border-radius: 12px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
padding-left: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.mobileHasMapper {
|
|
||||||
background: url('<%= asset_path('junto.png') %>') no-repeat 12px 0;
|
|
||||||
}
|
|
||||||
.mobileHasConversation {
|
|
||||||
background: url('<%= asset_path('junto.gif') %>') no-repeat 12px 0;
|
|
||||||
}
|
|
||||||
.mobileMetadata {
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
text-align: left;
|
|
||||||
display: block;
|
|
||||||
height: auto;
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
.desc {
|
|
||||||
padding: 0 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mapCard {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .title {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mapCard .mapScreenshot {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_header {
|
#mobile_header {
|
||||||
|
@ -217,7 +131,6 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||||
position: fixed;
|
position: fixed;
|
||||||
z-index: 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#menu_icon {
|
#menu_icon {
|
||||||
|
@ -240,16 +153,8 @@
|
||||||
line-height: 50px;
|
line-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mobile_header #menu_icon .unread-notifications-dot {
|
|
||||||
top: 5px;
|
|
||||||
left: 29px;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
border: 3px solid #eee;
|
|
||||||
border-radius: 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#mobile_menu {
|
#mobile_menu {
|
||||||
|
display: none;
|
||||||
background: #EEE;
|
background: #EEE;
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 50px;
|
top: 50px;
|
||||||
|
@ -257,30 +162,11 @@
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
width: 200px;
|
width: 200px;
|
||||||
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
||||||
z-index: 2;
|
}
|
||||||
|
|
||||||
li {
|
#mobile_menu li {
|
||||||
padding: 7px 10px;
|
padding: 10px;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
font-family: 'din-regular', arial, sans-serif;
|
|
||||||
|
|
||||||
.sprite {
|
|
||||||
margin-right: 6px;
|
|
||||||
margin-top: -2px;
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.notifications {
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.unread-notifications-dot {
|
|
||||||
top: 50%;
|
|
||||||
left: 0px;
|
|
||||||
margin-top: -4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
li.mobileMenuUser {
|
li.mobileMenuUser {
|
||||||
|
|
|
@ -1,237 +0,0 @@
|
||||||
$notifications-border-color: #DDDDDD;
|
|
||||||
$notifications-hover-color: #F6F6F6;
|
|
||||||
$unread_notifications_dot_size: 8px;
|
|
||||||
|
|
||||||
.unread-notifications-dot {
|
|
||||||
width: $unread_notifications_dot_size;
|
|
||||||
height: $unread_notifications_dot_size;
|
|
||||||
background-color: #e22;
|
|
||||||
border-radius: $unread_notifications_dot_size / 2;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upperRightUI {
|
|
||||||
.notificationsIcon {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notificationsBox {
|
|
||||||
position: absolute;
|
|
||||||
background: #FFFFFF;
|
|
||||||
border-radius: 2px;
|
|
||||||
width: 350px;
|
|
||||||
right: 0;
|
|
||||||
top: 50px;
|
|
||||||
box-shadow: 0 3px 6px rgba(0,0,0,0.16);
|
|
||||||
border: 1px solid $notifications-border-color;
|
|
||||||
|
|
||||||
.notificationsBoxTriangle {
|
|
||||||
min-width: 0 !important;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: 48px;
|
|
||||||
width: 20px !important;
|
|
||||||
height: 20px !important;
|
|
||||||
margin-left: -10px;
|
|
||||||
top: -11px;
|
|
||||||
border-left: 1px solid $notifications-border-color;
|
|
||||||
border-top: 1px solid $notifications-border-color;
|
|
||||||
border-bottom: 0 !important;
|
|
||||||
border-right: 0 !important;
|
|
||||||
background-color: #fff;
|
|
||||||
transform: rotate(45deg);
|
|
||||||
-webkit-transform: rotate(45deg);
|
|
||||||
-ms-transform: rotate(45deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.notifications {
|
|
||||||
max-height: 500px;
|
|
||||||
overflow-y: auto;
|
|
||||||
|
|
||||||
.notification {
|
|
||||||
font-size: 13px;
|
|
||||||
|
|
||||||
.notification-body {
|
|
||||||
border-bottom: 1px solid $notifications-border-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notificationsEmpty {
|
|
||||||
font-family: din-regular, helvetica, sans-serif;
|
|
||||||
margin: 50px 10px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notificationsBoxSeeAll {
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
text-align: center;
|
|
||||||
padding: 6px 0;
|
|
||||||
font-family: din-regular, helvetica, sans-serif;
|
|
||||||
border-top: 1px solid rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #333;
|
|
||||||
background: $notifications-hover-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.controller-notifications {
|
|
||||||
.notificationPage,
|
|
||||||
.notificationsPage {
|
|
||||||
font-family: 'din-regular', Sans-Serif;
|
|
||||||
|
|
||||||
& a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > .notification-title {
|
|
||||||
border-bottom: 1px solid #eee;
|
|
||||||
padding-bottom: 0.25em;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.back {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notificationsPage {
|
|
||||||
header {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.emptyInbox {
|
|
||||||
padding-top: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.notificationPage {
|
|
||||||
.thirty-two-avatar {
|
|
||||||
display: inline-block;
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 16px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button {
|
|
||||||
line-height: 32px;
|
|
||||||
|
|
||||||
img {
|
|
||||||
margin-top: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.decline {
|
|
||||||
background: #DB5D5D;
|
|
||||||
&:hover {
|
|
||||||
background: #DC4B4B;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-body {
|
|
||||||
p, div {
|
|
||||||
margin: 1em auto;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.notifications {
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
li:nth-last-child(2) {
|
|
||||||
.notification-body {
|
|
||||||
border-bottom: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification {
|
|
||||||
padding: 10px 10px 0 10px;
|
|
||||||
position: relative;
|
|
||||||
font-family: 'din-regular', Sans-Serif;
|
|
||||||
|
|
||||||
&.unread {
|
|
||||||
background: #EEE;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $notifications-hover-color;
|
|
||||||
|
|
||||||
.notification-read-unread {
|
|
||||||
display:block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-date {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& > a {
|
|
||||||
float: left;
|
|
||||||
width: 85%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-actor {
|
|
||||||
float: left;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-body {
|
|
||||||
margin-left: 50px;
|
|
||||||
line-height: 20px;
|
|
||||||
padding-bottom: 10px;
|
|
||||||
|
|
||||||
.in-bold {
|
|
||||||
font-family: 'din-medium', Sans-Serif;
|
|
||||||
}
|
|
||||||
|
|
||||||
.action {
|
|
||||||
background: #4fb5c0;
|
|
||||||
color: #FFF;
|
|
||||||
padding: 2px 6px;
|
|
||||||
border-radius: 3px;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 5px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-date {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
right: 10px;
|
|
||||||
color: #607d8b;
|
|
||||||
margin-top: -6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-read-unread {
|
|
||||||
display: none;
|
|
||||||
float: left;
|
|
||||||
width: 15%;
|
|
||||||
|
|
||||||
a, div {
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
margin-top: -10px;
|
|
||||||
text-align: center;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,87 +0,0 @@
|
||||||
.viewOnly {
|
|
||||||
float: left;
|
|
||||||
margin-left: 16px;
|
|
||||||
height: 32px;
|
|
||||||
border: 1px solid #BDBDBD;
|
|
||||||
border-radius: 2px;
|
|
||||||
background-color: #424242;
|
|
||||||
color: #FFF;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 32px;
|
|
||||||
|
|
||||||
&.isViewOnly {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.eyeball {
|
|
||||||
background: url('<%= asset_path('view-only.png') %>') no-repeat 4px 0;
|
|
||||||
padding-left: 40px;
|
|
||||||
border-right: #747474;
|
|
||||||
padding-right: 10px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requestNotice {
|
|
||||||
display: inline-block;
|
|
||||||
padding: 0 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requestAccess {
|
|
||||||
background-color: #a354cd;
|
|
||||||
&:hover {
|
|
||||||
background-color: #9150bc;
|
|
||||||
}
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requestPending {
|
|
||||||
background-color: #4fc059;
|
|
||||||
}
|
|
||||||
|
|
||||||
.requestNotAccepted {
|
|
||||||
background-color: #c04f4f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.request_access {
|
|
||||||
position: absolute;
|
|
||||||
width: 90%;
|
|
||||||
margin: 0 5%;
|
|
||||||
|
|
||||||
.monkey {
|
|
||||||
width: 250px;
|
|
||||||
height: 250px;
|
|
||||||
border: 6px solid #424242;
|
|
||||||
border-radius: 125px;
|
|
||||||
background: url(https://s3.amazonaws.com/metamaps-assets/site/monkeyselfie.jpg) no-repeat;
|
|
||||||
background-position: 50% 20%;
|
|
||||||
background-size: 100%;
|
|
||||||
margin: 80px auto 20px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.explainer_text {
|
|
||||||
padding: 0 20% 0 20%;
|
|
||||||
font-size: 24px;
|
|
||||||
line-height: 30px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.make_request {
|
|
||||||
background-color: #a354cd;
|
|
||||||
display: block;
|
|
||||||
width: 220px;
|
|
||||||
height: 14px;
|
|
||||||
padding: 16px 0;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
text-align: center;
|
|
||||||
border-radius: 2px;
|
|
||||||
font-size: 14px;
|
|
||||||
box-shadow: 0px 1px 1.5px rgba(0,0,0,0.12), 0 1px 1px rgba(0,0,0,0.24);
|
|
||||||
margin: 0 auto 20px auto;
|
|
||||||
text-decoration: none;
|
|
||||||
color: #FFFFFF !important;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -93,7 +93,7 @@
|
||||||
|
|
||||||
.sidebarSearchField {
|
.sidebarSearchField {
|
||||||
float: left;
|
float: left;
|
||||||
width: 379px;
|
width: 380px;
|
||||||
padding: 7px 10px 3px 10px;
|
padding: 7px 10px 3px 10px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
border-top: 1px solid #BDBDBD;
|
border-top: 1px solid #BDBDBD;
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
.unauthenticated .feedback-icon {
|
/* =USERVOICE ICON DEFINE
|
||||||
|
--------------------------------------------------------*/
|
||||||
|
|
||||||
|
.unauthenticated .uv-icon {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback-icon {
|
div.uv-icon.uv-bottom-left {
|
||||||
position: fixed;
|
|
||||||
background-image: url(<%= asset_data_uri 'feedback_sprite.png' %>);
|
background-image: url(<%= asset_data_uri 'feedback_sprite.png' %>);
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
color:#FFFFFF;
|
color:#FFFFFF;
|
||||||
|
@ -18,8 +20,6 @@
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feedback-icon:hover {
|
div.uv-icon.uv-bottom-left:hover {
|
||||||
background-position: 0 -110px;
|
background-position: 0 -110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module ApplicationCable
|
|
||||||
class Channel < ActionCable::Channel::Base
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,23 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module ApplicationCable
|
|
||||||
class Connection < ActionCable::Connection::Base
|
|
||||||
identified_by :current_user
|
|
||||||
|
|
||||||
def connect
|
|
||||||
self.current_user = find_verified_user
|
|
||||||
logger.add_tags 'ActionCable', current_user.name
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def find_verified_user
|
|
||||||
verified_user = User.find_by(id: cookies.signed['user.id'])
|
|
||||||
if verified_user && cookies.signed['user.expires_at'] > Time.now.getlocal
|
|
||||||
verified_user
|
|
||||||
else
|
|
||||||
reject_unauthorized_connection
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,18 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class MapChannel < ApplicationCable::Channel
|
|
||||||
# Called when the consumer has successfully
|
|
||||||
# become a subscriber of this channel.
|
|
||||||
def subscribed
|
|
||||||
map = Map.find(params[:id])
|
|
||||||
return unless Pundit.policy(current_user, map).show?
|
|
||||||
stream_from "map_#{params[:id]}"
|
|
||||||
Events::UserPresentOnMap.publish!(map, current_user)
|
|
||||||
end
|
|
||||||
|
|
||||||
def unsubscribed
|
|
||||||
map = Map.find(params[:id])
|
|
||||||
return unless Pundit.policy(current_user, map).show?
|
|
||||||
Events::UserNotPresentOnMap.publish!(map, current_user)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,90 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class AccessController < ApplicationController
|
|
||||||
before_action :require_user, only: %i[access access_request
|
|
||||||
approve_access approve_access_post
|
|
||||||
deny_access deny_access_post request_access]
|
|
||||||
before_action :set_map, only: %i[access access_request
|
|
||||||
approve_access approve_access_post
|
|
||||||
deny_access deny_access_post request_access]
|
|
||||||
after_action :verify_authorized
|
|
||||||
|
|
||||||
# GET maps/:id/request_access
|
|
||||||
def request_access
|
|
||||||
@map = nil
|
|
||||||
respond_to do |format|
|
|
||||||
format.html do
|
|
||||||
render 'maps/request_access'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/access_request
|
|
||||||
def access_request
|
|
||||||
AccessRequest.create(user: current_user, map: @map)
|
|
||||||
respond_to do |format|
|
|
||||||
format.json { head :ok }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/access
|
|
||||||
def access
|
|
||||||
user_ids = params[:access].to_a.map(&:to_i) || []
|
|
||||||
|
|
||||||
@map.add_new_collaborators(user_ids)
|
|
||||||
@map.remove_old_collaborators(user_ids)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json { head :ok }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET maps/:id/approve_access/:request_id
|
|
||||||
def approve_access
|
|
||||||
request = AccessRequest.find(params[:request_id])
|
|
||||||
request.approve # also marks mailboxer notification as read
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { redirect_to map_path(@map), notice: 'Request was approved' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET maps/:id/deny_access/:request_id
|
|
||||||
def deny_access
|
|
||||||
request = AccessRequest.find(params[:request_id])
|
|
||||||
request.deny # also marks mailboxer notification as read
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { redirect_to map_path(@map), notice: 'Request was turned down' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/approve_access/:request_id
|
|
||||||
def approve_access_post
|
|
||||||
request = AccessRequest.find(params[:request_id])
|
|
||||||
request.approve
|
|
||||||
respond_to do |format|
|
|
||||||
format.js
|
|
||||||
format.json do
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/deny_access/:request_id
|
|
||||||
def deny_access_post
|
|
||||||
request = AccessRequest.find(params[:request_id])
|
|
||||||
request.deny
|
|
||||||
respond_to do |format|
|
|
||||||
format.js
|
|
||||||
format.json do
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_map
|
|
||||||
@map = Map.find(params[:id])
|
|
||||||
authorize @map
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,13 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V1
|
module V1
|
||||||
class DeprecatedController < ApplicationController
|
class DeprecatedController < ApplicationController
|
||||||
def deprecated
|
# rubocop:disable Style/MethodMissing
|
||||||
render json: {
|
def method_missing
|
||||||
error: '/api/v1 has been deprecated! Please use /api/v2 instead.'
|
render json: { error: '/api/v1 is deprecated! Please use /api/v2 instead.' }
|
||||||
}, status: :gone
|
|
||||||
end
|
end
|
||||||
|
# rubocop:enable Style/MethodMissing
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
7
app/controllers/api/v1/mappings_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MappingsController < DeprecatedController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/controllers/api/v1/maps_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class MapsController < DeprecatedController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/controllers/api/v1/synapses_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class SynapsesController < DeprecatedController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/controllers/api/v1/tokens_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class TokensController < DeprecatedController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
app/controllers/api/v1/topics_controller.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
module Api
|
||||||
|
module V1
|
||||||
|
class TopicsController < DeprecatedController
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,11 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class MappingsController < WithUpdatesController
|
class MappingsController < RestfulController
|
||||||
def searchable_columns
|
|
||||||
[]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,9 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class MapsController < WithUpdatesController
|
class MapsController < RestfulController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
%i[name desc]
|
[:name, :desc]
|
||||||
end
|
|
||||||
|
|
||||||
def apply_filters(collection)
|
|
||||||
collection = collection.where(user_id: params[:user_id]) if params[:user_id]
|
|
||||||
collection
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
module V2
|
|
||||||
class MetacodesController < RestfulController
|
|
||||||
def searchable_columns
|
|
||||||
[:name]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class RestfulController < ActionController::Base
|
class RestfulController < ActionController::Base
|
||||||
|
@ -8,7 +7,7 @@ module Api
|
||||||
|
|
||||||
snorlax_used_rest!
|
snorlax_used_rest!
|
||||||
|
|
||||||
before_action :load_resource, only: %i[show update destroy]
|
before_action :load_resource, only: [:show, :update, :destroy]
|
||||||
after_action :verify_authorized
|
after_action :verify_authorized
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
@ -30,11 +29,6 @@ module Api
|
||||||
head :no_content
|
head :no_content
|
||||||
end
|
end
|
||||||
|
|
||||||
def catch_404
|
|
||||||
skip_authorization
|
|
||||||
render json: { error: '404 Not found' }, status: :not_found
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def accessible_records
|
def accessible_records
|
||||||
|
@ -46,7 +40,7 @@ module Api
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_user
|
def current_user
|
||||||
token_user || doorkeeper_user
|
super || token_user || doorkeeper_user || nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def load_resource
|
def load_resource
|
||||||
|
@ -76,8 +70,7 @@ module Api
|
||||||
|
|
||||||
def default_scope
|
def default_scope
|
||||||
{
|
{
|
||||||
embeds: embeds,
|
embeds: embeds
|
||||||
current_user: current_user
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -87,12 +80,12 @@ module Api
|
||||||
|
|
||||||
def token_user
|
def token_user
|
||||||
token = params[:access_token]
|
token = params[:access_token]
|
||||||
access_token = Token.find_by(token: token)
|
access_token = Token.find_by_token(token)
|
||||||
@token_user ||= access_token.user if access_token
|
@token_user ||= access_token.user if access_token
|
||||||
end
|
end
|
||||||
|
|
||||||
def doorkeeper_user
|
def doorkeeper_user
|
||||||
return if doorkeeper_token.blank?
|
return unless doorkeeper_token.present?
|
||||||
doorkeeper_render_error unless valid_doorkeeper_token?
|
doorkeeper_render_error unless valid_doorkeeper_token?
|
||||||
@doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id)
|
@doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id)
|
||||||
end
|
end
|
||||||
|
@ -142,7 +135,6 @@ module Api
|
||||||
collection = accessible_records
|
collection = accessible_records
|
||||||
collection = yield collection if block_given?
|
collection = yield collection if block_given?
|
||||||
collection = search_by_q(collection) if params[:q]
|
collection = search_by_q(collection) if params[:q]
|
||||||
collection = apply_filters(collection)
|
|
||||||
collection = order_by_sort(collection) if params[:sort]
|
collection = order_by_sort(collection) if params[:sort]
|
||||||
collection = collection.page(params[:page]).per(params[:per])
|
collection = collection.page(params[:page]).per(params[:per])
|
||||||
self.collection = collection
|
self.collection = collection
|
||||||
|
@ -150,41 +142,25 @@ module Api
|
||||||
|
|
||||||
# override this method to explicitly set searchable columns
|
# override this method to explicitly set searchable columns
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
return @searchable_columns unless @searchable_columns.nil?
|
|
||||||
|
|
||||||
columns = resource_class.columns.select do |column|
|
columns = resource_class.columns.select do |column|
|
||||||
column.type == :text || column.type == :string
|
column.type == :text || column.type == :string
|
||||||
end
|
end
|
||||||
@searchable_columns = columns.map(&:name)
|
columns.map(&:name)
|
||||||
end
|
|
||||||
|
|
||||||
# e.g. ?q=test&searchfields=name,desc
|
|
||||||
def searchfields
|
|
||||||
return searchable_columns if params[:searchfields].blank?
|
|
||||||
|
|
||||||
searchfields = params[:searchfields].split(',')
|
|
||||||
searchfields.select! { |f| searchable_columns.include?(f.to_sym) }
|
|
||||||
searchfields.empty? ? searchable_columns : searchfields
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# thanks to http://stackoverflow.com/questions/4430578
|
# thanks to http://stackoverflow.com/questions/4430578
|
||||||
def search_by_q(collection)
|
def search_by_q(collection)
|
||||||
table = resource_class.arel_table
|
table = resource_class.arel_table
|
||||||
safe_query = "%#{params[:q].gsub(/[%_]/, '\\\\\0')}%"
|
safe_query = "%#{params[:q].gsub(/[%_]/, '\\\\\0')}%"
|
||||||
search_column = ->(column) { table[column].matches(safe_query) }
|
search_column = -> (column) { table[column].matches(safe_query) }
|
||||||
|
|
||||||
condition = searchfields.reduce(nil) do |prev, column|
|
condition = searchable_columns.reduce(nil) do |prev, column|
|
||||||
next search_column.call(column) if prev.nil?
|
next search_column.call(column) if prev.nil?
|
||||||
search_column.call(column).or(prev)
|
search_column.call(column).or(prev)
|
||||||
end
|
end
|
||||||
collection.where(condition)
|
collection.where(condition)
|
||||||
end
|
end
|
||||||
|
|
||||||
def apply_filters(collection)
|
|
||||||
# override this function for specific filters
|
|
||||||
collection
|
|
||||||
end
|
|
||||||
|
|
||||||
def order_by_sort(collection)
|
def order_by_sort(collection)
|
||||||
builder = collection
|
builder = collection
|
||||||
sorts = params[:sort].split(',')
|
sorts = params[:sort].split(',')
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class SessionsController < ApplicationController
|
class SessionsController < ApplicationController
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
module V2
|
|
||||||
class StarsController < RestfulController
|
|
||||||
skip_before_action :load_resource
|
|
||||||
|
|
||||||
def create
|
|
||||||
@map = Map.find(params[:id])
|
|
||||||
@star = Star.new(user: current_user, map: @map)
|
|
||||||
authorize @map, :star?
|
|
||||||
create_action
|
|
||||||
|
|
||||||
if @star.errors.empty?
|
|
||||||
render json: @map, scope: default_scope, serializer: MapSerializer, root: serializer_root
|
|
||||||
else
|
|
||||||
respond_with_errors
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
@map = Map.find(params[:id])
|
|
||||||
authorize @map, :unstar?
|
|
||||||
@star = @map.stars.find_by(user: current_user)
|
|
||||||
@star.destroy if @star.present?
|
|
||||||
head :no_content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class SynapsesController < WithUpdatesController
|
class SynapsesController < RestfulController
|
||||||
def searchable_columns
|
def searchable_columns
|
||||||
[:desc]
|
[:desc]
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,31 +1,11 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class TokensController < RestfulController
|
class TokensController < RestfulController
|
||||||
protect_from_forgery
|
def my_tokens
|
||||||
|
authorize resource_class
|
||||||
def searchable_columns
|
instantiate_collection
|
||||||
[:description]
|
respond_with_collection
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
if params[:token].blank?
|
|
||||||
self.resource = resource_class.new
|
|
||||||
else
|
|
||||||
instantiate_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
resource.user = current_user if current_user.present?
|
|
||||||
authorize resource
|
|
||||||
create_action
|
|
||||||
respond_with_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def current_user
|
|
||||||
token_user || doorkeeper_user || method(:current_user).super_method.super_method.call
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,11 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
module Api
|
module Api
|
||||||
module V2
|
module V2
|
||||||
class TopicsController < WithUpdatesController
|
class TopicsController < RestfulController
|
||||||
def searchable_columns
|
|
||||||
%i[name desc link]
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
module V2
|
|
||||||
class UsersController < RestfulController
|
|
||||||
def current
|
|
||||||
raise Pundit::NotAuthorizedError if current_user.nil?
|
|
||||||
@user = current_user
|
|
||||||
authorize @user
|
|
||||||
show # delegate to the normal show function
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def searchable_columns
|
|
||||||
[:name]
|
|
||||||
end
|
|
||||||
|
|
||||||
# only ask serializer to return is_admin field if we're on the
|
|
||||||
# current_user action
|
|
||||||
def default_scope
|
|
||||||
super.merge(show_full_user: action_name == 'current')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,28 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Api
|
|
||||||
module V2
|
|
||||||
class WithUpdatesController < RestfulController
|
|
||||||
def create
|
|
||||||
instantiate_resource
|
|
||||||
resource.user = current_user if current_user.present?
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
authorize resource
|
|
||||||
create_action
|
|
||||||
respond_with_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def update
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
update_action
|
|
||||||
respond_with_resource
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
resource.updated_by = current_user if current_user.present?
|
|
||||||
destroy_action
|
|
||||||
head :no_content
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
include ApplicationHelper
|
include ApplicationHelper
|
||||||
include Pundit
|
include Pundit
|
||||||
|
@ -8,7 +7,6 @@ class ApplicationController < ActionController::Base
|
||||||
protect_from_forgery(with: :exception)
|
protect_from_forgery(with: :exception)
|
||||||
|
|
||||||
before_action :invite_link
|
before_action :invite_link
|
||||||
before_action :prepare_exception_notifier
|
|
||||||
after_action :allow_embedding
|
after_action :allow_embedding
|
||||||
|
|
||||||
def default_serializer_options
|
def default_serializer_options
|
||||||
|
@ -22,14 +20,23 @@ class ApplicationController < ActionController::Base
|
||||||
helper_method :authenticated?
|
helper_method :authenticated?
|
||||||
helper_method :admin?
|
helper_method :admin?
|
||||||
|
|
||||||
def handle_unauthorized
|
def after_sign_in_path_for(resource)
|
||||||
if authenticated? && (params[:controller] == 'maps') && (params[:action] == 'show')
|
sign_in_url = url_for(action: 'new', controller: 'sessions', only_path: false)
|
||||||
redirect_to request_access_map_path(params[:id])
|
|
||||||
elsif authenticated?
|
if request.referer == sign_in_url
|
||||||
redirect_to root_path, notice: "You don't have permission to see that page."
|
super
|
||||||
|
elsif params[:uv_login] == '1'
|
||||||
|
'http://support.metamaps.cc/login_success?sso=' + current_sso_token
|
||||||
else
|
else
|
||||||
store_location_for(resource, request.fullpath)
|
stored_location_for(resource) || request.referer || root_path
|
||||||
redirect_to sign_in_path, notice: 'Try signing in to do that.'
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_unauthorized
|
||||||
|
if authenticated?
|
||||||
|
head :forbidden # TODO: make this better
|
||||||
|
else
|
||||||
|
redirect_to new_user_session_path, notice: 'Try signing in to do that.'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -42,13 +49,13 @@ class ApplicationController < ActionController::Base
|
||||||
def require_no_user
|
def require_no_user
|
||||||
return true unless authenticated?
|
return true unless authenticated?
|
||||||
redirect_to edit_user_path(user), notice: 'You must be logged out.'
|
redirect_to edit_user_path(user), notice: 'You must be logged out.'
|
||||||
false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_user
|
def require_user
|
||||||
return true if authenticated?
|
return true if authenticated?
|
||||||
redirect_to sign_in_path, notice: 'You must be logged in.'
|
redirect_to new_user_session_path, notice: 'You must be logged in.'
|
||||||
false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
def require_admin
|
def require_admin
|
||||||
|
@ -75,10 +82,4 @@ class ApplicationController < ActionController::Base
|
||||||
# or allow a whitelist
|
# or allow a whitelist
|
||||||
# response.headers['X-Frame-Options'] = 'ALLOW-FROM http://blog.metamaps.cc'
|
# response.headers['X-Frame-Options'] = 'ALLOW-FROM http://blog.metamaps.cc'
|
||||||
end
|
end
|
||||||
|
|
||||||
def prepare_exception_notifier
|
|
||||||
request.env['exception_notifier.exception_data'] = {
|
|
||||||
current_user: current_user
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class ExploreController < ApplicationController
|
|
||||||
before_action :require_authentication, only: %i[mine shared starred]
|
|
||||||
before_action :authorize_explore
|
|
||||||
after_action :verify_authorized
|
|
||||||
after_action :verify_policy_scoped
|
|
||||||
|
|
||||||
respond_to :html, :json, :csv
|
|
||||||
|
|
||||||
# GET /explore/active
|
|
||||||
def active
|
|
||||||
@maps = map_scope(Map.where.not(name: 'Untitled Map').where.not(permission: 'private'))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html do
|
|
||||||
# root url => main/home. main/home renders maps/activemaps view.
|
|
||||||
redirect_to(root_url) && return if authenticated?
|
|
||||||
respond_with(@maps, @user)
|
|
||||||
end
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /explore/featured
|
|
||||||
def featured
|
|
||||||
@maps = map_scope(Map.where(featured: true))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { respond_with(@maps, @user) }
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /explore/mine
|
|
||||||
def mine
|
|
||||||
@maps = map_scope(Map.where(user_id: current_user.id))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { respond_with(@maps, @user) }
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /explore/shared
|
|
||||||
def shared
|
|
||||||
@maps = map_scope(Map.where(id: current_user.shared_maps.map(&:id)))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { respond_with(@maps, @user) }
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /explore/starred
|
|
||||||
def starred
|
|
||||||
@maps = map_scope(Map.where(id: current_user.stars.map(&:map_id)))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { respond_with(@maps, @user) }
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET /explore/mapper/:id
|
|
||||||
def mapper
|
|
||||||
@user = User.find(params[:id])
|
|
||||||
@maps = map_scope(Map.where(user: @user))
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html { respond_with(@maps, @user) }
|
|
||||||
format.json { render json: @maps.to_json }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def map_scope(scope)
|
|
||||||
policy_scope(scope).order(updated_at: :desc).page(params[:page]).per(20)
|
|
||||||
end
|
|
||||||
|
|
||||||
def authorize_explore
|
|
||||||
authorize :Explore
|
|
||||||
end
|
|
||||||
|
|
||||||
def require_authentication
|
|
||||||
# skip_policy_scope
|
|
||||||
redirect_to explore_active_path unless authenticated?
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,44 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
# bad code that should be checked over before entering one of the
|
|
||||||
# nice files from the right side of this repo
|
|
||||||
class HacksController < ApplicationController
|
|
||||||
include ActionView::Helpers::TextHelper # string truncate method
|
|
||||||
|
|
||||||
# rate limited by rack-attack - currently 5r/s
|
|
||||||
def load_url_title
|
|
||||||
authorize :Hack
|
|
||||||
url = params[:url]
|
|
||||||
response, url = get_with_redirects(url)
|
|
||||||
title = get_encoded_title(response)
|
|
||||||
render json: { success: true, title: title, url: url }
|
|
||||||
rescue StandardError
|
|
||||||
render json: { success: false }
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def get_with_redirects(url)
|
|
||||||
uri = URI.parse(url)
|
|
||||||
response = Net::HTTP.get_response(uri)
|
|
||||||
while response.code == '301'
|
|
||||||
uri = URI.parse(response['location'])
|
|
||||||
response = Net::HTTP.get_response(uri)
|
|
||||||
end
|
|
||||||
[response, uri.to_s]
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_encoded_title(http_response)
|
|
||||||
# ensure there's actually an html title tag
|
|
||||||
title = http_response.body.sub(%r{.*(<title>.*</title>).*}m, '\1')
|
|
||||||
return '' unless title.starts_with?('<title>')
|
|
||||||
return '' unless title.ends_with?('</title>')
|
|
||||||
title = title.sub('<title>', '').sub(%r{</title>$}, '')
|
|
||||||
|
|
||||||
# encode and trim the title to 140 usable characters
|
|
||||||
charset = http_response['content-type'].sub(/.*charset=(.*);?.*/, '\1')
|
|
||||||
charset = nil if charset == 'text/html'
|
|
||||||
title = title.force_encoding(charset) if charset
|
|
||||||
truncate(title, length: 140)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,31 +1,172 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MainController < ApplicationController
|
class MainController < ApplicationController
|
||||||
before_action :authorize_main
|
include TopicsHelper
|
||||||
after_action :verify_authorized
|
include MapsHelper
|
||||||
|
include UsersHelper
|
||||||
|
include SynapsesHelper
|
||||||
|
|
||||||
# GET /
|
after_action :verify_policy_scoped, except: [:requestinvite, :searchmappers]
|
||||||
|
|
||||||
|
respond_to :html, :json
|
||||||
|
|
||||||
|
# home page
|
||||||
def home
|
def home
|
||||||
|
@maps = policy_scope(Map).order('updated_at DESC').page(1).per(20)
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
if authenticated?
|
if !authenticated?
|
||||||
@maps = policy_scope(Map).where.not(name: 'Untitled Map').where.not(permission: 'private')
|
|
||||||
.order(updated_at: :desc).page(1).per(20)
|
|
||||||
render 'explore/active'
|
|
||||||
else
|
|
||||||
render 'main/home'
|
render 'main/home'
|
||||||
|
else
|
||||||
|
render 'maps/activemaps'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET /request
|
### SEARCHING ###
|
||||||
def requestinvite
|
|
||||||
|
# get /search/topics?term=SOMETERM
|
||||||
|
def searchtopics
|
||||||
|
term = params[:term]
|
||||||
|
user = params[:user] ? params[:user] : false
|
||||||
|
|
||||||
|
if term && !term.empty? && term.downcase[0..3] != 'map:' && term.downcase[0..6] != 'mapper:' && !term.casecmp('topic:').zero?
|
||||||
|
|
||||||
|
# remove "topic:" if appended at beginning
|
||||||
|
term = term[6..-1] if term.downcase[0..5] == 'topic:'
|
||||||
|
|
||||||
|
# if desc: search desc instead
|
||||||
|
desc = false
|
||||||
|
if term.downcase[0..4] == 'desc:'
|
||||||
|
term = term[5..-1]
|
||||||
|
desc = true
|
||||||
|
end
|
||||||
|
|
||||||
|
# if link: search link instead
|
||||||
|
link = false
|
||||||
|
if term.downcase[0..4] == 'link:'
|
||||||
|
term = term[5..-1]
|
||||||
|
link = true
|
||||||
|
end
|
||||||
|
|
||||||
|
# check whether there's a filter by metacode as part of the query
|
||||||
|
filterByMetacode = false
|
||||||
|
Metacode.all.each do |m|
|
||||||
|
lOne = m.name.length + 1
|
||||||
|
lTwo = m.name.length
|
||||||
|
|
||||||
|
if term.downcase[0..lTwo] == m.name.downcase + ':'
|
||||||
|
term = term[lOne..-1]
|
||||||
|
filterByMetacode = m
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
search = '%' + term.downcase + '%'
|
||||||
|
builder = policy_scope(Topic)
|
||||||
|
|
||||||
|
if filterByMetacode
|
||||||
|
if term == ''
|
||||||
|
builder = builder.none
|
||||||
|
else
|
||||||
|
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
|
||||||
|
builder = builder.where('LOWER("desc") like ?', search)
|
||||||
|
elsif link
|
||||||
|
builder = builder.where('LOWER("link") like ?', search)
|
||||||
|
else # regular case, just search the name
|
||||||
|
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
|
||||||
|
|
||||||
|
render json: autocomplete_array_json(@topics)
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
# get /search/maps?term=SOMETERM
|
||||||
|
def searchmaps
|
||||||
|
term = params[:term]
|
||||||
|
user = params[:user] ? params[:user] : nil
|
||||||
|
|
||||||
def authorize_main
|
if term && !term.empty? && term.downcase[0..5] != 'topic:' && term.downcase[0..6] != 'mapper:' && !term.casecmp('map:').zero?
|
||||||
authorize :Main
|
|
||||||
|
# remove "map:" if appended at beginning
|
||||||
|
term = term[4..-1] if term.downcase[0..3] == 'map:'
|
||||||
|
|
||||||
|
# if desc: search desc instead
|
||||||
|
desc = false
|
||||||
|
if term.downcase[0..4] == 'desc:'
|
||||||
|
term = term[5..-1]
|
||||||
|
desc = true
|
||||||
|
end
|
||||||
|
|
||||||
|
search = '%' + term.downcase + '%'
|
||||||
|
builder = policy_scope(Map)
|
||||||
|
|
||||||
|
builder = if desc
|
||||||
|
builder.where('LOWER("desc") like ?', search)
|
||||||
|
else
|
||||||
|
builder.where('LOWER("name") like ?', search)
|
||||||
|
end
|
||||||
|
builder = builder.where(user: user) if user
|
||||||
|
@maps = builder.order(:name)
|
||||||
|
else
|
||||||
|
@maps = []
|
||||||
|
end
|
||||||
|
|
||||||
|
render json: autocomplete_map_array_json(@maps)
|
||||||
|
end
|
||||||
|
|
||||||
|
# get /search/mappers?term=SOMETERM
|
||||||
|
def searchmappers
|
||||||
|
term = params[:term]
|
||||||
|
if term && !term.empty? && term.downcase[0..3] != 'map:' && term.downcase[0..5] != 'topic:' && !term.casecmp('mapper:').zero?
|
||||||
|
|
||||||
|
# remove "mapper:" if appended at beginning
|
||||||
|
term = term[7..-1] if term.downcase[0..6] == 'mapper:'
|
||||||
|
search = term.downcase + '%'
|
||||||
|
|
||||||
|
skip_policy_scope # TODO: builder = policy_scope(User)
|
||||||
|
builder = User.where('LOWER("name") like ?', search)
|
||||||
|
@mappers = builder.order(:name)
|
||||||
|
else
|
||||||
|
@mappers = []
|
||||||
|
end
|
||||||
|
render json: autocomplete_user_array_json(@mappers)
|
||||||
|
end
|
||||||
|
|
||||||
|
# get /search/synapses?term=SOMETERM OR
|
||||||
|
# get /search/synapses?topic1id=SOMEID&topic2id=SOMEID
|
||||||
|
def searchsynapses
|
||||||
|
term = params[:term]
|
||||||
|
topic1id = params[:topic1id]
|
||||||
|
topic2id = params[:topic2id]
|
||||||
|
|
||||||
|
if term && !term.empty?
|
||||||
|
@synapses = policy_scope(Synapse).where('LOWER("desc") like ?', '%' + term.downcase + '%').order('"desc"')
|
||||||
|
|
||||||
|
@synapses = @synapses.uniq(&:desc)
|
||||||
|
elsif topic1id && !topic1id.empty?
|
||||||
|
@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
|
||||||
|
else
|
||||||
|
@synapses = []
|
||||||
|
end
|
||||||
|
|
||||||
|
# limit to 5 results
|
||||||
|
@synapses = @synapses.to_a.slice(0, 5)
|
||||||
|
|
||||||
|
render json: autocomplete_synapse_array_json(@synapses)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MappingsController < ApplicationController
|
class MappingsController < ApplicationController
|
||||||
before_action :require_user, only: %i[create update destroy]
|
before_action :require_user, only: [:create, :update, :destroy]
|
||||||
after_action :verify_authorized, except: :index
|
after_action :verify_authorized, except: :index
|
||||||
after_action :verify_policy_scoped, only: :index
|
after_action :verify_policy_scoped, only: :index
|
||||||
|
|
||||||
|
@ -20,10 +19,10 @@ class MappingsController < ApplicationController
|
||||||
@mapping = Mapping.new(mapping_params)
|
@mapping = Mapping.new(mapping_params)
|
||||||
authorize @mapping
|
authorize @mapping
|
||||||
@mapping.user = current_user
|
@mapping.user = current_user
|
||||||
@mapping.updated_by = current_user
|
|
||||||
|
|
||||||
if @mapping.save
|
if @mapping.save
|
||||||
render json: @mapping, status: :created
|
render json: @mapping, status: :created
|
||||||
|
Events::NewMapping.publish!(@mapping, current_user)
|
||||||
else
|
else
|
||||||
render json: @mapping.errors, status: :unprocessable_entity
|
render json: @mapping.errors, status: :unprocessable_entity
|
||||||
end
|
end
|
||||||
|
@ -33,11 +32,8 @@ class MappingsController < ApplicationController
|
||||||
def update
|
def update
|
||||||
@mapping = Mapping.find(params[:id])
|
@mapping = Mapping.find(params[:id])
|
||||||
authorize @mapping
|
authorize @mapping
|
||||||
@mapping.updated_by = current_user
|
|
||||||
@mapping.map.updated_by = current_user
|
|
||||||
@mapping.assign_attributes(mapping_params)
|
|
||||||
|
|
||||||
if @mapping.save
|
if @mapping.update_attributes(mapping_params)
|
||||||
head :no_content
|
head :no_content
|
||||||
else
|
else
|
||||||
render json: @mapping.errors, status: :unprocessable_entity
|
render json: @mapping.errors, status: :unprocessable_entity
|
||||||
|
@ -48,8 +44,14 @@ class MappingsController < ApplicationController
|
||||||
def destroy
|
def destroy
|
||||||
@mapping = Mapping.find(params[:id])
|
@mapping = Mapping.find(params[:id])
|
||||||
authorize @mapping
|
authorize @mapping
|
||||||
@mapping.updated_by = current_user
|
|
||||||
@mapping.map.updated_by = current_user
|
mappable = @mapping.mappable
|
||||||
|
if mappable.defer_to_map
|
||||||
|
mappable.permission = mappable.defer_to_map.permission
|
||||||
|
mappable.defer_to_map_id = nil
|
||||||
|
mappable.save
|
||||||
|
end
|
||||||
|
|
||||||
@mapping.destroy
|
@mapping.destroy
|
||||||
|
|
||||||
head :no_content
|
head :no_content
|
||||||
|
|
|
@ -1,46 +1,108 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MapsController < ApplicationController
|
class MapsController < ApplicationController
|
||||||
before_action :require_user, only: %i[create update destroy events follow unfollow]
|
before_action :require_user, only: [:create, :update, :access, :star, :unstar, :screenshot, :events, :destroy]
|
||||||
before_action :set_map, only: %i[show conversation update destroy
|
after_action :verify_authorized, except: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps]
|
||||||
contains events export
|
after_action :verify_policy_scoped, only: [:activemaps, :featuredmaps, :mymaps, :sharedmaps, :starredmaps, :usermaps]
|
||||||
follow unfollow unfollow_from_email]
|
|
||||||
after_action :verify_authorized
|
respond_to :html, :json, :csv
|
||||||
|
|
||||||
|
autocomplete :map, :name, full: true, extra_data: [:user_id]
|
||||||
|
|
||||||
|
# GET /explore/active
|
||||||
|
def activemaps
|
||||||
|
page = params[:page].present? ? params[:page] : 1
|
||||||
|
@maps = policy_scope(Map).order('updated_at DESC')
|
||||||
|
.page(page).per(20)
|
||||||
|
|
||||||
# GET maps/:id
|
|
||||||
def show
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html do
|
format.html do
|
||||||
UserMap.where(map: @map, user: current_user).map(&:mark_invite_notifications_as_read)
|
# root url => main/home. main/home renders maps/activemaps view.
|
||||||
@allmappers = @map.contributors
|
redirect_to(root_url) && return if authenticated?
|
||||||
@allcollaborators = @map.editors
|
respond_with(@maps, @user)
|
||||||
@alltopics = policy_scope(@map.topics)
|
|
||||||
@allsynapses = policy_scope(@map.synapses)
|
|
||||||
@allmappings = policy_scope(@map.mappings)
|
|
||||||
@allmessages = @map.messages.sort_by(&:created_at)
|
|
||||||
@allstars = @map.stars
|
|
||||||
@allrequests = @map.access_requests
|
|
||||||
end
|
end
|
||||||
format.json { render json: @map }
|
format.json { render json: @maps.to_json }
|
||||||
format.csv { redirect_to action: :export, format: :csv }
|
|
||||||
format.ttl { redirect_to action: :export, format: :ttl }
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET maps/:id/conversation
|
# GET /explore/featured
|
||||||
def conversation
|
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|
|
respond_to do |format|
|
||||||
format.html do
|
format.html { respond_with(@maps, @user) }
|
||||||
UserMap.where(map: @map, user: current_user).map(&:mark_invite_notifications_as_read)
|
format.json { render json: @maps.to_json }
|
||||||
@allmappers = @map.contributors
|
end
|
||||||
@allcollaborators = @map.editors
|
end
|
||||||
@alltopics = policy_scope(@map.topics)
|
|
||||||
@allsynapses = policy_scope(@map.synapses)
|
# GET /explore/mine
|
||||||
@allmappings = policy_scope(@map.mappings)
|
def mymaps
|
||||||
@allmessages = @map.messages.sort_by(&:created_at)
|
unless authenticated?
|
||||||
@allstars = @map.stars
|
skip_policy_scope
|
||||||
@allrequests = @map.access_requests
|
return redirect_to explore_active_path
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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.to_json }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /explore/shared
|
||||||
|
def sharedmaps
|
||||||
|
unless authenticated?
|
||||||
|
skip_policy_scope
|
||||||
|
return redirect_to explore_active_path
|
||||||
|
end
|
||||||
|
|
||||||
|
page = params[:page].present? ? params[:page] : 1
|
||||||
|
@maps = policy_scope(
|
||||||
|
Map.where('maps.id IN (?)', current_user.shared_maps.map(&:id))
|
||||||
|
).order('updated_at DESC').page(page).per(20)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { respond_with(@maps, @user) }
|
||||||
|
format.json { render json: @maps.to_json }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET /explore/starred
|
||||||
|
def starredmaps
|
||||||
|
unless authenticated?
|
||||||
|
skip_policy_scope
|
||||||
|
return redirect_to explore_active_path
|
||||||
|
end
|
||||||
|
|
||||||
|
page = params[:page].present? ? params[:page] : 1
|
||||||
|
stars = current_user.stars.map(&:map_id)
|
||||||
|
@maps = policy_scope(
|
||||||
|
Map.where('maps.id IN (?)', stars)
|
||||||
|
).order('updated_at DESC').page(page).per(20)
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.html { respond_with(@maps, @user) }
|
||||||
|
format.json { render json: @maps.to_json }
|
||||||
|
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.to_json }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -58,24 +120,138 @@ class MapsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST maps
|
# GET maps/:id
|
||||||
def create
|
def show
|
||||||
@map = Map.new(create_map_params)
|
@map = Map.find(params[:id])
|
||||||
@map.user = current_user
|
|
||||||
@map.updated_by = current_user
|
|
||||||
@map.arranged = false
|
|
||||||
authorize @map
|
authorize @map
|
||||||
|
|
||||||
if params[:topicsToMap].present?
|
respond_to do |format|
|
||||||
create_topics!
|
format.html do
|
||||||
create_synapses! if params[:synapsesToMap].present?
|
@allmappers = @map.contributors
|
||||||
@map.arranged = true
|
@allcollaborators = @map.editors
|
||||||
|
@alltopics = @map.topics.to_a.delete_if { |t| !policy(t).show? }
|
||||||
|
@allsynapses = @map.synapses.to_a.delete_if { |s| !policy(s).show? }
|
||||||
|
@allmappings = @map.mappings.to_a.delete_if { |m| !policy(m).show? }
|
||||||
|
@allmessages = @map.messages.sort_by(&:created_at)
|
||||||
|
@allstars = @map.stars
|
||||||
|
|
||||||
|
respond_with(@allmappers, @allcollaborators, @allmappings, @allsynapses, @alltopics, @allmessages, @allstars, @map)
|
||||||
|
end
|
||||||
|
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
|
||||||
|
|
||||||
|
# POST maps/:id/events/:event
|
||||||
|
def events
|
||||||
|
map = Map.find(params[:id])
|
||||||
|
authorize map
|
||||||
|
|
||||||
|
valid_event = false
|
||||||
|
if params[:event] == 'conversation'
|
||||||
|
Events::ConversationStartedOnMap.publish!(map, current_user)
|
||||||
|
valid_event = true
|
||||||
|
elsif params[:event] == 'user_presence'
|
||||||
|
Events::UserPresentOnMap.publish!(map, current_user)
|
||||||
|
valid_event = true
|
||||||
end
|
end
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @map.save
|
format.json do
|
||||||
|
head :ok if valid_event
|
||||||
|
head :bad_request unless valid_event
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# GET maps/:id/contains
|
||||||
|
def contains
|
||||||
|
@map = Map.find(params[:id])
|
||||||
|
authorize @map
|
||||||
|
|
||||||
|
@allmappers = @map.contributors
|
||||||
|
@allcollaborators = @map.editors
|
||||||
|
@alltopics = @map.topics.to_a.delete_if { |t| !policy(t).show? }
|
||||||
|
@allsynapses = @map.synapses.to_a.delete_if { |s| !policy(s).show? }
|
||||||
|
@allmappings = @map.mappings.to_a.delete_if { |m| !policy(m).show? }
|
||||||
|
|
||||||
|
@json = {}
|
||||||
|
@json['map'] = @map
|
||||||
|
@json['topics'] = @alltopics
|
||||||
|
@json['synapses'] = @allsynapses
|
||||||
|
@json['mappings'] = @allmappings
|
||||||
|
@json['mappers'] = @allmappers
|
||||||
|
@json['collaborators'] = @allcollaborators
|
||||||
|
@json['messages'] = @map.messages.sort_by(&:created_at)
|
||||||
|
@json['stars'] = @map.stars
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json { render json: @json }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
if params[:topicsToMap]
|
||||||
|
@all = params[:topicsToMap]
|
||||||
|
@all = @all.split(',')
|
||||||
|
@all.each do |topic|
|
||||||
|
topic = topic.split('/')
|
||||||
|
mapping = Mapping.new
|
||||||
|
mapping.map = @map
|
||||||
|
mapping.user = @user
|
||||||
|
mapping.mappable = Topic.find(topic[0])
|
||||||
|
mapping.xloc = topic[1]
|
||||||
|
mapping.yloc = topic[2]
|
||||||
|
authorize mapping, :create?
|
||||||
|
mapping.save
|
||||||
|
end
|
||||||
|
|
||||||
|
if params[:synapsesToMap]
|
||||||
|
@synAll = params[:synapsesToMap]
|
||||||
|
@synAll = @synAll.split(',')
|
||||||
|
@synAll.each do |synapse_id|
|
||||||
|
mapping = Mapping.new
|
||||||
|
mapping.map = @map
|
||||||
|
mapping.user = @user
|
||||||
|
mapping.mappable = Synapse.find(synapse_id)
|
||||||
|
authorize mapping, :create?
|
||||||
|
mapping.save
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@map.arranged = true
|
||||||
|
end
|
||||||
|
|
||||||
|
authorize @map
|
||||||
|
|
||||||
|
if @map.save
|
||||||
|
respond_to do |format|
|
||||||
format.json { render json: @map }
|
format.json { render json: @map }
|
||||||
else
|
end
|
||||||
|
else
|
||||||
|
respond_to do |format|
|
||||||
format.json { render json: 'invalid params' }
|
format.json { render json: 'invalid params' }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -83,11 +259,11 @@ class MapsController < ApplicationController
|
||||||
|
|
||||||
# PUT maps/:id
|
# PUT maps/:id
|
||||||
def update
|
def update
|
||||||
@map.updated_by = current_user
|
@map = Map.find(params[:id])
|
||||||
@map.assign_attributes(update_map_params)
|
authorize @map
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @map.save
|
if @map.update_attributes(map_params)
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.json { render json: @map.errors, status: :unprocessable_entity }
|
format.json { render json: @map.errors, status: :unprocessable_entity }
|
||||||
|
@ -95,10 +271,90 @@ class MapsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# POST maps/:id/access
|
||||||
|
def access
|
||||||
|
@map = Map.find(params[:id])
|
||||||
|
authorize @map
|
||||||
|
userIds = params[:access] || []
|
||||||
|
added = userIds.select do |uid|
|
||||||
|
user = User.find(uid)
|
||||||
|
if user.nil? || (current_user && user == current_user)
|
||||||
|
false
|
||||||
|
else
|
||||||
|
!@map.collaborators.include?(user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
removed = @map.collaborators.select { |user| !userIds.include?(user.id.to_s) }.map(&:id)
|
||||||
|
added.each do |uid|
|
||||||
|
UserMap.create(user_id: uid.to_i, map_id: @map.id)
|
||||||
|
user = User.find(uid.to_i)
|
||||||
|
MapMailer.invite_to_edit_email(@map, current_user, user).deliver_later
|
||||||
|
end
|
||||||
|
removed.each do |uid|
|
||||||
|
@map.user_maps.select { |um| um.user_id == uid }.each(&:destroy)
|
||||||
|
end
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json do
|
||||||
|
render json: { message: 'Successfully altered edit permissions' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST maps/:id/star
|
||||||
|
def star
|
||||||
|
@map = Map.find(params[:id])
|
||||||
|
authorize @map
|
||||||
|
star = Star.find_by_map_id_and_user_id(@map.id, current_user.id)
|
||||||
|
star = Star.create(map_id: @map.id, user_id: current_user.id) unless star
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json do
|
||||||
|
render json: { message: 'Successfully starred map' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST maps/:id/unstar
|
||||||
|
def unstar
|
||||||
|
@map = Map.find(params[:id])
|
||||||
|
authorize @map
|
||||||
|
star = Star.find_by_map_id_and_user_id(@map.id, current_user.id)
|
||||||
|
star&.delete
|
||||||
|
|
||||||
|
respond_to do |format|
|
||||||
|
format.json do
|
||||||
|
render json: { message: 'Successfully unstarred map' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# POST maps/:id/upload_screenshot
|
||||||
|
def screenshot
|
||||||
|
@map = Map.find(params[:id])
|
||||||
|
authorize @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
|
||||||
|
|
||||||
|
if @map.save
|
||||||
|
render json: { message: 'Successfully uploaded the map screenshot.' }
|
||||||
|
else
|
||||||
|
render json: { message: 'Failed to upload image.' }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# DELETE maps/:id
|
# DELETE maps/:id
|
||||||
def destroy
|
def destroy
|
||||||
@map.updated_by = current_user
|
@map = Map.find(params[:id])
|
||||||
@map.destroy
|
authorize @map
|
||||||
|
|
||||||
|
@map.delete
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.json do
|
format.json do
|
||||||
|
@ -107,109 +363,10 @@ class MapsController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# GET maps/:id/contains
|
|
||||||
def contains
|
|
||||||
respond_to do |format|
|
|
||||||
format.json { render json: @map.contains(current_user).as_json(user: current_user) }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET maps/:id/export
|
|
||||||
def export
|
|
||||||
exporter = MapExportService.new(current_user, @map, base_url: request.base_url)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json { render json: exporter.json }
|
|
||||||
format.csv { send_data exporter.csv }
|
|
||||||
format.ttl { render text: exporter.rdf }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/events/:event
|
|
||||||
def events
|
|
||||||
valid_event = false
|
|
||||||
if params[:event] == 'conversation'
|
|
||||||
Events::ConversationStartedOnMap.publish!(@map, current_user)
|
|
||||||
valid_event = true
|
|
||||||
end
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json do
|
|
||||||
head :bad_request unless valid_event
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/follow
|
|
||||||
def follow
|
|
||||||
follow = FollowService.follow(@map, current_user, 'followed')
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json do
|
|
||||||
if follow
|
|
||||||
head :ok
|
|
||||||
else
|
|
||||||
head :bad_request
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/unfollow
|
|
||||||
def unfollow
|
|
||||||
FollowService.unfollow(@map, current_user)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json do
|
|
||||||
head :ok
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# GET maps/:id/unfollow_from_email
|
|
||||||
def unfollow_from_email
|
|
||||||
FollowService.unfollow(@map, current_user)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.html do
|
|
||||||
redirect_to map_path(@map), notice: 'You are no longer following this map'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_map
|
# Never trust parameters from the scary internet, only allow the white list through.
|
||||||
@map = Map.find(params[:id])
|
def map_params
|
||||||
authorize @map
|
params.require(:map).permit(:id, :name, :arranged, :desc, :permission)
|
||||||
end
|
|
||||||
|
|
||||||
def create_map_params
|
|
||||||
params.permit(:name, :desc, :permission, :source_id)
|
|
||||||
end
|
|
||||||
|
|
||||||
def update_map_params
|
|
||||||
params.require(:map).permit(:id, :name, :arranged, :desc, :permission, :screenshot)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_topics!
|
|
||||||
params[:topicsToMap].split(',').each do |topic|
|
|
||||||
topic = topic.split('/')
|
|
||||||
mapping = Mapping.new(map: @map, user: current_user,
|
|
||||||
mappable: Topic.find(topic[0]),
|
|
||||||
xloc: topic[1], yloc: topic[2])
|
|
||||||
authorize mapping, :create?
|
|
||||||
mapping.save
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_synapses!
|
|
||||||
params[:synapsesToMap].split(',').each do |synapse_id|
|
|
||||||
mapping = Mapping.new(map: @map, user: current_user,
|
|
||||||
mappable: Synapse.find(synapse_id))
|
|
||||||
authorize mapping, :create?
|
|
||||||
mapping.save
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MessagesController < ApplicationController
|
class MessagesController < ApplicationController
|
||||||
before_action :require_user, except: [:show]
|
before_action :require_user, except: [:show]
|
||||||
after_action :verify_authorized
|
after_action :verify_authorized
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MetacodeSetsController < ApplicationController
|
class MetacodeSetsController < ApplicationController
|
||||||
before_action :require_admin
|
before_action :require_admin
|
||||||
|
|
||||||
|
@ -56,13 +55,8 @@ class MetacodeSetsController < ApplicationController
|
||||||
@metacodes.each do |m|
|
@metacodes.each do |m|
|
||||||
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
||||||
end
|
end
|
||||||
format.html do
|
format.html { redirect_to metacode_sets_url, notice: 'Metacode set was successfully created.' }
|
||||||
redirect_to metacode_sets_url,
|
format.json { render json: @metacode_set, status: :created, location: metacode_sets_url }
|
||||||
notice: 'Metacode set was successfully created.'
|
|
||||||
end
|
|
||||||
format.json do
|
|
||||||
render json: @metacode_set, status: :created, location: metacode_sets_url
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
format.html { render action: 'new' }
|
format.html { render action: 'new' }
|
||||||
format.json { render json: @metacode_set.errors, status: :unprocessable_entity }
|
format.json { render json: @metacode_set.errors, status: :unprocessable_entity }
|
||||||
|
@ -79,20 +73,20 @@ class MetacodeSetsController < ApplicationController
|
||||||
if @metacode_set.update_attributes(metacode_set_params)
|
if @metacode_set.update_attributes(metacode_set_params)
|
||||||
|
|
||||||
# build an array of the IDs of the metacodes currently in the set
|
# build an array of the IDs of the metacodes currently in the set
|
||||||
current_metacodes = @metacode_set.metacodes.map { |m| m.id.to_s }
|
@currentMetacodes = @metacode_set.metacodes.map { |m| m.id.to_s }
|
||||||
# get the list of desired metacodes for the set from the user input and build an array out of it
|
# get the list of desired metacodes for the set from the user input and build an array out of it
|
||||||
new_metacodes = params[:metacodes][:value].split(',')
|
@newMetacodes = params[:metacodes][:value].split(',')
|
||||||
|
|
||||||
# remove the metacodes that were in it, but now aren't
|
# remove the metacodes that were in it, but now aren't
|
||||||
removed_metacodes = current_metacodes - new_metacodes
|
@removedMetacodes = @currentMetacodes - @newMetacodes
|
||||||
removed_metacodes.each do |m|
|
@removedMetacodes.each do |m|
|
||||||
inmetacodeset = InMetacodeSet.find_by(metacode_id: m, metacode_set_id: @metacode_set.id)
|
@inmetacodeset = InMetacodeSet.find_by_metacode_id_and_metacode_set_id(m, @metacode_set.id)
|
||||||
inmetacodeset.destroy
|
@inmetacodeset.destroy
|
||||||
end
|
end
|
||||||
|
|
||||||
# add the new metacodes
|
# add the new metacodes
|
||||||
added_metacodes = new_metacodes - current_metacodes
|
@addedMetacodes = @newMetacodes - @currentMetacodes
|
||||||
added_metacodes.each do |m|
|
@addedMetacodes.each do |m|
|
||||||
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class MetacodesController < ApplicationController
|
class MetacodesController < ApplicationController
|
||||||
before_action :require_admin, except: %i[index show]
|
before_action :require_admin, except: [:index, :show]
|
||||||
before_action :set_metacode, only: %i[edit update]
|
before_action :set_metacode, only: [:edit, :update]
|
||||||
|
|
||||||
# GET /metacodes
|
# GET /metacodes
|
||||||
# GET /metacodes.json
|
# GET /metacodes.json
|
||||||
|
|
|
@ -1,107 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class NotificationsController < ApplicationController
|
|
||||||
before_action :set_receipts, only: %i[index show mark_read mark_unread]
|
|
||||||
before_action :set_notification, only: %i[show mark_read mark_unread]
|
|
||||||
before_action :set_receipt, only: %i[show mark_read mark_unread]
|
|
||||||
|
|
||||||
def index
|
|
||||||
@notifications = current_user.mailbox.notifications.page(params[:page]).per(25)
|
|
||||||
respond_to do |format|
|
|
||||||
format.html
|
|
||||||
format.json do
|
|
||||||
notifications = @notifications.map do |notification|
|
|
||||||
receipt = @receipts.find_by(notification_id: notification.id)
|
|
||||||
NotificationDecorator.decorate(notification, receipt)
|
|
||||||
end
|
|
||||||
if !notifications.empty?
|
|
||||||
render json: notifications
|
|
||||||
else
|
|
||||||
render json: [].to_json
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def show
|
|
||||||
@receipt.update(is_read: true)
|
|
||||||
respond_to do |format|
|
|
||||||
format.html do
|
|
||||||
case @notification.notification_code
|
|
||||||
when MAP_ACCESS_APPROVED, MAP_INVITE_TO_EDIT
|
|
||||||
redirect_to map_path(@notification.notified_object.map)
|
|
||||||
when TOPIC_ADDED_TO_MAP
|
|
||||||
redirect_to map_path(@notification.notified_object.map)
|
|
||||||
when TOPIC_CONNECTED_1
|
|
||||||
redirect_to topic_path(@notification.notified_object.topic1)
|
|
||||||
when TOPIC_CONNECTED_2
|
|
||||||
redirect_to topic_path(@notification.notified_object.topic2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
format.json do
|
|
||||||
render json: NotificationDecorator.decorate(@notification, @receipt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def mark_read
|
|
||||||
@receipt.update(is_read: true)
|
|
||||||
respond_to do |format|
|
|
||||||
format.js
|
|
||||||
format.json do
|
|
||||||
render json: NotificationDecorator.decorate(@notification, @receipt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def mark_unread
|
|
||||||
@receipt.update(is_read: false)
|
|
||||||
respond_to do |format|
|
|
||||||
format.js
|
|
||||||
format.json do
|
|
||||||
render json: NotificationDecorator.decorate(@notification, @receipt)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def unsubscribe
|
|
||||||
unsubscribe_redirect_if_logged_out!
|
|
||||||
check_if_already_unsubscribed!
|
|
||||||
return if performed? # if one of these checks already redirected, we're done
|
|
||||||
|
|
||||||
if current_user.update(emails_allowed: false)
|
|
||||||
redirect_to edit_user_path(current_user),
|
|
||||||
notice: 'You will no longer receive emails from Metamaps.'
|
|
||||||
else
|
|
||||||
flash[:alert] = 'Sorry, something went wrong. You have not been unsubscribed from emails.'
|
|
||||||
redirect_to edit_user_path(current_user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def unsubscribe_redirect_if_logged_out!
|
|
||||||
return if current_user.present?
|
|
||||||
|
|
||||||
flash[:notice] = 'Continue to unsubscribe from emails by logging in.'
|
|
||||||
redirect_to "#{sign_in_path}?redirect_to=#{unsubscribe_notifications_path}"
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_if_already_unsubscribed!
|
|
||||||
return if current_user.emails_allowed
|
|
||||||
|
|
||||||
redirect_to edit_user_path(current_user), notice: 'You were already unsubscribed from emails.'
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_receipts
|
|
||||||
@receipts = current_user.mailboxer_notification_receipts
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_notification
|
|
||||||
@notification = current_user.mailbox.notifications.find_by(id: params[:id])
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_receipt
|
|
||||||
@receipt = @receipts.find_by(notification_id: params[:id])
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,171 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class SearchController < ApplicationController
|
|
||||||
include TopicsHelper
|
|
||||||
include MapsHelper
|
|
||||||
include UsersHelper
|
|
||||||
include SynapsesHelper
|
|
||||||
|
|
||||||
before_action :authorize_search
|
|
||||||
after_action :verify_authorized
|
|
||||||
after_action :verify_policy_scoped, only: %i[maps mappers synapses topics]
|
|
||||||
|
|
||||||
# get /search/topics?term=SOMETERM
|
|
||||||
def topics
|
|
||||||
term = params[:term]
|
|
||||||
user = params[:user] ? params[:user] : false
|
|
||||||
|
|
||||||
if term.present? && term.downcase[0..3] != 'map:' &&
|
|
||||||
term.downcase[0..6] != 'mapper:' && !term.casecmp('topic:').zero?
|
|
||||||
|
|
||||||
# remove "topic:" if appended at beginning
|
|
||||||
term = term[6..-1] if term.downcase[0..5] == 'topic:'
|
|
||||||
|
|
||||||
# if desc: search desc instead
|
|
||||||
desc = false
|
|
||||||
if term.downcase[0..4] == 'desc:'
|
|
||||||
term = term[5..-1]
|
|
||||||
desc = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# if link: search link instead
|
|
||||||
link = false
|
|
||||||
if term.downcase[0..4] == 'link:'
|
|
||||||
term = term[5..-1]
|
|
||||||
link = true
|
|
||||||
end
|
|
||||||
|
|
||||||
# check whether there's a filter by metacode as part of the query
|
|
||||||
filter_by_metacode = false
|
|
||||||
Metacode.all.each do |m|
|
|
||||||
length_one = m.name.length + 1
|
|
||||||
length_two = m.name.length
|
|
||||||
|
|
||||||
if term.downcase[0..length_two] == m.name.downcase + ':'
|
|
||||||
term = term[length_one..-1]
|
|
||||||
filter_by_metacode = m
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
search = '%' + term.downcase.strip + '%'
|
|
||||||
builder = policy_scope(Topic)
|
|
||||||
|
|
||||||
if filter_by_metacode
|
|
||||||
if term == ''
|
|
||||||
builder = builder.none
|
|
||||||
else
|
|
||||||
builder = builder.where('LOWER("name") like ? OR
|
|
||||||
LOWER("desc") like ? OR
|
|
||||||
LOWER("link") like ?', search, search, search)
|
|
||||||
builder = builder.where(metacode_id: filter_by_metacode.id)
|
|
||||||
end
|
|
||||||
elsif desc
|
|
||||||
builder = builder.where('LOWER("desc") like ?', search)
|
|
||||||
elsif link
|
|
||||||
builder = builder.where('LOWER("link") like ?', search)
|
|
||||||
else # regular case, just search the name
|
|
||||||
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
|
|
||||||
skip_policy_scope
|
|
||||||
@topics = []
|
|
||||||
end
|
|
||||||
|
|
||||||
render json: autocomplete_array_json(@topics).to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# get /search/maps?term=SOMETERM
|
|
||||||
def maps
|
|
||||||
term = params[:term]
|
|
||||||
user = params[:user] ? params[:user] : nil
|
|
||||||
|
|
||||||
if term.present? && term.downcase[0..5] != 'topic:' &&
|
|
||||||
term.downcase[0..6] != 'mapper:' && !term.casecmp('map:').zero?
|
|
||||||
|
|
||||||
# remove "map:" if appended at beginning
|
|
||||||
term = term[4..-1] if term.downcase[0..3] == 'map:'
|
|
||||||
|
|
||||||
# if desc: search desc instead
|
|
||||||
desc = false
|
|
||||||
if term.downcase[0..4] == 'desc:'
|
|
||||||
term = term[5..-1]
|
|
||||||
desc = true
|
|
||||||
end
|
|
||||||
|
|
||||||
search = '%' + term.downcase.strip + '%'
|
|
||||||
builder = policy_scope(Map)
|
|
||||||
|
|
||||||
builder = if desc
|
|
||||||
builder.where('LOWER("desc") like ?', search)
|
|
||||||
else
|
|
||||||
builder.where('LOWER("name") like ?', search)
|
|
||||||
end
|
|
||||||
builder = builder.where(user: user) if user
|
|
||||||
@maps = builder.order(:name)
|
|
||||||
else
|
|
||||||
skip_policy_scope
|
|
||||||
@maps = []
|
|
||||||
end
|
|
||||||
|
|
||||||
render json: autocomplete_map_array_json(@maps).to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# get /search/mappers?term=SOMETERM
|
|
||||||
def mappers
|
|
||||||
term = params[:term]
|
|
||||||
if term.present? && term.downcase[0..3] != 'map:' &&
|
|
||||||
term.downcase[0..5] != 'topic:' && !term.casecmp('mapper:').zero?
|
|
||||||
|
|
||||||
# remove "mapper:" if appended at beginning
|
|
||||||
term = term[7..-1] if term.downcase[0..6] == 'mapper:'
|
|
||||||
search = term.downcase.strip + '%'
|
|
||||||
|
|
||||||
builder = policy_scope(User).where('LOWER("name") like ?', search)
|
|
||||||
@mappers = builder.order(:name)
|
|
||||||
else
|
|
||||||
skip_policy_scope
|
|
||||||
@mappers = []
|
|
||||||
end
|
|
||||||
render json: autocomplete_user_array_json(@mappers).to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
# get /search/synapses?term=SOMETERM OR
|
|
||||||
# get /search/synapses?topic1id=SOMEID&topic2id=SOMEID
|
|
||||||
def synapses
|
|
||||||
term = params[:term]
|
|
||||||
topic1id = params[:topic1id]
|
|
||||||
topic2id = params[:topic2id]
|
|
||||||
|
|
||||||
if term.present?
|
|
||||||
@synapses = policy_scope(Synapse)
|
|
||||||
.where('LOWER("desc") like ?', '%' + term.downcase.strip + '%')
|
|
||||||
.order('"desc"')
|
|
||||||
|
|
||||||
@synapses = @synapses.uniq(&:desc)
|
|
||||||
elsif topic1id.present?
|
|
||||||
one = policy_scope(Synapse).where(topic1_id: topic1id, topic2_id: topic2id)
|
|
||||||
two = policy_scope(Synapse).where(topic2_id: topic1id, topic1_id: topic2id)
|
|
||||||
@synapses = one + two
|
|
||||||
@synapses.sort! { |s1, s2| s1.desc <=> s2.desc }.to_a
|
|
||||||
else
|
|
||||||
skip_policy_scope
|
|
||||||
@synapses = []
|
|
||||||
end
|
|
||||||
|
|
||||||
# limit to 5 results
|
|
||||||
@synapses = @synapses.to_a.slice(0, 5)
|
|
||||||
|
|
||||||
render json: autocomplete_synapse_array_json(@synapses).to_json
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def authorize_search
|
|
||||||
authorize :Search
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,38 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class StarsController < ApplicationController
|
|
||||||
before_action :require_user
|
|
||||||
before_action :set_map
|
|
||||||
after_action :verify_authorized
|
|
||||||
|
|
||||||
# POST maps/:id/star
|
|
||||||
def create
|
|
||||||
authorize @map, :star?
|
|
||||||
Star.find_or_create_by(map_id: @map.id, user_id: current_user.id)
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json do
|
|
||||||
render json: { message: 'Successfully starred map' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# POST maps/:id/unstar
|
|
||||||
def destroy
|
|
||||||
authorize @map, :unstar?
|
|
||||||
star = Star.find_by(map_id: @map.id, user_id: current_user.id)
|
|
||||||
star&.delete
|
|
||||||
|
|
||||||
respond_to do |format|
|
|
||||||
format.json do
|
|
||||||
render json: { message: 'Successfully unstarred map' }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def set_map
|
|
||||||
@map = Map.find(params[:id])
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,9 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class SynapsesController < ApplicationController
|
class SynapsesController < ApplicationController
|
||||||
include TopicsHelper
|
include TopicsHelper
|
||||||
|
|
||||||
before_action :require_user, only: %i[create update destroy]
|
before_action :require_user, only: [:create, :update, :destroy]
|
||||||
after_action :verify_authorized, except: :index
|
after_action :verify_authorized, except: :index
|
||||||
after_action :verify_policy_scoped, only: :index
|
after_action :verify_policy_scoped, only: :index
|
||||||
|
|
||||||
|
@ -23,20 +22,10 @@ class SynapsesController < ApplicationController
|
||||||
@synapse = Synapse.new(synapse_params)
|
@synapse = Synapse.new(synapse_params)
|
||||||
@synapse.desc = '' if @synapse.desc.nil?
|
@synapse.desc = '' if @synapse.desc.nil?
|
||||||
@synapse.desc.strip! # no trailing/leading whitespace
|
@synapse.desc.strip! # no trailing/leading whitespace
|
||||||
@synapse.user = current_user
|
authorize @synapse
|
||||||
@synapse.updated_by = current_user
|
|
||||||
|
|
||||||
# we want invalid params to return :unprocessable_entity
|
|
||||||
# so we have to authorize AFTER saving. But if authorize
|
|
||||||
# fails, we need to rollback the SQL transaction
|
|
||||||
success = nil
|
|
||||||
ActiveRecord::Base.transaction do
|
|
||||||
success = @synapse.save
|
|
||||||
success ? authorize(@synapse) : skip_authorization
|
|
||||||
end
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if success
|
if @synapse.save
|
||||||
format.json { render json: @synapse, status: :created }
|
format.json { render json: @synapse, status: :created }
|
||||||
else
|
else
|
||||||
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
||||||
|
@ -50,11 +39,9 @@ class SynapsesController < ApplicationController
|
||||||
@synapse = Synapse.find(params[:id])
|
@synapse = Synapse.find(params[:id])
|
||||||
@synapse.desc = '' if @synapse.desc.nil?
|
@synapse.desc = '' if @synapse.desc.nil?
|
||||||
authorize @synapse
|
authorize @synapse
|
||||||
@synapse.updated_by = current_user
|
|
||||||
@synapse.assign_attributes(synapse_params)
|
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
if @synapse.save
|
if @synapse.update_attributes(synapse_params)
|
||||||
format.json { head :no_content }
|
format.json { head :no_content }
|
||||||
else
|
else
|
||||||
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
||||||
|
@ -66,7 +53,6 @@ class SynapsesController < ApplicationController
|
||||||
def destroy
|
def destroy
|
||||||
@synapse = Synapse.find(params[:id])
|
@synapse = Synapse.find(params[:id])
|
||||||
authorize @synapse
|
authorize @synapse
|
||||||
@synapse.updated_by = current_user
|
|
||||||
@synapse.destroy
|
@synapse.destroy
|
||||||
|
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
|
@ -77,8 +63,6 @@ class SynapsesController < ApplicationController
|
||||||
private
|
private
|
||||||
|
|
||||||
def synapse_params
|
def synapse_params
|
||||||
params.require(:synapse).permit(
|
params.require(:synapse).permit(:id, :desc, :category, :weight, :permission, :node1_id, :node2_id, :user_id)
|
||||||
:id, :desc, :category, :weight, :permission, :topic1_id, :topic2_id
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class TokensController < ApplicationController
|
|
||||||
before_action :require_user, only: [:new]
|
|
||||||
|
|
||||||
def new
|
|
||||||
@token = Token.new(user: current_user)
|
|
||||||
render :new, layout: false
|
|
||||||
end
|
|
||||||
end
|
|