Compare commits
309 commits
feature/ex
...
develop
Author | SHA1 | Date | |
---|---|---|---|
|
98081097b4 | ||
|
f753392d49 | ||
|
38a209a970 | ||
|
bd7bf20810 | ||
|
955ebdd747 | ||
|
fdcd8a93f1 | ||
|
b5c52adf5e | ||
|
b7761a3627 | ||
|
e0d72fce14 | ||
|
139fdf8e2b | ||
|
4313f6eff8 | ||
|
91c004ebfd | ||
|
96056f43ef | ||
|
32e58fa8af | ||
|
5ebbd87afc | ||
|
006920b686 | ||
|
97448b389f | ||
|
f1ecc9eb0b | ||
|
ca2684fcf3 | ||
|
d9c53514fe | ||
|
e195b89bbd | ||
|
e66498a861 | ||
|
901eb4a513 | ||
|
cbf44e3dfe | ||
|
8b492d6dc8 | ||
|
b83f366284 | ||
|
1ac06d973c | ||
|
9af3754bc8 | ||
|
8169f24072 | ||
|
b9fb4a2829 | ||
|
9b52d0e081 | ||
|
14dc3687cd | ||
|
0a6e7918ef | ||
|
4a7595e76d | ||
|
e899179314 | ||
|
44fec58985 | ||
|
29a25c28a8 | ||
|
76c727cd61 | ||
|
693e6f5e10 | ||
|
a1d4c99ff6 | ||
|
55f2425501 | ||
|
f9c139c19e | ||
|
d51a22c5a9 | ||
|
567bc9d69d | ||
|
15f512efef | ||
|
5e6fb6290c | ||
|
8695297a0f | ||
|
216a19476b | ||
|
a0c9530c91 | ||
|
277644f59d | ||
|
0ffc01b3fb | ||
|
9471efb6bd | ||
|
fc8ac6eef1 | ||
|
9cc700c64d | ||
|
64ffc78f45 | ||
|
322da431eb | ||
|
3c7c8812a4 | ||
|
0d6963ebb0 | ||
|
c4d0bf8ce4 | ||
|
3406f2e04d | ||
|
a4c905df4e | ||
|
5f1fe4dc3f | ||
|
2515073393 | ||
|
a04cd0d395 | ||
|
da9e44afa0 | ||
|
e290244404 | ||
|
6e1878413f | ||
|
77846cfcb7 | ||
|
1ffc513617 | ||
|
3886e62a7b | ||
|
ad2ba33db6 | ||
|
cf9f54c738 | ||
|
f323796030 | ||
|
a080b82e7f | ||
|
1174123b60 | ||
|
35f77129ad | ||
|
a56991aede | ||
|
672b456193 | ||
|
21518c8696 | ||
|
29bf2a23e8 | ||
|
61eac509de | ||
|
4cc420eb63 | ||
|
ec3e09c578 | ||
|
3e03e0ebbf | ||
|
9ab7e7e170 | ||
|
5af2b8f216 | ||
|
8af66b1b2c | ||
|
9b2193ad8c | ||
|
1a8c7810be | ||
|
d87bb7c75c | ||
|
aceb3ff31e | ||
|
f26c6cf0b7 | ||
|
42f4ecb37b | ||
|
64f4249f44 | ||
|
958bd8c70c | ||
|
3830946723 | ||
|
3482e799fd | ||
|
e016b923a4 | ||
|
bb546779cd | ||
|
3829d32390 | ||
|
9783a5ee1e | ||
|
12fc0c71f6 | ||
|
c2cb8949eb | ||
|
4e7bf02749 | ||
|
3203c2b4d0 | ||
|
1ec9dc20e4 | ||
|
1af4728073 | ||
|
785e16eeae | ||
|
d08cb3f95e | ||
|
271fc7ebd0 | ||
|
9d590295cb | ||
|
dc4d44951e | ||
|
767414ad9f | ||
|
1ec897b8c8 | ||
|
00e2aefb4e | ||
|
aec0f104b8 | ||
|
db6d2e77da | ||
|
9585dce511 | ||
|
78acd7e0b0 | ||
|
328c1a14f3 | ||
|
10ac64c574 | ||
|
edce66c44d | ||
|
74df2559a4 | ||
|
a6694a3f72 | ||
|
8c7a657499 | ||
|
90f77cd4f7 | ||
|
af4dc869c0 | ||
|
2cae12e1ab | ||
|
49102ea474 | ||
|
f2a7cc1f19 | ||
|
a5d5cd6000 | ||
|
391a1d8b24 | ||
|
cc17c1ed38 | ||
|
eee1febbf9 | ||
|
c8f6374ac8 | ||
|
ed76162b63 | ||
|
1eb4187691 | ||
|
4a7dd54aca | ||
|
efd6258c7e | ||
|
f4d1b8ba35 | ||
|
47a74dd77b | ||
|
33276444c7 | ||
|
1124d76475 | ||
|
4ffa9460f5 | ||
|
44753dbfe1 | ||
|
77f76b1b5a | ||
|
e544d6a6db | ||
|
780e66632b | ||
|
de4f51bb5c | ||
|
5d0da4c5f1 | ||
|
9079d1bffc | ||
|
962881a35d | ||
|
8483b62603 | ||
|
e3b4dac1e1 | ||
|
8998e3858c | ||
|
ce51eeca8c | ||
|
3178f6e650 | ||
|
7ee96bf6c6 | ||
|
b740fef8fe | ||
|
55b031ccb7 | ||
|
9df389060e | ||
|
153cc38d1a | ||
|
4ff9619837 | ||
|
a6c1c0c730 | ||
|
529dec09a3 | ||
|
ddbaac513f | ||
|
ba943b20f1 | ||
|
4deb3f5ab9 | ||
|
47d0faadf2 | ||
|
9800cc27c6 | ||
|
7840e09e5f | ||
|
687b957737 | ||
|
9ce989eba5 | ||
|
2c85590d65 | ||
|
2b34d84715 | ||
|
013e3c7f21 | ||
|
8d771543d8 | ||
|
50639e8a0a | ||
|
9d52aa9c74 | ||
|
545706e17a | ||
|
95901e17e8 | ||
|
9dbbdf1150 | ||
|
4ee4aeaad2 | ||
|
bfdce21a66 | ||
|
53d4beddec | ||
|
d455ced683 | ||
|
d8698ef6f2 | ||
|
1374da35da | ||
|
2d0d0403b1 | ||
|
2d50f24be6 | ||
|
876c61a18e | ||
|
b0deafc53e | ||
|
a647d80efa | ||
|
559ad230ce | ||
|
26dfcbf823 | ||
|
915defcd1b | ||
|
dde097ea75 | ||
|
3706cd83e7 | ||
|
575a3ec8bf | ||
|
b2bf9978aa | ||
|
0441850504 | ||
|
3ae4072b5d | ||
|
00ecb0f6bb | ||
|
45a15da896 | ||
|
a96c8ae75c | ||
|
a137c21d2d | ||
|
952cf4e79f | ||
|
53bc4ee1c8 | ||
|
c60f7f4525 | ||
|
8df2cd8732 | ||
|
2c6da79df3 | ||
|
6e913efbae | ||
|
db81962c91 | ||
|
8330ef9679 | ||
|
696ff396b0 | ||
|
b16617286f | ||
|
fee011bba6 | ||
|
d16709e8e7 | ||
|
0ad10c0f5a | ||
|
d11278b63b | ||
|
2652d53e9b | ||
|
dc8d274487 | ||
|
2fd972ddce | ||
|
bba8231e8c | ||
|
1229e92feb | ||
|
ba3d5f07dd | ||
|
d47d7e50e7 | ||
|
af2c6ebef1 | ||
|
a9f19815e4 | ||
|
460de840b6 | ||
|
36ed85312e | ||
|
991c4cabdb | ||
|
38004c1f1f | ||
|
cd796f3ade | ||
|
c57015cb15 | ||
|
9223295320 | ||
|
b4bffbe427 | ||
|
6296df1102 | ||
|
2e0acfc170 | ||
|
99b21be27b | ||
|
2c60d7335c | ||
|
6f6e5bea06 | ||
|
6f0d391aaa | ||
|
b1a64c6e7a | ||
|
59b3d254dd | ||
|
f3539f54bf | ||
|
75ccfb0ab3 | ||
|
7b5bd53c28 | ||
|
5302f03196 | ||
|
536c458981 | ||
|
f64612f99b | ||
|
cbc38e0c93 | ||
|
42d671c05b | ||
|
08109ee5de | ||
|
0952c0f3c9 | ||
|
25b4d388de | ||
|
8b738f3d28 | ||
|
da94cd0c8b | ||
|
e9e6b1dc09 | ||
|
e84dfbaa33 | ||
|
cb95e027c4 | ||
|
8e50efb3c1 | ||
|
5ab5f6fec2 | ||
|
cbf1ec3afb | ||
|
d3315d962d | ||
|
ae05fb35d3 | ||
|
9e6ce90950 | ||
|
3868910dde | ||
|
5c1261892f | ||
|
9ada1ca935 | ||
|
df5cc4e1a8 | ||
|
ce073028c8 | ||
|
7d869d7b63 | ||
|
73e8f2d4c8 | ||
|
68f0e91259 | ||
|
b07941834c | ||
|
b914065bb3 | ||
|
33fc27ffd1 | ||
|
7ca7f0862f | ||
|
c604e69d77 | ||
|
fb12c7e202 | ||
|
9ab1c9c647 | ||
|
28d960459e | ||
|
ef84209de1 | ||
|
2d920cf66a | ||
|
40a97a5ae9 | ||
|
186129807e | ||
|
87228c27c1 | ||
|
6d8392d2e7 | ||
|
0960159265 | ||
|
88e98c7342 | ||
|
3f6f020ce1 | ||
|
8e958ec9a8 | ||
|
9debcdde39 | ||
|
b4ad51e69d | ||
|
9b95e91f1a | ||
|
c46e85529e | ||
|
85408a14d3 | ||
|
3b8a5d0c2e | ||
|
6f88c2a7eb | ||
|
f1e62fb6c1 | ||
|
0c52188014 | ||
|
7c0e0f731f | ||
|
1ba339b3be | ||
|
6129a27ecf | ||
|
d51e3f3b52 | ||
|
1317186f63 | ||
|
d6527ea80e | ||
|
00286fcc29 |
483 changed files with 16346 additions and 6166 deletions
1
.agignore
Normal file
1
.agignore
Normal file
|
@ -0,0 +1 @@
|
|||
app/assets/javascripts/metamaps.secret.bundle.js
|
|
@ -20,6 +20,8 @@ engines:
|
|||
enabled: true
|
||||
rubocop:
|
||||
enabled: true
|
||||
exclude_fingerprints:
|
||||
- 74f18007b920e8d81148d2f6a2756534
|
||||
ratings:
|
||||
paths:
|
||||
- 'Gemfile.lock'
|
||||
|
|
|
@ -6,7 +6,7 @@ export DB_USERNAME='postgres'
|
|||
export DB_PASSWORD='3112'
|
||||
export DB_HOST='localhost'
|
||||
export DB_PORT='5432'
|
||||
export DB_NAME='metamap002'
|
||||
export DB_NAME='metamaps'
|
||||
|
||||
export REALTIME_SERVER='http://localhost:5000'
|
||||
export MAILER_DEFAULT_URL='localhost:3000'
|
||||
|
|
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -15,6 +15,7 @@ app/assets/javascripts/webpacked
|
|||
|
||||
#secrets and config
|
||||
.env
|
||||
*.swp
|
||||
|
||||
# Ignore bundler config
|
||||
.bundle
|
||||
|
@ -22,6 +23,7 @@ app/assets/javascripts/webpacked
|
|||
# Ignore all logfiles and tempfiles.
|
||||
log/*.log
|
||||
tmp
|
||||
.tmp
|
||||
|
||||
coverage
|
||||
|
||||
|
@ -29,3 +31,5 @@ coverage
|
|||
*/.DS_Store
|
||||
.DS_Store?
|
||||
.vagrant
|
||||
gentle/
|
||||
startserver.sh
|
||||
|
|
10
.rubocop.yml
10
.rubocop.yml
|
@ -12,10 +12,18 @@ Rails:
|
|||
Enabled: true
|
||||
|
||||
Metrics/LineLength:
|
||||
Max: 100
|
||||
Max: 120
|
||||
|
||||
Metrics/AbcSize:
|
||||
Max: 16
|
||||
|
||||
Style/Documentation:
|
||||
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
|
||||
|
|
|
@ -22,3 +22,4 @@ script:
|
|||
addons:
|
||||
code_climate:
|
||||
repo_token: 479d3bf56798fbc7fff3fc8151a5ed09e8ac368fd5af332c437b9e07dbebb44e
|
||||
postgresql: "9.4"
|
||||
|
|
17
Gemfile
17
Gemfile
|
@ -1,15 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
source 'https://rubygems.org'
|
||||
ruby '2.3.0'
|
||||
|
||||
gem 'rails', '~> 5.0.0'
|
||||
|
||||
gem 'active_model_serializers'
|
||||
gem 'aws-sdk'
|
||||
gem 'aws-sdk', '~> 2.7.0'
|
||||
gem 'best_in_place'
|
||||
gem 'delayed_job'
|
||||
gem 'delayed_job_active_record'
|
||||
gem 'sucker_punch'
|
||||
gem 'devise'
|
||||
gem 'doorkeeper'
|
||||
gem 'dotenv-rails'
|
||||
|
@ -17,15 +17,18 @@ gem 'exception_notification'
|
|||
gem 'httparty'
|
||||
gem 'json'
|
||||
gem 'kaminari'
|
||||
gem 'mailboxer'
|
||||
gem 'paperclip'
|
||||
gem 'pg'
|
||||
gem 'puma'
|
||||
gem 'pundit'
|
||||
gem 'pundit_extra'
|
||||
gem 'rack-attack'
|
||||
gem 'rack-cors'
|
||||
gem 'redis'
|
||||
gem 'redis', '~> 3.3.3'
|
||||
gem 'slack-notifier'
|
||||
gem 'snorlax'
|
||||
gem 'sucker_punch'
|
||||
|
||||
# asset stuff
|
||||
gem 'jquery-rails'
|
||||
|
@ -34,19 +37,21 @@ gem 'sass-rails'
|
|||
gem 'uglifier'
|
||||
|
||||
group :test do
|
||||
gem 'factory_girl_rails'
|
||||
gem 'brakeman', require: false
|
||||
gem 'factory_bot_rails'
|
||||
gem 'json-schema'
|
||||
gem 'rspec-rails'
|
||||
gem 'shoulda-matchers'
|
||||
gem 'simplecov', require: false
|
||||
gem 'brakeman', require: false
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
gem 'better_errors'
|
||||
gem 'binding_of_caller'
|
||||
gem 'faker'
|
||||
gem 'pry-byebug'
|
||||
gem 'pry-rails'
|
||||
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758
|
||||
gem 'timecop'
|
||||
gem 'tunemygc'
|
||||
gem 'rubocop'
|
||||
end
|
||||
|
|
338
Gemfile.lock
338
Gemfile.lock
|
@ -1,263 +1,297 @@
|
|||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
actioncable (5.0.0.1)
|
||||
actionpack (= 5.0.0.1)
|
||||
nio4r (~> 1.2)
|
||||
actioncable (5.0.5)
|
||||
actionpack (= 5.0.5)
|
||||
nio4r (>= 1.2, < 3.0)
|
||||
websocket-driver (~> 0.6.1)
|
||||
actionmailer (5.0.0.1)
|
||||
actionpack (= 5.0.0.1)
|
||||
actionview (= 5.0.0.1)
|
||||
activejob (= 5.0.0.1)
|
||||
actionmailer (5.0.5)
|
||||
actionpack (= 5.0.5)
|
||||
actionview (= 5.0.5)
|
||||
activejob (= 5.0.5)
|
||||
mail (~> 2.5, >= 2.5.4)
|
||||
rails-dom-testing (~> 2.0)
|
||||
actionpack (5.0.0.1)
|
||||
actionview (= 5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
actionpack (5.0.5)
|
||||
actionview (= 5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
rack (~> 2.0)
|
||||
rack-test (~> 0.6.3)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
actionview (5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
actionview (5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
builder (~> 3.1)
|
||||
erubis (~> 2.7.0)
|
||||
rails-dom-testing (~> 2.0)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
||||
active_model_serializers (0.10.2)
|
||||
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
||||
active_model_serializers (0.10.6)
|
||||
actionpack (>= 4.1, < 6)
|
||||
activemodel (>= 4.1, < 6)
|
||||
jsonapi (~> 0.1.1.beta2)
|
||||
railties (>= 4.1, < 6)
|
||||
activejob (5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
case_transform (>= 0.2)
|
||||
jsonapi-renderer (>= 0.1.1.beta1, < 0.2)
|
||||
activejob (5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
globalid (>= 0.3.6)
|
||||
activemodel (5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
activerecord (5.0.0.1)
|
||||
activemodel (= 5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
activemodel (5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
activerecord (5.0.5)
|
||||
activemodel (= 5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
arel (~> 7.0)
|
||||
activesupport (5.0.0.1)
|
||||
activesupport (5.0.5)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (~> 0.7)
|
||||
minitest (~> 5.1)
|
||||
tzinfo (~> 1.1)
|
||||
addressable (2.3.8)
|
||||
arel (7.1.2)
|
||||
addressable (2.5.2)
|
||||
public_suffix (>= 2.0.2, < 4.0)
|
||||
arel (7.1.4)
|
||||
ast (2.3.0)
|
||||
aws-sdk (2.6.3)
|
||||
aws-sdk-resources (= 2.6.3)
|
||||
aws-sdk-core (2.6.3)
|
||||
aws-sdk (2.7.0)
|
||||
aws-sdk-resources (= 2.7.0)
|
||||
aws-sdk-core (2.7.0)
|
||||
aws-sigv4 (~> 1.0)
|
||||
jmespath (~> 1.0)
|
||||
aws-sdk-resources (2.6.3)
|
||||
aws-sdk-core (= 2.6.3)
|
||||
aws-sdk-resources (2.7.0)
|
||||
aws-sdk-core (= 2.7.0)
|
||||
aws-sigv4 (1.0.2)
|
||||
bcrypt (3.1.11)
|
||||
best_in_place (3.1.0)
|
||||
best_in_place (3.1.1)
|
||||
actionpack (>= 3.2)
|
||||
railties (>= 3.2)
|
||||
better_errors (2.1.1)
|
||||
better_errors (2.3.0)
|
||||
coderay (>= 1.0.0)
|
||||
erubis (>= 2.6.6)
|
||||
erubi (>= 1.0.0)
|
||||
rack (>= 0.9.0)
|
||||
binding_of_caller (0.7.2)
|
||||
debug_inspector (>= 0.0.1)
|
||||
brakeman (3.4.0)
|
||||
builder (3.2.2)
|
||||
byebug (9.0.5)
|
||||
climate_control (0.0.3)
|
||||
activesupport (>= 3.0)
|
||||
brakeman (3.7.2)
|
||||
builder (3.2.3)
|
||||
byebug (9.1.0)
|
||||
carrierwave (1.1.0)
|
||||
activemodel (>= 4.0.0)
|
||||
activesupport (>= 4.0.0)
|
||||
mime-types (>= 1.16)
|
||||
case_transform (0.2)
|
||||
activesupport
|
||||
climate_control (0.2.0)
|
||||
cocaine (0.5.8)
|
||||
climate_control (>= 0.0.3, < 1.0)
|
||||
coderay (1.1.1)
|
||||
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)
|
||||
coderay (1.1.2)
|
||||
concurrent-ruby (1.0.5)
|
||||
debug_inspector (0.0.3)
|
||||
delayed_job (4.1.3)
|
||||
activesupport (>= 3.0, < 5.2)
|
||||
delayed_job_active_record (4.1.2)
|
||||
activerecord (>= 3.0, < 5.2)
|
||||
delayed_job (>= 3.0, < 5)
|
||||
devise (4.2.0)
|
||||
devise (4.3.0)
|
||||
bcrypt (~> 3.0)
|
||||
orm_adapter (~> 0.1)
|
||||
railties (>= 4.1.0, < 5.1)
|
||||
railties (>= 4.1.0, < 5.2)
|
||||
responders
|
||||
warden (~> 1.2.3)
|
||||
diff-lcs (1.2.5)
|
||||
diff-lcs (1.3)
|
||||
docile (1.1.5)
|
||||
doorkeeper (4.2.0)
|
||||
doorkeeper (4.2.6)
|
||||
railties (>= 4.2)
|
||||
dotenv (2.1.1)
|
||||
dotenv-rails (2.1.1)
|
||||
dotenv (= 2.1.1)
|
||||
railties (>= 4.0, < 5.1)
|
||||
dotenv (2.2.1)
|
||||
dotenv-rails (2.2.1)
|
||||
dotenv (= 2.2.1)
|
||||
railties (>= 3.2, < 5.2)
|
||||
erubi (1.6.1)
|
||||
erubis (2.7.0)
|
||||
exception_notification (4.2.1)
|
||||
exception_notification (4.2.2)
|
||||
actionmailer (>= 4.0, < 6)
|
||||
activesupport (>= 4.0, < 6)
|
||||
execjs (2.7.0)
|
||||
factory_girl (4.7.0)
|
||||
factory_bot (4.8.2)
|
||||
activesupport (>= 3.0.0)
|
||||
factory_girl_rails (4.7.0)
|
||||
factory_girl (~> 4.7.0)
|
||||
factory_bot_rails (4.8.2)
|
||||
factory_bot (~> 4.8.2)
|
||||
railties (>= 3.0.0)
|
||||
globalid (0.3.7)
|
||||
activesupport (>= 4.1.0)
|
||||
httparty (0.14.0)
|
||||
faker (1.8.4)
|
||||
i18n (~> 0.5)
|
||||
ffi (1.9.18)
|
||||
globalid (0.4.0)
|
||||
activesupport (>= 4.2.0)
|
||||
httparty (0.15.6)
|
||||
multi_xml (>= 0.5.2)
|
||||
i18n (0.7.0)
|
||||
i18n (0.9.3)
|
||||
concurrent-ruby (~> 1.0)
|
||||
jmespath (1.3.1)
|
||||
jquery-rails (4.2.1)
|
||||
jquery-rails (4.3.1)
|
||||
rails-dom-testing (>= 1, < 3)
|
||||
railties (>= 4.2.0)
|
||||
thor (>= 0.14, < 2.0)
|
||||
jquery-ui-rails (5.0.5)
|
||||
jquery-ui-rails (6.0.1)
|
||||
railties (>= 3.2.16)
|
||||
json (1.8.3)
|
||||
json-schema (2.6.2)
|
||||
addressable (~> 2.3.8)
|
||||
jsonapi (0.1.1.beta2)
|
||||
json (~> 1.8)
|
||||
kaminari (0.17.0)
|
||||
actionpack (>= 3.0.0)
|
||||
activesupport (>= 3.0.0)
|
||||
json (2.1.0)
|
||||
json-schema (2.8.0)
|
||||
addressable (>= 2.4)
|
||||
jsonapi-renderer (0.1.3)
|
||||
kaminari (1.0.1)
|
||||
activesupport (>= 4.1.0)
|
||||
kaminari-actionview (= 1.0.1)
|
||||
kaminari-activerecord (= 1.0.1)
|
||||
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)
|
||||
nokogiri (>= 1.5.9)
|
||||
mail (2.6.4)
|
||||
mail (2.6.6)
|
||||
mime-types (>= 1.16, < 4)
|
||||
mailboxer (0.15.1)
|
||||
carrierwave (>= 0.5.8)
|
||||
rails (>= 5.0.0)
|
||||
method_source (0.8.2)
|
||||
mime-types (3.1)
|
||||
mime-types-data (~> 3.2015)
|
||||
mime-types-data (3.2016.0521)
|
||||
mimemagic (0.3.2)
|
||||
mini_portile2 (2.1.0)
|
||||
minitest (5.9.1)
|
||||
multi_xml (0.5.5)
|
||||
nio4r (1.2.1)
|
||||
nokogiri (1.6.8)
|
||||
mini_portile2 (~> 2.1.0)
|
||||
pkg-config (~> 1.1.7)
|
||||
mini_portile2 (2.3.0)
|
||||
minitest (5.11.1)
|
||||
multi_xml (0.6.0)
|
||||
nio4r (2.1.0)
|
||||
nokogiri (1.8.1)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
orm_adapter (0.5.0)
|
||||
paperclip (5.1.0)
|
||||
paperclip (5.2.0)
|
||||
activemodel (>= 4.2.0)
|
||||
activesupport (>= 4.2.0)
|
||||
cocaine (~> 0.5.5)
|
||||
mime-types
|
||||
mimemagic (~> 0.3.0)
|
||||
parser (2.3.1.4)
|
||||
ast (~> 2.2)
|
||||
pg (0.19.0)
|
||||
pkg-config (1.1.7)
|
||||
parser (2.4.0.2)
|
||||
ast (~> 2.3)
|
||||
pg (0.21.0)
|
||||
powerpack (0.1.1)
|
||||
pry (0.10.4)
|
||||
coderay (~> 1.1.0)
|
||||
method_source (~> 0.8.1)
|
||||
slop (~> 3.4)
|
||||
pry-byebug (3.4.0)
|
||||
byebug (~> 9.0)
|
||||
pry-byebug (3.5.0)
|
||||
byebug (~> 9.1)
|
||||
pry (~> 0.10)
|
||||
pry-rails (0.3.4)
|
||||
pry (>= 0.9.10)
|
||||
pry-rails (0.3.6)
|
||||
pry (>= 0.10.4)
|
||||
public_suffix (3.0.0)
|
||||
puma (3.10.0)
|
||||
pundit (1.1.0)
|
||||
activesupport (>= 3.0.0)
|
||||
pundit_extra (0.3.0)
|
||||
rack (2.0.1)
|
||||
rack (2.0.3)
|
||||
rack-attack (5.0.1)
|
||||
rack
|
||||
rack-cors (0.4.0)
|
||||
rack-cors (1.0.1)
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (5.0.0.1)
|
||||
actioncable (= 5.0.0.1)
|
||||
actionmailer (= 5.0.0.1)
|
||||
actionpack (= 5.0.0.1)
|
||||
actionview (= 5.0.0.1)
|
||||
activejob (= 5.0.0.1)
|
||||
activemodel (= 5.0.0.1)
|
||||
activerecord (= 5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
bundler (>= 1.3.0, < 2.0)
|
||||
railties (= 5.0.0.1)
|
||||
rails (5.0.5)
|
||||
actioncable (= 5.0.5)
|
||||
actionmailer (= 5.0.5)
|
||||
actionpack (= 5.0.5)
|
||||
actionview (= 5.0.5)
|
||||
activejob (= 5.0.5)
|
||||
activemodel (= 5.0.5)
|
||||
activerecord (= 5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
bundler (>= 1.3.0)
|
||||
railties (= 5.0.5)
|
||||
sprockets-rails (>= 2.0.0)
|
||||
rails-dom-testing (2.0.1)
|
||||
activesupport (>= 4.2.0, < 6.0)
|
||||
nokogiri (~> 1.6.0)
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
railties (5.0.0.1)
|
||||
actionpack (= 5.0.0.1)
|
||||
activesupport (= 5.0.0.1)
|
||||
railties (5.0.5)
|
||||
actionpack (= 5.0.5)
|
||||
activesupport (= 5.0.5)
|
||||
method_source
|
||||
rake (>= 0.8.7)
|
||||
thor (>= 0.18.1, < 2.0)
|
||||
rainbow (2.1.0)
|
||||
rake (11.3.0)
|
||||
redis (3.3.1)
|
||||
responders (2.3.0)
|
||||
railties (>= 4.2.0, < 5.1)
|
||||
rspec-core (3.5.3)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-expectations (3.5.0)
|
||||
rainbow (2.2.2)
|
||||
rake
|
||||
rake (12.3.0)
|
||||
rb-fsevent (0.10.2)
|
||||
rb-inotify (0.9.10)
|
||||
ffi (>= 0.5.0, < 2)
|
||||
redis (3.3.3)
|
||||
responders (2.4.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)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-mocks (3.5.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-mocks (3.6.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-rails (3.5.2)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-rails (3.6.1)
|
||||
actionpack (>= 3.0)
|
||||
activesupport (>= 3.0)
|
||||
railties (>= 3.0)
|
||||
rspec-core (~> 3.5.0)
|
||||
rspec-expectations (~> 3.5.0)
|
||||
rspec-mocks (~> 3.5.0)
|
||||
rspec-support (~> 3.5.0)
|
||||
rspec-support (3.5.0)
|
||||
rubocop (0.43.0)
|
||||
parser (>= 2.3.1.1, < 3.0)
|
||||
rspec-core (~> 3.6.0)
|
||||
rspec-expectations (~> 3.6.0)
|
||||
rspec-mocks (~> 3.6.0)
|
||||
rspec-support (~> 3.6.0)
|
||||
rspec-support (3.6.0)
|
||||
rubocop (0.48.1)
|
||||
parser (>= 2.3.3.1, < 3.0)
|
||||
powerpack (~> 0.1)
|
||||
rainbow (>= 1.99.1, < 3.0)
|
||||
ruby-progressbar (~> 1.7)
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-progressbar (1.8.1)
|
||||
sass (3.4.22)
|
||||
ruby-progressbar (1.9.0)
|
||||
sass (3.5.1)
|
||||
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)
|
||||
railties (>= 4.0.0, < 6)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
tilt (>= 1.1, < 3)
|
||||
shoulda-matchers (3.1.1)
|
||||
shoulda-matchers (3.1.2)
|
||||
activesupport (>= 4.0.0)
|
||||
simplecov (0.12.0)
|
||||
simplecov (0.15.0)
|
||||
docile (~> 1.1.0)
|
||||
json (>= 1.8, < 3)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
slack-notifier (1.5.1)
|
||||
simplecov-html (0.10.2)
|
||||
slack-notifier (2.3.1)
|
||||
slop (3.6.0)
|
||||
snorlax (0.1.6)
|
||||
rails (> 4.1)
|
||||
sprockets (3.7.0)
|
||||
sprockets (3.7.1)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.2.0)
|
||||
sprockets-rails (3.2.1)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
sucker_punch (2.0.2)
|
||||
sucker_punch (2.0.3)
|
||||
concurrent-ruby (~> 1.0.0)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
tilt (2.0.5)
|
||||
tunemygc (1.0.68)
|
||||
tzinfo (1.2.2)
|
||||
thor (0.20.0)
|
||||
thread_safe (0.3.6)
|
||||
tilt (2.0.8)
|
||||
timecop (0.9.1)
|
||||
tunemygc (1.0.69)
|
||||
tzinfo (1.2.4)
|
||||
thread_safe (~> 0.1)
|
||||
uglifier (3.0.2)
|
||||
uglifier (3.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
unicode-display_width (1.1.1)
|
||||
warden (1.2.6)
|
||||
unicode-display_width (1.3.0)
|
||||
warden (1.2.7)
|
||||
rack (>= 1.0)
|
||||
websocket-driver (0.6.4)
|
||||
websocket-driver (0.6.5)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
|
||||
|
@ -266,7 +300,7 @@ PLATFORMS
|
|||
|
||||
DEPENDENCIES
|
||||
active_model_serializers
|
||||
aws-sdk
|
||||
aws-sdk (~> 2.7.0)
|
||||
best_in_place
|
||||
better_errors
|
||||
binding_of_caller
|
||||
|
@ -277,31 +311,35 @@ DEPENDENCIES
|
|||
doorkeeper
|
||||
dotenv-rails
|
||||
exception_notification
|
||||
factory_girl_rails
|
||||
factory_bot_rails
|
||||
faker
|
||||
httparty
|
||||
jquery-rails
|
||||
jquery-ui-rails
|
||||
json
|
||||
json-schema
|
||||
kaminari
|
||||
mailboxer
|
||||
paperclip
|
||||
pg
|
||||
pry-byebug
|
||||
pry-rails
|
||||
puma
|
||||
pundit
|
||||
pundit_extra
|
||||
rack-attack
|
||||
rack-cors
|
||||
rails (~> 5.0.0)
|
||||
redis
|
||||
redis (~> 3.3.3)
|
||||
rspec-rails
|
||||
rubocop
|
||||
rubocop (~> 0.48.1)
|
||||
sass-rails
|
||||
shoulda-matchers
|
||||
simplecov
|
||||
slack-notifier
|
||||
snorlax
|
||||
sucker_punch
|
||||
timecop
|
||||
tunemygc
|
||||
uglifier
|
||||
|
||||
|
@ -309,4 +347,4 @@ RUBY VERSION
|
|||
ruby 2.3.0p0
|
||||
|
||||
BUNDLED WITH
|
||||
1.13.6
|
||||
1.16.1
|
||||
|
|
2
Procfile
2
Procfile
|
@ -1,3 +1,3 @@
|
|||
web: bundle exec rails server -p $PORT
|
||||
web: bundle exec puma -p $PORT
|
||||
worker: bundle exec rake jobs:work
|
||||
|
||||
|
|
54
README.md
54
README.md
|
@ -2,6 +2,7 @@ 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?
|
||||
|
||||
|
@ -16,44 +17,30 @@ Metamaps is developed and maintained by a distributed, nomadic community compris
|
|||
- 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)
|
||||
- Development Roadmap: [github.com/metamaps/metamaps/milestones](https://github.com/metamaps/metamaps/milestones)
|
||||
- To send us a personal message or request an invite to the open beta, get in touch with us via email, Twitter, or Hylo
|
||||
- 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 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 get set up as a developer, that's great! Read on for help getting your development environment set up.
|
||||
|
||||
## Installation
|
||||
## Installation for local use or development of Metamaps
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
To start servers which will run metamaps you can then run:
|
||||
```
|
||||
./bin/start
|
||||
```
|
||||
To stop them:
|
||||
```
|
||||
./bin/stop
|
||||
```
|
||||
With your webservers running, open a web browser and go to `http://localhost:3000`
|
||||
There are instructions for setup on various platforms, with particular support for Mac and Ubuntu, which can be found here:
|
||||
- [Mac Install Walkthrough][mac-installation]
|
||||
- [Ubuntu Install Walkthrough][ubuntu-installation]
|
||||
|
||||
You can sign in with the default account
|
||||
email: `user@user.com`
|
||||
password: `toolsplusconsciousness`
|
||||
OR create a new account at `/join`, and use access code `qwertyui`
|
||||
If you prefer to isolate your install in a virtual machine, you may find it simpler to setup using Vagrant:
|
||||
- [Vagrant installation][vagrant-installation]
|
||||
|
||||
Start mapping and programming!
|
||||
|
||||
We haven't set up instructions for using Vagrant on Windows, but there are instructions for a manual setup here:
|
||||
|
||||
- [For Windows][windows-installation]
|
||||
We don't promise support for Windows, but at one point we had it running and we've kept those docs available for reference
|
||||
- [Outdated Windows Walkthrough][windows-installation]
|
||||
|
||||
## Licensing information
|
||||
|
||||
|
@ -63,10 +50,13 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|||
|
||||
The license can be read [here][license].
|
||||
|
||||
Copyright (c) 2016 Connor Turland
|
||||
Copyright (c) 2017 Connor Turland
|
||||
|
||||
[site-beta]: http://metamaps.cc
|
||||
[license]: https://github.com/metamaps/metamaps/blob/develop/LICENSE
|
||||
[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
|
||||
[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
|
||||
|
|
1
Rakefile
Normal file → Executable file
1
Rakefile
Normal file → Executable file
|
@ -1,5 +1,6 @@
|
|||
#!/usr/bin/env rake
|
||||
# frozen_string_literal: true
|
||||
|
||||
# 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.
|
||||
|
||||
|
|
2
Vagrantfile
vendored
2
Vagrantfile
vendored
|
@ -37,7 +37,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
|||
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.network :forwarded_port, guest: 3000, host: 3000
|
||||
config.vm.network :forwarded_port, guest: 5001, host: 5001
|
||||
config.vm.network :forwarded_port, guest: 5000, host: 5000
|
||||
config.vm.network 'private_network', ip: '10.0.1.11'
|
||||
config.vm.synced_folder '.', '/vagrant', nfs: true
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
// eslint-disable spaced-comment
|
||||
// JS and CSS bundles
|
||||
//= link_directory ../javascripts .js
|
||||
//= link_directory ../stylesheets .css
|
||||
|
|
BIN
app/assets/images/.DS_Store
vendored
BIN
app/assets/images/.DS_Store
vendored
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 543 B |
Binary file not shown.
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
app/assets/images/user_sprite.png
Executable file → Normal file
BIN
app/assets/images/user_sprite.png
Executable file → Normal file
Binary file not shown.
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.6 KiB |
|
@ -10,6 +10,9 @@ Metamaps.ServerData['topic_link_signifier.png'] = '<%= asset_path('topic_link_si
|
|||
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'] %>'
|
||||
|
|
23
app/assets/javascripts/application-secret.js
Normal file
23
app/assets/javascripts/application-secret.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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 */
|
|
@ -1,4 +1,3 @@
|
|||
// eslint-disable spaced-comment
|
||||
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
||||
// listed below.
|
||||
//
|
||||
|
@ -10,11 +9,14 @@
|
|||
//
|
||||
// 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 ./webpacked/metamaps.bundle
|
||||
//= require ./Metamaps.ServerData
|
||||
//= require homepageVimeoFallback
|
||||
/* eslint-enable spaced-comment */
|
||||
|
|
438
app/assets/javascripts/cloudcarousel-secret.js
Normal file
438
app/assets/javascripts/cloudcarousel-secret.js
Normal file
|
@ -0,0 +1,438 @@
|
|||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// 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,14 +1,14 @@
|
|||
/* global $ */
|
||||
|
||||
$(document).ready(function () {
|
||||
$(document).ready(function() {
|
||||
if (window.location.pathname === '/') {
|
||||
$.ajax({
|
||||
type: 'GET',
|
||||
url: 'https://player.vimeo.com',
|
||||
error: function (e) {
|
||||
url: 'https://i.vimeocdn.com/video/',
|
||||
error: function(e) {
|
||||
$('.homeVideo').hide()
|
||||
$('.homeVideo').replaceWith($('<video/>', {
|
||||
poster: '/assets/metamaps-intro-poster.webp',
|
||||
poster: '<%= asset_path('metamaps-intro-poster.webp') %>',
|
||||
width: '560',
|
||||
height: '315',
|
||||
class: 'homeVideo',
|
161
app/assets/javascripts/lib/ajaxq.js
Normal file
161
app/assets/javascripts/lib/ajaxq.js
Normal file
|
@ -0,0 +1,161 @@
|
|||
// 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] = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}));
|
3836
app/assets/javascripts/metamaps.secret.bundle.js
Normal file
3836
app/assets/javascripts/metamaps.secret.bundle.js
Normal file
File diff suppressed because one or more lines are too long
12
app/assets/secret_stylesheets/application-secret.scss.erb
Normal file
12
app/assets/secret_stylesheets/application-secret.scss.erb
Normal file
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
109
app/assets/secret_stylesheets/special.scss.erb
Normal file
109
app/assets/secret_stylesheets/special.scss.erb
Normal file
|
@ -0,0 +1,109 @@
|
|||
#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,16 +56,15 @@
|
|||
}
|
||||
|
||||
li.toggledOff {
|
||||
opacity: 0.4;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.blackBox {
|
||||
.centerContent {
|
||||
width: 760px;
|
||||
margin: 0 auto;
|
||||
padding: 80px 0 60px 20px;
|
||||
background: rgba(0, 0, 0, 0.4);
|
||||
color: white;
|
||||
background: rgba(125, 125, 125, 0.4);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
|
@ -85,10 +84,10 @@
|
|||
display: table-row;
|
||||
}
|
||||
tr:nth-child(odd) {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
background: rgba(125, 125, 125, 0.2);
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
background: rgba(125, 125, 125, 0.3);
|
||||
}
|
||||
th,
|
||||
td {
|
||||
|
|
|
@ -193,10 +193,6 @@ button.button.btn-no:hover {
|
|||
display: block;
|
||||
width: 830px;
|
||||
}
|
||||
.requestInvite {
|
||||
display: block;
|
||||
margin: -720px auto 0;
|
||||
}
|
||||
.new_session,
|
||||
.new_user,
|
||||
.edit_user,
|
||||
|
@ -531,10 +527,12 @@ button.button.btn-no:hover {
|
|||
left: -1000px;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 340px;
|
||||
margin: -40px 0 0 -35px;
|
||||
z-index: 1;
|
||||
}
|
||||
body:not(.action-conversation) .new_topic {
|
||||
width: 340px;
|
||||
}
|
||||
|
||||
#new_topic .twitter-typeahead {
|
||||
position: absolute !important;
|
||||
|
@ -670,9 +668,21 @@ label {
|
|||
position: relative;
|
||||
/*overflow:hidden; */
|
||||
}
|
||||
.main.compressed {
|
||||
width: calc(100% - 300px);
|
||||
.compressed {
|
||||
.upperRightUI {
|
||||
right: 324px;
|
||||
}
|
||||
.upperRightMapButtons {
|
||||
right: 434px;
|
||||
}
|
||||
.mapControls {
|
||||
right: 324px;
|
||||
}
|
||||
.infoAndHelp {
|
||||
right: 370px;
|
||||
}
|
||||
}
|
||||
|
||||
#infovis-canvas {
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
|
@ -773,9 +783,9 @@ label {
|
|||
}
|
||||
.sidebarAccountIcon img {
|
||||
border-radius: 16px;
|
||||
width: 32px;
|
||||
}
|
||||
.sidebarAccountBox {
|
||||
display: none;
|
||||
height: auto;
|
||||
}
|
||||
.authenticated .sidebarAccountBox {
|
||||
|
@ -816,6 +826,7 @@ label {
|
|||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
color: #757575;
|
||||
cursor: pointer;
|
||||
}
|
||||
.accountListItem:hover {
|
||||
color: #424242;
|
||||
|
@ -826,7 +837,7 @@ label {
|
|||
position:absolute;
|
||||
pointer-events:none;
|
||||
background-repeat:no-repeat;
|
||||
background-image: url(<%= asset_data_uri('user_sprite.png') %>);
|
||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
||||
}
|
||||
.accountSettings .accountIcon {
|
||||
background-position: 0 0;
|
||||
|
@ -1037,7 +1048,6 @@ label[for="user_remember_me"] {
|
|||
}
|
||||
|
||||
.sidebarFilterBox {
|
||||
display:none;
|
||||
width: 319px;
|
||||
padding: 16px 0;
|
||||
overflow-y: auto;
|
||||
|
@ -1248,7 +1258,7 @@ h3.filterBox {
|
|||
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-metacode:hover > ul,
|
||||
.rightclickmenu .rc-metacode:hover #metacodeOptions > ul,
|
||||
.rightclickmenu .rc-siblings:hover > ul {
|
||||
display: block;
|
||||
}
|
||||
|
@ -1277,7 +1287,7 @@ h3.filterBox {
|
|||
.rightclickmenu li.toPrivate .rc-perm-icon {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
.rightclickmenu .rc-metacode > ul > li,
|
||||
.rightclickmenu .rc-metacode #metacodeOptions > ul > li,
|
||||
.rightclickmenu .rc-siblings > ul > li {
|
||||
padding: 6px 24px 6px 8px;
|
||||
white-space: nowrap;
|
||||
|
@ -1558,6 +1568,7 @@ h3.filterBox {
|
|||
box-sizing: border-box;
|
||||
margin: 0.75em;
|
||||
padding: 0.75em;
|
||||
padding-top: 0.85em;
|
||||
height: 3em;
|
||||
background-color: #AAB0FB;
|
||||
border-radius: 0.3em;
|
||||
|
@ -1904,14 +1915,10 @@ input.collaboratorSearchField {
|
|||
background-position: -32px 0;
|
||||
}
|
||||
.yourMap .mapPermission:hover {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||
cursor: pointer;
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.yourMap .mapPermission.minimize {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||
cursor: pointer;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.mapInfoBox .mapPermission .permissionSelect {
|
||||
list-style: none;
|
||||
|
@ -2012,6 +2019,7 @@ input.collaboratorSearchField {
|
|||
position: relative;
|
||||
cursor: pointer;
|
||||
display: none;
|
||||
padding: 0 2px;
|
||||
}
|
||||
.mapInfoShareIcon {
|
||||
width: 24px;
|
||||
|
@ -2051,6 +2059,43 @@ and it won't be important on password protected instances */
|
|||
.yourMap .mapInfoDelete {
|
||||
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 {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
|
@ -2270,6 +2315,9 @@ and it won't be important on password protected instances */
|
|||
}
|
||||
/* switch metacode set */
|
||||
|
||||
#switchMetacodes > p {
|
||||
margin: 16px 0 16px 0;
|
||||
}
|
||||
#metacodeSwitchTabs {
|
||||
width: 100%;
|
||||
font-size: 17px;
|
||||
|
@ -2277,28 +2325,43 @@ and it won't be important on password protected instances */
|
|||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
#metacodeSwitchTabs .setDesc {
|
||||
margin-bottom: 5px;
|
||||
font-family: 'din-medium', helvetica, sans-serif;
|
||||
color: #424242;
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
padding-right: 16px;
|
||||
}
|
||||
#switchMetacodes > p {
|
||||
margin: 16px 0 16px 0;
|
||||
}
|
||||
#metacodeSwitchTabs > ul {
|
||||
width: 130px;
|
||||
}
|
||||
#metacodeSwitchTabs > ul li {
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
#metacodeSwitchTabs li.ui-state-active a {
|
||||
color: #00BCD4;
|
||||
cursor: pointer;
|
||||
|
||||
.setDesc,
|
||||
.selectAll,
|
||||
.selectNone {
|
||||
margin-bottom: 5px;
|
||||
font-family: 'din-medium', helvetica, sans-serif;
|
||||
color: #424242;
|
||||
font-size: 14px;
|
||||
text-align: justify;
|
||||
padding-right: 16px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.selectAll,
|
||||
.selectNone {
|
||||
float: right;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover,
|
||||
&.selected {
|
||||
color: #00bcd4;
|
||||
}
|
||||
}
|
||||
|
||||
& > ul {
|
||||
width: 130px;
|
||||
|
||||
li {
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
|
||||
li.ui-state-active a {
|
||||
color: #00BCD4;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.metacodeSwitchTab {
|
||||
max-height: 300px;
|
||||
|
@ -2867,146 +2930,18 @@ and it won't be important on password protected instances */
|
|||
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 */
|
||||
|
||||
#wrapper .requestInvite {
|
||||
.requestInvite {
|
||||
width: 700px;
|
||||
margin: 0 auto;
|
||||
padding: 0 0 60px 0;
|
||||
background: #FFFFFF;
|
||||
color: white;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
height: calc(100% - 52px);
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
left: 50%;
|
||||
margin-left: -350px;
|
||||
margin-top: 52px;
|
||||
}
|
||||
|
||||
.home_bg {
|
||||
|
@ -3076,3 +3011,21 @@ script.data-gratipay-username {
|
|||
display: inline;
|
||||
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,17 +1,14 @@
|
|||
.centerContent {
|
||||
position: relative;
|
||||
margin: 92px auto 0 auto;
|
||||
padding: 20px 0 60px 20px;
|
||||
width: 760px;
|
||||
margin: 0 auto;
|
||||
width: auto;
|
||||
max-width: 800px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,.12),0 1px 2px rgba(0,0,0,.24);
|
||||
background: #fff;
|
||||
-webkit-border-radius: 3px;
|
||||
-moz-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #dcdcdc;
|
||||
margin-bottom: 10px;
|
||||
box-sizing: border-box;
|
||||
padding: 15px;
|
||||
font-family: 'din-regular', sans-serif;
|
||||
}
|
||||
|
||||
.centerContent .page-header {
|
||||
|
@ -129,3 +126,9 @@
|
|||
box-sizing: border-box;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.centerContent.withPadding {
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
$mid-gray: #8A8A8A;
|
||||
$mid-gray-opacity: rgba(66, 66, 66, 0.6);
|
||||
|
||||
.nameCounter {
|
||||
position: absolute;
|
||||
bottom: 1px;
|
||||
right: 2px;
|
||||
font-size: 11px;
|
||||
font-family: helvetica;
|
||||
font-family: helvetica, sans-serif;
|
||||
color: #727272;
|
||||
line-height: 11px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.riek-editing + .nameCounter {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nameCounter.forMap {
|
||||
|
@ -14,21 +22,20 @@
|
|||
}
|
||||
|
||||
.nameCounter.forTopic {
|
||||
|
||||
|
||||
}
|
||||
|
||||
#center-container {
|
||||
position:relative;
|
||||
height:100%;
|
||||
width:100%;
|
||||
|
||||
|
||||
/* background-color:#031924; */
|
||||
color:#444;
|
||||
}
|
||||
|
||||
.showcard {
|
||||
position:absolute;
|
||||
display:none;
|
||||
top:100px;
|
||||
left:100px;
|
||||
width:300px;
|
||||
|
@ -38,7 +45,7 @@
|
|||
z-index:2;
|
||||
color: #424242;
|
||||
border-radius:2px;
|
||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||
box-shadow: 2px 3px 3px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
||||
}
|
||||
|
||||
.text {
|
||||
|
@ -49,7 +56,6 @@
|
|||
width:100%;
|
||||
height:100%;
|
||||
position: absolute;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.showcard .permission {
|
||||
|
@ -61,7 +67,6 @@
|
|||
display:block;
|
||||
position:relative;
|
||||
width:100%;
|
||||
min-height:360px;
|
||||
z-index: 25;
|
||||
}
|
||||
.CardOnGraph.hasAttachment {
|
||||
|
@ -70,11 +75,10 @@
|
|||
|
||||
.CardOnGraph .title {
|
||||
word-break: break-word;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
display: table;
|
||||
padding: 8px 0 16px;
|
||||
height: 80px;
|
||||
padding: 20px 0;
|
||||
text-align: center;
|
||||
font-family: 'din-regular', sans-serif;
|
||||
width: 300px;
|
||||
|
@ -93,12 +97,11 @@
|
|||
cursor: text;
|
||||
}
|
||||
|
||||
.showcard .best_in_place_name textarea, .showcard .best_in_place_name input {
|
||||
.showcard .title .riek-editing {
|
||||
font-family: 'din-regular', sans-serif;
|
||||
color: #424242;
|
||||
font-size: 18px;
|
||||
line-height: 22px;
|
||||
height: 15px;
|
||||
font-size: 20px;
|
||||
line-height: 24px;
|
||||
padding: 5px 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
|
@ -112,30 +115,40 @@
|
|||
.CardOnGraph .scroll {
|
||||
display:block;
|
||||
padding: 8px 0 8px 16px;
|
||||
height: 152px;
|
||||
font-size: 13px;
|
||||
line-height:15px;
|
||||
font-family: helvetica, sans-serif;
|
||||
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 {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.CardOnGraph .best_in_place_desc textarea {
|
||||
.CardOnGraph .desc .riek-editing {
|
||||
font-size: 13px;
|
||||
line-height:15px;
|
||||
font-family: helvetica, sans-serif;
|
||||
color: #424242;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
width: 258px;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: none;
|
||||
font-size: 12px;
|
||||
line-height: 15px;
|
||||
background: none;
|
||||
resize: none;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -167,13 +180,11 @@
|
|||
* End Markdown styling
|
||||
*/
|
||||
|
||||
.CardOnGraph .best_in_place_desc {
|
||||
.CardOnGraph .riek_desc {
|
||||
display:block;
|
||||
margin-top:2px;
|
||||
padding-right: 18px;
|
||||
margin-right: 8px;
|
||||
padding-right: 26px;
|
||||
}
|
||||
.canEdit .CardOnGraph .best_in_place_desc:hover {
|
||||
.canEdit .CardOnGraph .riek_desc:not(.riek-editing):hover {
|
||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||
background-position: top right;
|
||||
background-repeat: no-repeat;
|
||||
|
@ -185,155 +196,215 @@
|
|||
}
|
||||
|
||||
.CardOnGraph .links {
|
||||
position:relative;
|
||||
border-bottom: 1px solid #BDBDBD;
|
||||
border-top: 1px solid #BDBDBD;
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
.linkItem {
|
||||
float:left;
|
||||
height:46px;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
color: #424242;
|
||||
font-size: 14px;
|
||||
line-height:14px;
|
||||
height:12px;
|
||||
padding:17px 0;
|
||||
}
|
||||
.linkItem a {
|
||||
color: #424242;
|
||||
z-index: 2;
|
||||
|
||||
.linkItem {
|
||||
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 .icon {
|
||||
position:absolute;
|
||||
width:100%;
|
||||
z-index:1;
|
||||
padding: 0;
|
||||
height: 48px;
|
||||
}
|
||||
.linkItem.contributor {
|
||||
margin-left:40px;
|
||||
z-index:1;
|
||||
padding:17px 16px 17px 30px;
|
||||
.CardOnGraph .info {
|
||||
position: relative;
|
||||
}
|
||||
.contributor .contributorIcon {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
left: 0;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
.contributor:hover .contributorName {
|
||||
display: block;
|
||||
}
|
||||
.linkItem {
|
||||
float: left;
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
color: $mid-gray-opacity;
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
|
||||
.contributorName {
|
||||
display: none;
|
||||
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;
|
||||
}
|
||||
a {
|
||||
color: $mid-gray-opacity;
|
||||
}
|
||||
}
|
||||
|
||||
.contributor div:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 128%;
|
||||
left: 13px;
|
||||
margin-top: -30px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-bottom: 4px solid #000000;
|
||||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.contributor {
|
||||
bottom: 7px;
|
||||
margin-left: 16px;
|
||||
|
||||
.linkItem.mapCount {
|
||||
margin-left: 12px;
|
||||
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;
|
||||
}
|
||||
.contributorIcon {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
border-radius: 16px;
|
||||
margin: 5px 5px 5px 0;
|
||||
top: 11px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.linkItem.mapCount:hover .hoverTip {
|
||||
display: block;
|
||||
}
|
||||
.CardOnGraph .mapCount .tip, .CardonGraph .mapCount .hoverTip {
|
||||
top: 44px;
|
||||
left: 0px;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
span {
|
||||
font-family: 'din-regular', sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.hoverTip {
|
||||
white-space: nowrap;
|
||||
font-family: 'din-regular';
|
||||
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;
|
||||
}
|
||||
.contributorName {
|
||||
font-family: din-regular;
|
||||
margin-top: 20px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 97px;
|
||||
padding: 0 8px 0 4px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
|
||||
.mapCount {
|
||||
padding:17px 38px 17px 0;
|
||||
width: 22px;
|
||||
text-align: right;
|
||||
|
||||
.CardOnGraph .mapCount .tip:before, .CardOnGraph .mapCount .hoverTip:before {
|
||||
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;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
|
||||
.CardOnGraph .mapCount .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;
|
||||
}
|
||||
&:hover .mapCountIcon {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
|
||||
.CardOnGraph .mapCount li.hideExtra {
|
||||
display: none;
|
||||
.tip, .hoverTip {
|
||||
top: 44px;
|
||||
right: 0px;
|
||||
font-size: 12px !important;
|
||||
|
||||
&:before {
|
||||
content: '';
|
||||
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 {
|
||||
|
@ -341,66 +412,10 @@
|
|||
color: #4FC059;
|
||||
}
|
||||
|
||||
.mapCount .tip a {
|
||||
color: white;
|
||||
.linkItem.mapPerm {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.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 {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
|
@ -422,14 +437,10 @@
|
|||
}
|
||||
|
||||
.yourTopic .mapPerm:hover, .yourEdge .mapPerm:hover {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>);
|
||||
background-position: -32px 0;
|
||||
cursor:pointer;
|
||||
}
|
||||
.yourTopic .mapPerm.minimize, .yourEdge .mapPerm.minimize {
|
||||
background-image: url(<%= asset_data_uri('arrowperms_sprite.png') %>) !important;
|
||||
background-position: 0 0;
|
||||
cursor: pointer;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mapPerm .permissionSelect {
|
||||
list-style: none;
|
||||
|
@ -465,63 +476,55 @@ cursor: pointer;
|
|||
}
|
||||
|
||||
.CardOnGraph .metacodeTitle {
|
||||
font-style: italic;
|
||||
font-family: 'vinyl';
|
||||
text-transform: uppercase;
|
||||
position: absolute;
|
||||
font-family: 'din-regular';
|
||||
line-height: 24px;
|
||||
height:24px;
|
||||
font-size: 24px;
|
||||
display: none;
|
||||
width: 90%;
|
||||
padding: 13px 0 9px 10%;
|
||||
background-color: #E0E0E0;
|
||||
height: 26px;
|
||||
font-size: 18px;
|
||||
padding: 13px 24px 9px 24px;
|
||||
color: #424242;
|
||||
width: 120px;
|
||||
max-width: 120px;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
.permission.canEdit .metacodeTitle {
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
.permission.canEdit .expandMetacodeSelect {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
left: 4px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
background-image: url(<%= asset_data_uri('arrowright_sprite.png') %>);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 -32px;
|
||||
display: inline-block;
|
||||
-webkit-transform: rotate(90deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
.permission.canEdit .minimize .expandMetacodeSelect {
|
||||
|
||||
|
||||
}
|
||||
|
||||
.CardOnGraph .metacodeImage {
|
||||
cursor:move;
|
||||
width:46px;
|
||||
height:46px;
|
||||
position:absolute;
|
||||
left:-23px;
|
||||
top:0;
|
||||
background-size:46px 46px;
|
||||
background-position:0 0;
|
||||
background-repeat:no-repeat;
|
||||
.CardOnGraph .metacodeName {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
#metacodeOptions {
|
||||
display:none;
|
||||
}
|
||||
.CardOnGraph .metacodeSelect {
|
||||
display:none;
|
||||
width:auto;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
background: #EAEAEA;
|
||||
left: 300px;
|
||||
white-space: nowrap;
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
box-shadow: 2px 2px 2px rgba(125, 125, 125, 0.23), -2px -1px 3px rgba(125, 125, 125, 0.16);
|
||||
}
|
||||
.CardOnGraph .metacodeSelect ul {
|
||||
position: relative;
|
||||
position: relative;
|
||||
line-height: 14px;
|
||||
font-size: 14px;
|
||||
font-family: helvetica, sans-serif;
|
||||
|
@ -610,11 +613,10 @@ background-color: #E0E0E0;
|
|||
display:block;
|
||||
}
|
||||
.CardOnGraph .tip {
|
||||
display:none;
|
||||
position: absolute;
|
||||
background: black;
|
||||
background: $mid-gray;
|
||||
top: 35px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
font-size:15px !important;
|
||||
|
@ -623,26 +625,23 @@ background-color: #E0E0E0;
|
|||
z-index:100;
|
||||
}
|
||||
|
||||
#embedlyLink {
|
||||
display: none;
|
||||
}
|
||||
#embedlyLinkLoader {
|
||||
margin: 0 auto;
|
||||
width: 28px;
|
||||
}
|
||||
|
||||
.CardOnGraph .attachments {
|
||||
border-top: 1px solid #BDBDBD;
|
||||
.CardOnGraph .link-adder {
|
||||
width:100%;
|
||||
height:47px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.attachments a {
|
||||
.link-adder a {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
margin-left: 40px;
|
||||
margin-left: 40px;
|
||||
padding-top:9px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
|
@ -652,7 +651,7 @@ background-color: #E0E0E0;
|
|||
display: inline-block;
|
||||
width: 102px;
|
||||
height: 12px;
|
||||
text-align: left;
|
||||
text-align: left;
|
||||
padding: 18px 0 18px 48px;
|
||||
font-size: 12px;
|
||||
color: #9e9e9e;
|
||||
|
@ -696,9 +695,9 @@ background-color: #E0E0E0;
|
|||
}
|
||||
|
||||
#addLinkInput input{
|
||||
padding: 9px 7px 9px 31px;
|
||||
padding: 9px 27px 9px 31px;
|
||||
height: 12px;
|
||||
width: 198px;
|
||||
width: 210px;
|
||||
margin: 0 0 0 0;
|
||||
border: none;
|
||||
outline: none;
|
||||
|
@ -752,7 +751,6 @@ font-family: 'din-regular', helvetica, sans-serif;
|
|||
-moz-border-radius-bottomright: 8px;
|
||||
-webkit-border-bottom-right-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
display: none;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
|
@ -839,10 +837,10 @@ font-family: 'din-regular', helvetica, sans-serif;
|
|||
line-height: 16px;
|
||||
}
|
||||
|
||||
.canEdit #edit_synapse_desc:hover {
|
||||
.canEdit span.titleWrapper:hover {
|
||||
background-image: url(<%= asset_data_uri('edit.png') %>);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 164px center;
|
||||
background-position: 95% 95%;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
|
@ -950,11 +948,11 @@ font-family: 'din-regular', helvetica, sans-serif;
|
|||
}
|
||||
#edit_synapse_right {
|
||||
background-image: url(<%= asset_data_uri('synapsedirectionright_sprite.png') %>);
|
||||
right: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
#edit_synapse_left {
|
||||
background-image: url(<%= asset_data_uri('synapsedirectionleft_sprite.png') %>);
|
||||
right: 56px;
|
||||
right: 56px;
|
||||
}
|
||||
#edit_synapse_left.checked, #edit_synapse_right.checked {
|
||||
background-position: 0 -48px;
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
padding-top: 92px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
/*.animations {
|
||||
|
@ -44,26 +47,9 @@
|
|||
transition-timing-function: ease-in-out;
|
||||
}*/
|
||||
|
||||
.mapElement {
|
||||
display: none;
|
||||
}
|
||||
.mapPage .mapElement,
|
||||
.topicPage .mapElement {
|
||||
display: block;
|
||||
}
|
||||
.mapPage .mapElementHidden,
|
||||
.topicPage .mapElement.mapInfoBox,
|
||||
.topicPage .mapElement.importDialog {
|
||||
display:none;
|
||||
}
|
||||
.topicPage .starMap {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* loading */
|
||||
|
||||
#loading {
|
||||
display: none;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
position: fixed;
|
||||
|
@ -182,10 +168,14 @@
|
|||
}
|
||||
|
||||
.upperRightMapButtons {
|
||||
top: -42px; /* puts it just offscreen */
|
||||
right: 138px;
|
||||
padding-right: 7px;
|
||||
border-right: 1px solid #747474;
|
||||
}
|
||||
.mapPage .upperRightMapButtons, .topicPage .upperRightMapButtons {
|
||||
top: 0;
|
||||
.unauthenticated .upperRightMapButtons {
|
||||
right: 115px;
|
||||
padding-right: 0;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
.upperRightIcon {
|
||||
|
@ -195,13 +185,7 @@
|
|||
background-repeat: no-repeat;
|
||||
cursor: pointer;
|
||||
}
|
||||
.mapPage .mapElement .importDialog {
|
||||
display: none;
|
||||
background-position: 0 0;
|
||||
}
|
||||
.mapPage.canEditMap .mapElement .importDialog {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sidebarFilterIcon {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
|
@ -210,7 +194,13 @@
|
|||
}
|
||||
.addMap {
|
||||
background-position: -96px 0;
|
||||
margin-right:10px;
|
||||
}
|
||||
.notificationsIcon {
|
||||
background-position: -128px 0;
|
||||
margin-right: 10px; // make it look more natural next to the account menu icon
|
||||
}
|
||||
.notificationsIcon:hover {
|
||||
background-position: -128px -32px;
|
||||
}
|
||||
.importDialog:hover {
|
||||
background-position: 0 -32px;
|
||||
|
@ -223,12 +213,19 @@
|
|||
}
|
||||
.addMap:hover {
|
||||
background-position: -96px -32px;
|
||||
margin-right:10px;
|
||||
}
|
||||
|
||||
|
||||
/* end upperRightUI */
|
||||
|
||||
/* map wrapper */
|
||||
.mapWrapper {
|
||||
position:absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* end map wrapper */
|
||||
|
||||
/* yield */
|
||||
|
||||
|
@ -349,22 +346,15 @@
|
|||
|
||||
/* infoAndHelp */
|
||||
|
||||
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
|
||||
right: 70px;
|
||||
}
|
||||
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
|
||||
.openCheatsheet .tooltipsAbove {
|
||||
right: 1px;
|
||||
left: auto;
|
||||
}
|
||||
|
||||
.unauthenticated .homePage .infoAndHelp {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.infoAndHelp {
|
||||
position: absolute;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
right: 70px;
|
||||
z-index: 3;
|
||||
width: auto;
|
||||
font-style: italic;
|
||||
|
@ -385,16 +375,12 @@
|
|||
}
|
||||
.mapInfoIcon {
|
||||
position: relative;
|
||||
top: 56px; /* puts it just offscreen */
|
||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
||||
background-repeat:no-repeat;
|
||||
background-image: url(<%= asset_path('mapinfo_sprite.png') %>);
|
||||
background-repeat:no-repeat;
|
||||
}
|
||||
.mapInfoIcon:hover {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.mapPage .mapInfoIcon {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.starMap {
|
||||
background-image: url(<%= asset_path('starmap_sprite.png') %>);
|
||||
|
@ -412,9 +398,6 @@
|
|||
background-position: 0 0;
|
||||
}
|
||||
|
||||
.unauthenticated .mapPage .starMap {
|
||||
display: none;
|
||||
}
|
||||
/* end infoAndHelp */
|
||||
|
||||
|
||||
|
@ -423,24 +406,17 @@
|
|||
.mapControls {
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
right:-32px; /* puts it just offscreen */
|
||||
right:24px;
|
||||
width:32px;
|
||||
z-index: 3;
|
||||
}
|
||||
.mapPage .mapControls, .topicPage .mapControls {
|
||||
right: 24px;
|
||||
}
|
||||
|
||||
.topicPage .zoomExtents {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mapControl {
|
||||
width:32px;
|
||||
height:32px;
|
||||
background-color: #424242;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 0;
|
||||
cursor:pointer;
|
||||
}
|
||||
|
||||
|
@ -448,19 +424,6 @@
|
|||
z-index: 4;
|
||||
}
|
||||
|
||||
.takeScreenshot {
|
||||
margin-bottom: 5px;
|
||||
border-radius: 2px;
|
||||
background-image: url(<%= asset_path 'screenshot_sprite.png' %>);
|
||||
display: none;
|
||||
}
|
||||
.takeScreenshot:hover {
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.canEditMap .takeScreenshot {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.zoomExtents {
|
||||
margin-bottom:5px;
|
||||
border-radius: 2px;
|
||||
|
@ -471,7 +434,7 @@
|
|||
background-position: -32px 0;
|
||||
}
|
||||
|
||||
.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,
|
||||
.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,
|
||||
.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 {
|
||||
display: block;
|
||||
}
|
||||
|
@ -535,6 +498,9 @@
|
|||
.sidebarFilterIcon .tooltipsUnder {
|
||||
margin-left: -4px;
|
||||
}
|
||||
.notificationsIcon .tooltipsUnder {
|
||||
left: -20px;
|
||||
}
|
||||
|
||||
.sidebarForkIcon .tooltipsUnder {
|
||||
margin-left: -34px;
|
||||
|
@ -590,16 +556,12 @@
|
|||
left: -8px;
|
||||
}
|
||||
|
||||
.openCheatsheet .tooltipsAbove {
|
||||
left: -4px;
|
||||
}
|
||||
|
||||
.sidebarAccountIcon .tooltipsUnder {
|
||||
margin-left: -12px;
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .takeScreenshot div:after, .chat-button div.tooltips::after {
|
||||
.zoomExtents div::after, .zoomIn div::after, .zoomOut div::after, .chat-button div.tooltips::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 57%;
|
||||
|
@ -612,7 +574,12 @@
|
|||
border-bottom: 5px solid transparent;
|
||||
}
|
||||
|
||||
.importDialog div:after, .sidebarFilterIcon div:after, .sidebarForkIcon div:after, .addMap div:after, .sidebarAccountIcon .tooltipsUnder:after {
|
||||
.addMap div:after,
|
||||
.importDialog div:after,
|
||||
.sidebarForkIcon div:after,
|
||||
.sidebarFilterIcon div:after,
|
||||
.notificationsIcon div:after,
|
||||
.sidebarAccountIcon .tooltipsUnder:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 40%;
|
||||
|
@ -623,9 +590,15 @@
|
|||
border-left: 5px solid transparent;
|
||||
border-right: 5px solid transparent;
|
||||
}
|
||||
.notificationsIcon .unread-notifications-dot:after {
|
||||
content: none;
|
||||
}
|
||||
.sidebarFilterIcon div:after {
|
||||
right: 37% !important;
|
||||
}
|
||||
.notificationsIcon div:after {
|
||||
right: 46% !important;
|
||||
}
|
||||
|
||||
.mapInfoIcon div:after, .openCheatsheet div:after, .starMap div:after, .openMetacodeSwitcher div:after, .pinCarousel div:after {
|
||||
content: '';
|
||||
|
@ -663,8 +636,11 @@
|
|||
|
||||
/* explore maps */
|
||||
|
||||
#explore {
|
||||
display: none;
|
||||
#react-app {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
#exploreMaps {
|
||||
|
@ -683,23 +659,28 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.appsPage #exploreMapsHeader {
|
||||
display: block;
|
||||
.requestInviteHeader {
|
||||
position: absolute;
|
||||
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);
|
||||
}
|
||||
|
||||
#exploreMapsHeader {
|
||||
#navBar {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.exploreMapsBar {
|
||||
.navBarContainer {
|
||||
z-index:2;
|
||||
background-color:#FAFAFA;
|
||||
height: 42px;
|
||||
padding-top: 52px;
|
||||
}
|
||||
|
||||
.exploreMapsMenu {
|
||||
.navBarMenu {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height:42px;
|
||||
|
@ -708,30 +689,29 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
.exploreMapsCenter {
|
||||
.navBarCenter {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.exploreMapsButton {
|
||||
color: #757575;
|
||||
.navBarButton {
|
||||
color: #757575;
|
||||
cursor: default;
|
||||
font-weight: normal;
|
||||
font-family: 'din-medium';
|
||||
font-size: 14px;
|
||||
height: 14px;
|
||||
padding: 14px 8px 12px 40px;
|
||||
border-bottom: 2px solid rgba(0,0,0,0);
|
||||
padding: 0 8px;
|
||||
border-bottom: 2px solid rgba(0,0,0,0);
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
position:relative;
|
||||
cursor: pointer;
|
||||
position:relative;
|
||||
}
|
||||
.exploreMapsButton:hover, .exploreMapsButton.active {
|
||||
.navBarButton:hover, .navBarButton.active {
|
||||
text-decoration: none;
|
||||
color: #424242;
|
||||
border-bottom: 2px solid #00BCD4;
|
||||
}
|
||||
|
||||
.exploreMapsButton.mapperButton {
|
||||
.navBarButton.mapperButton {
|
||||
height: 40px;
|
||||
padding: 0;
|
||||
}
|
||||
|
@ -748,57 +728,71 @@
|
|||
}
|
||||
|
||||
|
||||
.exploreMapsButton .exploreMapsIcon {
|
||||
.navBarButton .navBarIcon {
|
||||
background-repeat: no-repeat;
|
||||
width:32px;
|
||||
height:32px;
|
||||
position:absolute;
|
||||
top:5px;
|
||||
left:5px;
|
||||
margin-top:5px;
|
||||
margin-left:5px;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.exploreMapsCenter .authedApps .exploreMapsIcon {
|
||||
background-image: url(<%= asset_data_uri('user_sprite.png') %>);
|
||||
.navBarLinkText {
|
||||
padding: 11px 0 12px 0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.navBarCenter .authedApps .navBarIcon {
|
||||
background-image: url(<%= asset_path('user_sprite.png') %>);
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.exploreMapsCenter .myMaps .exploreMapsIcon {
|
||||
.navBarCenter .myMaps .navBarIcon {
|
||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: -32px 0;
|
||||
}
|
||||
.exploreMapsCenter .sharedMaps .exploreMapsIcon {
|
||||
.navBarCenter .sharedMaps .navBarIcon {
|
||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: -128px 0;
|
||||
}
|
||||
.exploreMapsCenter .activeMaps .exploreMapsIcon {
|
||||
.navBarCenter .activeMaps .navBarIcon {
|
||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: 0 0;
|
||||
}
|
||||
.exploreMapsCenter .featuredMaps .exploreMapsIcon {
|
||||
.navBarCenter .featuredMaps .navBarIcon {
|
||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: -96px 0;
|
||||
}
|
||||
.exploreMapsCenter .starredMaps .exploreMapsIcon {
|
||||
.navBarCenter .starredMaps .navBarIcon {
|
||||
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
|
||||
background-position: -96px 0;
|
||||
}
|
||||
.authedApps:hover .exploreMapsIcon, .authedApps.active .exploreMapsIcon {
|
||||
.navBarCenter .notificationsLink .navBarIcon {
|
||||
background-image: url(<%= asset_path 'topright_sprite.png' %>);
|
||||
background-position: -128px 0;
|
||||
}
|
||||
.authedApps:hover .navBarIcon, .authedApps.active .navBarIcon {
|
||||
background-position-x: -32px;
|
||||
}
|
||||
.myMaps:hover .exploreMapsIcon, .myMaps.active .exploreMapsIcon {
|
||||
.myMaps:hover .navBarIcon, .myMaps.active .navBarIcon {
|
||||
background-position: -32px -32px;
|
||||
}
|
||||
.activeMaps:hover .exploreMapsIcon, .activeMaps.active .exploreMapsIcon {
|
||||
.activeMaps:hover .navBarIcon, .activeMaps.active .navBarIcon {
|
||||
background-position: 0 -32px;
|
||||
}
|
||||
.featuredMaps:hover .exploreMapsIcon, .featuredMaps.active .exploreMapsIcon {
|
||||
.featuredMaps:hover .navBarIcon, .featuredMaps.active .navBarIcon {
|
||||
background-position: -96px -32px;
|
||||
}
|
||||
.starredMaps:hover .exploreMapsIcon, .starredMaps.active .exploreMapsIcon {
|
||||
.starredMaps:hover .navBarIcon, .starredMaps.active .navBarIcon {
|
||||
background-position: -96px -32px;
|
||||
}
|
||||
.sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
|
||||
.sharedMaps:hover .navBarIcon, .sharedMaps.active .navBarIcon {
|
||||
background-position: -128px -32px;
|
||||
}
|
||||
.notificationsLink:hover .navBarIcon, .notificationsLink.active .navBarIcon {
|
||||
background-position-y: -32px;
|
||||
}
|
||||
|
||||
.mapsWrapper {
|
||||
/*overflow-y: auto; */
|
||||
|
@ -814,7 +808,6 @@
|
|||
height: 80px;
|
||||
font-family: 'din-regular', helvetica, sans-serif;
|
||||
font-size: 32px;
|
||||
display: none;
|
||||
text-align: center;
|
||||
color: #999999;
|
||||
z-index: 0;
|
||||
|
@ -830,7 +823,6 @@
|
|||
/* toast */
|
||||
|
||||
.toast {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
|
|
263
app/assets/stylesheets/emoji-mart-0.3.5.css
Normal file
263
app/assets/stylesheets/emoji-mart-0.3.5.css
Normal file
|
@ -0,0 +1,263 @@
|
|||
.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 }
|
|
@ -1,348 +0,0 @@
|
|||
.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;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.chat-box .chat-messages .chat-message .chat-message-time {
|
||||
float: right;
|
||||
font-size: 10px;
|
||||
color: #757575;
|
||||
}
|
375
app/assets/stylesheets/junto.scss.erb
Normal file
375
app/assets/stylesheets/junto.scss.erb
Normal file
|
@ -0,0 +1,375 @@
|
|||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -211,6 +211,16 @@
|
|||
|
||||
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 {
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
#mobile_header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 720px) and (min-width : 504px) {
|
||||
@media only screen and (max-width : 752px) and (min-width : 504px) {
|
||||
.sidebarSearch .tt-hint, .sidebarSearch .sidebarSearchField {
|
||||
width: 160px !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* when this switches to two lines */
|
||||
@media only screen and (max-width : 728px) {
|
||||
.controller-notifications .notificationsPage .notification .notification-read-unread a {
|
||||
margin-top: -20px !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-width : 390px) {
|
||||
.map .mapCard .mobileMetadata {
|
||||
width: 190px;
|
||||
|
@ -18,15 +21,30 @@
|
|||
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, #exploreMapsHeader {
|
||||
.upperLeftUI, .upperRightUI, .openCheatsheet, .mapInfoIcon, .feedback-icon, .chat-box, #navBar {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#mobile_header {
|
||||
display: block;
|
||||
.notificationsPage .page-header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.controller-notifications .notificationsPage .notification .notification-read-unread {
|
||||
display: block !important;
|
||||
}
|
||||
.controller-notifications .notificationsPage .notification .notification-date {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.homeWrapper {
|
||||
|
@ -46,7 +64,7 @@
|
|||
height: auto;
|
||||
}
|
||||
.homeVideo {
|
||||
width: 100%;
|
||||
width: 100% !important;
|
||||
height: auto;
|
||||
}
|
||||
.fullWidthWrapper.withPartners {
|
||||
|
@ -57,7 +75,7 @@
|
|||
}
|
||||
|
||||
#yield {
|
||||
height: 100%;
|
||||
padding-top: 50px;
|
||||
}
|
||||
|
||||
.new_session, .new_user, .edit_user, .login, .forgotPassword {
|
||||
|
@ -66,7 +84,7 @@
|
|||
left: auto;
|
||||
width: 78%;
|
||||
padding: 16px 10%;
|
||||
margin: 50px auto 0 auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.centerGreyForm input[type="text"], .centerGreyForm input[type="email"], .centerGreyForm input[type="password"] {
|
||||
|
@ -82,15 +100,23 @@
|
|||
max-width: 360px;
|
||||
}
|
||||
|
||||
#wrapper .requestInvite {
|
||||
.requestInviteHeader {
|
||||
display: none;
|
||||
}
|
||||
.requestInvite {
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
height: calc(100% - 50px);
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
left: 0;
|
||||
margin-left: 0px;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
#exploreMaps > div {
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
|
||||
.mapper {
|
||||
width: 100%;
|
||||
margin: 0 0 30px 0;
|
||||
|
@ -191,6 +217,7 @@
|
|||
width: 100%;
|
||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
|
||||
position: fixed;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#menu_icon {
|
||||
|
@ -213,8 +240,16 @@
|
|||
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 {
|
||||
display: none;
|
||||
background: #EEE;
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
|
@ -222,20 +257,29 @@
|
|||
padding: 10px;
|
||||
width: 200px;
|
||||
box-shadow: 3px 3px 3px rgba(0,0,0,0.23), 3px 3px 3px rgba(0,0,0,0.16);
|
||||
}
|
||||
z-index: 2;
|
||||
|
||||
#mobile_menu li {
|
||||
padding: 10px;
|
||||
list-style: none;
|
||||
}
|
||||
li {
|
||||
padding: 7px 10px;
|
||||
list-style: none;
|
||||
font-family: 'din-regular', arial, sans-serif;
|
||||
|
||||
/*
|
||||
* the mobile menu, even if it's been opened by a user, should
|
||||
* not show up if they resize their browser back to full size
|
||||
*/
|
||||
@media only screen and (max-width : 504px) {
|
||||
#mobile_menu.visible {
|
||||
display: block;
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
237
app/assets/stylesheets/notifications.scss.erb
Normal file
237
app/assets/stylesheets/notifications.scss.erb
Normal file
|
@ -0,0 +1,237 @@
|
|||
$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,7 +1,6 @@
|
|||
.viewOnly {
|
||||
float: left;
|
||||
margin-left: 16px;
|
||||
display: none;
|
||||
height: 32px;
|
||||
border: 1px solid #BDBDBD;
|
||||
border-radius: 2px;
|
||||
|
@ -23,7 +22,7 @@
|
|||
}
|
||||
|
||||
.requestNotice {
|
||||
display: none;
|
||||
display: inline-block;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
|
@ -42,16 +41,6 @@
|
|||
.requestNotAccepted {
|
||||
background-color: #c04f4f;
|
||||
}
|
||||
|
||||
&.sendRequest .requestAccess {
|
||||
display: inline-block;
|
||||
}
|
||||
&.sentRequest .requestPending {
|
||||
display: inline-block;
|
||||
}
|
||||
&.requestDenied .requestNotAccepted {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.request_access {
|
||||
|
|
|
@ -93,7 +93,7 @@
|
|||
|
||||
.sidebarSearchField {
|
||||
float: left;
|
||||
width: 380px;
|
||||
width: 379px;
|
||||
padding: 7px 10px 3px 10px;
|
||||
height: 20px;
|
||||
border-top: 1px solid #BDBDBD;
|
||||
|
|
6
app/channels/application_cable/channel.rb
Normal file
6
app/channels/application_cable/channel.rb
Normal file
|
@ -0,0 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationCable
|
||||
class Channel < ActionCable::Channel::Base
|
||||
end
|
||||
end
|
23
app/channels/application_cable/connection.rb
Normal file
23
app/channels/application_cable/connection.rb
Normal file
|
@ -0,0 +1,23 @@
|
|||
# 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
|
18
app/channels/map_channel.rb
Normal file
18
app/channels/map_channel.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# 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,11 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
class AccessController < ApplicationController
|
||||
before_action :require_user, only: [:access, :access_request, :approve_access, :approve_access_post,
|
||||
:deny_access, :deny_access_post, :request_access]
|
||||
before_action :set_map, only: [:access, :access_request, :approve_access, :approve_access_post,
|
||||
:deny_access, :deny_access_post, :request_access]
|
||||
after_action :verify_authorized
|
||||
|
||||
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
|
||||
|
@ -19,14 +21,9 @@ class AccessController < ApplicationController
|
|||
|
||||
# POST maps/:id/access_request
|
||||
def access_request
|
||||
request = AccessRequest.create(user: current_user, map: @map)
|
||||
# what about push notification to map owner?
|
||||
MapMailer.access_request_email(request, @map).deliver_later
|
||||
|
||||
AccessRequest.create(user: current_user, map: @map)
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
format.json { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -34,24 +31,18 @@ class AccessController < ApplicationController
|
|||
def access
|
||||
user_ids = params[:access].to_a.map(&:to_i) || []
|
||||
|
||||
@map.add_new_collaborators(user_ids).each do |user_id|
|
||||
# add_new_collaborators returns array of added users,
|
||||
# who we then send an email to
|
||||
MapMailer.invite_to_edit_email(@map, current_user, User.find(user_id)).deliver_later
|
||||
end
|
||||
@map.add_new_collaborators(user_ids)
|
||||
@map.remove_old_collaborators(user_ids)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
format.json { head :ok }
|
||||
end
|
||||
end
|
||||
|
||||
# GET maps/:id/approve_access/:request_id
|
||||
def approve_access
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.approve()
|
||||
request.approve # also marks mailboxer notification as read
|
||||
respond_to do |format|
|
||||
format.html { redirect_to map_path(@map), notice: 'Request was approved' }
|
||||
end
|
||||
|
@ -60,7 +51,7 @@ class AccessController < ApplicationController
|
|||
# GET maps/:id/deny_access/:request_id
|
||||
def deny_access
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.deny()
|
||||
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
|
||||
|
@ -69,8 +60,9 @@ class AccessController < ApplicationController
|
|||
# POST maps/:id/approve_access/:request_id
|
||||
def approve_access_post
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.approve()
|
||||
request.approve
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
|
@ -80,8 +72,9 @@ class AccessController < ApplicationController
|
|||
# POST maps/:id/deny_access/:request_id
|
||||
def deny_access_post
|
||||
request = AccessRequest.find(params[:request_id])
|
||||
request.deny()
|
||||
request.deny
|
||||
respond_to do |format|
|
||||
format.js
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
|
@ -94,5 +87,4 @@ class AccessController < ApplicationController
|
|||
@map = Map.find(params[:id])
|
||||
authorize @map
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V1
|
||||
class DeprecatedController < ApplicationController
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class MappingsController < RestfulController
|
||||
class MappingsController < WithUpdatesController
|
||||
def searchable_columns
|
||||
[]
|
||||
end
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class MapsController < RestfulController
|
||||
class MapsController < WithUpdatesController
|
||||
def searchable_columns
|
||||
[:name, :desc]
|
||||
%i[name desc]
|
||||
end
|
||||
|
||||
def apply_filters(collection)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class MetacodesController < RestfulController
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class RestfulController < ActionController::Base
|
||||
|
@ -7,7 +8,7 @@ module Api
|
|||
|
||||
snorlax_used_rest!
|
||||
|
||||
before_action :load_resource, only: [:show, :update, :destroy]
|
||||
before_action :load_resource, only: %i[show update destroy]
|
||||
after_action :verify_authorized
|
||||
|
||||
def index
|
||||
|
@ -45,7 +46,7 @@ module Api
|
|||
end
|
||||
|
||||
def current_user
|
||||
token_user || doorkeeper_user || super
|
||||
token_user || doorkeeper_user
|
||||
end
|
||||
|
||||
def load_resource
|
||||
|
@ -86,12 +87,12 @@ module Api
|
|||
|
||||
def token_user
|
||||
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
|
||||
end
|
||||
|
||||
def doorkeeper_user
|
||||
return unless doorkeeper_token.present?
|
||||
return if doorkeeper_token.blank?
|
||||
doorkeeper_render_error unless valid_doorkeeper_token?
|
||||
@doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id)
|
||||
end
|
||||
|
@ -149,19 +150,30 @@ module Api
|
|||
|
||||
# override this method to explicitly set searchable columns
|
||||
def searchable_columns
|
||||
return @searchable_columns unless @searchable_columns.nil?
|
||||
|
||||
columns = resource_class.columns.select do |column|
|
||||
column.type == :text || column.type == :string
|
||||
end
|
||||
columns.map(&:name)
|
||||
@searchable_columns = 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
|
||||
|
||||
# thanks to http://stackoverflow.com/questions/4430578
|
||||
def search_by_q(collection)
|
||||
table = resource_class.arel_table
|
||||
safe_query = "%#{params[:q].gsub(/[%_]/, '\\\\\0')}%"
|
||||
search_column = -> (column) { table[column].matches(safe_query) }
|
||||
search_column = ->(column) { table[column].matches(safe_query) }
|
||||
|
||||
condition = searchable_columns.reduce(nil) do |prev, column|
|
||||
condition = searchfields.reduce(nil) do |prev, column|
|
||||
next search_column.call(column) if prev.nil?
|
||||
search_column.call(column).or(prev)
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class SessionsController < ApplicationController
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class StarsController < RestfulController
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class SynapsesController < RestfulController
|
||||
class SynapsesController < WithUpdatesController
|
||||
def searchable_columns
|
||||
[:desc]
|
||||
end
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class TokensController < RestfulController
|
||||
protect_from_forgery
|
||||
|
||||
def searchable_columns
|
||||
[:description]
|
||||
end
|
||||
|
@ -18,6 +21,12 @@ module Api
|
|||
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
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Api
|
||||
module V2
|
||||
class TopicsController < RestfulController
|
||||
class TopicsController < WithUpdatesController
|
||||
def searchable_columns
|
||||
[:name, :desc, :link]
|
||||
%i[name desc link]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
# 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
|
||||
|
|
28
app/controllers/api/v2/with_updates_controller.rb
Normal file
28
app/controllers/api/v2/with_updates_controller.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# 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,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationController < ActionController::Base
|
||||
include ApplicationHelper
|
||||
include Pundit
|
||||
|
@ -22,7 +23,7 @@ class ApplicationController < ActionController::Base
|
|||
helper_method :admin?
|
||||
|
||||
def handle_unauthorized
|
||||
if authenticated? and params[:controller] == 'maps' and params[:action] == 'show'
|
||||
if authenticated? && (params[:controller] == 'maps') && (params[:action] == 'show')
|
||||
redirect_to request_access_map_path(params[:id])
|
||||
elsif authenticated?
|
||||
redirect_to root_path, notice: "You don't have permission to see that page."
|
||||
|
@ -41,13 +42,13 @@ class ApplicationController < ActionController::Base
|
|||
def require_no_user
|
||||
return true unless authenticated?
|
||||
redirect_to edit_user_path(user), notice: 'You must be logged out.'
|
||||
return false
|
||||
false
|
||||
end
|
||||
|
||||
def require_user
|
||||
return true if authenticated?
|
||||
redirect_to sign_in_path, notice: 'You must be logged in.'
|
||||
return false
|
||||
false
|
||||
end
|
||||
|
||||
def require_admin
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ExploreController < ApplicationController
|
||||
before_action :require_authentication, only: [:mine, :shared, :starred]
|
||||
before_action :require_authentication, only: %i[mine shared starred]
|
||||
before_action :authorize_explore
|
||||
after_action :verify_authorized
|
||||
after_action :verify_policy_scoped
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# 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
|
||||
# TODO: what else can we do to make get_with_redirects safer?
|
||||
def load_url_title
|
||||
authorize :Hack
|
||||
url = params[:url]
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MainController < ApplicationController
|
||||
before_action :authorize_main
|
||||
after_action :verify_authorized
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MappingsController < ApplicationController
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
before_action :require_user, only: %i[create update destroy]
|
||||
after_action :verify_authorized, except: :index
|
||||
after_action :verify_policy_scoped, only: :index
|
||||
|
||||
|
@ -19,10 +20,10 @@ class MappingsController < ApplicationController
|
|||
@mapping = Mapping.new(mapping_params)
|
||||
authorize @mapping
|
||||
@mapping.user = current_user
|
||||
@mapping.updated_by = current_user
|
||||
|
||||
if @mapping.save
|
||||
render json: @mapping, status: :created
|
||||
Events::NewMapping.publish!(@mapping, current_user)
|
||||
else
|
||||
render json: @mapping.errors, status: :unprocessable_entity
|
||||
end
|
||||
|
@ -32,8 +33,11 @@ class MappingsController < ApplicationController
|
|||
def update
|
||||
@mapping = Mapping.find(params[:id])
|
||||
authorize @mapping
|
||||
@mapping.updated_by = current_user
|
||||
@mapping.map.updated_by = current_user
|
||||
@mapping.assign_attributes(mapping_params)
|
||||
|
||||
if @mapping.update_attributes(mapping_params)
|
||||
if @mapping.save
|
||||
head :no_content
|
||||
else
|
||||
render json: @mapping.errors, status: :unprocessable_entity
|
||||
|
@ -44,14 +48,8 @@ class MappingsController < ApplicationController
|
|||
def destroy
|
||||
@mapping = Mapping.find(params[:id])
|
||||
authorize @mapping
|
||||
|
||||
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.updated_by = current_user
|
||||
@mapping.map.updated_by = current_user
|
||||
@mapping.destroy
|
||||
|
||||
head :no_content
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MapsController < ApplicationController
|
||||
before_action :require_user, only: [:create, :update, :destroy, :events]
|
||||
before_action :set_map, only: [:show, :update, :destroy, :contains, :events, :export]
|
||||
before_action :require_user, only: %i[create update destroy events follow unfollow]
|
||||
before_action :set_map, only: %i[show conversation update destroy
|
||||
contains events export
|
||||
follow unfollow unfollow_from_email]
|
||||
after_action :verify_authorized
|
||||
|
||||
# GET maps/:id
|
||||
def show
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
UserMap.where(map: @map, user: current_user).map(&:mark_invite_notifications_as_read)
|
||||
@allmappers = @map.contributors
|
||||
@allcollaborators = @map.editors
|
||||
@alltopics = policy_scope(@map.topics)
|
||||
|
@ -19,6 +23,24 @@ class MapsController < ApplicationController
|
|||
end
|
||||
format.json { render json: @map }
|
||||
format.csv { redirect_to action: :export, format: :csv }
|
||||
format.ttl { redirect_to action: :export, format: :ttl }
|
||||
end
|
||||
end
|
||||
|
||||
# GET maps/:id/conversation
|
||||
def conversation
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
UserMap.where(map: @map, user: current_user).map(&:mark_invite_notifications_as_read)
|
||||
@allmappers = @map.contributors
|
||||
@allcollaborators = @map.editors
|
||||
@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
|
||||
end
|
||||
|
||||
|
@ -40,6 +62,7 @@ class MapsController < ApplicationController
|
|||
def create
|
||||
@map = Map.new(create_map_params)
|
||||
@map.user = current_user
|
||||
@map.updated_by = current_user
|
||||
@map.arranged = false
|
||||
authorize @map
|
||||
|
||||
|
@ -60,8 +83,11 @@ class MapsController < ApplicationController
|
|||
|
||||
# PUT maps/:id
|
||||
def update
|
||||
@map.updated_by = current_user
|
||||
@map.assign_attributes(update_map_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @map.update_attributes(update_map_params)
|
||||
if @map.save
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @map.errors, status: :unprocessable_entity }
|
||||
|
@ -71,7 +97,8 @@ class MapsController < ApplicationController
|
|||
|
||||
# DELETE maps/:id
|
||||
def destroy
|
||||
@map.delete
|
||||
@map.updated_by = current_user
|
||||
@map.destroy
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
|
@ -89,10 +116,12 @@ class MapsController < ApplicationController
|
|||
|
||||
# GET maps/:id/export
|
||||
def export
|
||||
exporter = MapExportService.new(current_user, @map)
|
||||
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
|
||||
|
||||
|
@ -102,9 +131,6 @@ class MapsController < ApplicationController
|
|||
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
|
||||
|
||||
respond_to do |format|
|
||||
|
@ -115,6 +141,43 @@ class MapsController < ApplicationController
|
|||
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
|
||||
|
||||
def set_map
|
||||
|
@ -123,7 +186,7 @@ class MapsController < ApplicationController
|
|||
end
|
||||
|
||||
def create_map_params
|
||||
params.permit(:name, :desc, :permission)
|
||||
params.permit(:name, :desc, :permission, :source_id)
|
||||
end
|
||||
|
||||
def update_map_params
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MessagesController < ApplicationController
|
||||
before_action :require_user, except: [:show]
|
||||
after_action :verify_authorized
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MetacodeSetsController < ApplicationController
|
||||
before_action :require_admin
|
||||
|
||||
|
@ -55,8 +56,13 @@ class MetacodeSetsController < ApplicationController
|
|||
@metacodes.each do |m|
|
||||
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
||||
end
|
||||
format.html { redirect_to metacode_sets_url, notice: 'Metacode set was successfully created.' }
|
||||
format.json { render json: @metacode_set, status: :created, location: metacode_sets_url }
|
||||
format.html do
|
||||
redirect_to 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
|
||||
format.html { render action: 'new' }
|
||||
format.json { render json: @metacode_set.errors, status: :unprocessable_entity }
|
||||
|
@ -73,20 +79,20 @@ class MetacodeSetsController < ApplicationController
|
|||
if @metacode_set.update_attributes(metacode_set_params)
|
||||
|
||||
# build an array of the IDs of the metacodes currently in the set
|
||||
@currentMetacodes = @metacode_set.metacodes.map { |m| m.id.to_s }
|
||||
current_metacodes = @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
|
||||
@newMetacodes = params[:metacodes][:value].split(',')
|
||||
new_metacodes = params[:metacodes][:value].split(',')
|
||||
|
||||
# remove the metacodes that were in it, but now aren't
|
||||
@removedMetacodes = @currentMetacodes - @newMetacodes
|
||||
@removedMetacodes.each do |m|
|
||||
@inmetacodeset = InMetacodeSet.find_by_metacode_id_and_metacode_set_id(m, @metacode_set.id)
|
||||
@inmetacodeset.destroy
|
||||
removed_metacodes = current_metacodes - new_metacodes
|
||||
removed_metacodes.each do |m|
|
||||
inmetacodeset = InMetacodeSet.find_by(metacode_id: m, metacode_set_id: @metacode_set.id)
|
||||
inmetacodeset.destroy
|
||||
end
|
||||
|
||||
# add the new metacodes
|
||||
@addedMetacodes = @newMetacodes - @currentMetacodes
|
||||
@addedMetacodes.each do |m|
|
||||
added_metacodes = new_metacodes - current_metacodes
|
||||
added_metacodes.each do |m|
|
||||
InMetacodeSet.create(metacode_id: m, metacode_set_id: @metacode_set.id)
|
||||
end
|
||||
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MetacodesController < ApplicationController
|
||||
before_action :require_admin, except: [:index, :show]
|
||||
before_action :set_metacode, only: [:edit, :update]
|
||||
before_action :require_admin, except: %i[index show]
|
||||
before_action :set_metacode, only: %i[edit update]
|
||||
|
||||
# GET /metacodes
|
||||
# GET /metacodes.json
|
||||
|
|
107
app/controllers/notifications_controller.rb
Normal file
107
app/controllers/notifications_controller.rb
Normal file
|
@ -0,0 +1,107 @@
|
|||
# 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,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SearchController < ApplicationController
|
||||
include TopicsHelper
|
||||
include MapsHelper
|
||||
|
@ -7,14 +8,15 @@ class SearchController < ApplicationController
|
|||
|
||||
before_action :authorize_search
|
||||
after_action :verify_authorized
|
||||
after_action :verify_policy_scoped, only: [:maps, :mappers, :synapses, :topics]
|
||||
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 && !term.empty? && term.downcase[0..3] != 'map:' && term.downcase[0..6] != 'mapper:' && !term.casecmp('topic:').zero?
|
||||
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:'
|
||||
|
@ -34,28 +36,28 @@ class SearchController < ApplicationController
|
|||
end
|
||||
|
||||
# check whether there's a filter by metacode as part of the query
|
||||
filterByMetacode = false
|
||||
filter_by_metacode = false
|
||||
Metacode.all.each do |m|
|
||||
lOne = m.name.length + 1
|
||||
lTwo = m.name.length
|
||||
length_one = m.name.length + 1
|
||||
length_two = m.name.length
|
||||
|
||||
if term.downcase[0..lTwo] == m.name.downcase + ':'
|
||||
term = term[lOne..-1]
|
||||
filterByMetacode = m
|
||||
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 filterByMetacode
|
||||
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: filterByMetacode.id)
|
||||
builder = builder.where(metacode_id: filter_by_metacode.id)
|
||||
end
|
||||
elsif desc
|
||||
builder = builder.where('LOWER("desc") like ?', search)
|
||||
|
@ -82,7 +84,8 @@ class SearchController < ApplicationController
|
|||
term = params[:term]
|
||||
user = params[:user] ? params[:user] : nil
|
||||
|
||||
if term && !term.empty? && term.downcase[0..5] != 'topic:' && term.downcase[0..6] != 'mapper:' && !term.casecmp('map:').zero?
|
||||
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:'
|
||||
|
@ -115,7 +118,8 @@ class SearchController < ApplicationController
|
|||
# get /search/mappers?term=SOMETERM
|
||||
def mappers
|
||||
term = params[:term]
|
||||
if term && !term.empty? && term.downcase[0..3] != 'map:' && term.downcase[0..5] != 'topic:' && !term.casecmp('mapper:').zero?
|
||||
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:'
|
||||
|
@ -137,14 +141,16 @@ class SearchController < ApplicationController
|
|||
topic1id = params[:topic1id]
|
||||
topic2id = params[:topic2id]
|
||||
|
||||
if term && !term.empty?
|
||||
@synapses = policy_scope(Synapse).where('LOWER("desc") like ?', '%' + term.downcase.strip + '%').order('"desc"')
|
||||
if term.present?
|
||||
@synapses = policy_scope(Synapse)
|
||||
.where('LOWER("desc") like ?', '%' + term.downcase.strip + '%')
|
||||
.order('"desc"')
|
||||
|
||||
@synapses = @synapses.uniq(&:desc)
|
||||
elsif topic1id && !topic1id.empty?
|
||||
@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
|
||||
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
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class StarsController < ApplicationController
|
||||
before_action :require_user
|
||||
before_action :set_map
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class SynapsesController < ApplicationController
|
||||
include TopicsHelper
|
||||
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
before_action :require_user, only: %i[create update destroy]
|
||||
after_action :verify_authorized, except: :index
|
||||
after_action :verify_policy_scoped, only: :index
|
||||
|
||||
|
@ -22,6 +23,8 @@ class SynapsesController < ApplicationController
|
|||
@synapse = Synapse.new(synapse_params)
|
||||
@synapse.desc = '' if @synapse.desc.nil?
|
||||
@synapse.desc.strip! # no trailing/leading whitespace
|
||||
@synapse.user = current_user
|
||||
@synapse.updated_by = current_user
|
||||
|
||||
# we want invalid params to return :unprocessable_entity
|
||||
# so we have to authorize AFTER saving. But if authorize
|
||||
|
@ -47,9 +50,11 @@ class SynapsesController < ApplicationController
|
|||
@synapse = Synapse.find(params[:id])
|
||||
@synapse.desc = '' if @synapse.desc.nil?
|
||||
authorize @synapse
|
||||
@synapse.updated_by = current_user
|
||||
@synapse.assign_attributes(synapse_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @synapse.update_attributes(synapse_params)
|
||||
if @synapse.save
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @synapse.errors, status: :unprocessable_entity }
|
||||
|
@ -61,6 +66,7 @@ class SynapsesController < ApplicationController
|
|||
def destroy
|
||||
@synapse = Synapse.find(params[:id])
|
||||
authorize @synapse
|
||||
@synapse.updated_by = current_user
|
||||
@synapse.destroy
|
||||
|
||||
respond_to do |format|
|
||||
|
@ -71,6 +77,8 @@ class SynapsesController < ApplicationController
|
|||
private
|
||||
|
||||
def synapse_params
|
||||
params.require(:synapse).permit(:id, :desc, :category, :weight, :permission, :topic1_id, :topic2_id, :user_id)
|
||||
params.require(:synapse).permit(
|
||||
:id, :desc, :category, :weight, :permission, :topic1_id, :topic2_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
10
app/controllers/tokens_controller.rb
Normal file
10
app/controllers/tokens_controller.rb
Normal file
|
@ -0,0 +1,10 @@
|
|||
# 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
|
|
@ -1,8 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TopicsController < ApplicationController
|
||||
include TopicsHelper
|
||||
|
||||
before_action :require_user, only: [:create, :update, :destroy]
|
||||
before_action :require_user, only: %i[create update destroy follow unfollow]
|
||||
before_action :set_topic, only: %i[show update relative_numbers
|
||||
relatives network destroy
|
||||
follow unfollow unfollow_from_email]
|
||||
after_action :verify_authorized, except: :autocomplete_topic
|
||||
|
||||
respond_to :html, :js, :json
|
||||
|
@ -10,26 +14,27 @@ class TopicsController < ApplicationController
|
|||
# GET /topics/autocomplete_topic
|
||||
def autocomplete_topic
|
||||
term = params[:term]
|
||||
if term && !term.empty?
|
||||
@topics = policy_scope(Topic).where('LOWER("name") like ?', term.downcase + '%').order('"name"')
|
||||
@mapTopics = @topics.select { |t| t&.metacode&.name == 'Metamap' }
|
||||
if term.present?
|
||||
topics = policy_scope(Topic)
|
||||
.where('LOWER("name") like ?', term.downcase + '%')
|
||||
.order('"name"')
|
||||
map_topics = topics.select { |t| t&.metacode&.name == 'Metamap' }
|
||||
# prioritize topics which point to maps, over maps
|
||||
@exclude = @mapTopics.length > 0 ? @mapTopics.map(&:name) : ['']
|
||||
@maps = policy_scope(Map).where('LOWER("name") like ? AND name NOT IN (?)', term.downcase + '%', @exclude).order('"name"')
|
||||
exclude = map_topics.length.positive? ? map_topics.map(&:name) : ['']
|
||||
maps = policy_scope(Map)
|
||||
.where('LOWER("name") like ? AND name NOT IN (?)', term.downcase + '%', exclude)
|
||||
.order('"name"')
|
||||
else
|
||||
@topics = []
|
||||
@maps = []
|
||||
topics = []
|
||||
maps = []
|
||||
end
|
||||
@all= @topics.to_a.concat(@maps.to_a).sort { |a, b| a.name <=> b.name }
|
||||
|
||||
@all = topics.to_a.concat(maps.to_a).sort_by(&:name)
|
||||
|
||||
render json: autocomplete_array_json(@all).to_json
|
||||
end
|
||||
|
||||
# GET topics/:id
|
||||
def show
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
@alltopics = [@topic].concat(policy_scope(Topic.relatives(@topic.id, current_user)).to_a)
|
||||
|
@ -45,9 +50,6 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/network
|
||||
def network
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
@alltopics = [@topic].concat(policy_scope(Topic.relatives(@topic.id, current_user)).to_a)
|
||||
@allsynapses = policy_scope(Synapse.for_topic(@topic.id))
|
||||
|
||||
|
@ -67,16 +69,13 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/relative_numbers
|
||||
def relative_numbers
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
topics_already_has = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
alltopics = policy_scope(Topic.relatives(@topic.id, current_user)).to_a
|
||||
alltopics.delete_if { |topic| topic.metacode_id != params[:metacode].to_i } if params[:metacode].present?
|
||||
alltopics.delete_if do |topic|
|
||||
!topicsAlreadyHas.index(topic.id).nil?
|
||||
if params[:metacode].present?
|
||||
alltopics.delete_if { |topic| topic.metacode_id != params[:metacode].to_i }
|
||||
end
|
||||
alltopics.delete_if { |topic| !topics_already_has.index(topic.id).nil? }
|
||||
|
||||
@json = Hash.new(0)
|
||||
alltopics.each do |t|
|
||||
|
@ -90,15 +89,14 @@ class TopicsController < ApplicationController
|
|||
|
||||
# GET topics/:id/relatives
|
||||
def relatives
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
topicsAlreadyHas = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
topics_already_has = params[:network] ? params[:network].split(',').map(&:to_i) : []
|
||||
|
||||
alltopics = policy_scope(Topic.relatives(@topic.id, current_user)).to_a
|
||||
alltopics.delete_if { |topic| topic.metacode_id != params[:metacode].to_i } if params[:metacode].present?
|
||||
if params[:metacode].present?
|
||||
alltopics.delete_if { |topic| topic.metacode_id != params[:metacode].to_i }
|
||||
end
|
||||
alltopics.delete_if do |topic|
|
||||
!topicsAlreadyHas.index(topic.id.to_s).nil?
|
||||
!topics_already_has.index(topic.id.to_s).nil?
|
||||
end
|
||||
|
||||
# find synapses between topics in alltopics array
|
||||
|
@ -108,9 +106,9 @@ class TopicsController < ApplicationController
|
|||
!synapse_ids.index(synapse.id).nil?
|
||||
end
|
||||
|
||||
creatorsAlreadyHas = params[:creators] ? params[:creators].split(',').map(&:to_i) : []
|
||||
creators_already_has = params[:creators] ? params[:creators].split(',').map(&:to_i) : []
|
||||
allcreators = (alltopics.map(&:user) + allsynapses.map(&:user)).uniq.delete_if do |user|
|
||||
!creatorsAlreadyHas.index(user.id).nil?
|
||||
!creators_already_has.index(user.id).nil?
|
||||
end
|
||||
|
||||
@json = {}
|
||||
|
@ -128,6 +126,8 @@ class TopicsController < ApplicationController
|
|||
def create
|
||||
@topic = Topic.new(topic_params)
|
||||
authorize @topic
|
||||
@topic.user = current_user
|
||||
@topic.updated_by = current_user
|
||||
|
||||
respond_to do |format|
|
||||
if @topic.save
|
||||
|
@ -141,11 +141,11 @@ class TopicsController < ApplicationController
|
|||
# PUT /topics/1
|
||||
# PUT /topics/1.json
|
||||
def update
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
@topic.updated_by = current_user
|
||||
@topic.assign_attributes(topic_params)
|
||||
|
||||
respond_to do |format|
|
||||
if @topic.update_attributes(topic_params)
|
||||
if @topic.save
|
||||
format.json { head :no_content }
|
||||
else
|
||||
format.json { render json: @topic.errors, status: :unprocessable_entity }
|
||||
|
@ -155,18 +155,58 @@ class TopicsController < ApplicationController
|
|||
|
||||
# DELETE topics/:id
|
||||
def destroy
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
|
||||
@topic.updated_by = current_user
|
||||
@topic.destroy
|
||||
respond_to do |format|
|
||||
format.json { head :no_content }
|
||||
end
|
||||
end
|
||||
|
||||
# POST topics/:id/follow
|
||||
def follow
|
||||
follow = FollowService.follow(@topic, current_user, 'followed')
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
if follow
|
||||
head :ok
|
||||
else
|
||||
head :bad_request
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# POST topics/:id/unfollow
|
||||
def unfollow
|
||||
FollowService.unfollow(@topic, current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
head :ok
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# GET topics/:id/unfollow_from_email
|
||||
def unfollow_from_email
|
||||
FollowService.unfollow(@topic, current_user)
|
||||
|
||||
respond_to do |format|
|
||||
format.html do
|
||||
redirect_to topic_path(@topic), notice: 'You are no longer following this topic'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_topic
|
||||
@topic = Topic.find(params[:id])
|
||||
authorize @topic
|
||||
end
|
||||
|
||||
def topic_params
|
||||
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :user_id, :metacode_id, :defer_to_map_id)
|
||||
params.require(:topic).permit(:id, :name, :desc, :link, :permission, :metacode_id, :defer_to_map_id)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
class Users::PasswordsController < Devise::PasswordsController
|
||||
protected
|
||||
|
||||
def after_resetting_password_path_for(resource)
|
||||
signed_in_root_path(resource)
|
||||
end
|
||||
module Users
|
||||
class PasswordsController < Devise::PasswordsController
|
||||
protected
|
||||
|
||||
def after_sending_reset_password_instructions_path_for(_resource_name)
|
||||
sign_in_path if is_navigational_format?
|
||||
def after_resetting_password_path_for(resource)
|
||||
signed_in_root_path(resource)
|
||||
end
|
||||
|
||||
def after_sending_reset_password_instructions_path_for(_resource_name)
|
||||
sign_in_path if is_navigational_format?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
# frozen_string_literal: true
|
||||
class Users::RegistrationsController < Devise::RegistrationsController
|
||||
before_action :configure_sign_up_params, only: [:create]
|
||||
before_action :configure_account_update_params, only: [:update]
|
||||
after_action :store_location, only: [:new]
|
||||
|
||||
protected
|
||||
module Users
|
||||
class RegistrationsController < Devise::RegistrationsController
|
||||
before_action :configure_sign_up_params, only: [:create]
|
||||
before_action :configure_account_update_params, only: [:update]
|
||||
after_action :store_location, only: [:new]
|
||||
|
||||
def after_update_path_for(resource)
|
||||
signed_in_root_path(resource)
|
||||
end
|
||||
protected
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
stored = stored_location_for(User)
|
||||
return stored if stored
|
||||
|
||||
if request.referer&.match(sign_in_url) || request.referer&.match(sign_up_url)
|
||||
super
|
||||
else
|
||||
request.referer || root_path
|
||||
def after_update_path_for(resource)
|
||||
signed_in_root_path(resource)
|
||||
end
|
||||
end
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
stored = stored_location_for(User)
|
||||
return stored if stored
|
||||
|
||||
private
|
||||
|
||||
def store_location
|
||||
if params[:redirect_to]
|
||||
store_location_for(User, params[:redirect_to])
|
||||
if request.referer&.match(sign_in_url) || request.referer&.match(sign_up_url)
|
||||
super
|
||||
else
|
||||
request.referer || root_path
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def configure_sign_up_params
|
||||
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :joinedwithcode])
|
||||
end
|
||||
private
|
||||
|
||||
def configure_account_update_params
|
||||
devise_parameter_sanitizer.permit(:account_update, keys: [:image])
|
||||
def store_location
|
||||
store_location_for(User, params[:redirect_to]) if params[:redirect_to]
|
||||
end
|
||||
|
||||
def configure_sign_up_params
|
||||
devise_parameter_sanitizer.permit(:sign_up, keys: %i[name joinedwithcode])
|
||||
end
|
||||
|
||||
def configure_account_update_params
|
||||
devise_parameter_sanitizer.permit(:account_update, keys: [:image])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,26 @@
|
|||
class Users::SessionsController < Devise::SessionsController
|
||||
protected
|
||||
# frozen_string_literal: true
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
stored = stored_location_for(User)
|
||||
return stored if stored
|
||||
module Users
|
||||
class SessionsController < Devise::SessionsController
|
||||
after_action :store_location, only: [:new]
|
||||
|
||||
if request.referer&.match(sign_in_url) || request.referer&.match(sign_up_url)
|
||||
super
|
||||
else
|
||||
request.referer || root_path
|
||||
protected
|
||||
|
||||
def after_sign_in_path_for(resource)
|
||||
stored = stored_location_for(User)
|
||||
return stored if stored
|
||||
|
||||
if request.referer&.match(sign_in_url) || request.referer&.match(sign_up_url)
|
||||
super
|
||||
else
|
||||
request.referer || root_path
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def store_location
|
||||
store_location_for(User, params[:redirect_to]) if params[:redirect_to]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class UsersController < ApplicationController
|
||||
before_action :require_user, only: [:edit, :update, :updatemetacodes]
|
||||
before_action :require_user, only: %i[edit update updatemetacodes update_metacode_focus]
|
||||
|
||||
respond_to :html, :json
|
||||
|
||||
|
@ -13,25 +14,25 @@ class UsersController < ApplicationController
|
|||
|
||||
# GET /users/:id/edit
|
||||
def edit
|
||||
@user = current_user
|
||||
respond_with(@user)
|
||||
@user = User.find(current_user.id)
|
||||
end
|
||||
|
||||
# PUT /users/:id
|
||||
def update
|
||||
@user = current_user
|
||||
@user = User.find(current_user.id)
|
||||
|
||||
if user_params[:password] == '' && user_params[:password_confirmation] == ''
|
||||
# not trying to change the password
|
||||
if @user.update_attributes(user_params.except(:password, :password_confirmation))
|
||||
update_follow_settings(@user, params[:settings])
|
||||
@user.image = nil if params[:remove_image] == '1'
|
||||
@user.save
|
||||
sign_in(@user, bypass: true)
|
||||
bypass_sign_in(@user)
|
||||
respond_to do |format|
|
||||
format.html { redirect_to root_url, notice: 'Account updated!' }
|
||||
format.html { redirect_to root_url, notice: 'Settings updated' }
|
||||
end
|
||||
else
|
||||
sign_in(@user, bypass: true)
|
||||
bypass_sign_in(@user)
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_user_path(@user), notice: @user.errors.to_a[0] }
|
||||
end
|
||||
|
@ -41,11 +42,12 @@ class UsersController < ApplicationController
|
|||
correct_pass = @user.valid_password?(params[:current_password])
|
||||
|
||||
if correct_pass && @user.update_attributes(user_params)
|
||||
update_follow_settings(@user, params[:settings])
|
||||
@user.image = nil if params[:remove_image] == '1'
|
||||
@user.save
|
||||
sign_in(@user, bypass: true)
|
||||
respond_to do |format|
|
||||
format.html { redirect_to root_url, notice: 'Account updated!' }
|
||||
format.html { redirect_to root_url, notice: 'Settings updated' }
|
||||
end
|
||||
else
|
||||
respond_to do |format|
|
||||
|
@ -93,9 +95,28 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
# PUT /user/update_metacode_focus
|
||||
def update_metacode_focus
|
||||
@user = current_user
|
||||
@user.settings.metacode_focus = params[:value]
|
||||
@user.save
|
||||
respond_to do |format|
|
||||
format.json { render json: { success: 'success' } }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_follow_settings(user, settings)
|
||||
user.settings.follow_topic_on_created = settings[:follow_topic_on_created]
|
||||
user.settings.follow_topic_on_contributed = settings[:follow_topic_on_contributed]
|
||||
user.settings.follow_map_on_created = settings[:follow_map_on_created]
|
||||
user.settings.follow_map_on_contributed = settings[:follow_map_on_contributed]
|
||||
end
|
||||
|
||||
def user_params
|
||||
params.require(:user).permit(:name, :email, :image, :password, :password_confirmation)
|
||||
params.require(:user).permit(
|
||||
:name, :email, :image, :password, :password_confirmation, :emails_allowed, :settings
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
51
app/decorators/notification_decorator.rb
Normal file
51
app/decorators/notification_decorator.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class NotificationDecorator
|
||||
class << self
|
||||
def decorate(notification, receipt)
|
||||
result = {
|
||||
id: notification.id,
|
||||
type: notification.notification_code,
|
||||
subject: notification.subject,
|
||||
is_read: receipt.is_read,
|
||||
created_at: notification.created_at,
|
||||
actor: notification.sender,
|
||||
data: {
|
||||
object: notification.notified_object
|
||||
}
|
||||
}
|
||||
|
||||
case notification.notification_code
|
||||
when MAP_ACCESS_APPROVED, MAP_ACCESS_REQUEST, MAP_INVITE_TO_EDIT
|
||||
map = notification.notified_object&.map
|
||||
result[:data][:map] = {
|
||||
id: map&.id,
|
||||
name: map&.name
|
||||
}
|
||||
when TOPIC_ADDED_TO_MAP
|
||||
topic = notification.notified_object&.eventable
|
||||
map = notification.notified_object&.map
|
||||
result[:data][:topic] = {
|
||||
id: topic&.id,
|
||||
name: topic&.name
|
||||
}
|
||||
result[:data][:map] = {
|
||||
id: map&.id,
|
||||
name: map&.name
|
||||
}
|
||||
when TOPIC_CONNECTED_1, TOPIC_CONNECTED_2
|
||||
topic1 = notification.notified_object&.topic1
|
||||
topic2 = notification.notified_object&.topic2
|
||||
result[:data][:topic1] = {
|
||||
id: topic1&.id,
|
||||
name: topic1&.name
|
||||
}
|
||||
result[:data][:topic2] = {
|
||||
id: topic2&.id,
|
||||
name: topic2&.name
|
||||
}
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,40 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ApplicationHelper
|
||||
def metacodeset
|
||||
metacodes = current_user.settings.metacodes
|
||||
return false unless metacodes[0].include?('metacodeset')
|
||||
if metacodes[0].sub('metacodeset-', '') == 'Most'
|
||||
return 'Most'
|
||||
elsif metacodes[0].sub('metacodeset-', '') == 'Recent'
|
||||
return 'Recent'
|
||||
end
|
||||
MetacodeSet.find(metacodes[0].sub('metacodeset-', '').to_i)
|
||||
end
|
||||
|
||||
def user_metacodes
|
||||
@m = current_user.settings.metacodes
|
||||
set = metacodeset
|
||||
@metacodes = if set && set == 'Most'
|
||||
Metacode.where(id: current_user.most_used_metacodes).to_a
|
||||
elsif set && set == 'Recent'
|
||||
Metacode.where(id: current_user.recent_metacodes).to_a
|
||||
elsif set
|
||||
set.metacodes.to_a
|
||||
else
|
||||
Metacode.where(id: @m).to_a
|
||||
end
|
||||
@metacodes.sort! { |m1, m2| m2.name.downcase <=> m1.name.downcase }.rotate!(-1)
|
||||
end
|
||||
|
||||
def user_most_used_metacodes
|
||||
@metacodes = current_user.most_used_metacodes.map { |id| Metacode.find(id) }
|
||||
end
|
||||
|
||||
def user_recent_metacodes
|
||||
@metacodes = current_user.recent_metacodes.map { |id| Metacode.find(id) }
|
||||
end
|
||||
|
||||
def invite_link
|
||||
"#{request.base_url}/join" + (current_user ? "?code=#{current_user.code}" : '')
|
||||
end
|
||||
|
||||
def user_unread_notification_count
|
||||
return 0 if current_user.nil?
|
||||
@uunc ||= current_user.mailboxer_notification_receipts.reduce(0) do |total, receipt|
|
||||
receipt.is_read ? total : total + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module ContentHelper
|
||||
def resource_name
|
||||
:user
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DeviseHelper
|
||||
def devise_error_messages!
|
||||
resource.errors.to_a[0]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module InMetacodeSetsHelper
|
||||
end
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MainHelper
|
||||
end
|
||||
|
|
15
app/helpers/map_mailer_helper.rb
Normal file
15
app/helpers/map_mailer_helper.rb
Normal file
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MapMailerHelper
|
||||
def access_approved_subject(map)
|
||||
map.name + ' - access approved'
|
||||
end
|
||||
|
||||
def access_request_subject(map)
|
||||
map.name + ' - request to edit'
|
||||
end
|
||||
|
||||
def invite_to_edit_subject(map)
|
||||
map.name + ' - invited to edit'
|
||||
end
|
||||
end
|
|
@ -1,3 +1,4 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MappingHelper
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MapsHelper
|
||||
# JSON autocomplete format for typeahead
|
||||
def autocomplete_map_array_json(maps)
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
module MetacodeSetsHelper
|
||||
end
|
|
@ -1,3 +1,79 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module MetacodesHelper
|
||||
def metacodeset
|
||||
metacodes = current_user.settings.metacodes
|
||||
|
||||
return false unless metacodes[0].include?('metacodeset')
|
||||
return 'Most' if metacodes[0].sub('metacodeset-', '') == 'Most'
|
||||
return 'Recent' if metacodes[0].sub('metacodeset-', '') == 'Recent'
|
||||
|
||||
MetacodeSet.find(metacodes[0].sub('metacodeset-', '').to_i)
|
||||
end
|
||||
|
||||
def user_metacodes
|
||||
@m = current_user.settings.metacodes
|
||||
set = metacodeset
|
||||
@metacodes = if set && set == 'Most'
|
||||
Metacode.where(id: current_user.most_used_metacodes).to_a
|
||||
elsif set && set == 'Recent'
|
||||
Metacode.where(id: current_user.recent_metacodes).to_a
|
||||
elsif set
|
||||
set.metacodes.to_a
|
||||
else
|
||||
Metacode.where(id: @m).to_a
|
||||
end
|
||||
|
||||
focus_code = user_metacode
|
||||
if !focus_code.nil? && @metacodes.index { |m| m.id == focus_code.id }.nil?
|
||||
@metacodes.push(focus_code)
|
||||
end
|
||||
|
||||
@metacodes.sort! { |m1, m2| m2.name.downcase <=> m1.name.downcase }
|
||||
|
||||
if !focus_code.nil?
|
||||
@metacodes.rotate!(@metacodes.index { |m| m.id == focus_code.id })
|
||||
else
|
||||
@metacodes.rotate!(-1)
|
||||
end
|
||||
end
|
||||
|
||||
def user_metacode
|
||||
current_user.settings.metacode_focus ? Metacode.find(current_user.settings.metacode_focus.to_i) : nil
|
||||
end
|
||||
|
||||
def user_most_used_metacodes
|
||||
@metacodes = current_user.most_used_metacodes.map { |id| Metacode.find(id) }
|
||||
end
|
||||
|
||||
def user_recent_metacodes
|
||||
@metacodes = current_user.recent_metacodes.map { |id| Metacode.find(id) }
|
||||
end
|
||||
|
||||
def metacode_sets_json
|
||||
metacode_sets = []
|
||||
metacode_sets << {
|
||||
name: 'Recently Used',
|
||||
metacodes: user_recent_metacodes
|
||||
.map { |m| { id: m.id, icon_path: asset_path(m.icon), name: m.name } }
|
||||
}
|
||||
metacode_sets << {
|
||||
name: 'Most Used',
|
||||
metacodes: user_most_used_metacodes
|
||||
.map { |m| { id: m.id, icon_path: asset_path(m.icon), name: m.name } }
|
||||
}
|
||||
metacode_sets += MetacodeSet.order('name').all.map do |set|
|
||||
{
|
||||
name: set.name,
|
||||
metacodes: set.metacodes.order('name')
|
||||
.map { |m| { id: m.id, icon_path: asset_path(m.icon), name: m.name } }
|
||||
}
|
||||
end
|
||||
metacode_sets << {
|
||||
name: 'All',
|
||||
metacodes: Metacode.order('name').all
|
||||
.map { |m| { id: m.id, icon_path: asset_path(m.icon), name: m.name } }
|
||||
}
|
||||
metacode_sets.to_json
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module SynapsesHelper
|
||||
## this one is for building our custom JSON autocomplete format for typeahead
|
||||
def autocomplete_synapse_generic_json(unique)
|
||||
|
|
11
app/helpers/topic_mailer_helper.rb
Normal file
11
app/helpers/topic_mailer_helper.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module TopicMailerHelper
|
||||
def added_to_map_subject(topic, map)
|
||||
topic.name + ' was added to map ' + map.name
|
||||
end
|
||||
|
||||
def connected_subject(topic)
|
||||
'new synapse to topic ' + topic.name
|
||||
end
|
||||
end
|
|
@ -1,10 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module TopicsHelper
|
||||
## this one is for building our custom JSON autocomplete format for typeahead
|
||||
def autocomplete_array_json(topics)
|
||||
topics.map do |t|
|
||||
is_map = t.is_a?(Map)
|
||||
metamapMetacode = Metacode.find_by_name('Metamap')
|
||||
metamap_metacode = Metacode.find_by(name: 'Metamap')
|
||||
{
|
||||
id: t.id,
|
||||
label: t.name,
|
||||
|
@ -16,11 +17,11 @@ module TopicsHelper
|
|||
|
||||
rtype: is_map ? 'map' : 'topic',
|
||||
inmaps: is_map ? [] : t.inmaps(current_user),
|
||||
inmapsLinks: is_map ? [] : t.inmapsLinks(current_user),
|
||||
type: is_map ? metamapMetacode.name : t.metacode.name,
|
||||
typeImageURL: is_map ? metamapMetacode.icon : t.metacode.icon,
|
||||
inmapsLinks: is_map ? [] : t.inmaps_links(current_user),
|
||||
type: is_map ? metamap_metacode.name : t.metacode.name,
|
||||
typeImageURL: is_map ? metamap_metacode.icon : t.metacode.icon,
|
||||
mapCount: is_map ? 0 : t.maps.count,
|
||||
synapseCount: is_map ? 0 : t.synapses.count,
|
||||
synapseCount: is_map ? 0 : t.synapses.count
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module UsersHelper
|
||||
# build custom json autocomplete for typeahead
|
||||
def autocomplete_user_array_json(users)
|
||||
|
|
|
@ -1,5 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationMailer < ActionMailer::Base
|
||||
default from: 'team@metamaps.cc'
|
||||
layout 'mailer'
|
||||
|
||||
class << self
|
||||
def mail_for_notification(notification)
|
||||
case notification.notification_code
|
||||
when MAP_ACCESS_REQUEST
|
||||
request = notification.notified_object
|
||||
MapMailer.access_request(request)
|
||||
when MAP_ACCESS_APPROVED
|
||||
request = notification.notified_object
|
||||
MapMailer.access_approved(request)
|
||||
when MAP_INVITE_TO_EDIT
|
||||
user_map = notification.notified_object
|
||||
MapMailer.invite_to_edit(user_map)
|
||||
when TOPIC_ADDED_TO_MAP
|
||||
event = notification.notified_object
|
||||
TopicMailer.added_to_map(event, notification.recipients[0])
|
||||
when TOPIC_CONNECTED_1
|
||||
synapse = notification.notified_object
|
||||
TopicMailer.connected(synapse, synapse.topic1, notification.recipients[0])
|
||||
when TOPIC_CONNECTED_2
|
||||
synapse = notification.notified_object
|
||||
TopicMailer.connected(synapse, synapse.topic2, notification.recipients[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
12
app/mailers/map_activity_mailer.rb
Normal file
12
app/mailers/map_activity_mailer.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MapActivityMailer < ApplicationMailer
|
||||
default from: 'team@metamaps.cc'
|
||||
|
||||
def daily_summary(user, map, summary_data)
|
||||
@user = user
|
||||
@map = map
|
||||
@summary_data = summary_data
|
||||
mail(to: user.email, subject: MapActivityService.subject_line(map))
|
||||
end
|
||||
end
|
|
@ -1,18 +1,24 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MapMailer < ApplicationMailer
|
||||
include MapMailerHelper
|
||||
default from: 'team@metamaps.cc'
|
||||
|
||||
def access_request_email(request, map)
|
||||
def access_approved(request)
|
||||
@request = request
|
||||
@map = map
|
||||
subject = @map.name + ' - request to edit'
|
||||
mail(to: @map.user.email, subject: subject)
|
||||
@map = request.map
|
||||
mail(to: request.user.email, subject: access_approved_subject(@map))
|
||||
end
|
||||
|
||||
def invite_to_edit_email(map, inviter, invitee)
|
||||
@inviter = inviter
|
||||
@map = map
|
||||
subject = @map.name + ' - invitation to edit'
|
||||
mail(to: invitee.email, subject: subject)
|
||||
def access_request(request)
|
||||
@request = request
|
||||
@map = request.map
|
||||
mail(to: @map.user.email, subject: access_request_subject(@map))
|
||||
end
|
||||
|
||||
def invite_to_edit(user_map)
|
||||
@inviter = user_map.map.user
|
||||
@map = user_map.map
|
||||
mail(to: user_map.user.email, subject: invite_to_edit_subject(@map))
|
||||
end
|
||||
end
|
||||
|
|
18
app/mailers/topic_mailer.rb
Normal file
18
app/mailers/topic_mailer.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class TopicMailer < ApplicationMailer
|
||||
include TopicMailerHelper
|
||||
default from: 'team@metamaps.cc'
|
||||
|
||||
def added_to_map(event, user)
|
||||
@entity = event.eventable
|
||||
@event = event
|
||||
mail(to: user.email, subject: added_to_map_subject(@entity, event.map))
|
||||
end
|
||||
|
||||
def connected(synapse, topic, user)
|
||||
@entity = topic
|
||||
@event = synapse
|
||||
mail(to: user.email, subject: connected_subject(topic))
|
||||
end
|
||||
end
|
|
@ -1,18 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AccessRequest < ApplicationRecord
|
||||
belongs_to :user
|
||||
belongs_to :map
|
||||
has_one :user_map
|
||||
|
||||
after_create :after_created_async
|
||||
|
||||
def approve
|
||||
self.approved = true
|
||||
self.answered = true
|
||||
self.save
|
||||
UserMap.create(user: self.user, map: self.map)
|
||||
MapMailer.invite_to_edit_email(self.map, self.map.user, self.user).deliver_later
|
||||
save
|
||||
|
||||
Mailboxer::Notification.where(notified_object: self).find_each do |notification|
|
||||
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
||||
end
|
||||
|
||||
UserMap.create(user: user, map: map, access_request: self)
|
||||
end
|
||||
|
||||
def deny
|
||||
self.approved = false
|
||||
self.answered = true
|
||||
self.save
|
||||
save
|
||||
|
||||
Mailboxer::Notification.where(notified_object: self).find_each do |notification|
|
||||
Mailboxer::Receipt.where(notification: notification).update_all(is_read: true)
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def after_created_async
|
||||
NotificationService.access_request(self)
|
||||
end
|
||||
handle_asynchronously :after_created_async
|
||||
end
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ApplicationRecord < ActiveRecord::Base
|
||||
self.abstract_class = true
|
||||
end
|
||||
|
|
39
app/models/attachment.rb
Normal file
39
app/models/attachment.rb
Normal file
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Attachment < ApplicationRecord
|
||||
belongs_to :attachable, polymorphic: true
|
||||
|
||||
has_attached_file :file,
|
||||
styles: lambda { |a|
|
||||
if a.instance.image?
|
||||
{
|
||||
thumb: 'x128#',
|
||||
medium: 'x320>'
|
||||
}
|
||||
else
|
||||
{}
|
||||
end
|
||||
}
|
||||
|
||||
validates_attachment_content_type :file, content_type: Attachable.allowed_types
|
||||
|
||||
def image?
|
||||
Attachable.image_types.include?(file.instance.file_content_type)
|
||||
end
|
||||
|
||||
def audio?
|
||||
Attachable.audio_types.include?(file.instance.file_content_type)
|
||||
end
|
||||
|
||||
def text?
|
||||
Attachable.text_types.include?(file.instance.file_content_type)
|
||||
end
|
||||
|
||||
def pdf?
|
||||
Attachable.pdf_types.include?(file.instance.file_content_type)
|
||||
end
|
||||
|
||||
def document?
|
||||
text? || pdf?
|
||||
end
|
||||
end
|
51
app/models/concerns/attachable.rb
Normal file
51
app/models/concerns/attachable.rb
Normal file
|
@ -0,0 +1,51 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Attachable
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
has_many :attachments, as: :attachable, dependent: :destroy
|
||||
end
|
||||
|
||||
def images
|
||||
attachments.where(file_content_type: image_types)
|
||||
end
|
||||
|
||||
def audios
|
||||
attachments.where(file_content_type: audio_types)
|
||||
end
|
||||
|
||||
def texts
|
||||
attachments.where(file_content_type: text_types)
|
||||
end
|
||||
|
||||
def pdfs
|
||||
attachments.where(file_content_type: pdf_types)
|
||||
end
|
||||
|
||||
def documents
|
||||
attachments.where(file_content_type: text_types + pdf_types)
|
||||
end
|
||||
|
||||
class << self
|
||||
def image_types
|
||||
['image/png', 'image/gif', 'image/jpeg']
|
||||
end
|
||||
|
||||
def audio_types
|
||||
['audio/ogg', 'audio/mp3']
|
||||
end
|
||||
|
||||
def text_types
|
||||
['text/plain']
|
||||
end
|
||||
|
||||
def pdf_types
|
||||
['application/pdf']
|
||||
end
|
||||
|
||||
def allowed_types
|
||||
image_types + audio_types + text_types + pdf_types
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,4 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Routing
|
||||
extend ActiveSupport::Concern
|
||||
include Rails.application.routes.url_helpers
|
||||
|
|
|
@ -1,31 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
class Event < ApplicationRecord
|
||||
KINDS = %w(user_present_on_map conversation_started_on_map topic_added_to_map synapse_added_to_map).freeze
|
||||
|
||||
# has_many :notifications, dependent: :destroy
|
||||
class Event < ApplicationRecord
|
||||
KINDS = %w[user_present_on_map user_not_present_on_map
|
||||
conversation_started_on_map
|
||||
topic_added_to_map topic_moved_on_map topic_removed_from_map
|
||||
synapse_added_to_map synapse_removed_from_map
|
||||
topic_updated synapse_updated].freeze
|
||||
|
||||
belongs_to :eventable, polymorphic: true
|
||||
belongs_to :map
|
||||
belongs_to :user
|
||||
|
||||
scope :chronologically, -> { order('created_at asc') }
|
||||
scope :chronologically, (-> { order('created_at asc') })
|
||||
|
||||
after_create :notify_webhooks!, if: :map
|
||||
|
||||
validates :kind, inclusion: { in: KINDS }
|
||||
validates :eventable, presence: true
|
||||
|
||||
# def notify!(user)
|
||||
# notifications.create!(user: user)
|
||||
# end
|
||||
|
||||
def belongs_to?(this_user)
|
||||
user_id == this_user.id
|
||||
end
|
||||
|
||||
def notify_webhooks!
|
||||
# group = self.discussion.group
|
||||
map.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
|
||||
# group.webhooks.each { |webhook| WebhookService.publish! webhook: webhook, event: self }
|
||||
end
|
||||
handle_asynchronously :notify_webhooks!
|
||||
end
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
class Events::ConversationStartedOnMap < Event
|
||||
# after_create :notify_users!
|
||||
|
||||
def self.publish!(map, user)
|
||||
create!(kind: 'conversation_started_on_map',
|
||||
eventable: map,
|
||||
map: map,
|
||||
user: user)
|
||||
module Events
|
||||
class ConversationStartedOnMap < Event
|
||||
# after_create :notify_users!
|
||||
|
||||
def self.publish!(map, user)
|
||||
create!(kind: 'conversation_started_on_map',
|
||||
eventable: map,
|
||||
map: map,
|
||||
user: user)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue