Compare commits

...

850 commits

Author SHA1 Message Date
Devin Howard
98081097b4 Revert "update rails dependencies"
Original commit broke the build, since some dependencies have breaking
changes.

This reverts commit f753392d49.
2018-11-09 07:42:26 -08:00
Devin Howard
f753392d49 update rails dependencies 2018-10-17 19:51:51 -07:00
Connor Turland
38a209a970 small bug fix (#1174)
if someone besides one of "us" tried to change their password, and their settings, it wouldn't work

in the typical case it would work fine
2018-03-11 21:57:23 -07:00
Devin Howard
bd7bf20810
factory_girl => factory_bot (#1172) 2018-03-10 08:10:09 -08:00
Devin Howard
955ebdd747
Change log level of Metamaps.Debug (#1170)
debug log level is invisible in Chrome by default, which is confusing
2018-02-05 21:35:53 -08:00
Devin Howard
fdcd8a93f1 tag 3.6.1 2018-01-24 20:02:28 -08:00
Devin Howard
b5c52adf5e update to paperclip 5.2.0 2018-01-24 19:52:33 -08:00
Devin Howard
b7761a3627
manual rubocop fixes (#1163) 2018-01-21 14:21:00 -08:00
Devin Howard
e0d72fce14
update nokogiri (#1169) 2018-01-21 14:20:21 -08:00
Devin Howard
139fdf8e2b
update rubocop to 0.48.1. We still want to match Code Climate though (#1168) 2018-01-20 14:10:26 -08:00
Devin Howard
4313f6eff8
TopicCard/Desc.spec.js (#1167)
TopicCard/Desc.spec.js
2018-01-20 13:31:36 -08:00
Devin Howard
91c004ebfd
TopicCard/Permission.spec.js (#1166) 2017-12-04 21:06:09 -08:00
Devin Howard
96056f43ef
TopicCard/Title.spec.js (#1165) 2017-12-02 12:45:05 -08:00
Devin Howard
32e58fa8af
tests for TopicCard/index.js (#1164) 2017-11-26 16:13:17 -08:00
Devin Howard
5ebbd87afc
automatic rubocop fixes (#1162) 2017-11-25 11:23:47 -08:00
Devin Howard
006920b686 fix broken experience if forgot password email isn't found 2017-11-13 07:16:25 -08:00
Devin Howard
97448b389f null check in synapse policy 2017-11-13 07:11:48 -08:00
Connor Turland
f1ecc9eb0b Merge pull request #1160 from metamaps/bug/map.info.box.closing
event listener was getting lost cuz react
2017-10-26 19:17:42 -04:00
Connor Turland
ca2684fcf3 event listener was getting lost cuz react 2017-10-26 19:09:28 -04:00
Connor Turland
d9c53514fe Update pull-changes.md 2017-10-25 06:44:20 -04:00
Connor Turland
e195b89bbd Merge pull request #1155 from metamaps/bug/fix.emails
fix map activity emails
2017-10-17 12:26:20 -04:00
Connor Turland
e66498a861 add logging for delayedJob 2017-10-17 12:20:51 -04:00
Connor Turland
901eb4a513 Update daily_summary.html.erb 2017-10-17 12:06:37 -04:00
Devin Howard
cbf44e3dfe add one view test 2017-10-17 08:28:00 -07:00
Connor Turland
8b492d6dc8 made the mistake of not checking all cases 2017-10-17 01:28:07 -04:00
Connor Turland
b83f366284 Merge pull request #1151 from metamaps/feature/admin.pages
move admin header to react
2017-10-15 16:05:18 -04:00
Connor Turland
1ac06d973c Merge pull request #1153 from metamaps/feature/follow.created
follow created maps as default setting
2017-10-15 14:08:04 -04:00
Connor Turland
9af3754bc8 follow created maps as default setting
if you are the map creator, we'd like to set you up to be following it by default
2017-10-15 14:07:11 -04:00
Connor Turland
8169f24072 Merge pull request #1150 from metamaps/rake-assets-precompile
run perms:fix on assets:precompile
2017-10-15 11:02:59 -04:00
Connor Turland
b9fb4a2829 move admin header to react 2017-10-15 10:56:51 -04:00
Connor Turland
9b52d0e081 fix tests 2017-10-15 10:56:04 -04:00
Devin Howard
14dc3687cd run perms:fix on assets:precompile 2017-10-14 12:02:41 -07:00
Metamaps on Linode
0a6e7918ef fix docs building by reverting raml2html 2017-10-14 14:55:42 -04:00
Metamaps on Linode
4a7595e76d fixup imports 2017-10-14 14:55:42 -04:00
Connor Turland
e899179314 Update first-deploy.md 2017-10-14 14:44:10 -04:00
Connor Turland
44fec58985 Merge pull request #1149 from metamaps/feature/reorg.react
reorg code to distinguish between route components and normal ones
2017-10-14 12:38:57 -04:00
Connor Turland
29a25c28a8 distinguish between route components and reusable components 2017-10-14 12:37:48 -04:00
Connor Turland
76c727cd61 Merge pull request #1148 from metamaps/feature/refactor.nav.bar
rename exploreMapsBar into reusable navBar
2017-10-14 12:30:29 -04:00
Connor Turland
693e6f5e10 bug fixes and make active class auto 2017-10-14 12:03:05 -04:00
Connor Turland
a1d4c99ff6 abstract exploreMapsBar into reusable navBar 2017-10-13 13:58:21 -04:00
Connor Turland
55f2425501 Merge pull request #1142 from metamaps/feature/notifs.box
Notifications Dropdown
2017-10-13 12:29:21 -04:00
Connor Turland
f9c139c19e ruby codeclimate fixes 2017-10-13 12:22:05 -04:00
Connor Turland
d51a22c5a9 eslint fixes 2017-10-13 12:13:36 -04:00
Connor Turland
567bc9d69d Merge pull request #1145 from metamaps/feature/lower.case.headings
Switch junto headings to have normal casing (not all uppercase)
2017-10-04 11:22:33 -04:00
Connor Turland
15f512efef improve notificationbox readability 2017-09-29 14:05:39 -04:00
Connor Turland
5e6fb6290c refactor for clarity 2017-09-29 13:06:33 -04:00
Connor Turland
8695297a0f wasn't using the proper serializer causing frontend error 2017-09-29 13:06:19 -04:00
Connor Turland
216a19476b add hover states and empty case 2017-09-28 12:28:33 -04:00
Connor Turland
a0c9530c91 Update index.js 2017-09-25 16:01:25 -04:00
Connor Turland
277644f59d improve styling, fix index notifs page 2017-09-25 15:21:04 -04:00
Connor Turland
0ffc01b3fb Merge pull request #1144 from metamaps/feature/hide-learn-markdown
hide "learn markdown" unless you're editing the topic card desc
2017-09-25 14:46:44 -04:00
Devin Howard
9471efb6bd hide "learn markdown" unless you're editing the topic card desc 2017-09-23 13:19:43 -07:00
Connor Turland
fc8ac6eef1 nest inconsistent data under data key 2017-09-23 11:20:02 -04:00
Connor Turland
9cc700c64d use decorator pattern for notifs api 2017-09-22 18:38:38 -04:00
Connor Turland
64ffc78f45 add the container for the notifications dropdown 2017-09-19 23:48:46 -04:00
Connor Turland
322da431eb Merge pull request #1139 from metamaps/feature/right.click.react
Right click/context menu redone in React
2017-09-19 11:49:30 -04:00
Connor Turland
3c7c8812a4 tempplate strings and new lines 2017-09-19 11:46:19 -04:00
Connor Turland
0d6963ebb0 eslint 2017-09-19 10:16:14 -04:00
Connor Turland
c4d0bf8ce4 clean up jquery ref and strings 2017-09-19 10:02:05 -04:00
Connor Turland
3406f2e04d make render a callback and use async apply for ease of use 2017-09-19 09:58:59 -04:00
Connor Turland
a4c905df4e move each li into its own function 2017-09-19 09:04:21 -04:00
Connor Turland
5f1fe4dc3f reimplement shifting menu according to click position 2017-09-19 08:37:00 -04:00
Connor Turland
2515073393 replace old edgeRightClick code 2017-09-19 00:46:23 -04:00
Connor Turland
a04cd0d395 call the right callbacks and show in the right context 2017-09-19 00:34:37 -04:00
Connor Turland
da9e44afa0 clear the right click menu the right way 2017-09-18 23:49:35 -04:00
Connor Turland
e290244404 beginning to come together 2017-09-18 23:30:33 -04:00
Connor Turland
6e1878413f wip right click in react 2017-09-18 21:09:35 -04:00
Connor Turland
77846cfcb7 missing period for consistency 2017-09-18 16:59:52 -04:00
Connor Turland
1ffc513617 Merge pull request #1137 from metamaps/feature/improve.desc
make desc edit area larger and resizable
2017-09-17 16:25:53 -04:00
Connor Turland
3886e62a7b make desc edit area larger and resizable 2017-09-17 09:01:44 -04:00
Devin Howard
ad2ba33db6 downgrade redis to 3.3.3
This fixes the following error seen on metamaps.cc:

> *A* `Gem::LoadError` *occurred while* `POST </mappings>` *was processed
> by* `mappings#create`: Specified 'redis' for Action Cable pubsub
> adapter, but the gem is not loaded. Add `gem 'redis'` to your Gemfile
> (and ensure its version is at the minimum required by Action Cable).

Backtrace
----------------

    ```/usr/local/rvm/rubies/ruby-2.3.0/lib/ruby/2.3.0/monitor.rb:214:in
    `mon_synchronize'
    /home/metamaps/metamaps.cc/app/models/mapping.rb:32:in `after_created'
    /home/metamaps/metamaps.cc/app/controllers/mappings_controller.rb:24:in
    `create'```
2017-09-16 13:41:50 -07:00
Devin Howard
cf9f54c738 tag v3.5 2017-09-16 12:27:02 -07:00
Connor Turland
f323796030 Merge pull request #1132 from metamaps/feature/mod.follow
add active scope to follows model
2017-09-13 22:45:50 -04:00
Connor Turland
a080b82e7f Merge pull request #1133 from metamaps/feature/topic.follow
Topic Card Design changes (to include 'follows')
2017-09-13 10:32:44 -04:00
Connor Turland
1174123b60 use scss vars and font fallbacks 2017-09-13 10:31:48 -04:00
Connor Turland
35f77129ad email job needs to respect active as well 2017-09-13 10:20:25 -04:00
Connor Turland
a56991aede add exception notifier for failed jobs 2017-09-13 10:18:00 -04:00
Connor Turland
672b456193 add markdown clarifications 2017-09-12 21:37:49 -04:00
Connor Turland
21518c8696 revert react router update and webpack config 2017-09-12 17:07:57 -04:00
Connor Turland
29bf2a23e8 review changes 2017-09-12 17:01:08 -04:00
Connor Turland
61eac509de Merge branch 'develop' into feature/topic.follow 2017-09-10 18:16:11 -04:00
Connor Turland
4cc420eb63 eslint fixes 2017-09-10 18:13:25 -04:00
Connor Turland
ec3e09c578 topic card design changes 2017-09-10 17:17:56 -04:00
Devin Howard
3e03e0ebbf update npm/gem dependencies (#1131)
* update npm/gem dependencies

* move to react prop-types package and fix jsdom usage

* fix sinon

* fix test support

* eslint?
2017-09-09 09:38:18 -07:00
Connor Turland
9ab7e7e170 topic card re-org 2017-09-08 16:58:17 -04:00
Connor Turland
5af2b8f216 add active scope to follows model 2017-09-08 13:42:56 -04:00
Connor Turland
8af66b1b2c Merge pull request #1130 from metamaps/feature/release.notifs
make notifs and follows work for all users
2017-09-03 18:44:33 -04:00
Connor Turland
9b2193ad8c show autofollow on client and mute on unfollow 2017-09-03 15:18:57 -04:00
Connor Turland
1a8c7810be fix eslint issue picked up by codeclimate 2017-09-03 09:13:15 -04:00
Connor Turland
d87bb7c75c make notifs and follows work for all users 2017-09-03 09:07:29 -04:00
Connor Turland
aceb3ff31e Merge pull request #1129 from metamaps/feature/map.activity.improved
improve email styling for release
2017-09-03 08:33:13 -04:00
Connor Turland
f26c6cf0b7 Merge pull request #1128 from metamaps/feature/prevent.notif.fork
dont send notification for each topic of forked map
2017-09-03 08:29:03 -04:00
Connor Turland
42f4ecb37b added bg color to sections 2017-09-03 08:27:05 -04:00
Connor Turland
64f4249f44 add comment 2017-09-02 14:12:07 -04:00
Connor Turland
958bd8c70c improve email styling for release 2017-09-02 14:06:23 -04:00
Connor Turland
3830946723 dont send notif for each topic of forked map 2017-09-02 09:59:21 -04:00
Connor Turland
3482e799fd Merge pull request #1127 from metamaps/update-docs
update docs
2017-07-26 09:26:59 -07:00
Connor Turland
e016b923a4 Update WindowsInstallation.md 2017-07-26 09:25:41 -07:00
Connor Turland
bb546779cd Update VagrantInstallation.md 2017-07-26 09:24:51 -07:00
Connor Turland
3829d32390 Update UbuntuInstallation.md 2017-07-26 09:22:34 -07:00
Connor Turland
9783a5ee1e Update MacInstallation.md 2017-07-26 09:22:06 -07:00
Connor Turland
12fc0c71f6 Update README.md 2017-07-26 09:21:16 -07:00
Connor Turland
c2cb8949eb Create VagrantInstallation.md 2017-07-25 17:22:27 -07:00
Connor Turland
4e7bf02749 Update README.md 2017-07-25 17:19:17 -07:00
Connor Turland
3203c2b4d0 de-prioritize vagrant docs, as its no longer our setup of choice 2017-07-25 17:18:07 -07:00
Connor Turland
1ec9dc20e4 Update MacInstallation.md 2017-07-25 17:07:46 -07:00
Connor Turland
1af4728073 Update UbuntuInstallation.md 2017-07-25 17:06:27 -07:00
Connor Turland
785e16eeae make Vagrantfile realtime server port match default 2017-07-25 16:57:37 -07:00
Connor Turland
d08cb3f95e Update UbuntuInstallation.md 2017-07-25 16:52:11 -07:00
Connor Turland
271fc7ebd0 Update MacInstallation.md 2017-07-25 16:47:33 -07:00
Connor Turland
9d590295cb Update WindowsInstallation.md 2017-07-25 16:44:40 -07:00
Connor Turland
dc4d44951e Update UbuntuInstallation.md 2017-07-25 16:41:47 -07:00
Connor Turland
767414ad9f Update MacInstallation.md 2017-07-25 16:37:16 -07:00
Connor Turland
1ec897b8c8 Update MacInstallation.md 2017-07-17 20:45:34 -07:00
Connor Turland
00e2aefb4e Delete ISSUE_TEMPLATE.md 2017-07-16 20:50:14 -07:00
Connor Turland
aec0f104b8 Merge pull request #1121 from JohnGillanders/develop
Update README.md
2017-07-09 23:32:41 -07:00
John Gillanders
db6d2e77da Merge pull request #1 from metamaps/develop
Updates from metamaps base 04/07/2017
2017-07-04 12:59:20 +12:00
John Gillanders
9585dce511 Update README.md
Added example of cloning repository using https:// protocol instead of SSH protocol - this is simpler to do since no set-up of SSH keys is required.
2017-07-04 12:49:28 +12:00
Devin Howard
78acd7e0b0 fix NoMethodError in mappings after_created when synapse's topic1/topic2 are nil 2017-05-20 10:58:06 -07:00
Devin Howard
328c1a14f3 mark v3.4.1 one commit too late 2017-05-13 19:32:51 -07:00
Devin Howard
10ac64c574 before destroy callback on maps to remove source_id foreign key relations (#1119) 2017-05-13 19:26:43 -07:00
Devin Howard
edce66c44d new react tests with enzyme library (#1116)
* move ImportDialogBox into a folder

* install enzyme

* start testing InfoAndHelp component

* add star logic to tests

* switch ImportDialogBox to using enzyme but tests are still failing

* make `npm run test` work

* tests pass again

* eslint

* try to fix travis by adding react-addons-test-utils again

* eslintrc for test dir

* remove duplicated code

* fix

* try to suppress 2 warnings
2017-05-13 13:50:52 -04:00
Devin Howard
74df2559a4 try to fix fatal on notifications index when a topic is invalid (#1115)
* try to fix fatal on notifications index when a topic is invalid

* Update index.html.erb
2017-05-13 13:49:46 -04:00
Robert Best
a6694a3f72 Improvements to Import (#1109)
* Changed URL Regex to make more links importable, also removed need for special text formatting in order to paste or drop new topic labels. (Didn't break TSV import mode)

* Removed console logs

* add url regex with full documentation

* don't eslint 3rd party lib

* check for TSV only at start of string

* fix a bug with event/e and eslint

* handleTEXT => handleText
2017-04-11 11:51:22 -04:00
Devin Howard
8c7a657499 update vimeo url, use asset path + erb for poster path (#1106) 2017-03-26 13:53:59 -07:00
Connor Turland
90f77cd4f7 simplify views/topiccard (#1102)
* simplify views/topiccard

* Update Links.js
2017-03-22 19:22:38 -04:00
Connor Turland
af4dc869c0 devins right shouldnt push straight to develop 2017-03-22 17:04:18 +00:00
Connor Turland
2cae12e1ab found a better way to handle junto chat panel 2017-03-22 16:35:28 +00:00
Connor Turland
49102ea474 only toggle if authorized 2017-03-22 16:13:59 +00:00
Connor Turland
f2a7cc1f19 stop using jquery ui for topic card dragging 2017-03-22 16:10:08 +00:00
Devin Howard
a5d5cd6000 fix editing synapse desc (#1101) 2017-03-20 19:32:54 -07:00
Devin Howard
391a1d8b24 link feedback directly to a hylo feedback tag (#1099) 2017-03-20 12:48:30 -07:00
Connor Turland
cc17c1ed38 add tiny divider between global and map items 2017-03-17 12:54:18 -04:00
Connor Turland
eee1febbf9 clean up unused vars and logs 2017-03-17 10:25:08 -04:00
Connor Turland
c8f6374ac8 remove no longer needed comments 2017-03-17 09:32:52 -04:00
Connor Turland
ed76162b63 added icons to mobile menu fixes #1095 2017-03-17 01:32:01 -04:00
Connor Turland
1eb4187691 broken import 2017-03-17 00:11:57 -04:00
Connor Turland
4a7dd54aca remove unused vars 2017-03-17 00:48:28 +00:00
Connor Turland
efd6258c7e mobile.js was already removed but not deleted 2017-03-17 00:29:24 +00:00
Connor Turland
f4d1b8ba35 ensure node is defined before calling function on it 2017-03-17 00:10:32 +00:00
Connor Turland
47a74dd77b react-router and rebuild app structure in react (#1091)
* initial restructuring

* stuff

* lock version number

* just keep using current mapinfobox

* fix map upperRightUI layout

* make mapsWidth work and add mobile

* remove filterBoxOpen for now

* redo the mobile menu in react

* get account menu and invite lightbox working

* fixed maps scrolling

* make other routes work

* fix signed out home page

* fix accountbox toggling

* add metacode edit routes

* lots of fixes

* fix map chat layout and tab bug

* improve topic card readability and fix dragging bug

* fixup mapchat stuff

* fix up navigation to use react-router

* jquery no longer handling access requests

* handle case where user hasn't loaded yet

* this shouldn't have been removed

* add frame for topic view

* rewrite map instructions

* fix toast (and sign out bug)

* fix apps pages and missing routes

* made our request invite page look nice

* filter box in react

* forgot to add one proptype

* remove extra comments

* handle page title and mobile title updates

* reenable google analytics

* make filterbox use onclickoutside

* reenable topic view in react

* fix csrf auth token

* fix little homepage styling issue

* try putting preparevizdata in a timeout

* installing render log to count

* little fixes

* fixup filters

* make filter map function names more readable

* eslint helps

* renaming for clarity

* use onclickoutside for account/sign in box

* add some logging to see whether this is source of many renders

* turns out chatview was heavily hogging memory

* tiimeout not needed
2017-03-16 17:58:56 -04:00
Robert Best
33276444c7 [Feature] Expand current selection to include neighbors by pressing CTRL+SHIFT+UP (#1090)
* Expand current selection to include neighbors by pressing CTRL+SHIFT+UP

* minor fixes as requested
2017-03-10 15:22:30 -08:00
Devin Howard
1124d76475 re-enable codeclimate duplication 2017-03-10 08:30:01 -08:00
Connor Turland
4ffa9460f5 bug fix for people who aren't testers on settings page 2017-03-10 11:29:00 -05:00
Connor Turland
44753dbfe1 Merge branch 'develop' 2017-03-09 14:55:59 -05:00
Connor Turland
77f76b1b5a variable name fix and make is_tester method global for reuse in views 2017-03-09 14:36:24 -05:00
Devin Howard
e544d6a6db refactor api and fix bugs (#1088)
* fix weird double-embed issue

* fix users/current api if not logged in

* turbocharge the api

* fix docs
2017-03-09 14:24:52 -05:00
Devin Howard
780e66632b fix react embedly (#1089) 2017-03-09 14:23:24 -05:00
Connor Turland
de4f51bb5c fix permissions and don't send if has map open 2017-03-08 15:45:40 -05:00
Connor Turland
5d0da4c5f1 method was preventing certain follows from succeeding 2017-03-08 15:02:22 -05:00
Connor Turland
9079d1bffc check permissions prior to sending 2017-03-08 15:01:58 -05:00
Connor Turland
962881a35d Update follow_service.rb 2017-03-08 14:13:47 -05:00
Connor Turland
8483b62603 allow users to select follow settings 2017-03-08 18:50:56 +00:00
Devin Howard
e3b4dac1e1 remove takeScreenshot button in favour of separate buttons in the map card and import/export dialogue (#1086) 2017-03-07 12:15:28 -05:00
Connor Turland
8998e3858c fixes bug where popups are happening 2017-03-07 16:55:15 +00:00
Devin Howard
ce51eeca8c remove dedupe plugin 2017-03-07 07:54:25 -08:00
Connor Turland
3178f6e650 bump version number 2017-03-07 03:58:29 +00:00
Connor Turland
7ee96bf6c6 Into master: two finger pan/zoom, map and topic follows (for internal testing) on the UI, map activity emails (#1084)
* fix topic spec

* fix synapse/mapping spec

* brakeman csrf warning suppressed :|

* follows for maps in the ui for internal testing only still (#1072)

* follows for maps in the ui for testers

* require user for these actions

* match how map follow works

* include ability to unfollow from email

* fixup templates

* add unfollow_from_email to the policies

* Update _cheatsheet.html.erb

Clean up text, clarify, and bring in line with current functionality

* topicsRegex and synapsesRegex should allow commas (#1073)

* even better import csv regexes

* prevent double prompt on file drop import

* topic card in react (#1031)

* its coming along

* links bar

* scssify a bunch

* metacode image working a bit better

* metacode selector in react topic card

* riek editing for name field on topic card

* riek submit on enter

* factor out Title and Links from Topic Card component, but not the listeners

* create working Desc editor

* styling is much better now

* textarea min height for desc

* disallow images in topic card markdown

* shift enter is linebreak, enter is save

* attachments split out, but it's pretty buggy

* move listeners into Links.js

* slightly wider metacodeTitle

* fix positioning on metacode selector

* fix metacode selection

* move metacode and permissions into subcomponents

* fixes

* prevent editing on desc/title if not authorized to edit

* fix topic card draggability

* fix embedly

* fix md test

* remove the removed link card manually with jquery

* fix test syntax

* eslint

* more eslin

* reuse authorizedToEdit

* convert metacode sets to a json object for react

* add the html in react whoop

* fix metacode styling

* sort wasn't working

* finishing metacode select

* readd the above link input border

* fix syntax

* multiline title editable textarea

* more portable metacode selector component

* factor out #metacodeOptions into one react component with a callback :D:D:D

* render metacodeOptions in right click menu with react

* render metacodeOptions in right click menu with react

* fix up right click menu's metacode editing

* fix topic card title character counter

* ignore metamaps secret bundle in ag

* simplify Attachments props

* factor out embedly card into its own component; it seems to help

* link resetter

* fix edit icon on title in topic card

* move mapCount and synapseCount hover/click logic to react

* fix up the showMore control

* metacode selection tweaks

* tweak links bar spacing in topic card

* rubocop

* remove TODOs

* more badass permissions selector

* close permission selector when you click outside

* fix overeager metacode selector

* more modular attachments component

* fix bug in Desc.js

* fix right click styling

* permission changes are different than edit rights

* bad module ref

* ensure maxLength on topic titles

* hellz yeah (#1074)

* fix drop from two touches to one

* don't commit activity service

* ability to select/unselect all metacodes in custom set with keyboard shortcut (fix #390) (#1078)

* ability to select/unselect all metacodes in custom set with keyboard shortcut

* select all button

* nicer all/none buttons

* set up react testing (#1080)

* install mocha-webpack. also switch hark to npm version instead of github version

* well, mocha-webpack runs

* add jsdom for tests

* upgrade to webpack 2

* fix npm run test errors

* ImportDialogBox component tests

* Fixes bug where pressing delete key while editing text will suggest... (#1083)

* Fixes bug where pressing delete key while editing text will suggest the deletion of selected map entities

* Changed the DEL key to remove entities instead of delete them

* temporarily disable code climate duplication engine

* add topic following for internal testing

* daily map activity emails (#1081)

* data prepared, task setup

* add the basics of the email template

* cover granular permissions

* unfollow this map

* break out permissions tests better

* rename so test runs
2017-03-06 22:49:46 -05:00
Connor Turland
b740fef8fe daily map activity emails (#1081)
* data prepared, task setup

* add the basics of the email template

* cover granular permissions

* unfollow this map

* break out permissions tests better

* rename so test runs
2017-03-06 22:42:22 -05:00
Connor Turland
55b031ccb7 add topic following for internal testing 2017-03-07 01:47:10 +00:00
Devin Howard
9df389060e temporarily disable code climate duplication engine 2017-03-06 09:29:36 -08:00
Robert Best
153cc38d1a Fixes bug where pressing delete key while editing text will suggest... (#1083)
* Fixes bug where pressing delete key while editing text will suggest the deletion of selected map entities

* Changed the DEL key to remove entities instead of delete them
2017-03-06 11:48:59 -05:00
Devin Howard
4ff9619837 set up react testing (#1080)
* install mocha-webpack. also switch hark to npm version instead of github version

* well, mocha-webpack runs

* add jsdom for tests

* upgrade to webpack 2

* fix npm run test errors

* ImportDialogBox component tests
2017-03-06 02:29:12 +08:00
Devin Howard
a6c1c0c730 ability to select/unselect all metacodes in custom set with keyboard shortcut (fix #390) (#1078)
* ability to select/unselect all metacodes in custom set with keyboard shortcut

* select all button

* nicer all/none buttons
2017-03-04 11:51:51 -05:00
Connor Turland
529dec09a3 don't commit activity service 2017-03-02 04:38:33 +00:00
Connor Turland
ddbaac513f fix drop from two touches to one 2017-03-02 04:35:13 +00:00
Connor Turland
ba943b20f1 hellz yeah (#1074) 2017-02-27 17:06:56 -05:00
Connor Turland
4deb3f5ab9 topic card in react (#1031)
* its coming along

* links bar

* scssify a bunch

* metacode image working a bit better

* metacode selector in react topic card

* riek editing for name field on topic card

* riek submit on enter

* factor out Title and Links from Topic Card component, but not the listeners

* create working Desc editor

* styling is much better now

* textarea min height for desc

* disallow images in topic card markdown

* shift enter is linebreak, enter is save

* attachments split out, but it's pretty buggy

* move listeners into Links.js

* slightly wider metacodeTitle

* fix positioning on metacode selector

* fix metacode selection

* move metacode and permissions into subcomponents

* fixes

* prevent editing on desc/title if not authorized to edit

* fix topic card draggability

* fix embedly

* fix md test

* remove the removed link card manually with jquery

* fix test syntax

* eslint

* more eslin

* reuse authorizedToEdit

* convert metacode sets to a json object for react

* add the html in react whoop

* fix metacode styling

* sort wasn't working

* finishing metacode select

* readd the above link input border

* fix syntax

* multiline title editable textarea

* more portable metacode selector component

* factor out #metacodeOptions into one react component with a callback :D:D:D

* render metacodeOptions in right click menu with react

* render metacodeOptions in right click menu with react

* fix up right click menu's metacode editing

* fix topic card title character counter

* ignore metamaps secret bundle in ag

* simplify Attachments props

* factor out embedly card into its own component; it seems to help

* link resetter

* fix edit icon on title in topic card

* move mapCount and synapseCount hover/click logic to react

* fix up the showMore control

* metacode selection tweaks

* tweak links bar spacing in topic card

* rubocop

* remove TODOs

* more badass permissions selector

* close permission selector when you click outside

* fix overeager metacode selector

* more modular attachments component

* fix bug in Desc.js

* fix right click styling

* permission changes are different than edit rights

* bad module ref

* ensure maxLength on topic titles
2017-02-26 11:42:47 -05:00
Devin Howard
47d0faadf2 prevent double prompt on file drop import 2017-02-25 13:04:00 -08:00
Devin Howard
9800cc27c6 even better import csv regexes 2017-02-25 12:15:45 -08:00
Devin Howard
7840e09e5f topicsRegex and synapsesRegex should allow commas (#1073) 2017-02-25 12:05:56 -08:00
ben, bro
687b957737 Update _cheatsheet.html.erb
Clean up text, clarify, and bring in line with current functionality
2017-02-23 22:03:33 -08:00
Connor Turland
9ce989eba5 add unfollow_from_email to the policies 2017-02-16 14:01:22 +00:00
Connor Turland
2c85590d65 fixup templates 2017-02-16 13:55:19 +00:00
Connor Turland
2b34d84715 include ability to unfollow from email 2017-02-16 13:42:35 +00:00
Connor Turland
013e3c7f21 follows for maps in the ui for internal testing only still (#1072)
* follows for maps in the ui for testers

* require user for these actions

* match how map follow works
2017-02-15 23:01:53 -05:00
Devin Howard
8d771543d8 Merge branch 'fix/rspec' into develop 2017-02-12 15:29:40 -08:00
Devin Howard
50639e8a0a Merge branch 'develop' 2017-02-12 15:11:19 -08:00
Devin Howard
9d52aa9c74 tag v3.3 2017-02-12 15:09:08 -08:00
Devin Howard
545706e17a disable cookie based auth on the API - mostly (#1070) 2017-02-12 12:54:54 -05:00
Devin Howard
95901e17e8 fix travis (#1071)
* fix topic spec

* fix synapse/mapping spec

* brakeman csrf warning suppressed :|
2017-02-12 12:53:04 -05:00
Devin Howard
9dbbdf1150 brakeman csrf warning suppressed :| 2017-02-11 20:00:42 -08:00
Devin Howard
4ee4aeaad2 fix synapse/mapping spec 2017-02-11 19:56:07 -08:00
Devin Howard
bfdce21a66 fix topic spec 2017-02-11 19:54:09 -08:00
Devin Howard
53d4beddec move hr tag in notification emails 2017-02-11 19:35:23 -08:00
Devin Howard
d455ced683 send mail by default is false in message from devs. also fixes a bug where the option didn't do anything 2017-02-11 19:30:58 -08:00
Connor Turland
d8698ef6f2 api stuffs (#1069)
* Update restful_controller.rb

* Update tokens_controller.rb

* /tokens/new form

* thats all
2017-02-11 19:29:03 -05:00
Connor Turland
1374da35da Update notification_service.rb 2017-02-11 15:29:31 -05:00
Connor Turland
2d0d0403b1 little fixes for deploy 2017-02-11 19:50:59 +00:00
Connor Turland
2d50f24be6 var misnamed 2017-02-11 14:21:47 +00:00
Connor Turland
876c61a18e Better experience of notifications. (#1066)
* all the good changes

* follows

* dont send duplicates

* remove follow_type for now

* dont add all the extra stuff we're not implementing yet

* refactor

* lots of fixes

* notifications improvements

* bad merge
2017-02-11 09:06:01 -05:00
Connor Turland
b0deafc53e Follows and some new notifications (#1063)
* all the good changes

* follows

* dont send duplicates

* remove follow_type for now

* dont add all the extra stuff we're not implementing yet

* refactor

* lots of fixes

* Delete activity.html.erb

* Delete activity.text.erb

* Update 20170209215819_create_follows.rb

* Update schema.rb

* Update mapping.rb

* Update mailboxer.rb
2017-02-11 00:20:42 -05:00
Connor Turland
a647d80efa third try to fix this little bug 2017-02-10 12:02:05 -05:00
Connor Turland
559ad230ce actually this fixes it 2017-02-10 11:52:58 -05:00
Connor Turland
26dfcbf823 edge case where realtime server is passing empty object 2017-02-10 11:45:05 -05:00
Connor Turland
915defcd1b little fixes 2017-02-10 00:32:15 +00:00
Connor Turland
dde097ea75 all the good changes (#1065) 2017-02-09 16:53:19 -05:00
Devin Howard
3706cd83e7 helper function and notification setup for messages from the devs to be sent to all users (#1064)
* message from devs notification type

* helper function for messages from devs

* don't use find_by_email

* temporary fix
2017-02-09 10:37:35 -05:00
Connor Turland
575a3ec8bf Rename user_not_present_on_map.rB to user_not_present_on_map.rb 2017-02-05 22:09:51 -05:00
Connor Turland
b2bf9978aa Update ISSUE_TEMPLATE.md 2017-02-05 14:34:47 -05:00
Connor Turland
0441850504 Secret.convo (#1059)
* set up for using secret css/js

* testing

* add stuff

* final tweak for secret convos

* looks like its all working

* realized this change is just good all around

* minor touch ups

* only us for now

* no longer validate presence of xloc/yloc

* fix syntax issue
2017-02-05 14:30:23 -05:00
Connor Turland
3ae4072b5d add ability to keep metacode focus 2017-02-05 06:28:10 +00:00
Robert Best
00ecb0f6bb Make DEL key delete selected items (With confirmation still :P ) (#1058)
* add del key

* made DEL key into delete shortcut
2017-02-03 14:23:04 -05:00
Devin Howard
45a15da896 fix error in loading url titles 2017-02-01 12:37:50 -05:00
Devin Howard
a96c8ae75c fix bug 2017-01-31 23:44:10 -05:00
Devin Howard
a137c21d2d searchfields api parameter (#1054) 2017-01-28 16:53:54 -05:00
Connor Turland
952cf4e79f keep permission of topic/synapse in sync with map its deferring to from beginning (#1053)
* Update topic.rb

* Update synapse.rb
2017-01-28 16:40:41 -05:00
Devin Howard
53bc4ee1c8 fix mapper page (#1050) 2017-01-28 15:44:38 -05:00
Connor Turland
c60f7f4525 add Story, which is on metamaps, total is now 48 2017-01-28 01:04:23 -05:00
Connor Turland
8df2cd8732 fix metacode names 2017-01-28 01:01:20 -05:00
Devin Howard
2c6da79df3 redirect /explore to / (#1051) 2017-01-27 15:16:31 -05:00
Connor Turland
6e913efbae track pageloads with google analytics. fixes #1012 (#1048)
* track pageloads with google analytics. fixes #1012

* Update Router.js
2017-01-25 20:57:34 -08:00
Connor Turland
db81962c91 some c9 files to gitignore 2017-01-26 00:24:31 +00:00
Connor Turland
8330ef9679 treat cable sub/unsub as joined/left map. fixes #1035 (#1047) 2017-01-25 15:32:13 -08:00
Devin Howard
696ff396b0 file attachments in db (re: #124) (#1043)
* file attachments in db

* rubocop

* factor out a bunch of file types

* thumb and medium image styles"

* syntax error in concern

* markdown is also plaintext

* rubocop
2017-01-24 15:10:40 -05:00
Devin Howard
b16617286f revert back to jquery 1 to fix best in place 2017-01-23 19:50:59 -05:00
Devin Howard
fee011bba6 fix readme bullets 2017-01-23 19:37:50 -05:00
Devin Howard
d16709e8e7 fix codeclimate style issues (#1046)
* bunch of code climate fixes

* more
2017-01-23 19:30:13 -05:00
Devin Howard
0ad10c0f5a fix style of thumb button on map card (#1044) 2017-01-23 14:02:14 -05:00
Devin Howard
d11278b63b map rdf export (fixes #1015) (#1036)
* simple rdf export of maps

* register ttl mime type

* owl

* mm

* fix up export service

* implement base url thing whoo

* add more rdf fields

* fix rdf syntax errors

* hide unused fields in rdf

* some code climate fixes

* update ontology a bit more

* syntax fix

* typo
2017-01-22 16:42:04 -05:00
Devin Howard
2652d53e9b update ruby dependencies too (#1042)
* update rubygem dependencies

* update backbone

* brakeman fix

* brakeman

* ugh syntax fix
2017-01-22 16:41:51 -05:00
Devin Howard
dc8d274487 whoops, I guess we do need jquery in package.json 2017-01-22 14:07:04 -05:00
Devin Howard
2fd972ddce ajax queue (fixes #853) (#1037)
* jquery.ajaxq

* install jquery.ajaxq from npm

* patch ajaxq into Backbone code

* use ajaxq library with more github stars

* eslint
2017-01-22 13:50:34 -05:00
Devin Howard
bba8231e8c update npm dependencies (#1038)
* only one github dependency left

* update npm deps

* exact versions of npm deps
2017-01-21 15:37:14 -05:00
Devin Howard
1229e92feb fix bug in Debug.js 2017-01-21 13:34:39 -05:00
Devin Howard
ba3d5f07dd try to fix metamaps.debug 2017-01-21 13:09:26 -05:00
Devin Howard
d47d7e50e7 mark v3.2 on develop 2017-01-21 13:04:28 -05:00
Devin Howard
af2c6ebef1 split screenshot function/button into two parts (#1027)
* split screenshot function into 4 separate helpers

* screenshot download button in import dialog box

* thumbnail button inside map info box

* import blue button styling

* fight with styling to make the button at least appear

* add more text

* fix tooltip display

* automatically start downloading the screenshot

* eslint

* revamp GlobalUI.notifyUser

* fix object destructuring syntax

* fix
2017-01-19 14:50:08 -05:00
Devin Howard
a9f19815e4 fix api embed to use the correct serializers (fix #998) (#1029)
* use correct serializer for singular embeds in api (almost fixes #998)

* fix has_many api embeds too!

* unused arg
2017-01-19 14:49:40 -05:00
Devin Howard
460de840b6 redis server 2017-01-18 16:38:34 -05:00
Devin Howard
36ed85312e fix crontab 2017-01-18 16:29:52 -05:00
Devin Howard
991c4cabdb move node installation further up 2017-01-18 13:40:48 -05:00
Devin Howard
38004c1f1f fix npm install isntructions 2017-01-18 13:34:32 -05:00
Devin Howard
cd796f3ade gist for unicode error on db:setup 2017-01-18 13:25:50 -05:00
Devin Howard
c57015cb15 rvm install needs sudo 2017-01-18 13:16:33 -05:00
Devin Howard
9223295320 add node source 2017-01-18 13:14:39 -05:00
Devin Howard
b4bffbe427 database called metamaps, not metamap002 in example 2017-01-18 13:10:09 -05:00
Devin Howard
6296df1102 need postgres dev headers 2017-01-18 13:09:47 -05:00
Devin Howard
2e0acfc170 update docs 2017-01-18 12:04:40 -05:00
Devin Howard
99b21be27b tag v3.2 2017-01-16 14:18:49 -05:00
Devin Howard
2c60d7335c Merge branch 'develop' (v3.2) 2017-01-16 11:21:02 -05:00
Connor Turland
6f6e5bea06 Update README.md 2017-01-15 20:23:18 -05:00
Connor Turland
6f0d391aaa Update ISSUE_TEMPLATE.md 2017-01-15 20:17:30 -05:00
Connor Turland
b1a64c6e7a Update ISSUE_TEMPLATE.md 2017-01-15 20:16:53 -05:00
Connor Turland
59b3d254dd include new info zones 2017-01-14 01:35:48 -05:00
Devin Howard
f3539f54bf hotfix ugh 2017-01-11 23:36:30 -05:00
Devin Howard
75ccfb0ab3 hotfix map title in meta tags whoops 2017-01-11 23:32:13 -05:00
Devin Howard
7b5bd53c28 I think this will fix the meta tags (#1030) 2017-01-11 23:27:05 -05:00
Connor Turland
5302f03196 remove exclamation mark 2017-01-11 23:00:19 -05:00
Devin Howard
536c458981 add code climate to the readme 2017-01-11 22:42:32 -05:00
Devin Howard
f64612f99b add meta tags to maps (#1028) 2017-01-11 22:26:45 -05:00
Connor Turland
cbc38e0c93 emoji-mart styling fix 2017-01-11 14:02:11 -05:00
Devin Howard
42d671c05b stop replacing shortcodes/emoticon in the live NewMessage textarea (#1026) 2017-01-11 13:56:44 -05:00
Devin Howard
08109ee5de remove instructions from ImportDialogBox (#1022)
* remove instructions from ImportDialogBox

* link back to docs.metamaps.cc for import instructions
2017-01-11 13:50:37 -05:00
Connor Turland
0952c0f3c9 Bug/name.overflow (#1025)
* creator name was pushing 'view only' off card

* Update MapCard.js
2017-01-11 13:36:07 -05:00
Devin Howard
25b4d388de eslint commands and apply some style fixes (#1021)
* auto eslint and add commands for eslint

* eslint the entire frontend folder
2017-01-11 12:52:34 -05:00
Devin Howard
8b738f3d28 emoticons turned on by default 2017-01-10 22:05:04 -05:00
Devin Howard
da94cd0c8b systemd job in deploy docs 2017-01-10 18:00:46 -05:00
Devin Howard
e9e6b1dc09 tweak chat emoji (#1019) 2017-01-09 14:55:21 -05:00
Connor Turland
e84dfbaa33 fix message styling 2017-01-09 13:27:39 -05:00
Devin Howard
cb95e027c4 Add emoji to chat (#1013)
* add emoji picker unstyled

* rename junto.css.erb => junto.scss.erb

* junto scss-ified

* add emoji mart css

* emoji are replaced in the text area

* remove unicode emoji from messages before sending to db

* add emoji back into messages on display

* bigger font size on chat messages

* tweak styling

* codeclimate (eslint)
2017-01-09 13:14:20 -05:00
Connor Turland
8e50efb3c1 render messages nicer 2017-01-04 18:12:07 -05:00
Connor Turland
5ab5f6fec2 Update README.md 2017-01-04 17:17:53 -05:00
Devin Howard
cbf1ec3afb fix missing npm github dep (#1011) 2017-01-04 12:34:08 -05:00
Connor Turland
d3315d962d only render google analytics if a tracking code envvar is set 2017-01-04 12:08:12 -05:00
Connor Turland
ae05fb35d3 more config updates for heroku 2017-01-04 11:14:03 -05:00
Connor Turland
9e6ce90950 update config for heroku and prod 2017-01-04 11:08:32 -05:00
Connor Turland
3868910dde Stream map related events from rails server via actioncable instead of nodejs (#1010)
* actioncable needs puma not webrick

* add framework

* remove the old way

* send events from server to client

* get all events working

* clean up receivable

* map is polymorphic on message

* add the moved event

* make todo comments clear

* verify before streaming from map channel

* rubocop fixes

* wasn't set up correctly for nodejs realtime
2017-01-03 16:12:58 -05:00
Connor Turland
5c1261892f remove the one pixel gap between search input and icon 2016-12-26 21:03:22 -05:00
Connor Turland
9ada1ca935 remove exclamation mark 2016-12-26 17:19:56 -05:00
Connor Turland
df5cc4e1a8 remove exclamation mark 2016-12-26 17:15:42 -05:00
Connor Turland
ce073028c8 remove exclamation mark 2016-12-26 17:13:42 -05:00
Connor Turland
7d869d7b63 remove exclamation mark 2016-12-26 17:10:41 -05:00
Connor Turland
73e8f2d4c8 re-implement chat in react (#997)
* hidously mangle ChatView to start moving it to React

* fix up Realtime/index.js - should be good now?

* in theory this should compile

* ok the MapChat renders using react...

* move Handlers code into react - woot

* try reintegrating backbone

* fix wrapper styling

* chat box opens and closes properly

* make the unread count work

* organize more sanely

* refactor some of the ChatView functions

* removed management of chatview from room

* css can stop handling logic right about now

* makin things work

* don't need room here anymore

* set raw html in message

* make pending work

* removeParticipant when mapper left was broken

* re-enable scrolling, focus, and blur
2016-12-21 03:56:29 -05:00
Connor Turland
68f0e91259 track forks (#994)
* track forks

* update api and docs

* fix tests
2016-12-18 16:17:51 -05:00
Devin Howard
b07941834c v3.1 in initializers 2016-12-16 17:22:48 -05:00
Devin Howard
b914065bb3 Merge branch 'develop'; tag v3.1 2016-12-16 17:17:24 -05:00
Devin Howard
33fc27ffd1 Merge pull request #989 from metamaps/fix/travis
fix travis
2016-12-16 17:16:32 -05:00
Devin Howard
7ca7f0862f fix mapping spec 2016-12-16 17:09:23 -05:00
Devin Howard
c604e69d77 enable postgresql 9.4 in travis 2016-12-16 17:09:23 -05:00
Connor Turland
fb12c7e202 Track everything we need to reconstruct maps (#984)
* feature/more.events

* keep mapping.user as the creator

* cleanup cruft and include slack notifs

* capture topic and synapse updates, store the old values

* avoid the mapping gets deleted problem

* include an indicator of which values changed

* style cleanup

* remove the hack in favor of a legit way

* updated schema file
2016-12-16 16:51:52 -05:00
Devin Howard
9ab1c9c647 Merge pull request #932 from metamaps/feature/mailboxer
mailboxer notification centre
2016-12-16 16:41:37 -05:00
Connor Turland
28d960459e styling of notifs list 2016-12-16 16:25:14 -05:00
Connor Turland
ef84209de1 make it look better when its taking up the full screen width 2016-12-16 16:25:13 -05:00
Connor Turland
2d920cf66a add maps links to nav locations 2016-12-16 16:25:13 -05:00
Connor Turland
40a97a5ae9 these are output in the main layout file 2016-12-16 16:25:13 -05:00
Devin Howard
186129807e fix spec, bugs, style 2016-12-16 16:25:08 -05:00
Connor Turland
87228c27c1 Fix mailboxer + email bugs 2016-12-16 16:24:24 -05:00
Connor Turland
6d8392d2e7 Make mailboxer look good and update email templates 2016-12-16 16:24:01 -05:00
Devin Howard
0960159265 Mailboxer notification pagination 2016-12-16 16:23:49 -05:00
Devin Howard
88e98c7342 polish mailboxer with bug fixes 2016-12-16 16:23:32 -05:00
Devin Howard
3f6f020ce1 grant/deny buttons mark access request notifications as read 2016-12-16 16:23:30 -05:00
Devin Howard
8e958ec9a8 invite to edit notifications marked as read in system once map is visited 2016-12-16 16:23:30 -05:00
Devin Howard
9debcdde39 Integrate rails mailers with mailboxer 2016-12-16 16:23:17 -05:00
Robert Best
b4ad51e69d reactify notification icon 2016-12-16 16:21:40 -05:00
Devin Howard
9b95e91f1a more style tweaks + brakeman fix 2016-12-16 16:21:23 -05:00
Connor Turland
c46e85529e little style tweaks to css and content 2016-12-16 16:21:01 -05:00
Devin Howard
85408a14d3 Initial notification centre using mailboxer 2016-12-16 16:20:53 -05:00
Connor Turland
3b8a5d0c2e Update message_policy.rb (#973) 2016-12-14 13:23:40 -05:00
Robert Best
6f88c2a7eb Update ISSUE_TEMPLATE.md 2016-12-12 13:49:26 -05:00
Robert Best
f1e62fb6c1 Update ISSUE_TEMPLATE.md
changed multiplication symbol so that double-clicking number placeholders works again.
2016-12-12 13:47:00 -05:00
Robert Best
0c52188014 Update ISSUE_TEMPLATE.md
reduced whitespace
2016-12-12 13:30:56 -05:00
Robert Best
7c0e0f731f Update ISSUE_TEMPLATE.md
changed multiplication sign from asterisks to x, because markdown treats asterisks as special.
2016-12-12 11:35:59 -05:00
Devin Howard
1ba339b3be subset of synapse creation changes (#970)
* esc cancels topic and synapse creation now

* close topic/synapse creation on right click

* backspace and delete don't close synapse creation anymore

* hitting tab saves the synapse you're creating
2016-12-11 17:15:09 -05:00
Devin Howard
6129a27ecf hit Ctrl+A a second time to select all synapses, too (#968) 2016-12-11 16:21:36 -05:00
Devin Howard
d51e3f3b52 update npm deps, EXCEPT socket.io and backbone (#950)
* update npm dependencies (with some exceptions)

* update autolinker, remove underscore
2016-12-11 16:09:12 -05:00
Robert Best
1317186f63 Update ISSUE_TEMPLATE.md
changed all place-holders to underscores, they ae easier to double-click so as to select/replace.
2016-12-09 13:40:58 -05:00
Robert Best
d6527ea80e Create ISSUE_TEMPLATE.md 2016-12-09 12:20:30 -05:00
Connor Turland
a133702be2 Some topics and synapses were hidden from users erroneously (#944)
* ensure topics and synapses have their permission match the map they're deferring to

* update permission of topics and synapses as map perm changes, when defer_to_map

* try enabling count threshold on rubocop

* remove unused mk_permission functions

* change *_count methods to use delegate to save lines in map.rb model

* rubocop topic.rb
2016-12-06 16:46:46 -05:00
Devin Howard
d2074ada79 fix policy scope errors in search controller (#947) 2016-12-06 13:09:42 -05:00
Devin Howard
00286fcc29 tag v3.0.4 2016-12-06 12:38:06 -05:00
Devin Howard
01cd624bfa add polyfill so chrome 49 can upload map thumbnail screenshots (#946) 2016-12-06 12:36:06 -05:00
Connor Turland
a5f793fe54 fixup topic card template 2016-12-02 21:21:37 +00:00
Devin Howard
d1aa62d382 fix policy scope error (#941) 2016-11-30 11:46:09 -05:00
Devin Howard
3f161c1076 make topic titles have width of 25 chars (#933) 2016-11-29 11:00:14 -05:00
Devin Howard
4da3a9d55f hide mobile menu if browser is resized to full size (#937) 2016-11-28 13:53:29 -05:00
Devin Howard
90c5bc26fc Active.Mapper was being initialized twice, causing errors (#934) 2016-11-27 21:12:05 -05:00
Devin Howard
5d8ff3efce realtime shouldn't poll forever if the dev server isn't up (#931) 2016-11-24 14:40:14 -05:00
Devin Howard
95b8b52224 fix NoMethodError in topics#autocomplete_topic (#930) 2016-11-24 14:16:58 -05:00
Devin Howard
55853c60f4 update user model with fixes, including style and recentMetacodes algorithm (#922) 2016-11-13 14:29:07 -08:00
Devin Howard
5b90c38b22 Merge pull request #902 from metamaps/fix/schema
fix db schema
2016-11-13 14:24:31 -08:00
Devin Howard
c03d6dd5f6 remove in_trash from schema to match production 2016-11-13 17:21:42 -05:00
Devin Howard
51d5d77629 Merge pull request #929 from metamaps/fix/develop-bugs
fix some develop bugs, merge master, and move realtime port to .env
2016-11-09 21:14:48 -05:00
Devin Howard
ce2d462578 fix bugs on develop branch 2016-11-09 20:44:00 -05:00
Devin Howard
4533a0f2fe merge changes from metamapscc instance branch (#913)
* homepage video fallback

* public/50x.html

* remove blog from public/ html pages

* remove video file since it's on metamaps.cc server

* eslint
2016-11-09 09:34:10 -05:00
Devin Howard
5851d57eef Merge branch 'master' into develop 2016-11-09 09:29:30 -05:00
Connor Turland
e1441acde0 synapse wasn't updating calculated_permission 2016-11-08 19:50:08 +00:00
Connor Turland
d1f75c8c24 oops! don't change rt server port 2016-11-08 19:45:51 +00:00
Connor Turland
83b58d43d5 only remove user once they've left all maps 2016-11-08 19:42:48 +00:00
Devin Howard
3759851621 fix access#access route (#926) 2016-11-08 09:37:06 -08:00
Devin Howard
a176cdf231 eslint frontend folder (#923) 2016-11-07 15:25:08 -05:00
Devin Howard
9df974a037 strip whitespace from search terms (#919) 2016-11-07 14:58:53 -05:00
Devin Howard
bd4072f81c Merge pull request #707 from metamaps/feature/split-out-backbone
finish removing global Metamaps references from frontend code
2016-11-07 14:58:20 -05:00
Devin Howard
6a2646c9cd fix mailer specs (#921) 2016-11-07 14:56:35 -05:00
Devin Howard
2f4fe525ce Fix a bunch of errors and style issues 2016-11-07 14:55:20 -05:00
Devin Howard
518782e1c7 remove Metamaps.Erb 2016-11-07 14:55:20 -05:00
Devin Howard
7c9b6a2205 try to move all rails data into Metamaps.ServerData
Metamaps.Erb and currentPage and currentSection are still not in; should they be?
2016-11-07 14:55:20 -05:00
Devin Howard
8026969799 start storing data in ServerData 2016-11-07 14:55:17 -05:00
Devin Howard
4b500a4428 move Metamaps.Loading into node modules 2016-11-07 14:40:43 -05:00
Devin Howard
0778179ba7 eslint 2016-11-07 14:40:43 -05:00
Devin Howard
bfd23c6d32 split Backbone.js into a bunch of different files. Still more work to do to modularize it 2016-11-07 14:40:43 -05:00
Devin Howard
9cb3074245 rename Metamaps.Backbone to Metamaps.DataModel 2016-11-07 14:40:43 -05:00
Devin Howard
e4d193572f fix mailer specs 2016-11-07 14:40:25 -05:00
Connor Turland
0f85abfda2 add channel to webhooks (#915) 2016-11-05 09:34:50 -07:00
Connor Turland
887c3f7570 fixes #903 and #831 (#911) 2016-11-04 15:02:56 -07:00
Connor Turland
667f5653a7 topic descriptions from old data can be nil 2016-11-04 21:03:11 +00:00
Connor Turland
48b93b2269 change grant to allow. fixes #909 (#910) 2016-11-04 13:22:06 -07:00
Connor Turland
9ad4684825 firefox needs e.pageX not e.x (#906) 2016-11-02 19:20:06 -07:00
Devin Howard
f516e1e73d fix up deploy docs 2016-11-01 16:31:36 +08:00
Devin Howard
2588636837 tag v3.0.1 - bugfixes for 3.0 2016-11-01 16:06:05 +08:00
Devin Howard
644df6fcdc fix pasting urls (#901) 2016-11-01 16:01:34 +08:00
Devin Howard
c10a4f4837 fix exception notification backtrace (#898) 2016-11-01 10:05:45 +08:00
Devin Howard
304722b528 fix api docs (#897)
* fix api docs

* more rake => rails
2016-11-01 09:52:10 +08:00
Devin Howard
a9c67e70d4 move webhook and event serializers back (#899) 2016-11-01 09:46:44 +08:00
Connor Turland
ed3e4780d2 bug when topic was in more than 5 maps fixes #891 (#894) 2016-10-31 17:10:44 -04:00
Connor Turland
b013499c76 misnamed variable errors out maps search (#893) 2016-10-31 16:41:37 -04:00
Devin Howard
5270c5a611 Merge branch 'develop' for v3.0 2016-10-31 19:51:02 +08:00
Devin Howard
5cfa8ffdc7 bump version to 3.0 2016-10-31 19:48:07 +08:00
Devin Howard
814c1acc0f a few markdown style updates (#885)
* markdown block padding

* a few more markdown style updates
2016-10-31 15:38:16 +08:00
Devin Howard
62e2acdd52 add about lightbox again (#884)
* add about lightbox again

* fix about lightbox style
2016-10-31 15:38:09 +08:00
Connor Turland
151e96f803 Metamaps.Realtime.synapseRemoved is not a function (#880) 2016-10-29 12:10:13 -04:00
Devin Howard
bc1f212c93 fix tab/shift-tab for metacode selection (#879) 2016-10-30 00:08:51 +08:00
Devin Howard
b9190233b1 enable sucker punch for heroku (#878) 2016-10-29 23:38:17 +08:00
Devin Howard
5e0e44b436 supercharge the schemas (#874)
* fix map schema - woot it works

* update other schemas to include embeddable attrs

* update current user schema/examples
2016-10-29 22:58:31 +08:00
Devin Howard
1fbfd56d57 filter maps by user_id in api (#872)
* filter maps by user_id in api

* test user_id map filter

* update starred maps example to make starred true lol

* add user id to map schema/examples
2016-10-29 22:07:27 +08:00
Devin Howard
a32f98bde2 to_json should be as_json or there's bugs (#870)
* to_json should be as_json or there's bugs

* revert explore controller, it's better without

* revert search controller and some topic methods
2016-10-29 18:28:29 +08:00
Connor Turland
6cc827d11c wasn't updating calculated_permission when updating permission (#869) 2016-10-28 18:26:40 -04:00
Devin Howard
de16420796 fix logCanvasAttributes error (#863) 2016-10-28 15:20:39 +08:00
Devin Howard
e49e5c258a make synapse permissions depend on topic1 and topic2 (#839)
* deep change to synapse policy - is this ok?

* make synapse policy resilient to nil topic1/topic2/map

* use a transaction to handle authorization vs invalid record in synapse controller

* more synapse controller tests

* inline documentation

* fix policy(Synapse).create?
2016-10-28 11:03:59 +08:00
Devin Howard
4dc32d7d2e fix metacodes page scrolling (#862)
* fix metacodes page scrolling

use scheme from
http://brandonhilkert.com/blog/page-specific-javascript-in-rails/

* switch overflow:hidden to be on explicit controllers
2016-10-28 10:55:04 +08:00
Devin Howard
9d821c920b reorder API authentication precedence to be: token, oauth, cookie (#860)
* reorder authentication to be: token, then oauth, then cookie

* all APIs but tokens are accessible anonymously (so add mappings to the list)

* fix mapping order
2016-10-28 10:51:58 +08:00
Devin Howard
6b1220b533 overflow-y: hidden on body to prevent openLightbox from showing a scrollbar (#859) 2016-10-27 18:40:42 -04:00
Devin Howard
4f3d12d7a5 fix import promises (#858) 2016-10-27 14:03:18 +08:00
Devin Howard
7b4a072fd8 attempt to fix import problems (#852) 2016-10-26 20:34:22 +08:00
Devin Howard
175a3ee73e policy_scope on has_many relationships in serializers (#840)
* token overrides current user in api

* policy scope has_many relationships

* fix hard coded topics - whoops

* handle policy_scope returning nil in application serializer
2016-10-26 19:56:30 +08:00
Devin Howard
b13587456d fix coordsToPixels calls even more 2016-10-26 19:11:40 +08:00
Devin Howard
f023a18069 fix pixel stuff for real? (#851)
* fix getPastelColor function (I think)

* fix pixelsToCoords and coordsToPixels function calls

* update signature of coord/pixel functions in Util.spec.js
2016-10-26 19:04:00 +08:00
Devin Howard
e640048386 fix topic card title word break css (#844) 2016-10-26 17:01:05 +08:00
Devin Howard
98725b3ee4 fix getPastelColor function (I think) (#850)
* fix getPastelColor function (I think)

* fix pixelsToCoords and coordsToPixels function calls

* update signature of coord/pixel functions in Util.spec.js
2016-10-26 14:26:48 +08:00
Devin Howard
8a95262f2c allow anonymous users to GET api routes (#842)
* make map methods use ActiveRecord relations so they don't error on pundit

* test for logged out maps GET api

* open up GET routes on maps/topics/synapses and update api docs
2016-10-26 08:37:23 +08:00
Robert Best
ed89f80f49 Update README.md
some small tweaks to grammar and word choice
2016-10-25 14:24:10 -04:00
Devin Howard
47bca5907e add tests for Metamaps.Util (#825)
* decouple Util from other Metamaps modules

* first few Util tests

* more Util tests

* remove dead code

* eslint
2016-10-25 12:28:51 +08:00
Devin Howard
5163794698 anonymous users are nil, so need to remove the raise (#841) 2016-10-25 12:26:22 +08:00
Robert Best
0b6348e13f This fix closes the topic creation spinner when the map is panned. (Since, sometimes a click turns into a really small pan) (#828) 2016-10-24 11:48:34 -04:00
Connor Turland
ce1205f6d7 one more mapper card style fix 2016-10-24 14:35:23 +00:00
Connor Turland
96d25cc91d mapper profile mobile styling 2016-10-24 14:23:05 +00:00
Connor Turland
a9ef6feebd mapper page bug fix and styling 2016-10-24 13:42:26 +00:00
Connor Turland
98e2de68da oooh was using ineffective media queries for desktop 2016-10-23 16:49:16 -04:00
Connor Turland
4c68fd90ca set useful num for desc truncation on map cards 2016-10-23 16:30:54 -04:00
Connor Turland
cda0c21a0b make it responsive (#820) 2016-10-23 16:12:07 -04:00
Connor Turland
a44edbb17e better transition from map to explore 2016-10-23 11:44:20 -04:00
Connor Turland
aa96d074af dont show import on topic page 2016-10-23 11:21:38 -04:00
Connor Turland
4f9b9460ad don't block all right clicks 2016-10-23 11:12:43 -04:00
Devin Howard
a63cd02bc6 fix develop branch bug 2016-10-23 22:51:16 +08:00
Devin Howard
fb6c8a74a7 scoping on topic json properties (#813) 2016-10-23 22:11:38 +08:00
Devin Howard
5db8e27496 make metacode selector reliable after switching metacode sets (#816) 2016-10-23 22:11:26 +08:00
Devin Howard
87dc20fa50 stop showing map info box on topic view (#815) 2016-10-23 22:07:38 +08:00
Devin Howard
154257d062 fix Ctrl+A (#814) 2016-10-23 18:02:59 +08:00
Connor Turland
497c6ae017 spelling mistake fix 2016-10-22 15:16:55 -04:00
Connor Turland
9600983311 remove Connor thinking out loud comment 2016-10-22 11:07:50 -04:00
Connor Turland
cbcdd912c9 Comments were for non-redux scenario 2016-10-22 11:04:14 -04:00
Connor Turland
1d13da4ab5 Update README.md 2016-10-22 10:59:43 -04:00
Connor Turland
d359eb063a fixed the oauth redirect bug and a bit more (#796) 2016-10-22 16:46:39 +08:00
Connor Turland
4187dbd803 fix it up (#804) 2016-10-22 03:58:19 -04:00
Connor Turland
d549083cce prefer variable height lightbox over scrolling visually 2016-10-22 03:10:33 -04:00
Connor Turland
bc8660c83e remove about lightbox in prep for homepage redo and about page 2016-10-22 03:10:09 -04:00
Robert Best
c0b35280f6 Middle.mouse.click features (Open contained link & copy text to clipboard) (#792)
* changed the code to be based off of the current dev branch

* Update JIT.js

* Update Util.js

* Update JIT.js

A few logical operators were replaced with their stricter counterpart.

* Update JIT.js

* Update index.js

* Update Util.js
2016-10-22 02:58:13 -04:00
Connor Turland
31078c554e just make it 'tutorial' 2016-10-22 02:41:36 -04:00
Robert Best
ea20ba45b3 Merge pull request #738 from metamaps/window.resize.fix
Makes it so that resizing the browser window doesn't change the user's current location on the map
2016-10-22 02:12:54 -04:00
Robert Best
37b989c38e Update Listeners.js 2016-10-22 01:52:43 -04:00
Robert Best
759ec7845b cleaned up the window resize function even further 2016-10-22 05:50:31 +00:00
Robert Best
cfb8f51214 simplified the window resize function by adding a Util function that logs the canvas attributes. 2016-10-22 05:21:32 +00:00
Robert Best
1cd7e22c40 Merge commit '858ca66d69ed9e43f4d3a4ce6be288508cf4efa1' of github.com:metamaps/metamaps into window.resize.fix 2016-10-22 05:00:10 +00:00
Robert Best
ad1889dfc5 Merge branch 'develop' of github.com:metamaps/metamaps into window.resize.fix 2016-10-22 04:54:31 +00:00
Connor Turland
cbc8e6cdd4 the return of the infinite scroll (#795) 2016-10-22 00:15:10 -04:00
Connor Turland
f8556c30a5 resize every time it renders 2016-10-21 19:10:28 -04:00
Connor Turland
8af1e69460 undo last commit, don't need for rails5 2016-10-21 18:25:07 -04:00
Connor Turland
d1e8ecbf3b readd 12factor for debugging on heroku 2016-10-21 18:22:15 -04:00
Connor Turland
8e38469b1f add border radius to mapper list 2016-10-21 18:10:37 -04:00
Connor Turland
abb997c75c some quick fixes for realtime server after devins refactor 2016-10-21 18:04:18 -04:00
Connor Turland
be8efa6025 add card features (#793) 2016-10-21 17:42:21 -04:00
Robert Best
439527c464 Merge pull request #724 from metamaps/feature/edge.shift
Made it so that the map pans when you drag a selection of topics near the edge of the window
2016-10-21 17:03:25 -04:00
Robert Best
f68deea202 changed all logical operators to be more strict 2016-10-21 20:59:16 +00:00
Robert Best
b61cdb04fc Fixed the glitchyness, and made it suitable to merge with develop 2016-10-21 20:47:14 +00:00
Robert Best
5c67fcbff7 this time I actually addressed the conflicts 2016-10-21 20:38:17 +00:00
Robert Best
2eeb0a671f Fixed cherry pick conflicts 2016-10-21 20:26:42 +00:00
Connor Turland
fb427a11f0 [WIP] keep client fresh with junto info globally (#791)
* push state to client

* junto status is live on map cards XD

* little fixes

* eslint stuff

* remove object rest spread

* i think this makes realtime work without needing babel-node
2016-10-21 09:29:04 -04:00
Connor Turland
7a09a1c620 last commit broke stuff 2016-10-20 18:27:14 -04:00
Connor Turland
103ed5cbd7 max at 4, use fewer if not enough maps 2016-10-20 18:10:28 -04:00
Devin Howard
b1a7e548a2 add email/twitter links 2016-10-20 07:01:15 +08:00
Connor Turland
52c340b8f5 center the explore maps div! (#787)
* ooh baby

* will add displayStyle again later if we actually build it
2016-10-19 14:40:42 -04:00
Connor Turland
9299ca5f2c dont do translate with arrow keys till we can block conflicts 2016-10-19 17:47:10 +00:00
Devin Howard
261ed49977 replace uservoice with docs.metamaps.cc + Hylo (#777)
* replace uservoice with docs.metamaps.cc + Hylo

* re-add the feedback tab as link to hylo
2016-10-19 13:39:57 -04:00
Devin Howard
e2d9b6aef2 Merge pull request #786 from metamaps/fix/empty-autocomplete
fix topic autocomplete controller action
2016-10-19 22:16:26 +08:00
Devin Howard
1042fb020d Merge pull request #778 from metamaps/feature/auto-copy-invite-link
copy share invite link to clipboard automatically where possible
2016-10-19 22:15:21 +08:00
Devin Howard
7f1c04015e fix topic autocomplete controller action 2016-10-19 22:10:38 +08:00
Devin Howard
f75d5253b3 Merge pull request #781 from metamaps/fix/registration
clean up and fix devise code
2016-10-19 14:36:39 +08:00
Devin Howard
bb6566a45e clean up and fix devise code 2016-10-19 12:40:52 +08:00
Devin Howard
2529e0d44f copy share invite link to clipboard automatically where possible 2016-10-19 11:07:20 +08:00
Connor Turland
139837e997 restructure realtime server for clarity (#780)
* restructure realtime server for clarity

* better indenting on signal.js

* don't need it because socketioconnection is being imported now
2016-10-18 20:29:21 -04:00
Connor Turland
d8cd536a95 too much logging 2016-10-18 14:10:41 -04:00
Connor Turland
29913cd10b fix for heroku 2016-10-18 14:08:10 -04:00
Connor Turland
d004e98ada holy insanity realtime refactor (#779)
* all the refactoring

* make it all work
2016-10-18 12:34:19 -04:00
Connor Turland
d2e097fd05 add webrtc logging 2016-10-17 22:59:28 -04:00
Connor Turland
fe0da255dd [WIP] display whether a map is live on every map card (#775)
* tidy up

* checkwhethertosave was no longer correct
2016-10-17 22:27:15 -04:00
Devin Howard
6e75274737 access request tests (#772)
* access request tests

* map mailer spec update
2016-10-17 10:53:53 -04:00
Devin Howard
6c9d464a9f Global => All Maps (#774) 2016-10-17 10:53:33 -04:00
Connor Turland
517cfcb913 remove static lib files in favor of npm ones (#773)
* remove static lib files in favor of npm ones

* update howler to work correctly

* patch npm modules to not use window
2016-10-17 10:39:08 -04:00
Devin Howard
0ee1b3284a fix check-canvas-support require 2016-10-17 13:47:42 +08:00
Devin Howard
b976c13db2 Merge pull request #770 from metamaps/feature/remove-canvas-function
remove check-canvas-support.js
2016-10-17 13:40:34 +08:00
Connor Turland
c0955d7c5e multiple policy issues (#771)
* multiple policy errors

* make some things more explicit
2016-10-17 01:20:48 -04:00
Connor Turland
332bb2ec08 Map Card changes (#769)
* map card rewrite underway

* star count

* css fix
2016-10-16 23:46:55 -04:00
Devin Howard
179849b639 remove check-canvas-support.js 2016-10-17 11:42:11 +08:00
Devin Howard
4f6dae304c Merge pull request #768 from metamaps/feature/default-rails-scripts
add scripts from default rails install
2016-10-17 10:51:47 +08:00
Devin Howard
3479fb7ff7 Merge pull request #767 from metamaps/fix/schema
schema update
2016-10-17 10:46:57 +08:00
Devin Howard
c113253fc5 add scripts from default rails install 2016-10-17 10:42:14 +08:00
Devin Howard
e46aa54ba3 schema update 2016-10-17 10:39:46 +08:00
Connor Turland
4602ded8a4 access requests (#762)
* start on access requests

* set up access requests further

* set default values for approved and answered
2016-10-16 20:22:00 -04:00
Devin Howard
14ea18a967 Merge pull request #764 from metamaps/fix/import-dialog-box
fix file upload box
2016-10-16 22:11:36 +08:00
Devin Howard
8180a8cc71 fix file upload box 2016-10-14 14:45:17 +08:00
Devin Howard
da5191171a Merge pull request #760 from metamaps/feature/mailer-tests
tests for map_mailer.rb
2016-10-14 11:24:31 +08:00
Devin Howard
26a8cddd14 mailer spec 2016-10-13 18:45:54 +08:00
Devin Howard
407ac1f29c more simplecov groups 2016-10-13 16:48:54 +08:00
Devin Howard
fc2849824f fix js syntax error 2016-10-13 16:48:46 +08:00
Devin Howard
6f3c74b7f1 token policy fix 2016-10-13 15:21:27 +08:00
Devin Howard
c3dbd59280 Merge pull request #758 from metamaps/feature/remove-gems
don't need coffeescript
2016-10-13 14:55:04 +08:00
Devin Howard
0e7e649f56 don't need coffeescript, tunemygc fails on Windows 2016-10-13 14:52:59 +08:00
Devin Howard
6e03132f1b fix spec 2016-10-13 14:51:58 +08:00
Devin Howard
b2a4acc99d make default category explicit in import.js 2016-10-13 14:24:08 +08:00
Devin Howard
7eae8deacb revamp HTML template a bit for api docs (#757)
* my_tokens endpoint moved to normal index

* remove secured_by from metacodes/users

* ch ch ch changes

* mess with template

* fix securedBy

* convenience open

* gross authentication notes at the top of every endpoint

* better ordering

* move login tutorials into security tab

* oauth tutorial

* getting closer

* remove unneeded Endpoints header

* ok looks OK
2016-10-12 13:54:43 -04:00
Devin Howard
62c489cba7 suggesting api doc updates (#756) 2016-10-12 12:22:38 -04:00
Devin Howard
3051723bcf [WIP] add markdown getting started page to api docs (#752)
* add markdown getting started page to api docs. TODO section 3

* Update getting-started.md
2016-10-11 12:08:31 -04:00
Devin Howard
858ca66d69 eslint updates 2016-10-10 17:22:22 +08:00
Devin Howard
a0c0dcbc79 Merge pull request #753 from metamaps/fix/screenshot-no-file
fix screenshot no file error
2016-10-10 13:01:50 +08:00
Devin Howard
6e6d33abbe fix screenshot no file error 2016-10-10 12:12:42 +08:00
Devin Howard
8b1d85c3ca actually the smart option is dumb 2016-10-09 10:24:13 +08:00
Devin Howard
56d3ef8bea Merge pull request #751 from metamaps/feature/markdown-xss-safe
enable xss filtering and smart quote replacement in markdown
2016-10-09 10:23:00 +08:00
Devin Howard
ba9e26bc05 enable xss filtering and smart quote replacement in markdown 2016-10-09 10:20:17 +08:00
Devin Howard
9ac24f7468 Merge pull request #744 from metamaps/feature/markdown-in-topic-cards
markdown in topic card description field
2016-10-08 16:58:32 +08:00
Devin Howard
fe1c57b458 further updates - make Enter update bip fields whaaat 2016-10-08 16:55:46 +08:00
Devin Howard
9d85dab975 Merge pull request #747 from metamaps/fix/unauth-error
redirect to root_path if you get a 403
2016-10-08 14:16:13 +08:00
Devin Howard
ab76b77bdd Merge pull request #748 from metamaps/feature/api-json-404
return 404s for all unmatched api routes
2016-10-08 14:16:00 +08:00
Devin Howard
9513087bbd remove unnecessary api v1 code 2016-10-08 14:12:54 +08:00
Devin Howard
2c64b67abd return 404s for all unmatched api routes 2016-10-08 13:58:19 +08:00
Devin Howard
be6a2401b6 fix spec. not sure how this should work 2016-10-08 13:42:25 +08:00
Devin Howard
0764133d11 Merge pull request #661 from metamaps/feature/file-upload-component
set up a dialog box to help with import/export
2016-10-08 12:34:28 +08:00
Devin Howard
129e3db946 redirect to root_path if you get a 403 2016-10-08 12:26:08 +08:00
Devin Howard
7eacda2ae7 code style 2016-10-08 09:35:05 +08:00
Devin Howard
f775629371 showCard .desc css for ul and a tags 2016-10-08 09:24:17 +08:00
Devin Howard
0085ce71e6 upgrade to best in place 3.0.0 alpha 2016-10-08 09:24:16 +08:00
Devin Howard
fc044294f1 add markdown to topic cards 2016-10-08 09:23:57 +08:00
Devin Howard
20da1ef39f fiddle with import icon 2016-10-08 00:21:04 +08:00
Devin Howard
42bb2cd86a look and feel updates 2016-10-08 00:16:37 +08:00
Devin Howard
dc55bae243 Merge pull request #740 from metamaps/feature/ctrl-or-meta
make all Ctrl shortcuts also work with Meta (Cmd on OSX)
2016-10-08 00:07:07 +08:00
Robert Best
b6da38e29e Update Listeners.js
Simplified based on Connor's suggestion about usage of variables.
2016-10-07 02:36:41 -04:00
Devin Howard
2b036bfb4e all Ctrl shortcuts now also work with Meta (Cmd on OSX) 2016-10-07 14:03:48 +08:00
Robert Best
3e4ff59a82 Update Listeners.js 2016-10-06 23:58:57 -04:00
Robert Best
08f89ee630 Update Listeners.js 2016-10-06 23:56:39 -04:00
Connor Turland
86a6e92bc3 dont show private maps in global collection (#734)
* dont show private maps in global collection

* Update explore_controller.rb

* Update main_controller.rb
2016-10-06 23:45:17 -04:00
Robert Best
b978247785 Put all the code within the if statement 2016-10-07 00:51:52 +00:00
Robert Best
0aeb6caadb Makes it so that resizing the browser window doesn't change the user's location on the map 2016-10-07 00:33:16 +00:00
Connor Turland
97d2868fad dont pan while using arrow keys during creation fixes #721 (#733) 2016-10-06 10:49:49 -04:00
Connor Turland
658f102a4e fixes #720 double topic create when pinned (#732) 2016-10-06 10:37:01 -04:00
Connor Turland
b52523e7be one more maps in maps error 2016-10-06 10:32:06 -04:00
Connor Turland
e72ae5df94 another issue from the maps in maps branch 2016-10-06 09:33:10 -04:00
Connor Turland
a56c4eb110 missing comma 2016-10-06 09:27:18 -04:00
Connor Turland
85dcad928f enable pulling in of references to maps through typeahead (#636) 2016-10-06 09:12:01 -04:00
Connor Turland
a79d6a824c dont do async: false (#731)
* dont do async: false

* account for case where callback isn't provided
2016-10-06 09:07:46 -04:00
Devin Howard
38c323a18a global lightbox css changes 2016-10-06 16:22:22 +08:00
Devin Howard
518773d6e1 pop up a lightbox using React to help you export 2016-10-06 16:22:21 +08:00
Devin Howard
33bcfc1505 move Maps into a folder 2016-10-06 16:20:27 +08:00
Devin Howard
d80d33761d Merge pull request #730 from metamaps/feature/synapse-check-for-topic-by-name
allow synapses to be imported by topic name as well as id
2016-10-06 14:09:43 +08:00
Devin Howard
df59c28aa8 Merge pull request #729 from metamaps/fix/chat-message-word-wrap
word wrap on chat message text
2016-10-06 14:08:59 +08:00
Devin Howard
b4d1250959 share normalizeKey between TSV, CSV, and JSON 2016-10-06 12:03:23 +08:00
Devin Howard
c0a220abc9 allow synapses to be imported by topic name as well as id 2016-10-06 11:52:05 +08:00
Devin Howard
eb4073c228 word wrap on chat message text. Fixes #726 2016-10-06 11:18:55 +08:00
Connor Turland
98fae4b721 fixes #711 toast button styling 2016-10-05 22:28:37 -04:00
Connor Turland
0cfbe41d95 don't prevent all right clicking 2016-10-05 22:22:38 -04:00
Connor Turland
c256d0891b dont conflict message sending with topic creation 2016-10-05 22:17:04 -04:00
Connor Turland
6d6a5099e9 Enable access to Most Used and Recently Used metacodes in lists and carousel (#708)
* used and recent

* enable most used and recent in all metacode select situations

* selected changed to active at some point

* switch recent and most used positions

* remove index doc page
2016-10-05 10:45:39 -04:00
Connor Turland
8d613eab33 improve descriptors 2016-10-05 10:38:38 -04:00
Devin Howard
d193c9a53c add starred to maps API (#719)
* add starred to maps API and endpoint to create/delete

* add token to requests without token param

* add minor version number to api version

* metacode/user use uri in schema

* make code climate happier
2016-10-05 10:36:03 -04:00
Devin Howard
40453242fa Merge pull request #717 from metamaps/feature/eslint-updates
eslint updates
2016-10-05 11:55:47 +08:00
Devin Howard
12417d8cd3 update JIT eslint style 2016-10-05 01:46:51 +08:00
Devin Howard
e3db00f229 Merge pull request #718 from metamaps/fix/raml
fix api documentation
2016-10-05 00:00:34 +08:00
Devin Howard
e2c0ce7c22 fix api documentation 2016-10-04 23:43:42 +08:00
Devin Howard
113a5a2530 fix a bunch of bug risk eslint warnings 2016-10-04 23:38:32 +08:00
Devin Howard
959260f234 Merge pull request #716 from metamaps/feature/new-endpoints
users and metacodes api endpoints
2016-10-04 23:12:04 +08:00
Devin Howard
dbc2ff75df make eslint work and update yoda config 2016-10-04 23:06:49 +08:00
Devin Howard
df29e48d8c rubocop + allow unauthed users to see all users 2016-10-04 22:51:21 +08:00
Devin Howard
2eae89a6b7 users and metacodes api endpoints 2016-10-04 22:28:10 +08:00
Devin Howard
c90460802e enable heroku to serve apidocs 2016-10-04 17:59:13 +08:00
Devin Howard
a9831946d0 ensure public/api directory exists 2016-10-04 16:33:15 +08:00
Devin Howard
bf733b57d2 Merge pull request #715 from metamaps/feature/faster-builds
speed up travis builds by excluding raml2html from npm install
2016-10-04 16:24:10 +08:00
Devin Howard
15b8440fbc move raml2html to optional dependencies so it can be installed globally 2016-10-04 16:21:09 +08:00
Devin Howard
c58a8da1a6 Merge pull request #714 from metamaps/feature/raml-1.0
update raml and create a build script for it
2016-10-04 16:10:02 +08:00
Devin Howard
8afef1bc4a make tokens description field optional 2016-10-04 16:08:07 +08:00
Devin Howard
8ac8aad105 PUT and PATCH parameters are optional 2016-10-04 15:30:06 +08:00
Devin Howard
2466a0912f raml2html build script 2016-10-04 15:22:24 +08:00
Devin Howard
3d7a2ef5b1 make raml traits work and be accurate/useful 2016-10-04 15:22:24 +08:00
Devin Howard
a2cde20f8f raml2html with 1.0 syntax working 2016-10-04 15:22:22 +08:00
Connor Turland
da3795a2c2 new map improvements (#710)
* prehighlight the text for editing when taken to a new map

* style
2016-10-02 22:49:45 -04:00
Devin Howard
6d2efefbbc Merge pull request #709 from metamaps/bug/backbone
backbone router fix
2016-10-03 08:28:36 +08:00
Devin Howard
7d0b56da19 Merge pull request #689 from metamaps/feature/user-in-slack-notification
Custom formatter for slack exception notifications
2016-10-03 08:26:13 +08:00
Devin Howard
87228a9631 delete old gems and upgrade aws/paperclip (#676)
* remove old gems from gemfile, upgrade aws/paperclip

* update paperclip config

* upload screenshots as a blob instead of base64 to maps controller
2016-10-02 18:29:35 -04:00
Connor Turland
0f740e751a topics wasn't in backbone routes 2016-10-02 17:37:14 -04:00
Devin Howard
afa4422608 Custom formatter for slack exception notifications 2016-10-02 17:07:45 +08:00
Devin Howard
7ec9feff80 Merge pull request #702 from metamaps/feature/quiet-assets
quiet assets again
2016-10-02 11:01:17 +08:00
Devin Howard
b3c7e12d9a assets.debug was why assets were loud 2016-10-02 10:53:35 +08:00
Devin Howard
bc139608c2 Search.focus() is the new Search.open() 2016-10-02 10:09:55 +08:00
Devin Howard
05c1e4c60d Merge pull request #699 from metamaps/feature/arrow-keys-pan
arrow key panning - fixes #239
2016-10-02 00:13:16 +08:00
Devin Howard
ca981898d4 arrow key panning - fixes #239 2016-10-02 00:09:55 +08:00
Devin Howard
77d353464b Merge pull request #698 from metamaps/feature/random-updates
more random js & import updates
2016-10-01 23:26:58 +08:00
Devin Howard
8f230736dc code climate 2016-10-01 13:47:16 +08:00
Devin Howard
bb013787b6 make AutoLayout skip over coordinates if there is a mapping at that exact position 2016-10-01 13:34:52 +08:00
Devin Howard
20a32afe3b integrate handleURL into Import 2016-10-01 13:18:50 +08:00
Devin Howard
c5564e02fc don't needt o open topic card 2016-10-01 12:47:30 +08:00
Devin Howard
4949f0dbd6 eslint and use AutoLayout 2016-10-01 12:43:30 +08:00
Devin Howard
99d07d2d65 Merge pull request #695 from metamaps/fix/topic-bugs
fix topic controller bugs
2016-10-01 12:38:56 +08:00
Devin Howard
fdf03ac83a source maps!
(I think)
2016-10-01 12:32:40 +08:00
Devin Howard
1562d8fcfe topics imported with a link get Reference metacode 2016-10-01 12:14:38 +08:00
Devin Howard
e5e8a3dcbb Merge pull request #697 from metamaps/feature/random-updates
import fixes + random config updates
2016-10-01 11:36:57 +08:00
Devin Howard
e093ca5a30 more liberally import csv 2016-10-01 11:21:42 +08:00
Devin Howard
4328a6205f enable code duplication checks on code climate 2016-10-01 11:20:31 +08:00
Devin Howard
01872e740e fix import if there are errors 2016-10-01 11:19:38 +08:00
Devin Howard
6ae391265e enable source maps 2016-10-01 10:49:34 +08:00
Devin Howard
ea18479822 Merge pull request #696 from metamaps/fix/import
fix tsv import
2016-09-30 22:38:36 +08:00
Devin Howard
0e79f2ae4b fix tsv 2016-09-30 22:33:09 +08:00
Devin Howard
7156fab3e2 fix topic controller bugs 2016-09-30 14:42:07 +08:00
Devin Howard
97c118a20b Merge pull request #693 from metamaps/feature/re-enable-search
re-enable Ctrl+/ search box focus shortcut
2016-09-30 12:02:44 +08:00
Devin Howard
b396b94477 re-enable Ctrl+/ search box focus shortcut 2016-09-30 11:55:43 +08:00
Devin Howard
e916ea32dc Merge pull request #690 from metamaps/feature/globalui-lint
eslint updates for GlobalUI.js
2016-09-30 11:54:40 +08:00
Devin Howard
816d5adf94 remove old code from GlobalUI.Search 2016-09-30 11:52:01 +08:00
Robert Best
8864dbbdcf Merge pull request #691 from metamaps/feature/better.zoom
I changed how zoom by mouse-wheel works so that it zooms based on whe…
2016-09-29 18:26:02 -04:00
Robert Best
44a183ed7b I changed how zoom by mouse-wheel works so that it zooms based on where your mouse pointer is 2016-09-29 21:32:55 +00:00
Devin Howard
e4e6043ded split GlobalUI into files 2016-09-30 00:20:16 +08:00
Devin Howard
24caafba74 move GlobalUI into a folder 2016-09-30 00:08:45 +08:00
Devin Howard
3b8199aac6 eslint updates for GlobalUI.js 2016-09-30 00:08:04 +08:00
Devin Howard
2f0b0f39e5 Merge pull request #688 from metamaps/fix/searchsynapses-undefined-topic
fix error when searching for synapse with undefined topic1id
2016-09-29 23:56:16 +08:00
Devin Howard
1d4d7f07e2 fix error when searching for synapse with undefined topic1id 2016-09-29 18:38:54 +08:00
Devin Howard
9af3f04f4d Merge pull request #685 from metamaps/feature/chatview-lint
update ChatView.js eslint style
2016-09-29 15:21:15 +08:00
Devin Howard
ec8dbbb4a7 Merge pull request #687 from metamaps/fix/rack-attack
disable 5 minute request limit on rack attack
2016-09-29 15:18:48 +08:00
Devin Howard
26977d06a8 disable 5 minute request limit on rack attack 2016-09-29 13:15:14 +08:00
Connor Turland
1bbc72fff0 was destroying and not reinitializing 2016-09-28 22:36:53 -04:00
Devin Howard
bca85337cc add template strings + outdent to chatview 2016-09-29 09:33:13 +08:00
Devin Howard
e858a2a773 update ChatView.js eslint style 2016-09-29 09:24:17 +08:00
Devin Howard
ee9a49d7c6 Merge pull request #683 from metamaps/fix/routes
fix routes.rb
2016-09-29 08:44:15 +08:00
Devin Howard
88297b4eaa fix routes.rb 2016-09-29 08:40:39 +08:00
Connor Turland
93341719a9 Update main_controller.rb (#682) 2016-09-28 20:22:55 -04:00
Devin Howard
db3cf0490f fix develop branch bugs (#679)
* bugfix - rename SearchController so it works

* remove unneeded respond_with

* fix to_json calls
2016-09-29 08:02:25 +08:00
Robert Best
9605b24640 Merge pull request #681 from metamaps/better-contextMenu-fix
Better default context menu suppression fix
2016-09-28 15:37:46 -04:00
Robert Best
e8746ee7d9 Update Create.js 2016-09-28 15:32:49 -04:00
Robert Best
a37f60060c Update JIT.js 2016-09-28 15:31:08 -04:00
Robert Best
4e506ad290 Update JIT.js 2016-09-28 15:18:44 -04:00
Robert Best
67c4912c62 Update index.js 2016-09-28 13:37:08 -04:00
Robert Best
10a2782f85 Update JIT.js 2016-09-28 13:03:44 -04:00
Robert Best
2c3b387e42 Update index.js 2016-09-28 13:00:32 -04:00
Devin Howard
d6a239d6b4 Merge pull request #670 from metamaps/feature/explore-controller-simplify
[WIP test it] clean up routes and some controllers
2016-09-28 22:34:34 +08:00
Devin Howard
466b1716a5 more changes to routes.rb 2016-09-28 22:29:53 +08:00
Devin Howard
9699b41159 make requestinvite controller method explicit 2016-09-28 22:29:53 +08:00
Devin Howard
c1acaba941 re-order config/routes.rb 2016-09-28 22:29:53 +08:00
Devin Howard
5b9eedc830 pull search routes into their own controller 2016-09-28 22:29:53 +08:00
Devin Howard
5065655436 factor stars into their own controller 2016-09-28 22:27:32 +08:00
Devin Howard
3ee8d41298 maps controller code climate 2016-09-28 22:27:32 +08:00
Devin Howard
f75ad41a82 factor out map_scope function 2016-09-28 22:27:32 +08:00
Devin Howard
bb87c9c2db simplify explore controller a bit 2016-09-28 22:27:32 +08:00
Devin Howard
a8b698b11c Merge pull request #677 from metamaps/feature/node1-topic1-migration
node{1,2}_id => topic{1,2}_id migration and code changes
2016-09-28 22:26:50 +08:00
Devin Howard
cc412ac491 Merge pull request #675 from metamaps/feature/no-xls-export
remove excel export
2016-09-28 22:25:04 +08:00
Robert Best
ac60370d6f Merge pull request #678 from metamaps/prevent-context-menu
Prevent default context menu from opening when topics/synapses are right-clicked
2016-09-28 05:27:03 -04:00
Robert Best
40b7e95b68 Update index.js
Prevents the default chrome context menu from appearing overtop the Metamaps context menu
2016-09-28 04:35:41 -04:00
Devin Howard
743c9b3af9 node{1,2}_id => topic{1,2}_id migration and code changes 2016-09-28 10:35:14 +08:00
Devin Howard
a86101dda0 remove excel export 2016-09-27 21:10:14 +08:00
Connor Turland
8f0b350a2d Fix underscore bug (#674)
* Update package.json

* Update ChatView.js
2016-09-26 20:39:33 -04:00
Connor Turland
c60e103d97 Update _switchmetacodes.html.erb 2016-09-26 20:28:06 -04:00
Devin Howard
7150b9fcce Merge pull request #673 from metamaps/fix/eslint-updates
Figured out eslint-3 + some small eslint fixes
2016-09-26 18:18:31 +08:00
Devin Howard
bc8ce0fee4 topic view bug fix 2016-09-26 14:04:31 +08:00
Devin Howard
12cb675bb5 switch to using the eslint-standard plugin again 2016-09-26 13:44:23 +08:00
Devin Howard
c9a79468f4 switch to eslint-3 2016-09-26 13:40:02 +08:00
Devin Howard
ebaae084ae simple eslint fixes 2016-09-26 13:37:42 +08:00
Devin Howard
e646585a7a Merge pull request #672 from metamaps/feature/eslint-config
fix eslint config for code climate
2016-09-26 10:50:30 +08:00
Devin Howard
0e17ec11ec fix eslint config for code climate
this is MOSTLY the same as feross/standard
2016-09-26 10:47:45 +08:00
Devin Howard
5649798e4b Merge pull request #668 from metamaps/fix/hide-addTopic-message-on-double-click
show/hide add a topic instructions more consistently
2016-09-25 23:51:00 +08:00
Devin Howard
c20e503785 show/hide add a topic instructions more consistently 2016-09-25 23:48:14 +08:00
Devin Howard
17870e7a4c Merge pull request #669 from metamaps/fix/remove-invalid-links
show link remover for invalid links too
2016-09-25 23:47:30 +08:00
Devin Howard
b49cb7766a Merge pull request #652 from metamaps/feature/explore-controller
refactor map controller
2016-09-25 23:47:22 +08:00
Devin Howard
fb563c6eed Merge pull request #648 from metamaps/feature/load-url-title-hack
hack to load link titles when pulling a url into a map
2016-09-25 23:47:10 +08:00
Devin Howard
03ba3a89f1 main controller renders by name 2016-09-25 23:37:08 +08:00
Devin Howard
05495b0224 move explore views to their own folder 2016-09-25 23:35:35 +08:00
Devin Howard
18d8929bf1 use .or to fix all sorts of @map.mappings bugs 2016-09-25 23:35:26 +08:00
Devin Howard
50f98aebea explore controller spec 2016-09-25 23:25:38 +08:00
Devin Howard
dad048eb20 rubocop 2016-09-25 23:25:38 +08:00
Devin Howard
c76de5b1d5 refactor map model a bit and fix bugs 2016-09-25 23:25:38 +08:00
Devin Howard
3f9077b380 clean up 2016-09-25 23:25:38 +08:00
Devin Howard
b722d2d3b0 fix map controller create spec 2016-09-25 23:25:38 +08:00
Devin Howard
5e180ac10e set up explore controller routes and rename methods 2016-09-25 23:25:38 +08:00
Devin Howard
686d80e274 move more logic into map model 2016-09-25 23:25:37 +08:00
Devin Howard
7275beb163 put CRUD at top of maps controller, and alphabetize other actions below 2016-09-25 23:25:37 +08:00
Devin Howard
40bd9ed95a refactor maps controller a bit 2016-09-25 23:25:37 +08:00
Devin Howard
1ab8703008 move explore maps methods into their own controller 2016-09-25 23:25:37 +08:00
Devin Howard
eed5ff76ef add rate limiting headers 2016-09-25 23:23:52 +08:00
Devin Howard
959aa693f3 ok, i guess this is ready 2016-09-25 23:22:20 +08:00
Devin Howard
7f8110b6be configure rack attack to allow 5r/s for the load_url_title route 2016-09-25 23:22:18 +08:00
Devin Howard
ceb2699760 install rack-attack 2016-09-25 22:54:40 +08:00
Devin Howard
cc2e3b9358 hack to get the <title> tag when importing a url, without CORS issues 2016-09-25 22:50:16 +08:00
Devin Howard
8c16c60554 show link remover for invalid links too 2016-09-25 22:44:07 +08:00
Devin Howard
cc986368be Merge pull request #667 from metamaps/feature/update-package.json
update package.json and save a bit of bundle size
2016-09-25 22:25:31 +08:00
Devin Howard
dd78c0c379 Merge pull request #665 from metamaps/fix/topic-to-map-transition
hide circles when transitioning from topic view to map view
2016-09-25 22:25:19 +08:00
Devin Howard
0df17c4aa0 update deps in package.json 2016-09-25 21:53:40 +08:00
Devin Howard
2ade375c20 babel-plugin-lodash to slim down bundle size by 300 KB 2016-09-25 21:53:26 +08:00
Devin Howard
11d13445fb fix authorizeToEdit call 2016-09-25 20:19:38 +08:00
Devin Howard
7734272737 hide circles when transitioning from topic view to map view
fixes #389
2016-09-25 20:10:18 +08:00
Devin Howard
43fafb8e6f Merge pull request #663 from metamaps/fix/git-versioning
fix git versioning
2016-09-25 19:48:48 +08:00
Devin Howard
5819447828 fix git versioning 2016-09-25 19:35:37 +08:00
Devin Howard
997a4b7329 Merge pull request #662 from metamaps/fix/no-add-topic-message-if-logged-out
hide double click to add topic message if can't edit map
2016-09-25 18:50:57 +08:00
Devin Howard
35d6dbd0b4 hide double click to add topic message if can't edit map 2016-09-25 15:04:14 +08:00
Devin Howard
1810faacbe Merge pull request #660 from metamaps/feature/csv
enable csv import using csv-parse module
2016-09-25 14:27:48 +08:00
Devin Howard
40f89b1c61 enable csv import using csv-parse module 2016-09-25 12:49:57 +08:00
Devin Howard
82b7c7e5ac Merge pull request #659 from metamaps/feature/js-fiddling
simplify js
2016-09-24 23:35:50 +08:00
Devin Howard
0a0ff2fdab remove fetch api - we don't want no polyfills, and already have jQuery 2016-09-24 23:28:11 +08:00
Devin Howard
045bd3fd73 Metamaps.Filter bug and use _.omit instead of util function 2016-09-24 23:23:12 +08:00
Devin Howard
79aa7717ed exact versions in package.json 2016-09-24 23:21:29 +08:00
Devin Howard
0bb7b1523d Metamaps.ReactComponents isn't needed anymore 2016-09-24 14:40:40 +08:00
Devin Howard
03eacde753 Merge pull request #656 from metamaps/feature/tech-debt
rubocop style updates
2016-09-24 13:59:27 +08:00
Devin Howard
a164dccc94 fix errors!! 2016-09-24 13:55:52 +08:00
Devin Howard
20bd959c69 fix models that rubocop broke >:( 2016-09-24 13:02:53 +08:00
Devin Howard
b0fac7648a Merge pull request #650 from metamaps/fix/map-serialization-bug
fix @maps serialization bug
2016-09-24 12:32:38 +08:00
Devin Howard
f8c11f234d more rubocop updates 2016-09-24 12:27:34 +08:00
Devin Howard
5fab6de48a fiddle with metacodes controller 2016-09-24 11:00:53 +08:00
Devin Howard
0ace202ace automatic rubocop updates 2016-09-24 11:00:46 +08:00
Robert Best
0a62eb3299 Merge pull request #655 from metamaps/feature/fix-map-titles
Feature/fix map titles
2016-09-23 16:48:44 -04:00
Robert Best
afa0cc96b9 Update index.js 2016-09-23 16:06:28 -04:00
Robert Best
f41ece6f1c Update index.js 2016-09-23 15:47:37 -04:00
Robert Best
b8ae2c4b6a Update Router.js 2016-09-23 15:45:11 -04:00
Devin Howard
c76657ecb4 fix restful controller style issuse 2016-09-23 18:54:05 +08:00
Devin Howard
8255653d24 disable duplication checking in code climate for now 2016-09-23 18:51:34 +08:00
Devin Howard
04a3027368 code climate linked to travis 2016-09-23 18:43:54 +08:00
Devin Howard
cbd9395142 Merge pull request #651 from metamaps/feature/update
update gems
2016-09-23 18:37:14 +08:00
Devin Howard
bb5ba4861d [WIP] code climate config file (#654)
code climate config file
2016-09-23 18:36:47 +08:00
Devin Howard
4afab70414 Merge pull request #653 from metamaps/fix/travis
safer git dating
2016-09-23 17:57:02 +08:00
Devin Howard
a7338f8960 safer git dating 2016-09-23 17:49:26 +08:00
Devin Howard
117b7910bf test 2016-09-23 17:40:30 +08:00
Devin Howard
ce1ad3e24b update gems 2016-09-23 15:28:31 +08:00
Devin Howard
df84bd9e1d fix @maps serialization bug
if @maps is empty, it returns {"maps":[]}, instead of [] like we expect
on the frontend.

This commit fixes this issue
2016-09-23 14:40:26 +08:00
Devin Howard
eef8a281cb Merge pull request #649 from metamaps/feature/Metamaps-in-frontend
move Metamaps code to webpack
2016-09-23 14:22:46 +08:00
Devin Howard
6f91ce5ff5 fix a few more errors 2016-09-23 14:12:27 +08:00
Devin Howard
e65a5e2d1c whoops, reenable travis npm test 2016-09-23 12:00:47 +08:00
Devin Howard
bda740491c moved JIT to npm. tests pass. whoop whoop 2016-09-23 11:59:23 +08:00
Connor Turland
700119cc9e opts can be undefined and throw error 2016-09-22 23:04:46 -04:00
Devin Howard
07e4ac3865 attempt to get npm testing working; fail 2016-09-23 10:37:59 +08:00
Connor Turland
499593fc82 fixing references 2016-09-22 21:40:49 -04:00
Connor Turland
f59a5775ae tweaks to import/exports 2016-09-22 20:16:18 -04:00
Devin Howard
73e7c38873 syntax fixes 2016-09-23 08:05:26 +08:00
Devin Howard
30fc943833 clean up backbone file imports 2016-09-23 00:20:05 +08:00
Devin Howard
a996734c79 remove Backbone from window 2016-09-23 00:16:15 +08:00
Devin Howard
30894a313f move views to their own frontend folder 2016-09-23 00:07:30 +08:00
Devin Howard
fe3012136d import _ 2016-09-22 23:51:33 +08:00
Devin Howard
59b471ac62 break Map into three files 2016-09-22 23:51:28 +08:00
Devin Howard
120c2c0b67 finish most except Backbone 2016-09-22 18:36:22 +08:00
Devin Howard
0065b201c7 make more code modular 2016-09-22 17:36:47 +08:00
Devin Howard
8ed2b3ffc1 remove Constants.js 2016-09-22 17:14:34 +08:00
Devin Howard
9c1543de64 move some variables into JIT 2016-09-22 17:08:53 +08:00
Devin Howard
8f100d99cb start to do stuff that may/may not work 2016-09-22 17:05:28 +08:00
Devin Howard
0562134157 low hanging fruit
Here is my TODO list:

already done
==> Account.js <==
==> Admin.js <==
==> AutoLayout.js <==
==> Listeners.js <==
==> Mapper.js <==
==> Organize.js <==
==> PasteInput.js <==
==> ReactComponents.js <==
==> Util.js <==

TODO (I think) simple to make modular
==> Backbone.js <==
==> Control.js <==
==> Create.js <==
==> Filter.js <==
==> Import.js <==
==> Mobile.js <==
==> Synapse.js <==
==> SynapseCard.js <==
==> Topic.js <==
==> TopicCard.js <==
==> Views.js <==
==> Visualize.js <==

TODO hard to make modular
==> Constants.js <==
==> Debug.js <==
==> GlobalUI.js <==
==> JIT.js <==
==> Map.js <==
==> Realtime.js <==
==> Router.js <==
2016-09-22 17:00:36 +08:00
Devin Howard
0a109895f7 merge realtime/package.json into top level package.json 2016-09-22 17:00:36 +08:00
Devin Howard
c0f63abc59 upgrade testing to es6 2016-09-22 17:00:36 +08:00
Devin Howard
d97b5c2977 make Util modular 2016-09-22 17:00:27 +08:00
Devin Howard
7f83f86460 refactor a bit, make a comment about the Constants file 2016-09-22 15:29:55 +08:00
Devin Howard
03446f548a start making the code modular. many files still need global scape 2016-09-22 15:23:14 +08:00
Devin Howard
d02c836805 remove Metamaps from filenames 2016-09-22 14:35:14 +08:00
Devin Howard
a4d31241a8 move Metamaps code into webpack 2016-09-22 14:28:20 +08:00
Devin Howard
b13ebc6716 Merge pull request #640 from metamaps/fix/password-reset-error
fix password reset error
2016-09-22 09:16:25 +08:00
Devin Howard
1370b63311 Merge pull request #639 from metamaps/feature/paste-url
Allow pasting URLs into the map to create a new topic
2016-09-22 09:16:03 +08:00
Connor Turland
2219e0d0dd Update Metamaps.Topic.js 2016-09-21 14:53:17 -04:00
Devin Howard
8b19c9e340 automatic versioning via git (#621) 2016-09-21 13:24:14 -04:00
Devin Howard
3843cab643 rails 5 + api v2 + raml api docs (#593)
* update Gemfile to rails 5 and ruby 2.3.0

* fiddle with javascripts and add sprockets manifest file

* update config directory for rails 5

* fix some errors with controllers/serializers

* fix travis and rspec

* new serializers renamed to serializers

* module Api::V1

* reusable embedding code

* add index/collections/paging. overriding most of snorlax now |:)

* raml api documentation + rspec tests to verify schemas/examples

* add sorting by ?sort and searching by ?q. Add pagination Link headers

* api v1 => v2

* fill out synapse api

* alphabetize map policy

* fix page thing

* fill out maps api

* formParameters => properties, and fiddle with map api

* more raml 1.0 stuff i'm learning about

* deprecate v1 api

* rails 5 uses ApplicationRecord class for app-wide model config

* Update topic spec for api v2

* workaround for user_preference.rb issue

* get ready for token api docs. also TODO is mapping api docs

* spec out mapping api

* map/mapping/synapse spec, plus other bugs

* awesome, token specs/apis are done

* add sanity checks to the api tests

* more cleanup

* devise fix

* fix starred map error
2016-09-21 13:22:40 -04:00
Devin Howard
1efd78ad7b initial attempt at focussing input field when entering multiple topics 2016-09-21 14:27:49 +08:00
Devin Howard
49084b98dd omg import bookmarks 😍 2016-09-21 10:48:47 +08:00
Devin Howard
fac59f346f fix topic init function 2016-09-21 10:24:57 +08:00
Devin Howard
ec96d69876 refactor import view:
-Paste Input wrapper class to abstract away getting input
-Add ability to drop files in PasteInput
-Add ability to drop .webloc files or paste a link to create a new topic with that link in the link and desc fields
2016-09-21 10:11:08 +08:00
Devin Howard
9515152315 move auto layout function into its own file 2016-09-21 10:10:08 +08:00
Connor Turland
aace6796f5 allow topic carousel to be pinned open (#643)
* so that rapid topic creation can happen in succession

* close when map closes
2016-09-19 20:30:34 -04:00
Connor Turland
61e27a4dcb height shouldn't stay hard set. fixes 622 2016-09-17 23:45:04 +00:00
Connor Turland
823c0c5990 no room is created if anon user (#642) 2016-09-17 15:06:54 -04:00
Connor Turland
698adf69cd Update README.md 2016-09-17 14:55:23 -04:00
Devin Howard
cd31452c79 update readme (#575)
* update readme

* remove google plus
2016-09-17 14:54:44 -04:00
Devin Howard
ca74e8c5fc Merge pull request #641 from metamaps/fix/get-siblings-by-type
Get siblings by metacode type returns only topics with that metacode - fix #538
2016-09-17 20:57:48 +08:00
Devin Howard
d1c390636a Get siblings by metacode type returns only topics with that metacode - fix #538 2016-09-17 17:12:39 +08:00
Devin Howard
4723c62b20 fix password reset error 2016-09-15 07:18:15 +08:00
Devin Howard
4bbb9df5af can't use ` with uglify 2016-09-14 10:45:42 +08:00
Devin Howard
40cb7606e3 enable metamaps.debug whoops 2016-09-13 15:21:00 +08:00
Devin Howard
0b64b6371f fix pull changes docs 2016-09-13 15:19:01 +08:00
Devin Howard
eaffc346fd v2.9.1 2016-09-13 14:30:09 +08:00
Connor Turland
6b2887e8da namespace the event listeners to turn them off (#637) 2016-09-11 18:47:59 -04:00
Connor Turland
4a8b017144 add nvmrc 2016-09-10 20:30:58 -04:00
Connor Turland
9070bfc836 use a subset of the simplest metacodes for new users (#633)
* use a subset of the simplest ones for new users

* Update user_preference.rb

* Update user_preference.rb
2016-09-09 20:36:49 -04:00
Connor Turland
d3bc3e3d18 dont change home link in the mapper profile case 2016-09-10 00:29:10 +00:00
Connor Turland
75260496be annoying scroll issue fix (#634) 2016-09-09 17:06:05 -04:00
Devin Howard
61465ff148 Merge pull request #630 from metamaps/feature/mapping-policy
add mapping policy
2016-09-05 18:58:38 +08:00
Devin Howard
8d372f780d Merge pull request #626 from metamaps/bug/detached
shouldn't reference relatives that are connected in private ways
2016-09-05 11:58:08 +08:00
Devin Howard
3e38fba215 remove relatives1 and relatives2 2016-09-05 11:55:19 +08:00
Devin Howard
e761e1693c use Topic.relatives scope to get all relatives 2016-09-05 11:52:35 +08:00
Devin Howard
158e2d5383 add mapping policy 2016-09-05 10:47:11 +08:00
Connor Turland
7de89cfa0f shouldn't reference relatives that are connected in private ways 2016-09-02 12:37:01 -04:00
Connor Turland
4a2f3203bd Update clean.css.erb 2016-09-01 15:41:20 -04:00
Devin Howard
8a55491dab forgot last updated 2016-09-01 15:48:47 +08:00
Devin Howard
b36dc03f59 bump version to 2.9.0 2016-09-01 10:14:02 +08:00
Connor Turland
549c086af4 styleee (#620) 2016-08-31 18:57:19 -04:00
Connor Turland
19dabe81cc Enable users to star maps, and to see their starred collection (#615)
* enable starring

* users should be able to star others maps

* proper star icon

* starred maps display as starred without refreshing

* oops

* make phrasing clearer
2016-08-31 16:58:49 -04:00
Connor Turland
370499e453 avoid prompt 2016-08-30 17:00:14 -04:00
Connor Turland
d7759c8c07 Redo all of explore together in React (#617)
* unify explore in react

* no more need for manual scroll reseting

* we're not opening/closing the search anymore
2016-08-21 21:02:49 -04:00
Connor Turland
c89a6771ea Fix mapper page bugs + other things (#611)
* fix centering of explore headers

* make sure the mobile map title updates

* styling was broken on admin pages

* fixup callbacks when fetching user

* enable loading more
2016-08-17 10:00:37 -04:00
Connor Turland
4cb1dfe401 include link to create new map in mobile menu 2016-08-16 15:45:54 +00:00
Connor Turland
21e2418281 move apps header out of exploreMapsHeader 2016-08-16 15:38:05 +00:00
Connor Turland
b8c8f25c83 fixup applications page 2016-08-16 14:30:10 +00:00
Connor Turland
b58f55353a switch so that backbone router is opt-in, not opt-out (#610) 2016-08-16 10:25:07 -04:00
Devin Howard
03e98e617b fix login redirect loop - fixes #602 (#609) 2016-08-16 08:03:22 -04:00
Connor Turland
57181e208f layout tweaks (#607)
* new map creation pops to new window

* hide the search on logged out homepage

* add { }

* just writing the same code better

* remove that old code
2016-08-16 08:03:06 -04:00
Connor Turland
da30078ef4 er, we use a static/modded version of best_in_place (#608) 2016-08-15 17:01:24 -04:00
Connor Turland
5b5fc86a3b enable text overflow for title on mob (#606) 2016-08-14 12:50:44 -04:00
Devin Howard
15ca43d49f Merge pull request #601 from metamaps/fix/nil-mapping-export
I think this fixes issue #566 but I'm not sure
2016-08-14 14:14:51 +08:00
Connor Turland
0140d68e87 adjusted media query breakpoints 2016-08-14 00:31:48 +00:00
Connor Turland
d4d992a0da improve styling for mobile of map list (#605) 2016-08-13 20:10:23 -04:00
Connor Turland
34ecf4f70b enable panning (#603) 2016-08-12 11:07:59 -04:00
Devin Howard
c77e3b2da5 Merge pull request #578 from metamaps/paring.down
remove all traces of Famous and improve mobile
2016-08-12 13:42:57 +08:00
Devin Howard
6eff5e640e Metamaps.Mobile.js dependencies comment 2016-08-12 13:32:51 +08:00
Connor Turland
ceb335e728 use border radius on profile image 2016-08-12 05:09:10 +00:00
Connor Turland
dc60c3f3ed add profile image and fix exploreMaps bar 2016-08-12 05:03:28 +00:00
Devin Howard
796f4d57a1 I think this fixes issue #566 but I'm not sure 2016-08-12 12:39:30 +08:00
Connor Turland
b4c75649ba all teh mobile things 2016-08-12 04:04:18 +00:00
Devin Howard
f4eb9250ad npm update 2016-08-12 10:51:14 +08:00
Connor Turland
449c2084bb make maps go under explore bar 2016-08-11 17:26:11 -04:00
Connor Turland
44bb0020bc Merge branch 'develop' into paring.down 2016-08-11 15:59:45 -04:00
Devin Howard
fae69133be try fixing react warnings again 2016-08-11 11:42:35 +08:00
Connor Turland
bdac00bc10 fix typo 2016-08-11 01:44:40 +00:00
Connor Turland
848bb11c08 needed to clear div switching between map view and topic view 2016-08-10 18:37:26 +00:00
Connor Turland
d5cec3844b make sure toast hides again 2016-08-10 18:08:48 +00:00
Connor Turland
a3f1d51bc6 make the toast work 2016-08-10 18:06:28 +00:00
Connor Turland
da090e60db remove homepage changes 2016-08-10 17:32:43 +00:00
Connor Turland
c308e276e8 Merge branch 'develop' into paring.down 2016-08-10 17:16:33 +00:00
Devin Howard
63b528c8bf don't import into textarea elements either - fix #579 (#598) 2016-08-10 13:14:33 -04:00
Devin Howard
9db5ce551e inject NODE_ENV into webpack - probably fixes #595 (#599) 2016-08-10 13:13:54 -04:00
Connor Turland
f71d552504 Merge branch 'develop' into paring.down 2016-08-10 17:09:37 +00:00
Devin Howard
beb52bc471 fix topic view keyboard shortcuts (#597)
* fix topic view selection crash on centerAndReveal

* topic view shortcuts switch to Alt

* change delete behaviour to be smarter

* fetchRelatives recursively handles arrays

* update topic url and Metamaps.Active.Topic when you center

* make heroku work 4 realz
2016-08-09 11:53:50 -04:00
Devin Howard
4478ca43b8 Merge pull request #594 from metamaps/feature/fix-heroku
multi-buildpack setup for heroku:
2016-08-09 20:35:06 +08:00
Devin Howard
b9247d2692 multi-buildpack setup for heroku:
$ heroku buildpacks:set https://github.com/heroku/heroku-buildpack-multi.git

will set it up
2016-08-09 13:49:38 +08:00
Devin Howard
3b24165fd0 Merge pull request #589 from metamaps/feature/topicview-remove-topics
enable removal of topics from topic view - fixes #467
2016-08-08 21:46:15 +08:00
Devin Howard
9cedf69432 fetch siblings & center topic keyboard shortcuts - fixes #466 (#588)
* fetch siblings & center topic keyboard shortcuts - fixes #466

* add keyboard shortcut labels

* update keyboard shortcuts to Ctrl+E, Ctrl+R, and Ctrl+T, and update docs

* zoom extents back to Ctrl+E and use e.preventDefault
2016-08-08 21:46:05 +08:00
Devin Howard
3050f1413a Merge pull request #587 from metamaps/feature/topicview-selection-box
fix selection box on radial view - fix #463
2016-08-08 21:43:22 +08:00
Devin Howard
5510cb2e99 enable removal of topics from topic view - fixes #467 2016-08-08 21:40:55 +08:00
Devin Howard
3b65ad923b only show travis build status badge for develop branch 2016-08-07 21:26:53 +08:00
Devin Howard
713063e578 fix npm testing script - it will actually break travis now 2016-08-07 20:00:44 +08:00
Devin Howard
b66b75615a remove frontend folder reference from travis 2016-08-07 19:45:11 +08:00
Devin Howard
77e8716588 Merge branch 'master' into develop 2016-08-07 17:23:57 +08:00
Devin Howard
fcc1dbdd11 Merge pull request #592 from metamaps/fix/synapse-import
fix: synapse import fails if synapses are missing desc
2016-08-07 17:21:21 +08:00
Devin Howard
23543ac7ad fix: synapse import fails if synapses are missing desc 2016-08-07 17:18:54 +08:00
Devin Howard
d778016571 fix selection box on radial view - fix #463 2016-08-07 13:17:25 +08:00
Devin Howard
00c54b7d66 fix another react bug 2016-08-05 10:54:18 +08:00
Devin Howard
980fca9844 remove spread syntax 2016-08-05 10:54:17 +08:00
Devin Howard
2274155801 split out a separate MapLink component for code reuse 2016-08-04 13:58:59 -04:00
Devin Howard
1774f8c530 object destructure + let/const 2016-08-04 13:58:59 -04:00
Devin Howard
2b2f6e6dc4 add propTypes 2016-08-04 13:58:59 -04:00
Connor Turland
17da8441f4 fixup react setup 2016-08-04 13:58:59 -04:00
Connor Turland
4005b301ac uncomment commented header lines 2016-08-04 13:58:59 -04:00
Connor Turland
804afc3e1d remove famous leftovers 2016-08-04 13:58:59 -04:00
Connor Turland
ede1dfb91c made the header more generic to serve other functions 2016-08-04 13:58:59 -04:00
Connor Turland
30e9a27663 almost rid of famous completely 2016-08-04 13:58:06 -04:00
Connor Turland
aed423214f started using react instead of famous 2016-08-04 13:57:35 -04:00
Connor Turland
6b2386a545 progress onthe home page 2016-08-04 13:56:39 -04:00
Connor Turland
293e68da05 remove old stuff 2016-08-04 13:56:39 -04:00
Devin Howard
a6951920eb fix module.exports javascript bug 2016-08-04 17:08:10 +08:00
Devin Howard
69bdb0bf01 hotfix master with mappable_policy.try 2016-08-04 17:04:01 +08:00
Devin Howard
194a4dc975 add production schema file 2016-08-04 16:53:09 +08:00
Devin Howard
52cbd57367 Merge pull request #586 from metamaps/merge/master-into-develop
merge master into develop
2016-08-04 10:53:00 +08:00
Devin Howard
6df8da16bc Merge branch 'master' into develop 2016-08-04 10:51:36 +08:00
Devin Howard
dc725c3b9a Merge pull request #583 from metamaps/fix/purple-metacodes
attempt to fix purple metacodes (#527)
2016-08-04 10:16:04 +08:00
Devin Howard
17a9a2d23a fix jquery error and move package.json etc to root dir 2016-08-03 22:40:14 +08:00
Devin Howard
6eff2d91c9 fix backbone jquery 2016-08-03 21:25:44 +08:00
Devin Howard
720f67cee7 move metacode loading earlier, and add a query string to work around amazon aws CORS issues 2016-08-03 08:54:10 +08:00
Devin Howard
6997142fd9 finish integrating npm. move underscore/backbone into npm management (#577)
* finish integrating npm. move underscore/backbone into npm management

* update docs for npm integration

* allow jsx or js extension

* change underscore version
2016-08-01 15:59:53 -04:00
Devin Howard
e6954eb37a Merge pull request #574 from metamaps/fix/synapse-search-duplicates
fix synapse autocomplete duplicates
2016-08-01 08:56:55 +08:00
Devin Howard
70a4f54399 switch to ruby 2.3.0 (#572) 2016-08-01 08:33:45 +08:00
Devin Howard
5fe03641cb move frontend code into a folder, and setup react build tooling with es6 transforms (#576) 2016-07-31 14:51:06 -04:00
Devin Howard
4161f70d2e remove duplicates from synapse search
there were 2 issues. one is synapses with leading/trailing whitespace. I've run a script on production to strip existing leading/trailing whitespace from synapse descs.

The second issue was that this code wasn't actually modifying the @synapses array, and collectedDesc wasn't doing anything. So this new line will be more effective.
2016-07-31 19:31:31 +08:00
Devin Howard
7d4da81272 Update code style automatically using rubocop gem (#563)
* install rubocop

* 1961 automatic rubocop fixes

* update rubocop.yml to ignore half of the remaining cops

* rubocop lint warnings

* random other warnings fixed
2016-07-26 08:14:23 +08:00
Devin Howard
17bccd809a Merge pull request #568 from metamaps/fix/import-export
use Wildcard if no metacode
2016-07-26 08:05:00 +08:00
Devin Howard
e5c9af8f95 use Wildcard if no metacode 2016-07-24 13:43:12 +08:00
Devin Howard
27942546b8 fix 2 bugs on develop (#565)
* fix js bug

* if mappable is nil it causes an error
2016-07-02 16:32:02 +08:00
Devin Howard
872ae90832 submit new map form on Enter - fixes #555 (#562)
* submit new map form on Enter - fixes #555

* update divs too
2016-07-01 16:48:38 +08:00
Devin Howard
6c22ebcc51 have policy_scope always use scope.all or something else to ensure it's an ActiveRecord relation 2016-06-28 14:49:46 +08:00
Devin Howard
b72536853f fix activemaps_path url bug (#559)
* fix activemaps_path url bug

* annoying doc updates

* skip policy scope if redirecting an explore page

* lol that would have been dumb
2016-06-20 08:32:39 +08:00
Devin Howard
f5912d511d fix activemaps_path url bug (#559)
* fix activemaps_path url bug

* annoying doc updates

* skip policy scope if redirecting an explore page

* lol that would have been dumb
2016-06-20 08:31:32 +08:00
Devin Howard
6e1797183e brakeman (#556)
* update rails to 4.2.5.1

* fix brakeman gem warning

* make brakeman happier and add it to travis

* install brakeman gem for static security analysis

* fix brakeman call in travis
2016-06-16 15:44:08 +08:00
Devin Howard
97e9f999d9 Merge branch 'master' into develop 2016-06-16 15:43:30 +08:00
Devin Howard
1f9078638e fix truncate bug when map desc is nil (#557) 2016-06-16 15:42:43 +08:00
Devin Howard
5cf3416dc6 Merge pull request #558 from metamaps/fix/truncate-bug
merge truncate fix + master into develop
2016-06-16 15:42:36 +08:00
Devin Howard
2989406954 fix truncate bug when map desc is nil 2016-06-15 12:17:32 +08:00
Devin Howard
b0860ef670 Merge branch 'develop' 2016-06-08 12:47:26 +08:00
Devin Howard
1d12aed3eb switch to dotenv-rails 2016-06-07 12:55:49 +08:00
Devin Howard
11f921b058 remove secret key from source control - fixme on production.
This will expire all cookies, but make our install more secure from
hackers who know their way around Github
2016-06-07 12:54:55 +08:00
Devin Howard
437c73b0fe Merge develop 2016-04-20 11:25:59 +08:00
Devin Howard
5a60135392 Merge branch 'develop' 2016-04-15 11:51:40 +08:00
Devin Howard
031e35e50c Merge branch 'develop' 2016-04-13 10:53:46 +08:00
Devin Howard
bd1e1ffe81 ruby gemset 2016-04-13 10:32:34 +08:00
Devin Howard
0de7333d6a Merge branch 'develop' 2016-04-13 10:26:01 +08:00
Devin Howard
a8d0d9da09 2.8.3:
- add Junto sounds
- fix json import
- fix invite link
2016-04-06 10:06:37 +08:00
Devin Howard
a83382efe9 Merge branch 'develop'
v2.8.2 - fixes import code
2016-03-31 10:11:49 +08:00
Raymon Johnstone
b2a4cbf3ec Merge pull request #522 from Tadasu85/master
Merge pull request #1 from metamaps/master
2016-03-27 18:09:16 -04:00
Connor Turland
e1c0509c91 Merge pull request #520 from metamaps/develop
fix request invite
2016-03-27 12:12:26 -07:00
Connor Turland
fbba487b83 Merge pull request #482 from metamaps/develop
merge develop into master (version 2.8!)
2016-03-27 00:43:54 -07:00
Raymon Johnstone
e23224aa16 Merge pull request #1 from metamaps/master
Syncing
2016-03-23 22:51:42 -04:00
677 changed files with 32953 additions and 38013 deletions

1
.agignore Normal file
View file

@ -0,0 +1 @@
app/assets/javascripts/metamaps.secret.bundle.js

10
.babelrc Normal file
View file

@ -0,0 +1,10 @@
{
"presets": [
"react",
"es2015"
],
"plugins": [
"lodash",
"transform-class-properties"
]
}

View file

@ -1 +1,2 @@
https://github.com/heroku/heroku-buildpack-nodejs.git
https://github.com/heroku/heroku-buildpack-ruby.git

38
.codeclimate.yml Normal file
View file

@ -0,0 +1,38 @@
---
engines:
brakeman:
enabled: true
bundler-audit:
enabled: true
duplication:
enabled: true
config:
languages:
count_threshold: 3 # rule of three
ruby:
mass_threshold: 36 # default: 18
javascript:
mass_threshold: 80 # default: 40
eslint:
enabled: true
channel: "eslint-3"
fixme:
enabled: true
rubocop:
enabled: true
exclude_fingerprints:
- 74f18007b920e8d81148d2f6a2756534
ratings:
paths:
- 'Gemfile.lock'
- '**.erb'
- '**.rb'
- '**.js'
- '**.jsx'
exclude_paths:
- app/assets/images/
- app/assets/javascripts/lib/
- frontend/src/patched/
- db/
- script/
- spec/

3
.eslintignore Normal file
View file

@ -0,0 +1,3 @@
**/*{.,-}min.js
frontend/src/patched/*
app/assets/javascripts/lib/*

26
.eslintrc.js Normal file
View file

@ -0,0 +1,26 @@
module.exports = {
"sourceType": "module",
"parser": "babel-eslint",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
}
},
"extends": "standard",
"installedESLint": true,
"env": {
"es6": true,
"node": true
},
"plugins": [
"promise",
"standard",
"react"
],
"rules": {
"react/jsx-uses-react": [2],
"react/jsx-uses-vars": [2],
"space-before-function-paren": [2, "never"],
"yoda": [2, "never", { "exceptRange": true }]
}
}

View file

@ -1,21 +1,27 @@
# Node JS env
export NODE_REALTIME_PORT='5000' # should match REALTIME_SERVER, below
# Rails env
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:5001'
export REALTIME_SERVER='http://localhost:5000'
export MAILER_DEFAULT_URL='localhost:3000'
export DEVISE_MAILER_SENDER='team@metamaps.cc'
export DEVISE_SECRET_KEY='f71c467e526f23d614b3b08866cad4788c502bed869c282f06e73ee6c94675b62fe1f6d52fa7ba8196b33031f0d2f3b67e27ea07693c52ecebccb01700cad614'
export SECRET_KEY_BASE='267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c8005f85ee99d6d01b1ab6394cdee9ca7f8c9213a0cf91d3d8d3350f096123e2caccbcc0924f'
# # you can safely leave these blank, unless you're deploying an instance, in
# # which case you'll need to set them up
#
# export S3_REGION
# export S3_BUCKET_NAME
# export AWS_ACCESS_KEY_ID
# export AWS_SECRET_ACCESS_KEY
# export SSO_KEY
#
# export SMTP_DOMAIN
# export SMTP_PASSWORD

7
.gitignore vendored
View file

@ -7,11 +7,15 @@
#assety stuff
public/assets
public/metamaps_mobile
public/api/index.html
vendor/
node_modules
npm-debug.log
app/assets/javascripts/webpacked
#secrets and config
.env
*.swp
# Ignore bundler config
.bundle
@ -19,6 +23,7 @@ node_modules
# Ignore all logfiles and tempfiles.
log/*.log
tmp
.tmp
coverage
@ -26,3 +31,5 @@ coverage
*/.DS_Store
.DS_Store?
.vagrant
gentle/
startserver.sh

1
.nvmrc Normal file
View file

@ -0,0 +1 @@
6.2.2

29
.rubocop.yml Normal file
View file

@ -0,0 +1,29 @@
AllCops:
TargetRubyVersion: 2.3
Exclude:
- 'db/**/*'
- 'tmp/**/*'
- 'bin/**/*'
- 'vendor/**/*'
- 'app/assets/javascripts/node_modules/**/*'
- 'Vagrantfile'
Rails:
Enabled: true
Metrics/LineLength:
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

View file

@ -1 +1 @@
ruby-2.1.3
2.3.0

View file

@ -1,3 +1,7 @@
if ENV['COVERAGE'] == 'on'
SimpleCov.start 'rails'
SimpleCov.start 'rails' do
add_group 'Policies', 'app/policies'
add_group 'Services', 'app/services'
add_group 'Serializers', 'app/serializers'
end
end

View file

@ -5,7 +5,7 @@ cache:
directories:
- app/assets/javascripts/node_modules
rvm:
- 2.1.3
- 2.3.0
before_script:
- echo "Rspec setup"
- export RAILS_ENV=test
@ -16,6 +16,10 @@ before_script:
- . $HOME/.nvm/nvm.sh
- nvm install stable
- nvm use stable
- (cd app/assets/javascripts && npm install)
- npm install --no-optional
script:
- bundle exec rspec && (cd app/assets/javascripts && npm test)
- bundle exec rspec && bundle exec brakeman -q -z && npm test
addons:
code_climate:
repo_token: 479d3bf56798fbc7fff3fc8151a5ed09e8ac368fd5af332c437b9e07dbebb44e
postgresql: "9.4"

52
Gemfile
View file

@ -1,50 +1,44 @@
# frozen_string_literal: true
source 'https://rubygems.org'
ruby '2.1.3'
ruby '2.3.0'
gem 'rails', '4.2.4'
gem 'rails', '~> 5.0.0'
gem 'active_model_serializers', '~> 0.8.1'
gem 'aws-sdk', '< 2.0'
gem 'best_in_place' #in-place editing
gem 'delayed_job', '~> 4.0.2'
gem 'delayed_job_active_record', '~> 4.0.1'
gem 'active_model_serializers'
gem 'aws-sdk', '~> 2.7.0'
gem 'best_in_place'
gem 'delayed_job'
gem 'delayed_job_active_record'
gem 'devise'
gem 'doorkeeper'
gem 'dotenv'
gem 'dotenv-rails'
gem 'exception_notification'
gem 'formtastic'
gem 'formula'
gem 'httparty'
gem 'json'
gem 'kaminari' # pagination
gem 'kaminari'
gem 'mailboxer'
gem 'paperclip'
gem 'pg'
gem 'puma'
gem 'pundit'
gem 'pundit_extra'
gem 'rack-attack'
gem 'rack-cors'
gem 'rails3-jquery-autocomplete'
gem 'redis'
gem 'redis', '~> 3.3.3'
gem 'slack-notifier'
gem 'snorlax'
gem 'uservoice-ruby'
gem 'sucker_punch'
# asset stuff
gem 'jquery-rails'
gem 'jquery-ui-rails'
gem 'jbuilder'
group :assets do
gem 'coffee-rails'
gem 'sass-rails'
gem 'uglifier'
# gem 'therubyracer'
end
group :production do
gem 'rails_12factor'
end
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'
@ -54,8 +48,10 @@ end
group :development, :test do
gem 'better_errors'
gem 'binding_of_caller'
gem 'faker'
gem 'pry-byebug'
gem 'pry-rails'
gem 'quiet_assets'
gem 'rubocop', '~> 0.48.1' # match code climate https://github.com/tootsuite/mastodon/issues/1758
gem 'timecop'
gem 'tunemygc'
end

View file

@ -1,308 +1,350 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.2.4)
actionpack (= 4.2.4)
actionview (= 4.2.4)
activejob (= 4.2.4)
actioncable (5.0.5)
actionpack (= 5.0.5)
nio4r (>= 1.2, < 3.0)
websocket-driver (~> 0.6.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 (~> 1.0, >= 1.0.5)
actionpack (4.2.4)
actionview (= 4.2.4)
activesupport (= 4.2.4)
rack (~> 1.6)
rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-dom-testing (~> 2.0)
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 (4.2.4)
activesupport (= 4.2.4)
actionview (5.0.5)
activesupport (= 5.0.5)
builder (~> 3.1)
erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2)
active_model_serializers (0.8.3)
activemodel (>= 3.0)
activejob (4.2.4)
activesupport (= 4.2.4)
globalid (>= 0.3.0)
activemodel (4.2.4)
activesupport (= 4.2.4)
builder (~> 3.1)
activerecord (4.2.4)
activemodel (= 4.2.4)
activesupport (= 4.2.4)
arel (~> 6.0)
activesupport (4.2.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.0.3)
active_model_serializers (0.10.6)
actionpack (>= 4.1, < 6)
activemodel (>= 4.1, < 6)
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.5)
activesupport (= 5.0.5)
activerecord (5.0.5)
activemodel (= 5.0.5)
activesupport (= 5.0.5)
arel (~> 7.0)
activesupport (5.0.5)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (~> 0.7)
json (~> 1.7, >= 1.7.7)
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
addressable (2.3.8)
arel (6.0.3)
aws-sdk (1.66.0)
aws-sdk-v1 (= 1.66.0)
aws-sdk-v1 (1.66.0)
json (~> 1.4)
nokogiri (>= 1.4.4)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
arel (7.1.4)
ast (2.3.0)
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.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)
builder (3.2.2)
byebug (8.2.2)
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)
coffee-rails (4.1.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.1.x)
coffee-script (2.4.1)
coffee-script-source
execjs
coffee-script-source (1.10.0)
concurrent-ruby (1.0.1)
debug_inspector (0.0.2)
delayed_job (4.0.6)
activesupport (>= 3.0, < 5.0)
delayed_job_active_record (4.0.3)
activerecord (>= 3.0, < 5.0)
delayed_job (>= 3.0, < 4.1)
devise (3.5.6)
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.3.0)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 3.2.6, < 5)
railties (>= 4.1.0, < 5.2)
responders
thread_safe (~> 0.1)
warden (~> 1.2.3)
diff-lcs (1.2.5)
diff-lcs (1.3)
docile (1.1.5)
doorkeeper (3.1.0)
railties (>= 3.2)
dotenv (2.1.0)
doorkeeper (4.2.6)
railties (>= 4.2)
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.1.4)
actionmailer (~> 4.0)
activesupport (~> 4.0)
execjs (2.6.0)
ezcrypto (0.7.2)
factory_girl (4.5.0)
exception_notification (4.2.2)
actionmailer (>= 4.0, < 6)
activesupport (>= 4.0, < 6)
execjs (2.7.0)
factory_bot (4.8.2)
activesupport (>= 3.0.0)
factory_girl_rails (4.6.0)
factory_girl (~> 4.5.0)
factory_bot_rails (4.8.2)
factory_bot (~> 4.8.2)
railties (>= 3.0.0)
formtastic (3.1.3)
actionpack (>= 3.2.13)
formula (1.1.1)
rails (> 3.0.0)
globalid (0.3.6)
activesupport (>= 4.1.0)
httparty (0.13.7)
json (~> 1.8)
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)
jbuilder (2.4.1)
activesupport (>= 3.0.0, < 5.1)
multi_json (~> 1.2)
jquery-rails (4.1.1)
i18n (0.9.3)
concurrent-ruby (~> 1.0)
jmespath (1.3.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.1)
addressable (~> 2.3.8)
kaminari (0.16.3)
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.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2016.0221)
mimemagic (0.3.0)
mini_portile2 (2.0.0)
minitest (5.8.4)
multi_json (1.11.2)
multi_xml (0.5.5)
nokogiri (1.6.7.2)
mini_portile2 (~> 2.0.0.rc2)
oauth (0.5.1)
mime-types-data (3.2016.0521)
mimemagic (0.3.2)
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 (4.3.5)
activemodel (>= 3.2.0)
activesupport (>= 3.2.0)
paperclip (5.2.0)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
cocaine (~> 0.5.5)
mime-types
mimemagic (= 0.3.0)
pg (0.18.4)
pry (0.10.3)
mimemagic (~> 0.3.0)
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.3.0)
byebug (~> 8.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.1.1)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rack (1.6.4)
rack-cors (0.4.0)
pundit_extra (0.3.0)
rack (2.0.3)
rack-attack (5.0.1)
rack
rack-cors (1.0.1)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.2.4)
actionmailer (= 4.2.4)
actionpack (= 4.2.4)
actionview (= 4.2.4)
activejob (= 4.2.4)
activemodel (= 4.2.4)
activerecord (= 4.2.4)
activesupport (= 4.2.4)
bundler (>= 1.3.0, < 2.0)
railties (= 4.2.4)
sprockets-rails
rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha)
rails-dom-testing (1.0.7)
activesupport (>= 4.2.0.beta, < 5.0)
nokogiri (~> 1.6.0)
rails-deprecated_sanitizer (>= 1.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.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.0.3)
loofah (~> 2.0)
rails3-jquery-autocomplete (1.0.15)
rails (>= 3.2)
rails_12factor (0.0.3)
rails_serve_static_assets
rails_stdout_logging
rails_serve_static_assets (0.0.5)
rails_stdout_logging (0.0.4)
railties (4.2.4)
actionpack (= 4.2.4)
activesupport (= 4.2.4)
railties (5.0.5)
actionpack (= 5.0.5)
activesupport (= 5.0.5)
method_source
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (11.1.1)
redis (3.2.2)
responders (2.1.1)
railties (>= 4.2.0, < 5.1)
rspec-core (3.4.4)
rspec-support (~> 3.4.0)
rspec-expectations (3.4.0)
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.4.0)
rspec-mocks (3.4.1)
rspec-support (~> 3.6.0)
rspec-mocks (3.6.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.4.0)
rspec-rails (3.4.2)
actionpack (>= 3.0, < 4.3)
activesupport (>= 3.0, < 4.3)
railties (>= 3.0, < 4.3)
rspec-core (~> 3.4.0)
rspec-expectations (~> 3.4.0)
rspec-mocks (~> 3.4.0)
rspec-support (~> 3.4.0)
rspec-support (3.4.1)
sass (3.4.21)
sass-rails (5.0.4)
railties (>= 4.0.0, < 5.0)
rspec-support (~> 3.6.0)
rspec-rails (3.6.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 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.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.11.2)
simplecov (0.15.0)
docile (~> 1.1.0)
json (~> 1.8)
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.5)
snorlax (0.1.6)
rails (> 4.1)
sprockets (3.5.2)
sprockets (3.7.1)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-rails (3.0.4)
sprockets-rails (3.2.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
sprockets (>= 3.0.0)
thor (0.19.1)
thread_safe (0.3.5)
tilt (2.0.2)
tunemygc (1.0.65)
tzinfo (1.2.2)
sucker_punch (2.0.3)
concurrent-ruby (~> 1.0.0)
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 (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
uservoice-ruby (0.0.11)
ezcrypto (>= 0.7.2)
json (>= 1.7.5)
oauth (>= 0.4.7)
warden (1.2.6)
uglifier (3.2.0)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.3.0)
warden (1.2.7)
rack (>= 1.0)
websocket-driver (0.6.5)
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.2)
PLATFORMS
ruby
DEPENDENCIES
active_model_serializers (~> 0.8.1)
aws-sdk (< 2.0)
active_model_serializers
aws-sdk (~> 2.7.0)
best_in_place
better_errors
binding_of_caller
coffee-rails
delayed_job (~> 4.0.2)
delayed_job_active_record (~> 4.0.1)
brakeman
delayed_job
delayed_job_active_record
devise
doorkeeper
dotenv
dotenv-rails
exception_notification
factory_girl_rails
formtastic
formula
factory_bot_rails
faker
httparty
jbuilder
jquery-rails
jquery-ui-rails
json
json-schema
kaminari
mailboxer
paperclip
pg
pry-byebug
pry-rails
puma
pundit
pundit_extra
quiet_assets
rack-attack
rack-cors
rails (= 4.2.4)
rails3-jquery-autocomplete
rails_12factor
redis
rails (~> 5.0.0)
redis (~> 3.3.3)
rspec-rails
rubocop (~> 0.48.1)
sass-rails
shoulda-matchers
simplecov
slack-notifier
snorlax
sucker_punch
timecop
tunemygc
uglifier
uservoice-ruby
RUBY VERSION
ruby 2.3.0p0
BUNDLED WITH
1.16.1

View file

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

View file

@ -1,79 +1,62 @@
Metamaps
=======
[![Join the chat at https://gitter.im/metamaps/metamaps](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/metamaps/metamaps?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![Build Status](https://travis-ci.org/metamaps/metamaps.svg)](https://travis-ci.org/metamaps/metamaps)
[![Build Status](https://travis-ci.org/metamaps/metamaps.svg?branch=develop)](https://travis-ci.org/metamaps/metamaps)
[![Code Climate](https://codeclimate.com/github/metamaps/metamaps/badges/gpa.svg)](https://codeclimate.com/github/metamaps/metamaps)
Welcome to the Metamaps GitHub repo.
## What is Metamaps?
## About
Metamaps is a free and open-source technology for changemakers, innovators, educators and students. It enables individuals and communities to build and visualize their shared knowledge and unlock their collective intelligence.
Metamaps is a free and AGPL open source technology for changemakers, innovators, educators and students. It enables individuals and communities to build and visualize their shared knowledge and unlock their collective intelligence. You can find out about more about the project at the [blog][site-blog].
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in an open beta.
You can find a version of this software running at [metamaps.cc][site-beta], where the technology is being tested in a private beta.
Metamaps is developed and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch by using whichever of these channels you prefer:
Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter.
## How do I learn more?
- Contact: [team@metamaps.cc](mailto:team@metamaps.cc) or [@metamapps](https://twitter.com/metamapps) on Twitter
- User Documentation: [docs.metamaps.cc](https://docs.metamaps.cc)
- User Community: [hylo.com/c/metamaps](https://www.hylo.com/c/metamaps)
- To see what we're developing, or to weigh in on what you'd like to see developed, see our [Metamaps Feedback and Features](https://trello.com/b/uFOA6a2x/metamaps-feedback-feature-ideas-requests) board on trello
- To follow along with, or contribute,to our design process, see our [Metamaps Design](https://trello.com/b/8HlCikOX/metamaps-design) board on trello
- To follow along with, or contribute to, our development process, see our [Github Issues and Pull Requests](https://github.com/metamaps/metamaps/issues)
- Request an invite to the open beta [here](https://metamaps.cc/request)
To get connected with the community interested in Metamaps, join our [Google+ community][community].
## Installation
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.
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`
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`
Start mapping and programming!
We haven't figured out Vagrant for Windows yet, but we have a set of manual instructions here:
- [For Windows][windows-installation]
## Contributing
Cloning this repository directly is primarily for those wishing to contribute to our codebase. Check out our [contributing instructions][contributing] to get involved.
## Community
<!-- 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].
- To participate in discussions and a public forum about Metamaps, join the [Google+ community][community]
- For contributors, read more instructions in [CONTRIBUTING.md][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 for local use or development of Metamaps
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.
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]
If you prefer to isolate your install in a virtual machine, you may find it simpler to setup using Vagrant:
- [Vagrant installation][vagrant-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
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or(at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
The license can be read [here][license].
Copyright (c) 2015 Connor Turland
Copyright (c) 2017 Connor Turland
[site-blog]: http://blog.metamaps.cc
[site-beta]: http://metamaps.cc
[community]: https://plus.google.com/u/0/communities/115060009262157699234
[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

2
Rakefile Normal file → Executable file
View file

@ -1,4 +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.

16
Vagrantfile vendored
View file

@ -9,7 +9,7 @@ sudo apt-get install git curl -y
# rvm and ruby
su - vagrant -c 'curl -sSL https://rvm.io/mpapis.asc | gpg --import -'
su - vagrant -c 'curl -sSL https://get.rvm.io | bash -s stable --ruby=2.1.3'
su - vagrant -c 'curl -sSL https://get.rvm.io | bash -s stable --ruby=2.3.0'
# install some other deps
sudo apt-get install nodejs -y
@ -31,15 +31,15 @@ sudo -u postgres psql -c "ALTER USER postgres WITH PASSWORD '3112';"
SCRIPT
VAGRANTFILE_API_VERSION = "2"
VAGRANTFILE_API_VERSION = '2'
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.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 "private_network", ip: "10.0.1.11"
config.vm.synced_folder ".", "/vagrant", :nfs => true
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
config.vm.provision "shell", inline: $script
config.vm.provision 'shell', inline: $script
end

View file

@ -0,0 +1,7 @@
// eslint-disable spaced-comment
// JS and CSS bundles
//= link_directory ../javascripts .js
//= link_directory ../stylesheets .css
// Other
//= link_tree ../images

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 667 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 822 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 739 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

View file

@ -0,0 +1,21 @@
/* global Metamaps */
/* erb variables from rails */
Metamaps.ServerData = Metamaps.ServerData || {}
Metamaps.ServerData['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
Metamaps.ServerData['user.png'] = '<%= asset_path('user.png') %>'
Metamaps.ServerData['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
Metamaps.ServerData['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
Metamaps.ServerData['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
Metamaps.ServerData['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
Metamaps.ServerData['sounds/MM_sounds.mp3'] = '<%= asset_path 'sounds/MM_sounds.mp3' %>'
Metamaps.ServerData['sounds/MM_sounds.ogg'] = '<%= asset_path 'sounds/MM_sounds.ogg' %>'
Metamaps.ServerData['exploremaps_sprite.png'] = '<%= asset_path 'exploremaps_sprite.png' %>'
Metamaps.ServerData['map_control_sprite.png'] = '<%= asset_path 'map_control_sprite.png' %>'
Metamaps.ServerData['user_sprite.png'] = '<%= asset_path 'user_sprite.png' %>'
Metamaps.ServerData.Metacodes = <%= Metacode.all.to_json.gsub(%r[(icon.*?)(\"},)], '\1?purple=stupid\2').html_safe %>
Metamaps.ServerData.REALTIME_SERVER = '<%= ENV['REALTIME_SERVER'] %>'
Metamaps.ServerData.RAILS_ENV = '<%= ENV['RAILS_ENV'] %>'
Metamaps.ServerData.VERSION = '<%= METAMAPS_VERSION %>'
Metamaps.ServerData.BUILD = '<%= METAMAPS_BUILD %>'
Metamaps.ServerData.LAST_UPDATED = '<%= METAMAPS_LAST_UPDATED %>'

View file

@ -1,9 +0,0 @@
Change directories to where this file is, and then run
npm install
to set up your testing environment. Then use
npm test
to see the results of testing the current javascript files.

View 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 */

View file

@ -9,41 +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 ./orderedLibraries/underscore
//= require ./orderedLibraries/backbone
//= require action_cable
//= require_directory ./lib
//= require ./src/Metamaps.GlobalUI
//= require ./src/Metamaps.Router
//= require ./src/Metamaps.Backbone
//= require ./src/Metamaps.Views
//= require ./src/views/chatView
//= require ./src/views/videoView
//= require ./src/views/room
//= require ./src/JIT
//= require ./src/check-canvas-support
//= require ./src/Metamaps
//= require ./src/Metamaps.Create
//= require ./src/Metamaps.TopicCard
//= require ./src/Metamaps.SynapseCard
//= require ./src/Metamaps.Visualize
//= require ./src/Metamaps.Util
//= require ./src/Metamaps.Realtime
//= require ./src/Metamaps.Control
//= require ./src/Metamaps.Filter
//= require ./src/Metamaps.Listeners
//= require ./src/Metamaps.Organize
//= require ./src/Metamaps.Topic
//= require ./src/Metamaps.Synapse
//= require ./src/Metamaps.Map
//= require ./src/Metamaps.Account
//= require ./src/Metamaps.Mapper
//= require ./src/Metamaps.Admin
//= require ./src/Metamaps.Import
//= require ./src/Metamaps.JIT
//= require_directory ./shims
//= require_directory ./require
//= require_directory ./famous
//= require ./webpacked/metamaps.bundle
//= require ./Metamaps.ServerData
//= require homepageVimeoFallback
/* eslint-enable spaced-comment */

View 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);

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,29 @@
/* global $ */
$(document).ready(function() {
if (window.location.pathname === '/') {
$.ajax({
type: 'GET',
url: 'https://i.vimeocdn.com/video/',
error: function(e) {
$('.homeVideo').hide()
$('.homeVideo').replaceWith($('<video/>', {
poster: '<%= asset_path('metamaps-intro-poster.webp') %>',
width: '560',
height: '315',
class: 'homeVideo',
controls: ''
}))
$('.homeVideo').append($('<source/>', {
src: 'https://metamaps.cc/videos/metamaps-intro.mp4',
type: 'video/mp4'
}))
$('.homeVideo').append(
'<p>You can watch our instruction video at ' +
'<a href="https://metamaps.cc/videos/metamaps-intro.mp4">' +
'https://metamaps.cc/videos/metamaps-intro.mp4</a>.'
)
}
})
}// if
})

File diff suppressed because it is too large Load diff

View 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] = [];
}
}
};
}));

View file

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

View file

@ -0,0 +1,685 @@
/*
* BestInPlace (for jQuery)
* version: 3.0.0.alpha (2014)
*
* By Bernat Farrero based on the work of Jan Varwig.
* Examples at http://bernatfarrero.com
*
* Licensed under the MIT:
* http://www.opensource.org/licenses/mit-license.php
*
* @requires jQuery
*
* Usage:
*
* Attention.
* The format of the JSON object given to the select inputs is the following:
* [["key", "value"],["key", "value"]]
* The format of the JSON object given to the checkbox inputs is the following:
* ["falseValue", "trueValue"]
*/
//= require jquery.autosize
function BestInPlaceEditor(e) {
'use strict';
this.element = e;
this.initOptions();
this.bindForm();
this.initPlaceHolder();
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
}
BestInPlaceEditor.prototype = {
// Public Interface Functions //////////////////////////////////////////////
activate: function () {
'use strict';
var to_display;
if (this.isPlaceHolder()) {
to_display = "";
} else if (this.original_content) {
to_display = this.original_content;
} else {
switch (this.formType) {
case 'input':
case 'textarea':
if (this.display_raw) {
to_display = this.element.html().replace(/&amp;/gi, '&');
}
else {
var value = this.element.data('bipValue');
if (typeof value === 'undefined') {
to_display = '';
} else if (typeof value === 'string') {
to_display = this.element.data('bipValue').replace(/&amp;/gi, '&');
} else {
to_display = this.element.data('bipValue');
}
}
break;
case 'select':
to_display = this.element.html();
}
}
this.oldValue = this.isPlaceHolder() ? "" : this.element.html();
this.display_value = to_display;
jQuery(this.activator).unbind("click", this.clickHandler);
this.activateForm();
this.element.trigger(jQuery.Event("best_in_place:activate"));
},
abort: function () {
'use strict';
this.activateText(this.oldValue);
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:abort"));
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
abortIfConfirm: function () {
'use strict';
if (!this.useConfirm) {
this.abort();
return;
}
if (confirm(BestInPlaceEditor.defaults.locales[''].confirmMessage)) {
this.abort();
}
},
update: function () {
'use strict';
var editor = this,
value = this.getValue();
// Avoid request if no change is made
if (this.formType in {"input": 1, "textarea": 1} && value === this.oldValue) {
this.abort();
return true;
}
editor.ajax({
"type": this.requestMethod(),
"dataType": BestInPlaceEditor.defaults.ajaxDataType,
"data": editor.requestData(),
"success": function (data, status, xhr) {
editor.loadSuccessCallback(data, status, xhr);
},
"error": function (request, error) {
editor.loadErrorCallback(request, error);
}
});
switch (this.formType) {
case "select":
this.previousCollectionValue = value;
// search for the text for the span
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
break;
case "checkbox":
$.each(this.values, function(index, arr){ if (String(arr[0]) === String(value)) editor.element.html(arr[1]); });
break;
default:
if (value !== "") {
if (this.display_raw) {
editor.element.html(value);
} else {
editor.element.text(value);
}
} else {
editor.element.html(this.placeHolder);
}
}
editor.element.data('bipValue', value);
editor.element.attr('data-bip-value', value);
editor.element.trigger(jQuery.Event("best_in_place:update"));
},
activateForm: function () {
'use strict';
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
},
activateText: function (value) {
'use strict';
this.element.html(value);
if (this.isPlaceHolder()) {
this.element.html(this.placeHolder);
}
},
// Helper Functions ////////////////////////////////////////////////////////
initOptions: function () {
// Try parent supplied info
'use strict';
var self = this;
self.element.parents().each(function () {
var $parent = jQuery(this);
self.url = self.url || $parent.data("bipUrl");
self.activator = self.activator || $parent.data("bipActivator");
self.okButton = self.okButton || $parent.data("bipOkButton");
self.okButtonClass = self.okButtonClass || $parent.data("bipOkButtonClass");
self.cancelButton = self.cancelButton || $parent.data("bipCancelButton");
self.cancelButtonClass = self.cancelButtonClass || $parent.data("bipCancelButtonClass");
self.skipBlur = self.skipBlur || $parent.data("bipSkipBlur");
});
// Load own attributes (overrides all others)
self.url = self.element.data("bipUrl") || self.url || document.location.pathname;
self.collection = self.element.data("bipCollection") || self.collection;
self.formType = self.element.data("bipType") || "input";
self.objectName = self.element.data("bipObject") || self.objectName;
self.attributeName = self.element.data("bipAttribute") || self.attributeName;
self.activator = self.element.data("bipActivator") || self.element;
self.okButton = self.element.data("bipOkButton") || self.okButton;
self.okButtonClass = self.element.data("bipOkButtonClass") || self.okButtonClass || BestInPlaceEditor.defaults.okButtonClass;
self.cancelButton = self.element.data("bipCancelButton") || self.cancelButton;
self.cancelButtonClass = self.element.data("bipCancelButtonClass") || self.cancelButtonClass || BestInPlaceEditor.defaults.cancelButtonClass;
self.skipBlur = self.element.data("bipSkipBlur") || self.skipBlur || BestInPlaceEditor.defaults.skipBlur;
self.isNewObject = self.element.data("bipNewObject");
self.dataExtraPayload = self.element.data("bipExtraPayload");
// Fix for default values of 0
if (self.element.data("bipPlaceholder") == null) {
self.placeHolder = BestInPlaceEditor.defaults.locales[''].placeHolder;
} else {
self.placeHolder = self.element.data("bipPlaceholder");
}
self.inner_class = self.element.data("bipInnerClass");
self.html_attrs = self.element.data("bipHtmlAttrs");
self.original_content = self.element.data("bipOriginalContent") || self.original_content;
// if set the input won't be satinized
self.display_raw = self.element.data("bip-raw");
self.useConfirm = self.element.data("bip-confirm");
if (self.formType === "select" || self.formType === "checkbox") {
self.values = self.collection;
self.collectionValue = self.element.data("bipValue") || self.collectionValue;
}
},
bindForm: function () {
'use strict';
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
},
initPlaceHolder: function () {
'use strict';
// TODO add placeholder for select and checkbox
if (this.element.html() === "") {
this.element.addClass('bip-placeholder');
this.element.html(this.placeHolder);
}
},
isPlaceHolder: function () {
'use strict';
// TODO: It only work when form is deactivated.
// Condition will fail when form is activated
return this.element.html() === "" || this.element.html() === this.placeHolder;
},
getValue: function () {
'use strict';
alert(BestInPlaceEditor.defaults.locales[''].uninitializedForm);
},
// Trim and Strips HTML from text
sanitizeValue: function (s) {
'use strict';
return jQuery.trim(s);
},
requestMethod: function() {
'use strict';
return this.isNewObject ? 'post' : BestInPlaceEditor.defaults.ajaxMethod;
},
/* Generate the data sent in the POST request */
requestData: function () {
'use strict';
// To prevent xss attacks, a csrf token must be defined as a meta attribute
var csrf_token = jQuery('meta[name=csrf-token]').attr('content'),
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
var data = {}
data['_method'] = this.requestMethod()
data[this.objectName] = this.dataExtraPayload || {}
data[this.objectName][this.attributeName] = this.getValue()
if (csrf_param !== undefined && csrf_token !== undefined) {
data[csrf_param] = csrf_token
}
return jQuery.param(data);
},
ajax: function (options) {
'use strict';
options.url = this.url;
options.beforeSend = function (xhr) {
xhr.setRequestHeader("Accept", "application/json");
};
return jQuery.ajax(options);
},
// Handlers ////////////////////////////////////////////////////////////////
loadSuccessCallback: function (data, status, xhr) {
'use strict';
data = jQuery.trim(data);
//Update original content with current text.
if (this.display_raw) {
this.original_content = this.element.html();
} else {
this.original_content = this.element.text();
}
if (data && data !== "") {
var response = jQuery.parseJSON(data);
if (response !== null && response.hasOwnProperty("display_as")) {
this.element.data('bip-original-content', this.element.text());
this.element.html(response.display_as);
}
if (this.isNewObject && response && response[this.objectName]) {
if (response[this.objectName]["id"]) {
this.isNewObject = false
this.url += "/" + response[this.objectName]["id"] // in REST a POST /thing url should become PUT /thing/123
}
}
}
this.element.toggleClass('bip-placeholder', this.isPlaceHolder());
this.element.trigger(jQuery.Event("best_in_place:success"), [data, status, xhr]);
this.element.trigger(jQuery.Event("ajax:success"), [data, status, xhr]);
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
if (this.collectionValue !== null && this.formType === "select") {
this.collectionValue = this.previousCollectionValue;
this.previousCollectionValue = null;
}
},
loadErrorCallback: function (request, error) {
'use strict';
this.activateText(this.oldValue);
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
this.element.trigger(jQuery.Event("ajax:error"), request, error);
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
clickHandler: function (event) {
'use strict';
event.preventDefault();
event.data.editor.activate();
},
setHtmlAttributes: function () {
'use strict';
var formField = this.element.find(this.formType);
if (this.html_attrs) {
var attrs = this.html_attrs;
$.each(attrs, function (key, val) {
formField.attr(key, val);
});
}
},
placeButtons: function (output, field) {
'use strict';
if (field.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('class', field.okButtonClass)
.attr('value', field.okButton)
);
}
if (field.cancelButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'button')
.attr('class', field.cancelButtonClass)
.attr('value', field.cancelButton)
);
}
}
};
// Button cases:
// If no buttons, then blur saves, ESC cancels
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
BestInPlaceEditor.forms = {
"input": {
activateForm: function () {
'use strict';
var output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline');
var input_elt = jQuery(document.createElement('input'))
.attr('type', 'text')
.attr('name', this.attributeName)
.val(this.display_value);
// Add class to form input
if (this.inner_class) {
input_elt.addClass(this.inner_class);
}
output.append(input_elt);
this.placeButtons(output, this);
this.element.html(output);
this.setHtmlAttributes();
this.element.find("input[type='text']")[0].select();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
}
if (!this.okButton) {
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
}
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue: function () {
'use strict';
return this.sanitizeValue(this.element.find("input").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
inputBlurHandler: function (event) {
'use strict';
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abort();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler: function (event) {
'use strict';
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler: function (event) {
'use strict';
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abort();
event.stopPropagation(); // Without this, click isn't handled
},
keyupHandler: function (event) {
'use strict';
if (event.keyCode === 27) {
event.data.editor.abort();
event.stopImmediatePropagation();
}
}
},
"select": {
activateForm: function () {
'use strict';
var output = jQuery(document.createElement('form'))
.attr('action', 'javascript:void(0)')
.attr('style', 'display:inline'),
selected = '',
select_elt = jQuery(document.createElement('select'))
.attr('class', this.inner_class !== null ? this.inner_class : ''),
currentCollectionValue = this.collectionValue,
key, value,
a = this.values;
$.each(a, function(index, arr){
key = arr[0];
value = arr[1];
var option_elt = jQuery(document.createElement('option'))
.val(key)
.html(value);
if (currentCollectionValue) {
if (String(key) === String(currentCollectionValue)) option_elt.attr('selected', 'selected');
}
select_elt.append(option_elt);
});
output.append(select_elt);
this.element.html(output);
this.setHtmlAttributes();
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
this.element.find("select")[0].focus();
// automatically click on the select so you
// don't have to click twice
try {
var e = document.createEvent("MouseEvents");
e.initMouseEvent("mousedown", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
this.element.find("select")[0].dispatchEvent(e);
}
catch(e) {
// browser doesn't support this, e.g. IE8
}
},
getValue: function () {
'use strict';
return this.sanitizeValue(this.element.find("select").val());
},
blurHandler: function (event) {
'use strict';
event.data.editor.update();
},
keyupHandler: function (event) {
'use strict';
if (event.keyCode === 27) {
event.data.editor.abort();
}
}
},
"checkbox": {
activateForm: function () {
'use strict';
this.collectionValue = !this.getValue();
this.setHtmlAttributes();
this.update();
},
getValue: function () {
'use strict';
return this.collectionValue;
}
},
"textarea": {
activateForm: function () {
'use strict';
// grab width and height of text
var width = this.element.css('width');
var height = this.element.css('height');
// construct form
var output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline');
var textarea_elt = jQuery(document.createElement('textarea'))
.attr('name', this.attributeName)
.val(this.sanitizeValue(this.display_value));
if (this.inner_class !== null) {
textarea_elt.addClass(this.inner_class);
}
output.append(textarea_elt);
this.placeButtons(output, this);
this.element.html(output);
this.setHtmlAttributes();
// set width and height of textarea
jQuery(this.element.find("textarea")[0]).css({'min-width': width, 'min-height': height});
jQuery(this.element.find("textarea")[0]).autosize();
this.element.find("textarea")[0].focus();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
}
if (!this.skipBlur) {
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
}
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue: function () {
'use strict';
return this.sanitizeValue(this.element.find("textarea").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
blurHandler: function (event) {
'use strict';
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abortIfConfirm();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler: function (event) {
'use strict';
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler: function (event) {
'use strict';
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abortIfConfirm();
event.stopPropagation(); // Without this, click isn't handled
},
keyupHandler: function (event) {
'use strict';
if (event.keyCode === 27) {
event.data.editor.abortIfConfirm();
}
}
}
};
BestInPlaceEditor.defaults = {
locales: {},
ajaxMethod: "put", //TODO Change to patch when support to 3.2 is dropped
ajaxDataType: 'text',
okButtonClass: '',
cancelButtonClass: '',
skipBlur: false
};
// Default locale
BestInPlaceEditor.defaults.locales[''] = {
confirmMessage: "Are you sure you want to discard your changes?",
uninitializedForm: "The form was not properly initialized. getValue is unbound",
placeHolder: '-'
};
jQuery.fn.best_in_place = function () {
'use strict';
function setBestInPlace(element) {
if (!element.data('bestInPlaceEditor')) {
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
return true;
}
}
jQuery(this.context).delegate(this.selector, 'click', function () {
var el = jQuery(this);
if (setBestInPlace(el)) {
el.click();
}
});
this.each(function () {
setBestInPlace(jQuery(this));
});
return this;
};

View file

@ -1,780 +0,0 @@
/*
BestInPlace (for jQuery)
version: 0.1.0 (01/01/2011)
@requires jQuery >= v1.4
@requires jQuery.purr to display pop-up windows
By Bernat Farrero based on the work of Jan Varwig.
Examples at http://bernatfarrero.com
Licensed under the MIT:
http://www.opensource.org/licenses/mit-license.php
Usage:
Attention.
The format of the JSON object given to the select inputs is the following:
[["key", "value"],["key", "value"]]
The format of the JSON object given to the checkbox inputs is the following:
["falseValue", "trueValue"]
*/
function BestInPlaceEditor(e) {
this.element = e;
this.initOptions();
this.bindForm();
this.initNil();
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
}
BestInPlaceEditor.prototype = {
// Public Interface Functions //////////////////////////////////////////////
activate : function() {
var to_display = "";
if (this.isNil()) {
to_display = "";
}
else if (this.original_content) {
to_display = this.original_content;
}
else {
if (this.sanitize) {
to_display = this.element.text();
} else {
to_display = this.element.html();
}
}
this.oldValue = this.isNil() ? "" : this.element.html();
this.display_value = to_display;
jQuery(this.activator).unbind("click", this.clickHandler);
this.activateForm();
this.element.trigger(jQuery.Event("best_in_place:activate"));
},
abort : function() {
this.activateText(this.oldValue);
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:abort"));
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
abortIfConfirm : function () {
if (!this.useConfirm) {
this.abort();
return;
}
if (confirm("Are you sure you want to discard your changes?")) {
this.abort();
}
},
update : function() {
var editor = this;
if (this.formType in {"input":1, "textarea":1} && this.getValue() == this.oldValue)
{ // Avoid request if no change is made
this.abort();
return true;
}
editor.ajax({
"type" : "post",
"dataType" : "text",
"data" : editor.requestData(),
"success" : function(data){ editor.loadSuccessCallback(data); },
"error" : function(request, error){ editor.loadErrorCallback(request, error); }
});
if (this.formType == "select") {
var value = this.getValue();
this.previousCollectionValue = value;
jQuery.each(this.values, function(i, v) {
if (value == v[0]) {
editor.element.html(v[1]);
}
}
);
} else if (this.formType == "checkbox") {
editor.element.html(this.getValue() ? this.values[1] : this.values[0]);
} else {
if (this.getValue() !== "") {
editor.element.text(this.getValue());
} else {
editor.element.html(this.nil);
}
}
editor.element.trigger(jQuery.Event("best_in_place:update"));
},
activateForm : function() {
alert("The form was not properly initialized. activateForm is unbound");
},
activateText : function(value){
this.element.html(value);
if(this.isNil()) this.element.html(this.nil);
},
// Helper Functions ////////////////////////////////////////////////////////
initOptions : function() {
// Try parent supplied info
var self = this;
self.element.parents().each(function(){
$parent = jQuery(this);
self.url = self.url || $parent.attr("data-url");
self.collection = self.collection || $parent.attr("data-collection");
self.formType = self.formType || $parent.attr("data-type");
self.objectName = self.objectName || $parent.attr("data-object");
self.attributeName = self.attributeName || $parent.attr("data-attribute");
self.activator = self.activator || $parent.attr("data-activator");
self.okButton = self.okButton || $parent.attr("data-ok-button");
self.okButtonClass = self.okButtonClass || $parent.attr("data-ok-button-class");
self.cancelButton = self.cancelButton || $parent.attr("data-cancel-button");
self.cancelButtonClass = self.cancelButtonClass || $parent.attr("data-cancel-button-class");
self.nil = self.nil || $parent.attr("data-nil");
self.inner_class = self.inner_class || $parent.attr("data-inner-class");
self.html_attrs = self.html_attrs || $parent.attr("data-html-attrs");
self.original_content = self.original_content || $parent.attr("data-original-content");
self.collectionValue = self.collectionValue || $parent.attr("data-value");
});
// Try Rails-id based if parents did not explicitly supply something
self.element.parents().each(function(){
var res = this.id.match(/^(\w+)_(\d+)$/i);
if (res) {
self.objectName = self.objectName || res[1];
}
});
// Load own attributes (overrides all others)
self.url = self.element.attr("data-url") || self.url || document.location.pathname;
self.collection = self.element.attr("data-collection") || self.collection;
self.formType = self.element.attr("data-type") || self.formtype || "input";
self.objectName = self.element.attr("data-object") || self.objectName;
self.attributeName = self.element.attr("data-attribute") || self.attributeName;
self.activator = self.element.attr("data-activator") || self.element;
self.okButton = self.element.attr("data-ok-button") || self.okButton;
self.okButtonClass = self.element.attr("data-ok-button-class") || self.okButtonClass || "";
self.cancelButton = self.element.attr("data-cancel-button") || self.cancelButton;
self.cancelButtonClass = self.element.attr("data-cancel-button-class") || self.cancelButtonClass || "";
self.nil = self.element.attr("data-nil") || self.nil || "—";
self.inner_class = self.element.attr("data-inner-class") || self.inner_class || null;
self.html_attrs = self.element.attr("data-html-attrs") || self.html_attrs;
self.original_content = self.element.attr("data-original-content") || self.original_content;
self.collectionValue = self.element.attr("data-value") || self.collectionValue;
if (!self.element.attr("data-sanitize")) {
self.sanitize = true;
}
else {
self.sanitize = (self.element.attr("data-sanitize") == "true");
}
if (!self.element.attr("data-use-confirm")) {
self.useConfirm = true;
} else {
self.useConfirm = (self.element.attr("data-use-confirm") != "false");
}
if ((self.formType == "select" || self.formType == "checkbox") && self.collection !== null)
{
self.values = jQuery.parseJSON(self.collection);
}
},
bindForm : function() {
this.activateForm = BestInPlaceEditor.forms[this.formType].activateForm;
this.getValue = BestInPlaceEditor.forms[this.formType].getValue;
},
initNil: function() {
if (this.element.html() === "")
{
this.element.html(this.nil);
}
},
isNil: function() {
// TODO: It only work when form is deactivated.
// Condition will fail when form is activated
return this.element.html() === "" || this.element.html() === this.nil;
},
getValue : function() {
alert("The form was not properly initialized. getValue is unbound");
},
// Trim and Strips HTML from text
sanitizeValue : function(s) {
return jQuery.trim(s);
},
/* Generate the data sent in the POST request */
requestData : function() {
// To prevent xss attacks, a csrf token must be defined as a meta attribute
csrf_token = jQuery('meta[name=csrf-token]').attr('content');
csrf_param = jQuery('meta[name=csrf-param]').attr('content');
var data = "_method=put";
data += "&" + this.objectName + '[' + this.attributeName + ']=' + encodeURIComponent(this.getValue());
if (csrf_param !== undefined && csrf_token !== undefined) {
data += "&" + csrf_param + "=" + encodeURIComponent(csrf_token);
}
return data;
},
ajax : function(options) {
options.url = this.url;
options.beforeSend = function(xhr){ xhr.setRequestHeader("Accept", "application/json"); };
return jQuery.ajax(options);
},
// Handlers ////////////////////////////////////////////////////////////////
loadSuccessCallback : function(data) {
data = jQuery.trim(data);
if(data && data!=""){
var response = jQuery.parseJSON(jQuery.trim(data));
if (response !== null && response.hasOwnProperty("display_as")) {
this.element.attr("data-original-content", this.element.text());
this.original_content = this.element.text();
this.element.html(response["display_as"]);
}
this.element.trigger(jQuery.Event("best_in_place:success"), data);
this.element.trigger(jQuery.Event("ajax:success"), data);
} else {
this.element.trigger(jQuery.Event("best_in_place:success"));
this.element.trigger(jQuery.Event("ajax:success"));
}
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
if (this.collectionValue !== null && this.formType == "select") {
this.collectionValue = this.previousCollectionValue;
this.previousCollectionValue = null;
}
},
loadErrorCallback : function(request, error) {
this.activateText(this.oldValue);
this.element.trigger(jQuery.Event("best_in_place:error"), [request, error]);
this.element.trigger(jQuery.Event("ajax:error"), request, error);
// Binding back after being clicked
jQuery(this.activator).bind('click', {editor: this}, this.clickHandler);
this.element.trigger(jQuery.Event("best_in_place:deactivate"));
},
clickHandler : function(event) {
event.preventDefault();
event.data.editor.activate();
},
setHtmlAttributes : function() {
var formField = this.element.find(this.formType);
if(this.html_attrs){
var attrs = jQuery.parseJSON(this.html_attrs);
for(var key in attrs){
formField.attr(key, attrs[key]);
}
}
}
};
// Button cases:
// If no buttons, then blur saves, ESC cancels
// If just Cancel button, then blur saves, ESC or clicking Cancel cancels (careful of blur event!)
// If just OK button, then clicking OK saves (careful of blur event!), ESC or blur cancels
// If both buttons, then clicking OK saves, ESC or clicking Cancel or blur cancels
BestInPlaceEditor.forms = {
"input" : {
activateForm : function() {
var output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline');
var input_elt = jQuery(document.createElement('input'))
.attr('type', 'text')
.attr('name', this.attributeName)
.val(this.display_value);
if(this.inner_class !== null) {
input_elt.addClass(this.inner_class);
}
output.append(input_elt);
if(this.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('class', this.okButtonClass)
.attr('value', this.okButton)
)
}
if(this.cancelButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'button')
.attr('class', this.cancelButtonClass)
.attr('value', this.cancelButton)
)
}
this.element.html(output);
this.setHtmlAttributes();
// START METAMAPS CODE
//this.element.find("input[type='text']")[0].select();
this.element.find("input[type='text']")[0].focus();
// END METAMAPS CODE
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.input.cancelButtonHandler);
}
this.element.find("input[type='text']").bind('blur', {editor: this}, BestInPlaceEditor.forms.input.inputBlurHandler);
// START METAMAPS CODE
this.element.find("input[type='text']").bind('keydown', {editor: this}, BestInPlaceEditor.forms.input.keydownHandler);
// END METAMAPS CODE
this.element.find("input[type='text']").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue : function() {
return this.sanitizeValue(this.element.find("input").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
inputBlurHandler : function(event) {
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abort();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abort();
event.stopPropagation(); // Without this, click isn't handled
},
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abort();
}
// START METAMAPS CODE
else if (event.keyCode == 13 && !event.shiftKey) {
event.data.editor.update();
}
// END METAMAPS CODE
}
},
"date" : {
activateForm : function() {
var that = this,
output = jQuery(document.createElement('form'))
.addClass('form_in_place')
.attr('action', 'javascript:void(0);')
.attr('style', 'display:inline'),
input_elt = jQuery(document.createElement('input'))
.attr('type', 'text')
.attr('name', this.attributeName)
.attr('value', this.sanitizeValue(this.display_value));
if(this.inner_class !== null) {
input_elt.addClass(this.inner_class);
}
output.append(input_elt)
this.element.html(output);
this.setHtmlAttributes();
this.element.find('input')[0].select();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.input.submitHandler);
this.element.find("input").bind('keyup', {editor: this}, BestInPlaceEditor.forms.input.keyupHandler);
this.element.find('input')
.datepicker({
onClose: function() {
that.update();
}
})
.datepicker('show');
},
getValue : function() {
return this.sanitizeValue(this.element.find("input").val());
},
submitHandler : function(event) {
event.data.editor.update();
},
// START METAMAPS CODE
keydownHandler : function(event) {
if (event.keyCode == 13 && !event.shiftKey) {
event.preventDefault();
event.stopPropagation();
return false;
}
},
// END METAMAPS CODE
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abort();
}
}
},
"select" : {
activateForm : function() {
var output = jQuery(document.createElement('form'))
.attr('action', 'javascript:void(0)')
.attr('style', 'display:inline');
selected = '',
oldValue = this.oldValue,
select_elt = jQuery(document.createElement('select'))
.attr('class', this.inned_class !== null ? this.inner_class : '' ),
currentCollectionValue = this.collectionValue;
jQuery.each(this.values, function (index, value) {
var option_elt = jQuery(document.createElement('option'))
// .attr('value', value[0])
.val(value[0])
.html(value[1]);
if(value[0] == currentCollectionValue) {
option_elt.attr('selected', 'selected');
}
select_elt.append(option_elt);
});
output.append(select_elt);
this.element.html(output);
this.setHtmlAttributes();
this.element.find("select").bind('change', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('blur', {editor: this}, BestInPlaceEditor.forms.select.blurHandler);
this.element.find("select").bind('keyup', {editor: this}, BestInPlaceEditor.forms.select.keyupHandler);
this.element.find("select")[0].focus();
},
getValue : function() {
return this.sanitizeValue(this.element.find("select").val());
// return this.element.find("select").val();
},
blurHandler : function(event) {
event.data.editor.update();
},
keyupHandler : function(event) {
if (event.keyCode == 27) event.data.editor.abort();
}
},
"checkbox" : {
activateForm : function() {
this.collectionValue = !this.getValue();
this.setHtmlAttributes();
this.update();
},
getValue : function() {
return this.collectionValue;
}
},
"textarea" : {
activateForm : function() {
// grab width and height of text
width = this.element.css('width');
height = this.element.css('height');
// construct form
var output = jQuery(document.createElement('form'))
.attr('action', 'javascript:void(0)')
.attr('style', 'display:inline')
.append(jQuery(document.createElement('textarea'))
.val(this.sanitizeValue(this.display_value)));
if(this.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('value', this.okButton)
);
}
if(this.cancelButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'button')
.attr('value', this.cancelButton)
)
}
this.element.html(output);
this.setHtmlAttributes();
// set width and height of textarea
jQuery(this.element.find("textarea")[0]).css({ 'min-width': width, 'min-height': height });
jQuery(this.element.find("textarea")[0]).elastic();
this.element.find("textarea")[0].focus();
this.element.find("form").bind('submit', {editor: this}, BestInPlaceEditor.forms.textarea.submitHandler);
if (this.cancelButton) {
this.element.find("input[type='button']").bind('click', {editor: this}, BestInPlaceEditor.forms.textarea.cancelButtonHandler);
}
this.element.find("textarea").bind('blur', {editor: this}, BestInPlaceEditor.forms.textarea.blurHandler);
// START METAMAPS CODE
this.element.find("textarea").bind('keydown', {editor: this}, BestInPlaceEditor.forms.textarea.keydownHandler);
// END METAMAPS CODE
this.element.find("textarea").bind('keyup', {editor: this}, BestInPlaceEditor.forms.textarea.keyupHandler);
this.blurTimer = null;
this.userClicked = false;
},
getValue : function() {
return this.sanitizeValue(this.element.find("textarea").val());
},
// When buttons are present, use a timer on the blur event to give precedence to clicks
blurHandler : function(event) {
if (event.data.editor.okButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.abortIfConfirm();
}
}, 500);
} else {
if (event.data.editor.cancelButton) {
event.data.editor.blurTimer = setTimeout(function () {
if (!event.data.editor.userClicked) {
event.data.editor.update();
}
}, 500);
} else {
event.data.editor.update();
}
}
},
submitHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.update();
},
cancelButtonHandler : function(event) {
event.data.editor.userClicked = true;
clearTimeout(event.data.editor.blurTimer);
event.data.editor.abortIfConfirm();
event.stopPropagation(); // Without this, click isn't handled
},
// START METAMAPS CODE
keydownHandler : function(event) {
if (event.keyCode == 13 && !event.shiftKey) {
event.preventDefault();
event.stopPropagation();
return false;
}
},
// END METAMAPS CODE
keyupHandler : function(event) {
if (event.keyCode == 27) {
event.data.editor.abortIfConfirm();
}
// START METAMAPS CODE
else if (event.keyCode == 13 && !event.shiftKey) {
event.data.editor.update();
}
// END METAMAPS CODE
}
}
};
jQuery.fn.best_in_place = function() {
function setBestInPlace(element) {
if (!element.data('bestInPlaceEditor')) {
element.data('bestInPlaceEditor', new BestInPlaceEditor(element));
return true;
}
}
jQuery(this.context).delegate(this.selector, 'click', function () {
var el = jQuery(this);
if (setBestInPlace(el))
el.click();
});
this.each(function () {
setBestInPlace(jQuery(this));
});
return this;
};
/**
* @name Elastic
* @descripton Elastic is Jquery plugin that grow and shrink your textareas automaticliy
* @version 1.6.5
* @requires Jquery 1.2.6+
*
* @author Jan Jarfalk
* @author-email jan.jarfalk@unwrongest.com
* @author-website http://www.unwrongest.com
*
* @licens MIT License - http://www.opensource.org/licenses/mit-license.php
*/
(function(jQuery){
if (typeof jQuery.fn.elastic !== 'undefined') return;
jQuery.fn.extend({
elastic: function() {
// We will create a div clone of the textarea
// by copying these attributes from the textarea to the div.
var mimics = [
'paddingTop',
'paddingRight',
'paddingBottom',
'paddingLeft',
'fontSize',
'lineHeight',
'fontFamily',
'width',
'fontWeight'];
return this.each( function() {
// Elastic only works on textareas
if ( this.type != 'textarea' ) {
return false;
}
var $textarea = jQuery(this),
$twin = jQuery('<div />').css({'position': 'absolute','display':'none','word-wrap':'break-word'}),
lineHeight = parseInt($textarea.css('line-height'),10) || parseInt($textarea.css('font-size'),'10'),
minheight = parseInt($textarea.css('height'),10) || lineHeight*3,
maxheight = parseInt($textarea.css('max-height'),10) || Number.MAX_VALUE,
goalheight = 0,
i = 0;
// Opera returns max-height of -1 if not set
if (maxheight < 0) { maxheight = Number.MAX_VALUE; }
// Append the twin to the DOM
// We are going to meassure the height of this, not the textarea.
$twin.appendTo($textarea.parent());
// Copy the essential styles (mimics) from the textarea to the twin
i = mimics.length;
while(i--){
$twin.css(mimics[i].toString(),$textarea.css(mimics[i].toString()));
}
// Sets a given height and overflow state on the textarea
function setHeightAndOverflow(height, overflow){
curratedHeight = Math.floor(parseInt(height,10));
if($textarea.height() != curratedHeight){
$textarea.css({'height': curratedHeight + 'px','overflow':overflow});
}
}
// This function will update the height of the textarea if necessary
function update() {
// Get curated content from the textarea.
var textareaContent = $textarea.val().replace(/&/g,'&amp;').replace(/ /g, '&nbsp;').replace(/<|>/g, '&gt;').replace(/\n/g, '<br />');
// Compare curated content with curated twin.
var twinContent = $twin.html().replace(/<br>/ig,'<br />');
if(textareaContent+'&nbsp;' != twinContent){
// Add an extra white space so new rows are added when you are at the end of a row.
$twin.html(textareaContent+'&nbsp;');
// Change textarea height if twin plus the height of one line differs more than 3 pixel from textarea height
if(Math.abs($twin.height() + lineHeight - $textarea.height()) > 3){
var goalheight = $twin.height()+lineHeight;
if(goalheight >= maxheight) {
setHeightAndOverflow(maxheight,'auto');
} else if(goalheight <= minheight) {
setHeightAndOverflow(minheight,'hidden');
} else {
setHeightAndOverflow(goalheight,'hidden');
}
}
}
}
// Hide scrollbars
$textarea.css({'overflow':'hidden'});
// Update textarea size on keyup, change, cut and paste
$textarea.bind('keyup change cut paste', function(){
update();
});
// Compact textarea on blur
// Lets animate this....
$textarea.bind('blur',function(){
if($twin.height() < maxheight){
if($twin.height() > minheight) {
$textarea.height($twin.height());
} else {
$textarea.height(minheight);
}
}
});
// And this line is to catch the browser paste event
$textarea.on("input paste", function(e){ setTimeout( update, 250); });
// Run update once when elastic is initialized
update();
});
}
});
})(jQuery);

View file

@ -0,0 +1,2 @@
!function(t){"use strict";var e=t.HTMLCanvasElement&&t.HTMLCanvasElement.prototype,o=t.Blob&&function(){try{return Boolean(new Blob)}catch(t){return!1}}(),n=o&&t.Uint8Array&&function(){try{return 100===new Blob([new Uint8Array(100)]).size}catch(t){return!1}}(),r=t.BlobBuilder||t.WebKitBlobBuilder||t.MozBlobBuilder||t.MSBlobBuilder,a=/^data:((.*?)(;charset=.*?)?)(;base64)?,/,i=(o||r)&&t.atob&&t.ArrayBuffer&&t.Uint8Array&&function(t){var e,i,l,u,b,c,d,B,f;if(e=t.match(a),!e)throw new Error("invalid data URI");for(i=e[2]?e[1]:"text/plain"+(e[3]||";charset=US-ASCII"),l=!!e[4],u=t.slice(e[0].length),b=l?atob(u):decodeURIComponent(u),c=new ArrayBuffer(b.length),d=new Uint8Array(c),B=0;B<b.length;B+=1)d[B]=b.charCodeAt(B);return o?new Blob([n?d:c],{type:i}):(f=new r,f.append(c),f.getBlob(i))};t.HTMLCanvasElement&&!e.toBlob&&(e.mozGetAsFile?e.toBlob=function(t,o,n){t(n&&e.toDataURL&&i?i(this.toDataURL(o,n)):this.mozGetAsFile("blob",o))}:e.toDataURL&&i&&(e.toBlob=function(t,e,o){t(i(this.toDataURL(e,o)))})),"function"==typeof define&&define.amd?define(function(){return i}):"object"==typeof module&&module.exports?module.exports=i:t.dataURLtoBlob=i}(window);
//# sourceMappingURL=canvas-to-blob.min.js.map

View file

@ -156,43 +156,48 @@ jQuery.browser = browser;
event.data.rotate(-1);
return false;
});
$(options.buttonRight).bind('mouseup',this,function(event){
$(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) {
event.data.rotate(-1);
event.preventDefault();
event.stopPropagation();
} else if (event.keyCode == 9) {
event.data.rotate(1);
event.preventDefault();
event.stopPropagation();
}
if (event.keyCode == 9) {
if (event.shiftKey) {
event.data.rotate(-1)
} else {
event.data.rotate(1)
}
event.preventDefault();
event.stopPropagation();
Metamaps.Create.newTopic.metacode = $(items[event.data.frontIndex].image).attr('data-id');
}
});
// END METAMAPS CODE
// You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel
if (options.mouseWheel)
{
// START METAMAPS CODE
$('body').bind('mousewheel',this,function(event, delta) {
if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) {
event.data.rotate(delta);
return false;
}
});
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;
});
*/
// ORIGINAL CODE
// $(container).bind('mousewheel',this,function(event, delta) {
// event.data.rotate(delta);
// return false;
// });
//
}
$(container).bind('mouseover click',this,function(event){
$(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');
@ -206,22 +211,27 @@ jQuery.browser = browser;
//$(options.titleBox).html( ($(event.target).attr('title') ));
if ( options.bringToFront && event.type == 'click' )
{
$(options.titleBox).html( ($(event.target).attr('title') ));
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(event.target).attr('data-id');
// NOT METAMAPS CODE
$(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);
}
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){
@ -245,11 +255,6 @@ jQuery.browser = browser;
this.showFrontText = function()
{
if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet.
// METAMAPS CODE
Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('data-id');
//$('img.cloudcarousel').css({"background":"none", "width":"","height":""});
//$(items[this.frontIndex].image).css({"width":"45px","height":"45px"});
// NOT METAMAPS CODE
$(options.titleBox).html( $(items[this.frontIndex].image).attr('title'));
$(options.altBox).html( $(items[this.frontIndex].image).attr('alt'));
};
@ -423,4 +428,4 @@ jQuery.browser = browser;
return this;
};
})(jQuery);
})(jQuery);

File diff suppressed because it is too large Load diff

View file

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

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

View file

@ -1,41 +0,0 @@
var USERVOICE;
if(USERVOICE == undefined) {
USERVOICE = {};
}
USERVOICE.load = function (name, id, email, sso_token) {
// Include the UserVoice JavaScript SDK (only needed once on a page)
UserVoice=window.UserVoice||[];(function(){var uv=document.createElement('script');uv.type='text/javascript';uv.async=true;uv.src='//widget.uservoice.com/wybK0nSMNuhlWkIKzTyWg.js';var s=document.getElementsByTagName('script')[0];s.parentNode.insertBefore(uv,s)})();
//
// UserVoice Javascript SDK developer documentation:
// https://www.uservoice.com/o/javascript-sdk
//
// Set colors
UserVoice.push(['set', {
accent_color: '#448dd6',
trigger_color: 'white',
trigger_background_color: 'rgba(46, 49, 51, 0.6)'
}]);
// Identify the user and pass traits
// To enable, replace sample data with actual user traits and uncomment the line
if (name) {
UserVoice.push(['setSSO', sso_token]);
UserVoice.push(['identify', {
'email': email, // Users email address
'name': name, // Users real name
'id': id, // Optional: Unique id of the user
}]);
}
// Add default trigger to the bottom-left corner of the window:
UserVoice.push(['addTrigger', { mode: 'contact', trigger_position: 'bottom-left' }]);
// Or, use your own custom trigger:
//UserVoice.push(['addTrigger', '#barometer_tab', { mode: 'contact' }]);
// Autoprompt for Satisfaction and SmartVote (only displayed under certain conditions)
UserVoice.push(['autoprompt', {}]);
};

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,22 +0,0 @@
{
"name": "metamaps-frontend",
"version": "1.0.0",
"description": "Metamaps frontend - currently just tests",
"scripts": {
"test": "mocha test || echo 'Run `npm install` to setup testing'"
},
"repository": {
"type": "git",
"url": "git+https://github.com/metamaps/metamaps.git"
},
"author": "",
"license": "AGPL-3.0",
"bugs": {
"url": "https://github.com/metamaps/metamaps/issues"
},
"homepage": "https://github.com/metamaps/metamaps#readme",
"devDependencies": {
"chai": "^3.5.0",
"mocha": "^2.4.5"
}
}

View file

@ -1,36 +0,0 @@
/*
RequireJS 2.1.11 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
Available via the MIT or new BSD license.
see: http://github.com/jrburke/requirejs for details
*/
var requirejs,require,define;
(function(ca){function G(b){return"[object Function]"===M.call(b)}function H(b){return"[object Array]"===M.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function U(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function s(b,c){return ga.call(b,c)}function j(b,c){return s(b,c)&&b[c]}function B(b,c){for(var d in b)if(s(b,d)&&c(b[d],d))break}function V(b,c,d,g){c&&B(c,function(c,h){if(d||!s(b,h))g&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
RegExp)?(b[h]||(b[h]={}),V(b[h],c,d,g)):b[h]=c});return b}function t(b,c){return function(){return c.apply(b,arguments)}}function da(b){throw b;}function ea(b){if(!b)return b;var c=ca;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,g){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=g;d&&(c.originalError=d);return c}function ha(b){function c(a,e,b){var f,n,c,d,g,h,i,I=e&&e.split("/");n=I;var m=l.map,k=m&&m["*"];if(a&&"."===a.charAt(0))if(e){n=
I.slice(0,I.length-1);a=a.split("/");e=a.length-1;l.nodeIdCompat&&R.test(a[e])&&(a[e]=a[e].replace(R,""));n=a=n.concat(a);d=n.length;for(e=0;e<d;e++)if(c=n[e],"."===c)n.splice(e,1),e-=1;else if(".."===c)if(1===e&&(".."===n[2]||".."===n[0]))break;else 0<e&&(n.splice(e-1,2),e-=2);a=a.join("/")}else 0===a.indexOf("./")&&(a=a.substring(2));if(b&&m&&(I||k)){n=a.split("/");e=n.length;a:for(;0<e;e-=1){d=n.slice(0,e).join("/");if(I)for(c=I.length;0<c;c-=1)if(b=j(m,I.slice(0,c).join("/")))if(b=j(b,d)){f=b;
g=e;break a}!h&&(k&&j(k,d))&&(h=j(k,d),i=e)}!f&&h&&(f=h,g=i);f&&(n.splice(0,g,f),a=n.join("/"))}return(f=j(l.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(e){if(e.getAttribute("data-requiremodule")===a&&e.getAttribute("data-requirecontext")===i.contextName)return e.parentNode.removeChild(e),!0})}function g(a){var e=j(l.paths,a);if(e&&H(e)&&1<e.length)return e.shift(),i.require.undef(a),i.require([a]),!0}function u(a){var e,b=a?a.indexOf("!"):-1;-1<b&&(e=a.substring(0,
b),a=a.substring(b+1,a.length));return[e,a]}function m(a,e,b,f){var n,d,g=null,h=e?e.name:null,l=a,m=!0,k="";a||(m=!1,a="_@r"+(M+=1));a=u(a);g=a[0];a=a[1];g&&(g=c(g,h,f),d=j(p,g));a&&(g?k=d&&d.normalize?d.normalize(a,function(a){return c(a,h,f)}):c(a,h,f):(k=c(a,h,f),a=u(k),g=a[0],k=a[1],b=!0,n=i.nameToUrl(k)));b=g&&!d&&!b?"_unnormalized"+(Q+=1):"";return{prefix:g,name:k,parentMap:e,unnormalized:!!b,url:n,originalName:l,isDefine:m,id:(g?g+"!"+k:k)+b}}function q(a){var e=a.id,b=j(k,e);b||(b=k[e]=new i.Module(a));
return b}function r(a,e,b){var f=a.id,n=j(k,f);if(s(p,f)&&(!n||n.defineEmitComplete))"defined"===e&&b(p[f]);else if(n=q(a),n.error&&"error"===e)b(n.error);else n.on(e,b)}function w(a,e){var b=a.requireModules,f=!1;if(e)e(a);else if(v(b,function(e){if(e=j(k,e))e.error=a,e.events.error&&(f=!0,e.emit("error",a))}),!f)h.onError(a)}function x(){S.length&&(ia.apply(A,[A.length,0].concat(S)),S=[])}function y(a){delete k[a];delete W[a]}function F(a,e,b){var f=a.map.id;a.error?a.emit("error",a.error):(e[f]=
!0,v(a.depMaps,function(f,c){var d=f.id,g=j(k,d);g&&(!a.depMatched[c]&&!b[d])&&(j(e,d)?(a.defineDep(c,p[d]),a.check()):F(g,e,b))}),b[f]=!0)}function D(){var a,e,b=(a=1E3*l.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],c=[],h=!1,k=!0;if(!X){X=!0;B(W,function(a){var i=a.map,m=i.id;if(a.enabled&&(i.isDefine||c.push(a),!a.error))if(!a.inited&&b)g(m)?h=e=!0:(f.push(m),d(m));else if(!a.inited&&(a.fetched&&i.isDefine)&&(h=!0,!i.prefix))return k=!1});if(b&&f.length)return a=C("timeout","Load timeout for modules: "+
f,null,f),a.contextName=i.contextName,w(a);k&&v(c,function(a){F(a,{},{})});if((!b||e)&&h)if((z||fa)&&!Y)Y=setTimeout(function(){Y=0;D()},50);X=!1}}function E(a){s(p,a[0])||q(m(a[0],null,!0)).init(a[1],a[2])}function K(a){var a=a.currentTarget||a.srcElement,e=i.onScriptLoad;a.detachEvent&&!Z?a.detachEvent("onreadystatechange",e):a.removeEventListener("load",e,!1);e=i.onScriptError;(!a.detachEvent||Z)&&a.removeEventListener("error",e,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function L(){var a;
for(x();A.length;){a=A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var X,$,i,N,Y,l={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},k={},W={},aa={},A=[],p={},T={},ba={},M=1,Q=1;N={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?p[a.map.id]=a.exports:a.exports=p[a.map.id]={}},module:function(a){return a.module?
a.module:a.module={id:a.map.id,uri:a.map.url,config:function(){return j(l.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};$=function(a){this.events=j(aa,a.id)||{};this.map=a;this.shim=j(l.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};$.prototype={init:function(a,e,b,f){f=f||{};if(!this.inited){this.factory=e;if(b)this.on("error",b);else this.events.error&&(b=t(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=
b;this.inited=!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,e){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=e)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],t(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
this.map.url;T[a]||(T[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,e,b=this.map.id;e=this.depExports;var f=this.exports,c=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(c)){if(this.events.error&&this.map.isDefine||h.onError!==da)try{f=i.execCb(b,c,e,f)}catch(d){a=d}else f=i.execCb(b,c,e,f);this.map.isDefine&&void 0===f&&((e=this.module)?f=e.exports:this.usingExports&&
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=c;this.exports=f;if(this.map.isDefine&&!this.ignore&&(p[b]=f,h.onResourceLoad))h.onResourceLoad(i,this.map,this.depMaps);y(b);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
this.map,b=a.id,d=m(a.prefix);this.depMaps.push(d);r(d,"defined",t(this,function(f){var d,g;g=j(ba,this.map.id);var J=this.map.name,u=this.map.parentMap?this.map.parentMap.name:null,p=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(J=f.normalize(J,function(a){return c(a,u,!0)})||""),f=m(a.prefix+"!"+J,this.map.parentMap),r(f,"defined",t(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),g=j(k,f.id)){this.depMaps.push(f);
if(this.events.error)g.on("error",t(this,function(a){this.emit("error",a)}));g.enable()}}else g?(this.map.url=i.nameToUrl(g),this.load()):(d=t(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),d.error=t(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(k,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),d.fromText=t(this,function(f,c){var g=a.name,J=m(g),k=O;c&&(f=c);k&&(O=!1);q(J);s(l.config,b)&&(l.config[g]=l.config[b]);try{h.exec(f)}catch(j){return w(C("fromtexteval",
"fromText eval for "+b+" failed: "+j,j,[b]))}k&&(O=!0);this.depMaps.push(J);i.completeLoad(g);p([g],d)}),f.load(a.name,p,d,l))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){W[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,t(this,function(a,b){var c,f;if("string"===typeof a){a=m(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=j(N,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;r(a,"defined",t(this,function(a){this.defineDep(b,
a);this.check()}));this.errback&&r(a,"error",t(this,this.errback))}c=a.id;f=k[c];!s(N,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,t(this,function(a){var b=j(k,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:l,contextName:b,registry:k,defined:p,urlFetched:T,defQueue:A,Module:$,makeModuleMap:m,
nextTick:h.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=l.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(l[b]||(l[b]={}),V(l[b],a,!0,!0)):l[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(ba[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),l.shim=b);a.packages&&v(a.packages,function(a){var b,
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(l.paths[b]=a.location);l.pkgs[b]=a.name+"/"+(a.main||"main").replace(ja,"").replace(R,"")});B(k,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=m(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ca,arguments));return b||a.exports&&ea(a.exports)}},makeRequire:function(a,e){function g(f,c,d){var j,l;e.enableBuildCallback&&(c&&G(c))&&(c.__requireJsBuild=
!0);if("string"===typeof f){if(G(c))return w(C("requireargs","Invalid require call"),d);if(a&&s(N,f))return N[f](k[a.id]);if(h.get)return h.get(i,f,a,g);j=m(f,a,!1,!0);j=j.id;return!s(p,j)?w(C("notloaded",'Module name "'+j+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):p[j]}L();i.nextTick(function(){L();l=q(m(null,a));l.skipMap=e.skipMap;l.init(f,c,d,{enabled:!0});D()});return g}e=e||{};V(g,{isBrowser:z,toUrl:function(b){var e,d=b.lastIndexOf("."),g=b.split("/")[0];if(-1!==
d&&(!("."===g||".."===g)||1<d))e=b.substring(d,b.length),b=b.substring(0,d);return i.nameToUrl(c(b,a&&a.id,!0),e,!0)},defined:function(b){return s(p,m(b,a,!1,!0).id)},specified:function(b){b=m(b,a,!1,!0).id;return s(p,b)||s(k,b)}});a||(g.undef=function(b){x();var c=m(b,a,!0),e=j(k,b);d(b);delete p[b];delete T[c.url];delete aa[b];U(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&(aa[b]=e.events),y(b))});return g},enable:function(a){j(k,a.id)&&q(a).enable()},completeLoad:function(a){var b,
c,f=j(l.shim,a)||{},d=f.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=j(k,a);if(!b&&!s(p,a)&&c&&!c.inited){if(l.enforceDefine&&(!d||!ea(d)))return g(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,f.deps||[],f.exportsFn])}D()},nameToUrl:function(a,b,c){var f,d,g;(f=j(l.pkgs,a))&&(a=f);if(f=j(ba,a))return i.nameToUrl(f,b,c);if(h.jsExtRegExp.test(a))f=a+(b||"");else{f=l.paths;a=a.split("/");for(d=a.length;0<d;d-=1)if(g=a.slice(0,
d).join("/"),g=j(f,g)){H(g)&&(g=g[0]);a.splice(0,d,g);break}f=a.join("/");f+=b||(/^data\:|\?/.test(f)||c?"":".js");f=("/"===f.charAt(0)||f.match(/^[\w\+\.\-]+:/)?"":l.baseUrl)+f}return l.urlArgs?f+((-1===f.indexOf("?")?"?":"&")+l.urlArgs):f},load:function(a,b){h.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ka.test((a.currentTarget||a.srcElement).readyState))P=null,a=K(a),i.completeLoad(a.id)},onScriptError:function(a){var b=K(a);if(!g(b.id))return w(C("scripterror",
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var h,x,y,D,K,E,P,L,q,Q,la=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,ma=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,R=/\.js$/,ja=/^\.\//;x=Object.prototype;var M=x.toString,ga=x.hasOwnProperty,ia=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),fa=!z&&"undefined"!==typeof importScripts,ka=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
Z="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},r={},S=[],O=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;r=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(r=require,require=void 0);h=requirejs=function(b,c,d,g){var u,m="_";!H(b)&&"string"!==typeof b&&(u=b,H(c)?(b=c,c=d,d=g):b=[]);u&&u.context&&(m=u.context);(g=j(F,m))||(g=F[m]=h.s.newContext(m));u&&g.configure(u);return g.require(b,c,d)};h.config=function(b){return h(b)};
h.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=h);h.version="2.1.11";h.jsExtRegExp=/^\/|:|\?|\.js$/;h.isBrowser=z;x=h.s={contexts:F,newContext:ha};h({});v(["toUrl","undef","defined","specified"],function(b){h[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;h.onError=da;h.createNode=function(b){var c=
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};h.load=function(b,c,d){var g=b&&b.config||{};if(z)return g=h.createNode(g,c,d),g.setAttribute("data-requirecontext",b.contextName),g.setAttribute("data-requiremodule",c),g.attachEvent&&!(g.attachEvent.toString&&0>g.attachEvent.toString().indexOf("[native code"))&&!Z?(O=!0,g.attachEvent("onreadystatechange",b.onScriptLoad)):
(g.addEventListener("load",b.onScriptLoad,!1),g.addEventListener("error",b.onScriptError,!1)),g.src=d,L=g,D?y.insertBefore(g,D):y.appendChild(g),L=null,g;if(fa)try{importScripts(d),b.completeLoad(c)}catch(j){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,j,[c]))}};z&&!r.skipDataMain&&U(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(K=b.getAttribute("data-main"))return q=K,r.baseUrl||(E=q.split("/"),q=E.pop(),Q=E.length?E.join("/")+"/":"./",r.baseUrl=
Q),q=q.replace(R,""),h.jsExtRegExp.test(q)&&(q=K),r.deps=r.deps?r.deps.concat(q):[q],!0});define=function(b,c,d){var g,h;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(la,"").replace(ma,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(O){if(!(g=L))P&&"interactive"===P.readyState||U(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return P=b}),g=P;g&&(b||
(b=g.getAttribute("data-requiremodule")),h=F[g.getAttribute("data-requirecontext")])}(h?h.defQueue:S).push([b,c,d])};define.amd={jQuery:!0};h.exec=function(b){return eval(b)};h(r)}})(this);

View file

@ -1,138 +0,0 @@
/*
* classList.js: Cross-browser full element.classList implementation.
* 2011-06-15
*
* By Eli Grey, http://eligrey.com
* Public Domain.
* NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
*/
/*global self, document, DOMException */
/*! @source http://purl.eligrey.com/github/classList.js/blob/master/classList.js*/
if (typeof document !== "undefined" && !("classList" in document.createElement("a"))) {
(function (view) {
"use strict";
var
classListProp = "classList"
, protoProp = "prototype"
, elemCtrProto = (view.HTMLElement || view.Element)[protoProp]
, objCtr = Object
, strTrim = String[protoProp].trim || function () {
return this.replace(/^\s+|\s+$/g, "");
}
, arrIndexOf = Array[protoProp].indexOf || function (item) {
var
i = 0
, len = this.length
;
for (; i < len; i++) {
if (i in this && this[i] === item) {
return i;
}
}
return -1;
}
// Vendors: please allow content code to instantiate DOMExceptions
, DOMEx = function (type, message) {
this.name = type;
this.code = DOMException[type];
this.message = message;
}
, checkTokenAndGetIndex = function (classList, token) {
if (token === "") {
throw new DOMEx(
"SYNTAX_ERR"
, "An invalid or illegal string was specified"
);
}
if (/\s/.test(token)) {
throw new DOMEx(
"INVALID_CHARACTER_ERR"
, "String contains an invalid character"
);
}
return arrIndexOf.call(classList, token);
}
, ClassList = function (elem) {
var
trimmedClasses = strTrim.call(elem.className)
, classes = trimmedClasses ? trimmedClasses.split(/\s+/) : []
, i = 0
, len = classes.length
;
for (; i < len; i++) {
this.push(classes[i]);
}
this._updateClassName = function () {
elem.className = this.toString();
};
}
, classListProto = ClassList[protoProp] = []
, classListGetter = function () {
return new ClassList(this);
}
;
// Most DOMException implementations don't allow calling DOMException's toString()
// on non-DOMExceptions. Error's toString() is sufficient here.
DOMEx[protoProp] = Error[protoProp];
classListProto.item = function (i) {
return this[i] || null;
};
classListProto.contains = function (token) {
token += "";
return checkTokenAndGetIndex(this, token) !== -1;
};
classListProto.add = function (token) {
token += "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.push(token);
this._updateClassName();
}
};
classListProto.remove = function (token) {
token += "";
var index = checkTokenAndGetIndex(this, token);
if (index !== -1) {
this.splice(index, 1);
this._updateClassName();
}
};
classListProto.toggle = function (token) {
token += "";
if (checkTokenAndGetIndex(this, token) === -1) {
this.add(token);
} else {
this.remove(token);
}
};
classListProto.toString = function () {
return this.join(" ");
};
if (objCtr.defineProperty) {
var classListPropDesc = {
get: classListGetter
, enumerable: true
, configurable: true
};
try {
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
} catch (ex) { // IE 8 doesn't support enumerable:true
if (ex.number === -0x7FF5EC54) {
classListPropDesc.enumerable = false;
objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
}
}
} else if (objCtr[protoProp].__defineGetter__) {
elemCtrProto.__defineGetter__(classListProp, classListGetter);
}
}(self));
}

View file

@ -1,23 +0,0 @@
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}

View file

@ -1,13 +0,0 @@
// adds requestAnimationFrame functionality
// Source: http://strd6.com/2011/05/better-window-requestanimationframe-shim/
window.requestAnimationFrame || (window.requestAnimationFrame =
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, element) {
return window.setTimeout(function() {
callback(+new Date());
}, 1000 / 60);
});

View file

@ -1,723 +0,0 @@
/* global Metamaps, Backbone, _, $ */
/*
* Metamaps.Backbone.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Collaborators
* - Metamaps.Creators
* - Metamaps.Filter
* - Metamaps.JIT
* - Metamaps.Loading
* - Metamaps.Map
* - Metamaps.Mapper
* - Metamaps.Mappers
* - Metamaps.Mappings
* - Metamaps.Metacodes
* - Metamaps.Realtime
* - Metamaps.Synapse
* - Metamaps.SynapseCard
* - Metamaps.Synapses
* - Metamaps.Topic
* - Metamaps.TopicCard
* - Metamaps.Topics
* - Metamaps.Visualize
*/
Metamaps.Backbone = {}
Metamaps.Backbone.Map = Backbone.Model.extend({
urlRoot: '/maps',
blacklist: ['created_at', 'updated_at', 'created_at_clean', 'updated_at_clean', 'user_name', 'contributor_count', 'topic_count', 'synapse_count', 'topics', 'synapses', 'mappings', 'mappers'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
save: function (key, val, options) {
var attrs
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key
options = val
} else {
(attrs = {})[key] = val
}
var newOptions = options || {}
var s = newOptions.success
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt)
model.trigger('saved')
}
return Backbone.Model.prototype.save.call(this, attrs, newOptions)
},
initialize: function () {
this.on('changeByOther', this.updateView)
this.on('saved', this.savedEvent)
},
savedEvent: function () {
Metamaps.Realtime.sendMapChange(this)
},
authorizeToEdit: function (mapper) {
if (mapper && (
this.get('permission') === 'commons' ||
this.get('collaborator_ids').includes(mapper.get('id')) ||
this.get('user_id') === mapper.get('id'))) {
return true
} else {
return false
}
},
authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) {
return true
} else {
return false
}
},
getUser: function () {
return Metamaps.Mapper.get(this.get('user_id'))
},
fetchContained: function () {
var bb = Metamaps.Backbone
var that = this
var start = function (data) {
that.set('mappers', new bb.MapperCollection(data.mappers))
that.set('topics', new bb.TopicCollection(data.topics))
that.set('synapses', new bb.SynapseCollection(data.synapses))
that.set('mappings', new bb.MappingCollection(data.mappings))
}
$.ajax({
url: '/maps/' + this.id + '/contains.json',
success: start,
error: errorFunc,
async: false
})
},
getTopics: function () {
if (!this.get('topics')) {
this.fetchContained()
}
return this.get('topics')
},
getSynapses: function () {
if (!this.get('synapses')) {
this.fetchContained()
}
return this.get('synapses')
},
getMappings: function () {
if (!this.get('mappings')) {
this.fetchContained()
}
return this.get('mappings')
},
getMappers: function () {
if (!this.get('mappers')) {
this.fetchContained()
}
return this.get('mappers')
},
attrForCards: function () {
function capitalize (string) {
return string.charAt(0).toUpperCase() + string.slice(1)
}
var n = this.get('name')
var d = this.get('desc')
var maxNameLength = 32
var maxDescLength = 118
var truncatedName = n ? (n.length > maxNameLength ? n.substring(0, maxNameLength) + '...' : n) : ''
var truncatedDesc = d ? (d.length > maxDescLength ? d.substring(0, maxDescLength) + '...' : d) : ''
var obj = {
id: this.id,
name: truncatedName,
fullName: n,
desc: truncatedDesc,
permission: this.get('permission') ? capitalize(this.get('permission')) : 'Commons',
editPermission: this.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEdit' : 'cannotEdit',
contributor_count_number: '<span class="cCountColor">' + this.get('contributor_count') + '</span>',
contributor_count_string: this.get('contributor_count') === 1 ? ' contributor' : ' contributors',
topic_count_number: '<span class="tCountColor">' + this.get('topic_count') + '</span>',
topic_count_string: this.get('topic_count') === 1 ? ' topic' : ' topics',
synapse_count_number: '<span class="sCountColor">' + this.get('synapse_count') + '</span>',
synapse_count_string: this.get('synapse_count') === 1 ? ' synapse' : ' synapses',
screenshot: '<img src="' + this.get('screenshot_url') + '" />'
}
return obj
},
updateView: function () {
var map = Metamaps.Active.Map
var isActiveMap = this.id === map.id
if (isActiveMap) {
Metamaps.Map.InfoBox.updateNameDescPerm(this.get('name'), this.get('desc'), this.get('permission'))
this.updateMapWrapper()
}
},
updateMapWrapper: function () {
var map = Metamaps.Active.Map
var isActiveMap = this.id === map.id
var authorized = map && map.authorizeToEdit(Metamaps.Active.Mapper) ? 'canEditMap' : ''
var commonsMap = map && map.get('permission') === 'commons' ? 'commonsMap' : ''
if (isActiveMap) {
$('.wrapper').removeClass('canEditMap commonsMap').addClass(authorized + ' ' + commonsMap)
}
}
})
Metamaps.Backbone.MapsCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Map,
initialize: function (models, options) {
this.id = options.id
this.sortBy = options.sortBy
if (options.mapperId) {
this.mapperId = options.mapperId
}
// this.page represents the NEXT page to fetch
this.page = models.length > 0 ? (models.length < 20 ? 'loadedAll' : 2) : 1
},
url: function () {
if (!this.mapperId) {
return '/explore/' + this.id + '.json'
} else {
return '/explore/mapper/' + this.mapperId + '.json'
}
},
comparator: function (a, b) {
a = a.get(this.sortBy)
b = b.get(this.sortBy)
var temp
if (this.sortBy === 'name') {
a = a ? a.toLowerCase() : ''
b = b ? b.toLowerCase() : ''
} else {
// this is for updated_at and created_at
temp = a
a = b
b = temp
a = (new Date(a)).getTime()
b = (new Date(b)).getTime()
}
return a > b ? 1 : a < b ? -1 : 0
},
getMaps: function (cb) {
var self = this
Metamaps.Loading.show()
if (this.page !== 'loadedAll') {
var numBefore = this.length
this.fetch({
remove: false,
silent: true,
data: { page: this.page },
success: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
if (collection.length - numBefore < 20) {
self.page = 'loadedAll'
} else {
self.page += 1
}
self.trigger('successOnFetch', cb)
},
error: function (collection, response, options) {
// you can pass additional options to the event you trigger here as well
self.trigger('errorOnFetch')
}
})
} else {
self.trigger('successOnFetch', cb)
}
}
})
Metamaps.Backbone.Message = Backbone.Model.extend({
urlRoot: '/messages',
blacklist: ['created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
prepareLiForFilter: function () {
/* var li = ''
* li += '<li data-id="' + this.id.toString() + '">'
* li += '<img src="' + this.get("image") + '" data-id="' + this.id.toString() + '"'
* li += ' alt="' + this.get('name') + '" />'
* li += '<p>' + this.get('name') + '</p></li>'
* return li
*/
}
})
Metamaps.Backbone.MessageCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Message,
url: '/messages'
})
Metamaps.Backbone.Mapper = Backbone.Model.extend({
urlRoot: '/users',
blacklist: ['created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
prepareLiForFilter: function () {
var li = ''
li += '<li data-id="' + this.id.toString() + '">'
li += '<img src="' + this.get('image') + '" data-id="' + this.id.toString() + '"'
li += ' alt="' + this.get('name') + '" />'
li += '<p>' + this.get('name') + '</p></li>'
return li
}
})
Metamaps.Backbone.MapperCollection = Backbone.Collection.extend({
model: Metamaps.Backbone.Mapper,
url: '/users'
})
Metamaps.Backbone.init = function () {
var self = Metamaps.Backbone
self.Metacode = Backbone.Model.extend({
initialize: function () {
var image = new Image()
image.crossOrigin = 'Anonymous'
image.src = this.get('icon')
this.set('image', image)
},
prepareLiForFilter: function () {
var li = ''
li += '<li data-id="' + this.id.toString() + '">'
li += '<img src="' + this.get('icon') + '" data-id="' + this.id.toString() + '"'
li += ' alt="' + this.get('name') + '" />'
li += '<p>' + this.get('name').toLowerCase() + '</p></li>'
return li
}
})
self.MetacodeCollection = Backbone.Collection.extend({
model: this.Metacode,
url: '/metacodes',
comparator: function (a, b) {
a = a.get('name').toLowerCase()
b = b.get('name').toLowerCase()
return a > b ? 1 : a < b ? -1 : 0
}
})
self.Topic = Backbone.Model.extend({
urlRoot: '/topics',
blacklist: ['node', 'created_at', 'updated_at', 'user_name', 'user_image', 'map_count', 'synapse_count'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
save: function (key, val, options) {
var attrs
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key
options = val
} else {
(attrs = {})[key] = val
}
var newOptions = options || {}
var s = newOptions.success
var permBefore = this.get('permission')
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt)
model.trigger('saved')
if (permBefore === 'private' && model.get('permission') !== 'private') {
model.trigger('noLongerPrivate')
}
else if (permBefore !== 'private' && model.get('permission') === 'private') {
model.trigger('nowPrivate')
}
}
return Backbone.Model.prototype.save.call(this, attrs, newOptions)
},
initialize: function () {
if (this.isNew()) {
this.set({
'user_id': Metamaps.Active.Mapper.id,
'desc': '',
'link': '',
'permission': Metamaps.Active.Map ? Metamaps.Active.Map.get('permission') : 'commons'
})
}
this.on('changeByOther', this.updateCardView)
this.on('change', this.updateNodeView)
this.on('saved', this.savedEvent)
this.on('nowPrivate', function () {
var removeTopicData = {
mappableid: this.id
}
$(document).trigger(Metamaps.JIT.events.removeTopic, [removeTopicData])
})
this.on('noLongerPrivate', function () {
var newTopicData = {
mappingid: this.getMapping().id,
mappableid: this.id
}
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData])
})
this.on('change:metacode_id', Metamaps.Filter.checkMetacodes, this)
},
authorizeToEdit: function (mapper) {
if (mapper &&
(this.get('calculated_permission') === 'commons' ||
this.get('collaborator_ids').includes(mapper.get('id')) ||
this.get('user_id') === mapper.get('id'))) {
return true
} else {
return false
}
},
authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) return true
else return false
},
getDate: function () {},
getMetacode: function () {
return Metamaps.Metacodes.get(this.get('metacode_id'))
},
getMapping: function () {
if (!Metamaps.Active.Map) return false
return Metamaps.Mappings.findWhere({
map_id: Metamaps.Active.Map.id,
mappable_type: 'Topic',
mappable_id: this.isNew() ? this.cid : this.id
})
},
createNode: function () {
var mapping
var node = {
adjacencies: [],
id: this.isNew() ? this.cid : this.id,
name: this.get('name')
}
if (Metamaps.Active.Map) {
mapping = this.getMapping()
node.data = {
$mapping: null,
$mappingID: mapping.id
}
}
return node
},
updateNode: function () {
var mapping
var node = this.get('node')
node.setData('topic', this)
if (Metamaps.Active.Map) {
mapping = this.getMapping()
node.setData('mapping', mapping)
}
return node
},
savedEvent: function () {
Metamaps.Realtime.sendTopicChange(this)
},
updateViews: function () {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
var node = this.get('node')
// update topic card, if this topic is the one open there
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
Metamaps.TopicCard.showCard(node)
}
// update the node on the map
if (onPageWithTopicCard && node) {
node.name = this.get('name')
Metamaps.Visualize.mGraph.plot()
}
},
updateCardView: function () {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
var node = this.get('node')
// update topic card, if this topic is the one open there
if (onPageWithTopicCard && this == Metamaps.TopicCard.openTopicCard) {
Metamaps.TopicCard.showCard(node)
}
},
updateNodeView: function () {
var onPageWithTopicCard = Metamaps.Active.Map || Metamaps.Active.Topic
var node = this.get('node')
// update the node on the map
if (onPageWithTopicCard && node) {
node.name = this.get('name')
Metamaps.Visualize.mGraph.plot()
}
}
})
self.TopicCollection = Backbone.Collection.extend({
model: self.Topic,
url: '/topics'
})
self.Synapse = Backbone.Model.extend({
urlRoot: '/synapses',
blacklist: ['edge', 'created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
save: function (key, val, options) {
var attrs
// Handle both `"key", value` and `{key: value}` -style arguments.
if (key == null || typeof key === 'object') {
attrs = key
options = val
} else {
(attrs = {})[key] = val
}
var newOptions = options || {}
var s = newOptions.success
var permBefore = this.get('permission')
newOptions.success = function (model, response, opt) {
if (s) s(model, response, opt)
model.trigger('saved')
if (permBefore === 'private' && model.get('permission') !== 'private') {
model.trigger('noLongerPrivate')
}
else if (permBefore !== 'private' && model.get('permission') === 'private') {
model.trigger('nowPrivate')
}
}
return Backbone.Model.prototype.save.call(this, attrs, newOptions)
},
initialize: function () {
if (this.isNew()) {
this.set({
'user_id': Metamaps.Active.Mapper.id,
'permission': Metamaps.Active.Map ? Metamaps.Active.Map.get('permission') : 'commons',
'category': 'from-to'
})
}
this.on('changeByOther', this.updateCardView)
this.on('change', this.updateEdgeView)
this.on('saved', this.savedEvent)
this.on('noLongerPrivate', function () {
var newSynapseData = {
mappingid: this.getMapping().id,
mappableid: this.id
}
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData])
})
this.on('nowPrivate', function () {
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
mappableid: this.id
}])
})
this.on('change:desc', Metamaps.Filter.checkSynapses, this)
},
prepareLiForFilter: function () {
var li = ''
li += '<li data-id="' + this.get('desc') + '">'
li += '<img src="' + Metamaps.Erb['synapse16.png'] + '"'
li += ' alt="synapse icon" />'
li += '<p>' + this.get('desc') + '</p></li>'
return li
},
authorizeToEdit: function (mapper) {
if (mapper && (this.get('calculated_permission') === 'commons' || this.get('collaborator_ids').includes(mapper.get('id')) || this.get('user_id') === mapper.get('id'))) return true
else return false
},
authorizePermissionChange: function (mapper) {
if (mapper && this.get('user_id') === mapper.get('id')) return true
else return false
},
getTopic1: function () {
return Metamaps.Topics.get(this.get('node1_id'))
},
getTopic2: function () {
return Metamaps.Topics.get(this.get('node2_id'))
},
getDirection: function () {
var t1 = this.getTopic1(),
t2 = this.getTopic2()
return t1 && t2 ? [
t1.get('node').id,
t2.get('node').id
] : false
},
getMapping: function () {
if (!Metamaps.Active.Map) return false
return Metamaps.Mappings.findWhere({
map_id: Metamaps.Active.Map.id,
mappable_type: 'Synapse',
mappable_id: this.isNew() ? this.cid : this.id
})
},
createEdge: function (providedMapping) {
var mapping, mappingID
var synapseID = this.isNew() ? this.cid : this.id
var edge = {
nodeFrom: this.get('node1_id'),
nodeTo: this.get('node2_id'),
data: {
$synapses: [],
$synapseIDs: [synapseID],
}
}
if (Metamaps.Active.Map) {
mapping = providedMapping || this.getMapping()
mappingID = mapping.isNew() ? mapping.cid : mapping.id
edge.data.$mappings = []
edge.data.$mappingIDs = [mappingID]
}
return edge
},
updateEdge: function () {
var mapping
var edge = this.get('edge')
edge.getData('synapses').push(this)
if (Metamaps.Active.Map) {
mapping = this.getMapping()
edge.getData('mappings').push(mapping)
}
return edge
},
savedEvent: function () {
Metamaps.Realtime.sendSynapseChange(this)
},
updateViews: function () {
this.updateCardView()
this.updateEdgeView()
},
updateCardView: function () {
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic
var edge = this.get('edge')
// update synapse card, if this synapse is the one open there
if (onPageWithSynapseCard && edge == Metamaps.SynapseCard.openSynapseCard) {
Metamaps.SynapseCard.showCard(edge)
}
},
updateEdgeView: function () {
var onPageWithSynapseCard = Metamaps.Active.Map || Metamaps.Active.Topic
var edge = this.get('edge')
// update the edge on the map
if (onPageWithSynapseCard && edge) {
Metamaps.Visualize.mGraph.plot()
}
}
})
self.SynapseCollection = Backbone.Collection.extend({
model: self.Synapse,
url: '/synapses'
})
self.Mapping = Backbone.Model.extend({
urlRoot: '/mappings',
blacklist: ['created_at', 'updated_at'],
toJSON: function (options) {
return _.omit(this.attributes, this.blacklist)
},
initialize: function () {
if (this.isNew()) {
this.set({
'user_id': Metamaps.Active.Mapper.id,
'map_id': Metamaps.Active.Map ? Metamaps.Active.Map.id : null
})
}
},
getMap: function () {
return Metamaps.Map.get(this.get('map_id'))
},
getTopic: function () {
if (this.get('mappable_type') === 'Topic') return Metamaps.Topic.get(this.get('mappable_id'))
else return false
},
getSynapse: function () {
if (this.get('mappable_type') === 'Synapse') return Metamaps.Synapse.get(this.get('mappable_id'))
else return false
}
})
self.MappingCollection = Backbone.Collection.extend({
model: self.Mapping,
url: '/mappings'
})
Metamaps.Metacodes = Metamaps.Metacodes ? new self.MetacodeCollection(Metamaps.Metacodes) : new self.MetacodeCollection()
Metamaps.Topics = Metamaps.Topics ? new self.TopicCollection(Metamaps.Topics) : new self.TopicCollection()
Metamaps.Synapses = Metamaps.Synapses ? new self.SynapseCollection(Metamaps.Synapses) : new self.SynapseCollection()
Metamaps.Mappers = Metamaps.Mappers ? new self.MapperCollection(Metamaps.Mappers) : new self.MapperCollection()
Metamaps.Collaborators = Metamaps.Collaborators ? new self.MapperCollection(Metamaps.Collaborators) : new self.MapperCollection()
// this is for topic view
Metamaps.Creators = Metamaps.Creators ? new self.MapperCollection(Metamaps.Creators) : new self.MapperCollection()
if (Metamaps.Active.Map) {
Metamaps.Mappings = Metamaps.Mappings ? new self.MappingCollection(Metamaps.Mappings) : new self.MappingCollection()
Metamaps.Active.Map = new self.Map(Metamaps.Active.Map)
}
if (Metamaps.Active.Topic) Metamaps.Active.Topic = new self.Topic(Metamaps.Active.Topic)
// attach collection event listeners
self.attachCollectionEvents = function () {
Metamaps.Topics.on('add remove', function (topic) {
Metamaps.Map.InfoBox.updateNumbers()
Metamaps.Filter.checkMetacodes()
Metamaps.Filter.checkMappers()
})
Metamaps.Synapses.on('add remove', function (synapse) {
Metamaps.Map.InfoBox.updateNumbers()
Metamaps.Filter.checkSynapses()
Metamaps.Filter.checkMappers()
})
if (Metamaps.Active.Map) {
Metamaps.Mappings.on('add remove', function (mapping) {
Metamaps.Map.InfoBox.updateNumbers()
Metamaps.Filter.checkSynapses()
Metamaps.Filter.checkMetacodes()
Metamaps.Filter.checkMappers()
})
}
}
self.attachCollectionEvents()
}; // end Metamaps.Backbone.init

View file

@ -1,437 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Control.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Control
* - Metamaps.Filter
* - Metamaps.GlobalUI
* - Metamaps.JIT
* - Metamaps.Mappings
* - Metamaps.Metacodes
* - Metamaps.Mouse
* - Metamaps.Selected
* - Metamaps.Settings
* - Metamaps.Synapses
* - Metamaps.Topics
* - Metamaps.Visualize
*/
Metamaps.Control = {
init: function () {},
selectNode: function (node, e) {
var filtered = node.getData('alpha') === 0
if (filtered || Metamaps.Selected.Nodes.indexOf(node) != -1) return
node.selected = true
node.setData('dim', 30, 'current')
Metamaps.Selected.Nodes.push(node)
},
deselectAllNodes: function () {
var l = Metamaps.Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Metamaps.Selected.Nodes[i]
Metamaps.Control.deselectNode(node)
}
Metamaps.Visualize.mGraph.plot()
},
deselectNode: function (node) {
delete node.selected
node.setData('dim', 25, 'current')
// remove the node
Metamaps.Selected.Nodes.splice(
Metamaps.Selected.Nodes.indexOf(node), 1)
},
deleteSelected: function () {
if (!Metamaps.Active.Map) return
var n = Metamaps.Selected.Nodes.length
var e = Metamaps.Selected.Edges.length
var ntext = n == 1 ? '1 topic' : n + ' topics'
var etext = e == 1 ? '1 synapse' : e + ' synapses'
var text = 'You have ' + ntext + ' and ' + etext + ' selected. '
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var r = confirm(text + 'Are you sure you want to permanently delete them all? This will remove them from all maps they appear on.')
if (r == true) {
Metamaps.Control.deleteSelectedEdges()
Metamaps.Control.deleteSelectedNodes()
}
},
deleteSelectedNodes: function () { // refers to deleting topics permanently
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var l = Metamaps.Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
var node = Metamaps.Selected.Nodes[i]
Metamaps.Control.deleteNode(node.id)
}
},
deleteNode: function (nodeid) { // refers to deleting topics permanently
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
var topic = node.getData('topic')
var permToDelete = Metamaps.Active.Mapper.id === topic.get('user_id') || Metamaps.Active.Mapper.get('admin')
if (permToDelete) {
var mappableid = topic.id
var mapping = node.getData('mapping')
topic.destroy()
Metamaps.Mappings.remove(mapping)
$(document).trigger(Metamaps.JIT.events.deleteTopic, [{
mappableid: mappableid
}])
Metamaps.Control.hideNode(nodeid)
} else {
Metamaps.GlobalUI.notifyUser('Only topics you created can be deleted')
}
},
removeSelectedNodes: function () { // refers to removing topics permanently from a map
if (!Metamaps.Active.Map) return
var l = Metamaps.Selected.Nodes.length,
i,
node,
authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
for (i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i]
Metamaps.Control.removeNode(node.id)
}
},
removeNode: function (nodeid) { // refers to removing topics permanently from a map
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var topic = node.getData('topic')
var mappableid = topic.id
var mapping = node.getData('mapping')
mapping.destroy()
Metamaps.Topics.remove(topic)
$(document).trigger(Metamaps.JIT.events.removeTopic, [{
mappableid: mappableid
}])
Metamaps.Control.hideNode(nodeid)
},
hideSelectedNodes: function () {
var l = Metamaps.Selected.Nodes.length,
i,
node
for (i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i]
Metamaps.Control.hideNode(node.id)
}
},
hideNode: function (nodeid) {
var node = Metamaps.Visualize.mGraph.graph.getNode(nodeid)
var graph = Metamaps.Visualize.mGraph
Metamaps.Control.deselectNode(node)
node.setData('alpha', 0, 'end')
node.eachAdjacency(function (adj) {
adj.setData('alpha', 0, 'end')
})
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'
],
duration: 500
})
setTimeout(function () {
if (nodeid == Metamaps.Visualize.mGraph.root) { // && Metamaps.Visualize.type === "RGraph"
var newroot = _.find(graph.graph.nodes, function (n) { return n.id !== nodeid; })
graph.root = newroot ? newroot.id : null
}
Metamaps.Visualize.mGraph.graph.removeNode(nodeid)
}, 500)
Metamaps.Filter.checkMetacodes()
Metamaps.Filter.checkMappers()
},
selectEdge: function (edge) {
var filtered = edge.getData('alpha') === 0; // don't select if the edge is filtered
if (filtered || Metamaps.Selected.Edges.indexOf(edge) != -1) return
var width = Metamaps.Mouse.edgeHoveringOver === edge ? 4 : 2
edge.setDataset('current', {
showDesc: true,
lineWidth: width,
color: Metamaps.Settings.colors.synapses.selected
})
Metamaps.Visualize.mGraph.plot()
Metamaps.Selected.Edges.push(edge)
},
deselectAllEdges: function () {
var l = Metamaps.Selected.Edges.length
for (var i = l - 1; i >= 0; i -= 1) {
var edge = Metamaps.Selected.Edges[i]
Metamaps.Control.deselectEdge(edge)
}
Metamaps.Visualize.mGraph.plot()
},
deselectEdge: function (edge) {
edge.setData('showDesc', false, 'current')
edge.setDataset('current', {
lineWidth: 2,
color: Metamaps.Settings.colors.synapses.normal
})
if (Metamaps.Mouse.edgeHoveringOver == edge) {
edge.setDataset('current', {
showDesc: true,
lineWidth: 4
})
}
Metamaps.Visualize.mGraph.plot()
// remove the edge
Metamaps.Selected.Edges.splice(
Metamaps.Selected.Edges.indexOf(edge), 1)
},
deleteSelectedEdges: function () { // refers to deleting topics permanently
var edge,
l = Metamaps.Selected.Edges.length
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
for (var i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i]
Metamaps.Control.deleteEdge(edge)
}
},
deleteEdge: function (edge) {
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
var permToDelete = Metamaps.Active.Mapper.id === synapse.get('user_id') || Metamaps.Active.Mapper.get('admin')
if (permToDelete) {
if (edge.getData('synapses').length - 1 === 0) {
Metamaps.Control.hideEdge(edge)
}
var mappableid = synapse.id
synapse.destroy()
// the server will destroy the mapping, we just need to remove it here
Metamaps.Mappings.remove(mapping)
edge.getData('mappings').splice(index, 1)
edge.getData('synapses').splice(index, 1)
if (edge.getData('displayIndex')) {
delete edge.data.$displayIndex
}
$(document).trigger(Metamaps.JIT.events.deleteSynapse, [{
mappableid: mappableid
}])
} else {
Metamaps.GlobalUI.notifyUser('Only synapses you created can be deleted')
}
},
removeSelectedEdges: function () {
var l = Metamaps.Selected.Edges.length,
i,
edge
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
for (i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i]
Metamaps.Control.removeEdge(edge)
}
Metamaps.Selected.Edges = [ ]
},
removeEdge: function (edge) {
if (!Metamaps.Active.Map) return
var authorized = Metamaps.Active.Map.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
Metamaps.GlobalUI.notifyUser('Cannot edit Public map.')
return
}
if (edge.getData('mappings').length - 1 === 0) {
Metamaps.Control.hideEdge(edge)
}
var index = edge.getData('displayIndex') ? edge.getData('displayIndex') : 0
var synapse = edge.getData('synapses')[index]
var mapping = edge.getData('mappings')[index]
var mappableid = synapse.id
mapping.destroy()
Metamaps.Synapses.remove(synapse)
edge.getData('mappings').splice(index, 1)
edge.getData('synapses').splice(index, 1)
if (edge.getData('displayIndex')) {
delete edge.data.$displayIndex
}
$(document).trigger(Metamaps.JIT.events.removeSynapse, [{
mappableid: mappableid
}])
},
hideSelectedEdges: function () {
var edge,
l = Metamaps.Selected.Edges.length,
i
for (i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i]
Metamaps.Control.hideEdge(edge)
}
Metamaps.Selected.Edges = [ ]
},
hideEdge: function (edge) {
var from = edge.nodeFrom.id
var to = edge.nodeTo.id
edge.setData('alpha', 0, 'end')
Metamaps.Control.deselectEdge(edge)
Metamaps.Visualize.mGraph.fx.animate({
modes: ['edge-property:alpha'],
duration: 500
})
setTimeout(function () {
Metamaps.Visualize.mGraph.graph.removeAdjacence(from, to)
}, 500)
Metamaps.Filter.checkSynapses()
Metamaps.Filter.checkMappers()
},
updateSelectedPermissions: function (permission) {
var edge, synapse, node, topic
Metamaps.GlobalUI.notifyUser('Working...')
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0,
sCount = 0
// change the permission of the selected synapses, if logged in user is the original creator
var l = Metamaps.Selected.Edges.length
for (var i = l - 1; i >= 0; i -= 1) {
edge = Metamaps.Selected.Edges[i]
synapse = edge.getData('synapses')[0]
if (synapse.authorizePermissionChange(Metamaps.Active.Mapper)) {
synapse.save({
permission: permission
})
sCount++
}
}
// change the permission of the selected topics, if logged in user is the original creator
var l = Metamaps.Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i]
topic = node.getData('topic')
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
topic.save({
permission: permission
})
nCount++
}
}
var nString = nCount == 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and ')
var sString = sCount == 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses')
var message = nString + sString + ' you created updated to ' + permission
Metamaps.GlobalUI.notifyUser(message)
},
updateSelectedMetacodes: function (metacode_id) {
var node, topic
Metamaps.GlobalUI.notifyUser('Working...')
var metacode = Metamaps.Metacodes.get(metacode_id)
// variables to keep track of how many nodes and synapses you had the ability to change the permission of
var nCount = 0
// change the permission of the selected topics, if logged in user is the original creator
var l = Metamaps.Selected.Nodes.length
for (var i = l - 1; i >= 0; i -= 1) {
node = Metamaps.Selected.Nodes[i]
topic = node.getData('topic')
if (topic.authorizeToEdit(Metamaps.Active.Mapper)) {
topic.save({
'metacode_id': metacode_id
})
nCount++
}
}
var nString = nCount == 1 ? (nCount.toString() + ' topic') : (nCount.toString() + ' topics')
var message = nString + ' you can edit updated to ' + metacode.get('name')
Metamaps.GlobalUI.notifyUser(message)
Metamaps.Visualize.mGraph.plot()
},
}; // end Metamaps.Control

View file

@ -1,326 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Create.js
*
* Dependencies:
* - Metamaps.Backbone
* - Metamaps.GlobalUI
* - Metamaps.Metacodes
* - Metamaps.Mouse
* - Metamaps.Selected
* - Metamaps.Synapse
* - Metamaps.Topic
* - Metamaps.Visualize
*/
Metamaps.Create = {
isSwitchingSet: false, // indicates whether the metacode set switch lightbox is open
selectedMetacodeSet: null,
selectedMetacodeSetIndex: null,
selectedMetacodeNames: [],
newSelectedMetacodeNames: [],
selectedMetacodes: [],
newSelectedMetacodes: [],
init: function () {
var self = Metamaps.Create
self.newTopic.init()
self.newSynapse.init()
// // SWITCHING METACODE SETS
$('#metacodeSwitchTabs').tabs({
selected: self.selectedMetacodeSetIndex
}).addClass('ui-tabs-vertical ui-helper-clearfix')
$('#metacodeSwitchTabs .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left')
$('.customMetacodeList li').click(self.toggleMetacodeSelected) // within the custom metacode set tab
},
toggleMetacodeSelected: function () {
var self = Metamaps.Create
if ($(this).attr('class') != 'toggledOff') {
$(this).addClass('toggledOff')
var value_to_remove = $(this).attr('id')
var name_to_remove = $(this).attr('data-name')
self.newSelectedMetacodes.splice(self.newSelectedMetacodes.indexOf(value_to_remove), 1)
self.newSelectedMetacodeNames.splice(self.newSelectedMetacodeNames.indexOf(name_to_remove), 1)
} else if ($(this).attr('class') == 'toggledOff') {
$(this).removeClass('toggledOff')
self.newSelectedMetacodes.push($(this).attr('id'))
self.newSelectedMetacodeNames.push($(this).attr('data-name'))
}
},
updateMetacodeSet: function (set, index, custom) {
if (custom && Metamaps.Create.newSelectedMetacodes.length == 0) {
alert('Please select at least one metacode to use!')
return false
}
var codesToSwitchToIds
var metacodeModels = new Metamaps.Backbone.MetacodeCollection()
Metamaps.Create.selectedMetacodeSetIndex = index
Metamaps.Create.selectedMetacodeSet = 'metacodeset-' + set
if (!custom) {
codesToSwitchToIds = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(',')
$('.customMetacodeList li').addClass('toggledOff')
Metamaps.Create.selectedMetacodes = []
Metamaps.Create.selectedMetacodeNames = []
Metamaps.Create.newSelectedMetacodes = []
Metamaps.Create.newSelectedMetacodeNames = []
}
else if (custom) {
// uses .slice to avoid setting the two arrays to the same actual array
Metamaps.Create.selectedMetacodes = Metamaps.Create.newSelectedMetacodes.slice(0)
Metamaps.Create.selectedMetacodeNames = Metamaps.Create.newSelectedMetacodeNames.slice(0)
codesToSwitchToIds = Metamaps.Create.selectedMetacodes.slice(0)
}
// sort by name
for (var i = 0; i < codesToSwitchToIds.length; i++) {
metacodeModels.add(Metamaps.Metacodes.get(codesToSwitchToIds[i]))
}
metacodeModels.sort()
$('#metacodeImg, #metacodeImgTitle').empty()
$('#metacodeImg').removeData('cloudcarousel')
var newMetacodes = ''
metacodeModels.each(function (metacode) {
newMetacodes += '<img class="cloudcarousel" width="40" height="40" src="' + metacode.get('icon') + '" data-id="' + metacode.id + '" title="' + metacode.get('name') + '" alt="' + metacode.get('name') + '"/>'
})
$('#metacodeImg').empty().append(newMetacodes).CloudCarousel({
titleBox: $('#metacodeImgTitle'),
yRadius: 40,
xRadius: 190,
xPos: 170,
yPos: 40,
speed: 0.3,
mouseWheel: true,
bringToFront: true
})
Metamaps.GlobalUI.closeLightbox()
$('#topic_name').focus()
var mdata = {
'metacodes': {
'value': custom ? Metamaps.Create.selectedMetacodes.toString() : Metamaps.Create.selectedMetacodeSet
}
}
$.ajax({
type: 'POST',
dataType: 'json',
url: '/user/updatemetacodes',
data: mdata,
success: function (data) {
console.log('selected metacodes saved')
},
error: function () {
console.log('failed to save selected metacodes')
}
})
},
cancelMetacodeSetSwitch: function () {
var self = Metamaps.Create
self.isSwitchingSet = false
if (self.selectedMetacodeSet != 'metacodeset-custom') {
$('.customMetacodeList li').addClass('toggledOff')
self.selectedMetacodes = []
self.selectedMetacodeNames = []
self.newSelectedMetacodes = []
self.newSelectedMetacodeNames = []
} else { // custom set is selected
// reset it to the current actual selection
$('.customMetacodeList li').addClass('toggledOff')
for (var i = 0; i < self.selectedMetacodes.length; i++) {
$('#' + self.selectedMetacodes[i]).removeClass('toggledOff')
}
// uses .slice to avoid setting the two arrays to the same actual array
self.newSelectedMetacodeNames = self.selectedMetacodeNames.slice(0)
self.newSelectedMetacodes = self.selectedMetacodes.slice(0)
}
$('#metacodeSwitchTabs').tabs('option', 'active', self.selectedMetacodeSetIndex)
$('#topic_name').focus()
},
newTopic: {
init: function () {
$('#topic_name').keyup(function () {
Metamaps.Create.newTopic.name = $(this).val()
})
var topicBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/topics/autocomplete_topic?term=%QUERY',
wildcard: '%QUERY',
},
})
// initialize the autocomplete results for the metacode spinner
$('#topic_name').typeahead(
{
highlight: true,
minLength: 2,
},
[{
name: 'topic_autocomplete',
limit: 8,
display: function (s) { return s.label; },
templates: {
suggestion: function (s) {
return Hogan.compile($('#topicAutocompleteTemplate').html()).render(s)
},
},
source: topicBloodhound,
}]
)
// tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete
$('#topic_name').bind('typeahead:select', function (event, datum, dataset) {
Metamaps.Topic.getTopicFromAutocomplete(datum.id)
})
// initialize metacode spinner and then hide it
$('#metacodeImg').CloudCarousel({
titleBox: $('#metacodeImgTitle'),
yRadius: 40,
xRadius: 190,
xPos: 170,
yPos: 40,
speed: 0.3,
mouseWheel: true,
bringToFront: true
})
$('.new_topic').hide()
},
name: null,
newId: 1,
beingCreated: false,
metacode: null,
x: null,
y: null,
addSynapse: false,
open: function () {
$('#new_topic').fadeIn('fast', function () {
$('#topic_name').focus()
})
Metamaps.Create.newTopic.beingCreated = true
Metamaps.Create.newTopic.name = ''
},
hide: function () {
$('#new_topic').fadeOut('fast')
$('#topic_name').typeahead('val', '')
Metamaps.Create.newTopic.beingCreated = false
}
},
newSynapse: {
init: function () {
var self = Metamaps.Create.newSynapse
var synapseBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/synapses?term=%QUERY',
wildcard: '%QUERY',
},
})
var existingSynapseBloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/synapses?topic1id=%TOPIC1&topic2id=%TOPIC2',
prepare: function (query, settings) {
var self = Metamaps.Create.newSynapse
if (Metamaps.Selected.Nodes.length < 2) {
settings.url = settings.url.replace('%TOPIC1', self.topic1id).replace('%TOPIC2', self.topic2id)
return settings
} else {
return null
}
},
},
})
// initialize the autocomplete results for synapse creation
$('#synapse_desc').typeahead(
{
highlight: true,
minLength: 2,
},
[{
name: 'synapse_autocomplete',
display: function (s) { return s.label; },
templates: {
suggestion: function (s) {
return Hogan.compile("<div class='genericSynapseDesc'>{{label}}</div>").render(s)
},
},
source: synapseBloodhound,
},
{
name: 'existing_synapses',
limit: 50,
display: function (s) { return s.label; },
templates: {
suggestion: function (s) {
return Hogan.compile($('#synapseAutocompleteTemplate').html()).render(s)
},
header: '<h3>Existing synapses</h3>'
},
source: existingSynapseBloodhound,
}]
)
$('#synapse_desc').keyup(function (e) {
var ESC = 27, BACKSPACE = 8, DELETE = 46
if (e.keyCode === BACKSPACE && $(this).val() === '' ||
e.keyCode === DELETE && $(this).val() === '' ||
e.keyCode === ESC) {
Metamaps.Create.newSynapse.hide()
} // if
Metamaps.Create.newSynapse.description = $(this).val()
})
$('#synapse_desc').focusout(function () {
if (Metamaps.Create.newSynapse.beingCreated) {
Metamaps.Synapse.createSynapseLocally()
}
})
$('#synapse_desc').bind('typeahead:select', function (event, datum, dataset) {
if (datum.id) { // if they clicked on an existing synapse get it
Metamaps.Synapse.getSynapseFromAutocomplete(datum.id)
} else {
Metamaps.Create.newSynapse.description = datum.value
Metamaps.Synapse.createSynapseLocally()
}
})
},
beingCreated: false,
description: null,
topic1id: null,
topic2id: null,
newSynapseId: null,
open: function () {
$('#new_synapse').fadeIn(100, function () {
$('#synapse_desc').focus()
})
Metamaps.Create.newSynapse.beingCreated = true
},
hide: function () {
$('#new_synapse').fadeOut('fast')
$('#synapse_desc').typeahead('val', '')
Metamaps.Create.newSynapse.beingCreated = false
Metamaps.Create.newTopic.addSynapse = false
Metamaps.Create.newSynapse.topic1id = 0
Metamaps.Create.newSynapse.topic2id = 0
Metamaps.Mouse.synapseStartCoordinates = []
Metamaps.Visualize.mGraph.plot()
},
}
}; // end Metamaps.Create

View file

@ -1,13 +0,0 @@
/*
* Metamaps.Debug.js.erb
*
* Dependencies: none!
*/
Metamaps.Debug = function () {
console.debug(Metamaps)
console.debug(`Metamaps Version: ${Metamaps.VERSION}`)
}
Metamaps.debug = function () {
Metamaps.Debug()
}

View file

@ -1,466 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Filter.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Control
* - Metamaps.Creators
* - Metamaps.GlobalUI
* - Metamaps.Mappers
* - Metamaps.Metacodes
* - Metamaps.Settings
* - Metamaps.Synapses
* - Metamaps.Topics
* - Metamaps.Visualize
*/
Metamaps.Filter = {
filters: {
name: '',
metacodes: [],
mappers: [],
synapses: []
},
visible: {
metacodes: [],
mappers: [],
synapses: []
},
isOpen: false,
changing: false,
init: function () {
var self = Metamaps.Filter
$('.sidebarFilterIcon').click(self.toggleBox)
$('.sidebarFilterBox .showAllMetacodes').click(self.filterNoMetacodes)
$('.sidebarFilterBox .showAllSynapses').click(self.filterNoSynapses)
$('.sidebarFilterBox .showAllMappers').click(self.filterNoMappers)
$('.sidebarFilterBox .hideAllMetacodes').click(self.filterAllMetacodes)
$('.sidebarFilterBox .hideAllSynapses').click(self.filterAllSynapses)
$('.sidebarFilterBox .hideAllMappers').click(self.filterAllMappers)
self.bindLiClicks()
self.getFilterData()
},
toggleBox: function (event) {
var self = Metamaps.Filter
if (self.isOpen) self.close()
else self.open()
event.stopPropagation()
},
open: function () {
var self = Metamaps.Filter
Metamaps.GlobalUI.Account.close()
$('.sidebarFilterIcon div').addClass('hide')
if (!self.isOpen && !self.changing) {
self.changing = true
var height = $(document).height() - 108
$('.sidebarFilterBox').css('max-height', height + 'px').fadeIn(200, function () {
self.changing = false
self.isOpen = true
})
}
},
close: function () {
var self = Metamaps.Filter
$('.sidebarFilterIcon div').removeClass('hide')
if (!self.changing) {
self.changing = true
$('.sidebarFilterBox').fadeOut(200, function () {
self.changing = false
self.isOpen = false
})
}
},
reset: function () {
var self = Metamaps.Filter
self.filters.metacodes = []
self.filters.mappers = []
self.filters.synapses = []
self.visible.metacodes = []
self.visible.mappers = []
self.visible.synapses = []
$('#filter_by_metacode ul').empty()
$('#filter_by_mapper ul').empty()
$('#filter_by_synapse ul').empty()
$('.filterBox .showAll').addClass('active')
},
/*
Most of this data essentially depends on the ruby function which are happening for filter inside view filterBox
But what these function do is load this data into three accessible array within java : metacodes, mappers and synapses
*/
getFilterData: function () {
var self = Metamaps.Filter
var metacode, mapper, synapse
$('#filter_by_metacode li').each(function () {
metacode = $(this).attr('data-id')
self.filters.metacodes.push(metacode)
self.visible.metacodes.push(metacode)
})
$('#filter_by_mapper li').each(function () {
mapper = ($(this).attr('data-id'))
self.filters.mappers.push(mapper)
self.visible.mappers.push(mapper)
})
$('#filter_by_synapse li').each(function () {
synapse = ($(this).attr('data-id'))
self.filters.synapses.push(synapse)
self.visible.synapses.push(synapse)
})
},
bindLiClicks: function () {
var self = Metamaps.Filter
$('#filter_by_metacode ul li').unbind().click(self.toggleMetacode)
$('#filter_by_mapper ul li').unbind().click(self.toggleMapper)
$('#filter_by_synapse ul li').unbind().click(self.toggleSynapse)
},
// an abstraction function for checkMetacodes, checkMappers, checkSynapses to reduce
// code redundancy
/*
@param
*/
updateFilters: function (collection, propertyToCheck, correlatedModel, filtersToUse, listToModify) {
var self = Metamaps.Filter
var newList = []
var removed = []
var added = []
// the first option enables us to accept
// ['Topics', 'Synapses'] as 'collection'
if (typeof collection === 'object') {
Metamaps[collection[0]].each(function (model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
Metamaps[collection[1]].each(function (model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
} else if (typeof collection === 'string') {
Metamaps[collection].each(function (model) {
var prop = model.get(propertyToCheck)
if (prop !== null) {
prop = prop.toString()
if (newList.indexOf(prop) === -1) {
newList.push(prop)
}
}
})
}
removed = _.difference(self.filters[filtersToUse], newList)
added = _.difference(newList, self.filters[filtersToUse])
// remove the list items for things no longer present on the map
_.each(removed, function (identifier) {
$('#filter_by_' + listToModify + ' li[data-id="' + identifier + '"]').fadeOut('fast', function () {
$(this).remove()
})
index = self.visible[filtersToUse].indexOf(identifier)
self.visible[filtersToUse].splice(index, 1)
})
var model, li, jQueryLi
function sortAlpha (a, b) {
return a.childNodes[1].innerHTML.toLowerCase() > b.childNodes[1].innerHTML.toLowerCase() ? 1 : -1
}
// for each new filter to be added, create a list item for it and fade it in
_.each(added, function (identifier) {
model = Metamaps[correlatedModel].get(identifier) ||
Metamaps[correlatedModel].find(function (model) {
return model.get(propertyToCheck) === identifier
})
li = model.prepareLiForFilter()
jQueryLi = $(li).hide()
$('li', '#filter_by_' + listToModify + ' ul').add(jQueryLi.fadeIn('fast'))
.sort(sortAlpha).appendTo('#filter_by_' + listToModify + ' ul')
self.visible[filtersToUse].push(identifier)
})
// update the list of filters with the new list we just generated
self.filters[filtersToUse] = newList
// make sure clicks on list items still trigger the right events
self.bindLiClicks()
},
checkMetacodes: function () {
var self = Metamaps.Filter
self.updateFilters('Topics', 'metacode_id', 'Metacodes', 'metacodes', 'metacode')
},
checkMappers: function () {
var self = Metamaps.Filter
var onMap = Metamaps.Active.Map ? true : false
if (onMap) {
self.updateFilters('Mappings', 'user_id', 'Mappers', 'mappers', 'mapper')
} else {
// on topic view
self.updateFilters(['Topics', 'Synapses'], 'user_id', 'Creators', 'mappers', 'mapper')
}
},
checkSynapses: function () {
var self = Metamaps.Filter
self.updateFilters('Synapses', 'desc', 'Synapses', 'synapses', 'synapse')
},
filterAllMetacodes: function (e) {
var self = Metamaps.Filter
$('#filter_by_metacode ul li').addClass('toggledOff')
$('.showAllMetacodes').removeClass('active')
$('.hideAllMetacodes').addClass('active')
self.visible.metacodes = []
self.passFilters()
},
filterNoMetacodes: function (e) {
var self = Metamaps.Filter
$('#filter_by_metacode ul li').removeClass('toggledOff')
$('.showAllMetacodes').addClass('active')
$('.hideAllMetacodes').removeClass('active')
self.visible.metacodes = self.filters.metacodes.slice()
self.passFilters()
},
filterAllMappers: function (e) {
var self = Metamaps.Filter
$('#filter_by_mapper ul li').addClass('toggledOff')
$('.showAllMappers').removeClass('active')
$('.hideAllMappers').addClass('active')
self.visible.mappers = []
self.passFilters()
},
filterNoMappers: function (e) {
var self = Metamaps.Filter
$('#filter_by_mapper ul li').removeClass('toggledOff')
$('.showAllMappers').addClass('active')
$('.hideAllMappers').removeClass('active')
self.visible.mappers = self.filters.mappers.slice()
self.passFilters()
},
filterAllSynapses: function (e) {
var self = Metamaps.Filter
$('#filter_by_synapse ul li').addClass('toggledOff')
$('.showAllSynapses').removeClass('active')
$('.hideAllSynapses').addClass('active')
self.visible.synapses = []
self.passFilters()
},
filterNoSynapses: function (e) {
var self = Metamaps.Filter
$('#filter_by_synapse ul li').removeClass('toggledOff')
$('.showAllSynapses').addClass('active')
$('.hideAllSynapses').removeClass('active')
self.visible.synapses = self.filters.synapses.slice()
self.passFilters()
},
// an abstraction function for toggleMetacode, toggleMapper, toggleSynapse
// to reduce code redundancy
// gets called in the context of a list item in a filter box
toggleLi: function (whichToFilter) {
var self = Metamaps.Filter, index
var id = $(this).attr('data-id')
if (self.visible[whichToFilter].indexOf(id) == -1) {
self.visible[whichToFilter].push(id)
$(this).removeClass('toggledOff')
} else {
index = self.visible[whichToFilter].indexOf(id)
self.visible[whichToFilter].splice(index, 1)
$(this).addClass('toggledOff')
}
self.passFilters()
},
toggleMetacode: function () {
var self = Metamaps.Filter
self.toggleLi.call(this, 'metacodes')
if (self.visible.metacodes.length === self.filters.metacodes.length) {
$('.showAllMetacodes').addClass('active')
$('.hideAllMetacodes').removeClass('active')
}
else if (self.visible.metacodes.length === 0) {
$('.showAllMetacodes').removeClass('active')
$('.hideAllMetacodes').addClass('active')
} else {
$('.showAllMetacodes').removeClass('active')
$('.hideAllMetacodes').removeClass('active')
}
},
toggleMapper: function () {
var self = Metamaps.Filter
self.toggleLi.call(this, 'mappers')
if (self.visible.mappers.length === self.filters.mappers.length) {
$('.showAllMappers').addClass('active')
$('.hideAllMappers').removeClass('active')
}
else if (self.visible.mappers.length === 0) {
$('.showAllMappers').removeClass('active')
$('.hideAllMappers').addClass('active')
} else {
$('.showAllMappers').removeClass('active')
$('.hideAllMappers').removeClass('active')
}
},
toggleSynapse: function () {
var self = Metamaps.Filter
self.toggleLi.call(this, 'synapses')
if (self.visible.synapses.length === self.filters.synapses.length) {
$('.showAllSynapses').addClass('active')
$('.hideAllSynapses').removeClass('active')
}
else if (self.visible.synapses.length === 0) {
$('.showAllSynapses').removeClass('active')
$('.hideAllSynapses').addClass('active')
} else {
$('.showAllSynapses').removeClass('active')
$('.hideAllSynapses').removeClass('active')
}
},
passFilters: function () {
var self = Metamaps.Filter
var visible = self.visible
var passesMetacode, passesMapper, passesSynapse
var onMap
if (Metamaps.Active.Map) {
onMap = true
}
else if (Metamaps.Active.Topic) {
onMap = false
}
var opacityForFilter = onMap ? 0 : 0.4
Metamaps.Topics.each(function (topic) {
var n = topic.get('node')
var metacode_id = topic.get('metacode_id').toString()
if (visible.metacodes.indexOf(metacode_id) == -1) passesMetacode = false
else passesMetacode = true
if (onMap) {
// when on a map,
// we filter by mapper according to the person who added the
// topic or synapse to the map
var user_id = topic.getMapping().get('user_id').toString()
if (visible.mappers.indexOf(user_id) == -1) passesMapper = false
else passesMapper = true
} else {
// when on a topic view,
// we filter by mapper according to the person who created the
// topic or synapse
var user_id = topic.get('user_id').toString()
if (visible.mappers.indexOf(user_id) == -1) passesMapper = false
else passesMapper = true
}
if (passesMetacode && passesMapper) {
if (n) {
n.setData('alpha', 1, 'end')
}
else console.log(topic)
} else {
if (n) {
Metamaps.Control.deselectNode(n, true)
n.setData('alpha', opacityForFilter, 'end')
n.eachAdjacency(function (e) {
Metamaps.Control.deselectEdge(e, true)
})
}
else console.log(topic)
}
})
// flag all the edges back to 'untouched'
Metamaps.Synapses.each(function (synapse) {
var e = synapse.get('edge')
e.setData('touched', false)
})
Metamaps.Synapses.each(function (synapse) {
var e = synapse.get('edge')
var desc
var user_id = synapse.get('user_id').toString()
if (e && !e.getData('touched')) {
var synapses = e.getData('synapses')
// if any of the synapses represent by the edge are still unfiltered
// leave the edge visible
passesSynapse = false
for (var i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) passesSynapse = true
}
// if the synapse description being displayed is now being
// filtered, set the displayIndex to the first unfiltered synapse if there is one
var displayIndex = e.getData('displayIndex') ? e.getData('displayIndex') : 0
var displayedSynapse = synapses[displayIndex]
desc = displayedSynapse.get('desc')
if (passesSynapse && visible.synapses.indexOf(desc) == -1) {
// iterate and find an unfiltered one
for (var i = 0; i < synapses.length; i++) {
desc = synapses[i].get('desc')
if (visible.synapses.indexOf(desc) > -1) {
e.setData('displayIndex', i)
break
}
}
}
if (onMap) {
// when on a map,
// we filter by mapper according to the person who added the
// topic or synapse to the map
user_id = synapse.getMapping().get('user_id').toString()
}
if (visible.mappers.indexOf(user_id) == -1) passesMapper = false
else passesMapper = true
var color = Metamaps.Settings.colors.synapses.normal
if (passesSynapse && passesMapper) {
e.setData('alpha', 1, 'end')
e.setData('color', color, 'end')
} else {
Metamaps.Control.deselectEdge(e, true)
e.setData('alpha', opacityForFilter, 'end')
}
e.setData('touched', true)
}
else if (!e) console.log(synapse)
})
// run the animation
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:alpha',
'edge-property:alpha'],
duration: 200
})
}
}; // end Metamaps.Filter

View file

@ -1,699 +0,0 @@
var Metamaps = {}; // this variable declaration defines a Javascript object that will contain all the variables and functions used by us, broken down into 'sub-modules' that look something like this
/*
* unless you are on a page with the Javascript InfoVis Toolkit (Topic or Map) the only section in the metamaps
* object will be these
GlobalUI
Active
Maps
Mappers
Backbone
* all these get added when you are on a page with the Javascript Infovis Toolkit
Settings
Touch
Mouse
Selected
Metacodes
Topics
Synapses
Mappings
Create
TopicCard
SynapseCard
Visualize
Util
Realtime
Control
Filter
Listeners
Organize
Map
Mapper
Topic
Synapse
JIT
*/
Metamaps.Active = {
Map: null,
Topic: null,
Mapper: null
};
Metamaps.Maps = {};
$(document).ready(function () {
function init() {
for (var prop in Metamaps) {
// this runs the init function within each sub-object on the Metamaps one
if (Metamaps.hasOwnProperty(prop) &&
Metamaps[prop] != null &&
Metamaps[prop].hasOwnProperty('init') &&
typeof (Metamaps[prop].init) == 'function'
) {
Metamaps[prop].init();
}
}
}
// initialize the famous ui
var callFamous = function(){
if (Metamaps.Famous) {
Metamaps.Famous.build();
init();
}
else {
setTimeout(callFamous, 100);
}
}
callFamous();
});
Metamaps.GlobalUI = {
notifyTimeout: null,
lightbox: null,
init: function () {
var self = Metamaps.GlobalUI;
self.Search.init();
self.CreateMap.init();
self.Account.init();
//bind lightbox clicks
$('.openLightbox').click(function (event) {
self.openLightbox($(this).attr('data-open'));
event.preventDefault();
return false;
});
$('#lightbox_screen, #lightbox_close').click(self.closeLightbox);
// initialize global backbone models and collections
if (Metamaps.Active.Mapper) Metamaps.Active.Mapper = new Metamaps.Backbone.Mapper(Metamaps.Active.Mapper);
var myCollection = Metamaps.Maps.Mine ? Metamaps.Maps.Mine : [];
var sharedCollection = Metamaps.Maps.Shared ? Metamaps.Maps.Shared : [];
var mapperCollection = [];
var mapperOptionsObj = {id: 'mapper', sortBy: 'updated_at' };
if (Metamaps.Maps.Mapper) {
mapperCollection = Metamaps.Maps.Mapper.models;
mapperOptionsObj.mapperId = Metamaps.Maps.Mapper.id;
}
var featuredCollection = Metamaps.Maps.Featured ? Metamaps.Maps.Featured : [];
var activeCollection = Metamaps.Maps.Active ? Metamaps.Maps.Active : [];
Metamaps.Maps.Mine = new Metamaps.Backbone.MapsCollection(myCollection, {id: 'mine', sortBy: 'updated_at' });
Metamaps.Maps.Shared = new Metamaps.Backbone.MapsCollection(sharedCollection, {id: 'shared', sortBy: 'updated_at' });
// 'Mapper' refers to another mapper
Metamaps.Maps.Mapper = new Metamaps.Backbone.MapsCollection(mapperCollection, mapperOptionsObj);
Metamaps.Maps.Featured = new Metamaps.Backbone.MapsCollection(featuredCollection, {id: 'featured', sortBy: 'updated_at' });
Metamaps.Maps.Active = new Metamaps.Backbone.MapsCollection(activeCollection, {id: 'active', sortBy: 'updated_at' });
},
openLightbox: function (which) {
var self = Metamaps.GlobalUI;
$('.lightboxContent').hide();
$('#' + which).show();
self.lightbox = which;
$('#lightbox_overlay').show();
var heightOfContent = '-' + ($('#lightbox_main').height() / 2) + 'px';
// animate the content in from the bottom
$('#lightbox_main').animate({
'top': '50%',
'margin-top': heightOfContent
}, 200, 'easeOutCubic');
// fade the black overlay in
$('#lightbox_screen').animate({
'opacity': '0.42'
}, 200);
if (which == "switchMetacodes") {
Metamaps.Create.isSwitchingSet = true;
}
},
closeLightbox: function (event) {
var self = Metamaps.GlobalUI;
if (event) event.preventDefault();
// animate the lightbox content offscreen
$('#lightbox_main').animate({
'top': '100%',
'margin-top': '0'
}, 200, 'easeInCubic');
// fade the black overlay out
$('#lightbox_screen').animate({
'opacity': '0.0'
}, 200, function () {
$('#lightbox_overlay').hide();
});
if (self.lightbox === 'forkmap') Metamaps.GlobalUI.CreateMap.reset('fork_map');
if (self.lightbox === 'newmap') Metamaps.GlobalUI.CreateMap.reset('new_map');
if (Metamaps.Create && Metamaps.Create.isSwitchingSet) {
Metamaps.Create.cancelMetacodeSetSwitch();
}
self.lightbox = null;
},
notifyUser: function (message, leaveOpen) {
var self = Metamaps.GlobalUI;
function famousReady() {
Metamaps.Famous.toast.surf.setContent(message);
Metamaps.Famous.toast.show();
clearTimeout(self.notifyTimeOut);
if (!leaveOpen) {
self.notifyTimeOut = setTimeout(function () {
Metamaps.Famous.toast.hide();
}, 8000);
}
}
// initialize the famous ui
var callFamous = function(){
if (Metamaps.Famous && Metamaps.Famous.toast) {
famousReady();
}
else {
setTimeout(callFamous, 100);
}
}
callFamous();
},
clearNotify: function() {
var self = Metamaps.GlobalUI;
clearTimeout(self.notifyTimeOut);
Metamaps.Famous.toast.hide();
},
shareInvite: function(inviteLink) {
window.prompt("To copy the invite link, press: Ctrl+C, Enter", inviteLink);
}
};
Metamaps.GlobalUI.CreateMap = {
newMap: null,
emptyMapForm: "",
emptyForkMapForm: "",
topicsToMap: [],
synapsesToMap: [],
init: function () {
var self = Metamaps.GlobalUI.CreateMap;
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
self.bindFormEvents();
self.emptyMapForm = $('#new_map').html();
},
bindFormEvents: function () {
var self = Metamaps.GlobalUI.CreateMap;
$('.new_map button.cancel').unbind().bind('click', function (event) {
event.preventDefault();
Metamaps.GlobalUI.closeLightbox();
});
$('.new_map button.submitMap').unbind().bind('click', self.submit);
// bind permission changer events on the createMap form
$('.permIcon').unbind().bind('click', self.switchPermission);
},
closeSuccess: function () {
$('#mapCreatedSuccess').fadeOut(300, function(){
$(this).remove();
});
},
generateSuccessMessage: function (id) {
var stringStart = "<div id='mapCreatedSuccess'><h6>SUCCESS!</h6>Your map has been created. Do you want to: <a id='mapGo' href='/maps/";
stringStart += id;
stringStart += "' onclick='Metamaps.GlobalUI.CreateMap.closeSuccess();'>Go to your new map</a>";
stringStart += "<span>OR</span><a id='mapStay' href='#' onclick='Metamaps.GlobalUI.CreateMap.closeSuccess(); return false;'>Stay on this ";
var page = Metamaps.Active.Map ? 'map' : 'page';
var stringEnd = "</a></div>";
return stringStart + page + stringEnd;
},
switchPermission: function () {
var self = Metamaps.GlobalUI.CreateMap;
self.newMap.set('permission', $(this).attr('data-permission'));
$(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected');
$(this).find('.mapPermIcon').addClass('selected');
var permText = $(this).find('.tip').html();
$(this).parents('.new_map').find('.permText').html(permText);
},
submit: function (event) {
if (event) event.preventDefault();
var self = Metamaps.GlobalUI.CreateMap;
if (Metamaps.GlobalUI.lightbox === 'forkmap') {
self.newMap.set('topicsToMap', self.topicsToMap);
self.newMap.set('synapsesToMap', self.synapsesToMap);
}
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
var $form = $(formId);
self.newMap.set('name', $form.find('#map_name').val());
self.newMap.set('desc', $form.find('#map_desc').val());
if (self.newMap.get('name').length===0){
self.throwMapNameError();
return;
}
self.newMap.save(null, {
success: self.success
// TODO add error message
});
Metamaps.GlobalUI.closeLightbox();
Metamaps.GlobalUI.notifyUser('Working...');
},
throwMapNameError: function () {
var self = Metamaps.GlobalUI.CreateMap;
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
var $form = $(formId);
var message = $("<div class='feedback_message'>Please enter a map name...</div>");
$form.find('#map_name').after(message);
setTimeout(function(){
message.fadeOut('fast', function(){
message.remove();
});
}, 5000);
},
success: function (model) {
var self = Metamaps.GlobalUI.CreateMap;
//push the new map onto the collection of 'my maps'
Metamaps.Maps.Mine.add(model);
var formId = Metamaps.GlobalUI.lightbox === 'forkmap' ? '#fork_map' : '#new_map';
var form = $(formId);
Metamaps.GlobalUI.clearNotify();
$('#wrapper').append(self.generateSuccessMessage(model.id));
},
reset: function (id) {
var self = Metamaps.GlobalUI.CreateMap;
var form = $('#' + id);
if (id === "fork_map") {
self.topicsToMap = [];
self.synapsesToMap = [];
form.html(self.emptyForkMapForm);
}
else {
form.html(self.emptyMapForm);
}
self.bindFormEvents();
self.newMap = new Metamaps.Backbone.Map({ permission: 'commons' });
return false;
},
};
Metamaps.GlobalUI.Account = {
isOpen: false,
changing: false,
init: function () {
var self = Metamaps.GlobalUI.Account;
$('.sidebarAccountIcon').click(self.toggleBox);
$('.sidebarAccountBox').click(function(event){
event.stopPropagation();
});
$('body').click(self.close);
},
toggleBox: function (event) {
var self = Metamaps.GlobalUI.Account;
if (self.isOpen) self.close();
else self.open();
event.stopPropagation();
},
open: function () {
var self = Metamaps.GlobalUI.Account;
Metamaps.Filter.close();
$('.sidebarAccountIcon .tooltipsUnder').addClass('hide');
if (!self.isOpen && !self.changing) {
self.changing = true;
$('.sidebarAccountBox').fadeIn(200, function () {
self.changing = false;
self.isOpen = true;
$('.sidebarAccountBox #user_email').focus();
});
}
},
close: function () {
var self = Metamaps.GlobalUI.Account;
$('.sidebarAccountIcon .tooltipsUnder').removeClass('hide');
if (!self.changing) {
self.changing = true;
$('.sidebarAccountBox #user_email').blur();
$('.sidebarAccountBox').fadeOut(200, function () {
self.changing = false;
self.isOpen = false;
});
}
}
};
Metamaps.GlobalUI.Search = {
locked: false,
isOpen: false,
limitTopicsToMe: false,
limitMapsToMe: false,
timeOut: null,
changing: false,
optionsInitialized: false,
init: function () {
var self = Metamaps.GlobalUI.Search;
var loader = new CanvasLoader('searchLoading');
loader.setColor('#4fb5c0'); // default is '#000000'
loader.setDiameter(24); // default is 40
loader.setDensity(41); // default is 40
loader.setRange(0.9); // default is 1.3
loader.show(); // Hidden by default
// bind the hover events
$(".sidebarSearch").hover(function () {
self.open()
}, function () {
self.close(800, false)
});
$('.sidebarSearchIcon').click(function (e) {
$('.sidebarSearchField').focus();
});
$('.sidebarSearch').click(function (e) {
e.stopPropagation();
});
$('body').click(function (e) {
self.close(0, false);
});
// open if the search is closed and user hits ctrl+/
// close if they hit ESC
$('body').bind('keyup', function (e) {
switch (e.which) {
case 191:
if ((e.ctrlKey && !self.isOpen) || (e.ctrlKey && self.locked)) {
self.open(true); // true for focus
}
break;
case 27:
if (self.isOpen) {
self.close(0, true);
}
break;
default:
break; //console.log(e.which);
}
});
self.startTypeahead();
},
lock: function() {
var self = Metamaps.GlobalUI.Search;
self.locked = true;
},
unlock: function() {
var self = Metamaps.GlobalUI.Search;
self.locked = false;
},
open: function (focus) {
var self = Metamaps.GlobalUI.Search;
clearTimeout(self.timeOut);
if (!self.isOpen && !self.changing && !self.locked) {
self.changing = true;
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
width: '400px'
}, 300, function () {
if (focus) $('.sidebarSearchField').focus();
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
padding: '7px 10px 3px 10px',
width: '380px'
});
self.changing = false;
self.isOpen = true;
});
}
},
close: function (closeAfter, bypass) {
var self = Metamaps.GlobalUI.Search;
self.timeOut = setTimeout(function () {
if (!self.locked && !self.changing && self.isOpen && (bypass || $('.sidebarSearchField.tt-input').val() == '')) {
self.changing = true;
$('.sidebarSearchField, .sidebarSearch .tt-hint').css({
padding: '7px 0 3px 0',
width: '400px'
});
$('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({
width: '0'
}, 300, function () {
$('.sidebarSearchField').typeahead('val', '');
$('.sidebarSearchField').blur();
self.changing = false;
self.isOpen = false;
});
}
}, closeAfter);
},
startTypeahead: function () {
var self = Metamaps.GlobalUI.Search;
var mapheader = Metamaps.Active.Mapper ? '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><input type="checkbox" class="limitToMe" id="limitMapsToMe"></input><label for="limitMapsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>' : '<div class="searchMapsHeader searchHeader"><h3 class="search-heading">Maps</h3><div class="minimizeResults minimizeMapResults"></div><div class="clearfloat"></div></div>';
var topicheader = Metamaps.Active.Mapper ? '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><input type="checkbox" class="limitToMe" id="limitTopicsToMe"></input><label for="limitTopicsToMe" class="limitToMeLabel">added by me</label><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>' : '<div class="searchTopicsHeader searchHeader"><h3 class="search-heading">Topics</h3><div class="minimizeResults minimizeTopicResults"></div><div class="clearfloat"></div></div>';
var mapperheader = '<div class="searchMappersHeader searchHeader"><h3 class="search-heading">Mappers</h3><div class="minimizeResults minimizeMapperResults"></div><div class="clearfloat"></div></div>';
var topics = {
name: 'topics',
limit: 9999,
display: function(s) { return s.label; },
templates: {
notFound: function(s) {
return Hogan.compile(topicheader + $('#topicSearchTemplate').html()).render({
value: "No results",
label: "No results",
typeImageURL: Metamaps.Erb['icons/wildcard.png'],
rtype: "noresult"
});
},
header: topicheader,
suggestion: function(s) {
return Hogan.compile($('#topicSearchTemplate').html()).render(s);
},
},
source: new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/topics',
prepare: function(query, settings) {
settings.url += '?term=' + query;
if (Metamaps.Active.Mapper && self.limitTopicsToMe) {
settings.url += "&user=" + Metamaps.Active.Mapper.id.toString();
}
return settings;
},
},
}),
};
var maps = {
name: 'maps',
limit: 9999,
display: function(s) { return s.label; },
templates: {
notFound: function(s) {
return Hogan.compile(mapheader + $('#mapSearchTemplate').html()).render({
value: "No results",
label: "No results",
rtype: "noresult"
});
},
header: mapheader,
suggestion: function(s) {
return Hogan.compile($('#mapSearchTemplate').html()).render(s);
},
},
source: new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/maps',
prepare: function(query, settings) {
settings.url += '?term=' + query;
if (Metamaps.Active.Mapper && self.limitMapsToMe) {
settings.url += "&user=" + Metamaps.Active.Mapper.id.toString();
}
return settings;
},
},
}),
};
var mappers = {
name: 'mappers',
limit: 9999,
display: function(s) { return s.label; },
templates: {
notFound: function(s) {
return Hogan.compile(mapperheader + $('#mapperSearchTemplate').html()).render({
value: "No results",
label: "No results",
rtype: "noresult",
profile: Metamaps.Erb['user.png']
});
},
header: mapperheader,
suggestion: function(s) {
return Hogan.compile($('#mapperSearchTemplate').html()).render(s);
},
},
source: new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/mappers?term=%QUERY',
wildcard: '%QUERY',
},
}),
};
// Take all that crazy setup data and put it together into one beautiful typeahead call!
$('.sidebarSearchField').typeahead(
{
highlight: true,
},
[topics, maps, mappers]
);
//Set max height of the search results box to prevent it from covering bottom left footer
$('.sidebarSearchField').bind('typeahead:render', function (event) {
self.initSearchOptions();
self.hideLoader();
var h = $(window).height();
$(".tt-dropdown-menu").css('max-height', h - 100);
if (self.limitTopicsToMe) {
$('#limitTopicsToMe').prop('checked', true);
}
if (self.limitMapsToMe) {
$('#limitMapsToMe').prop('checked', true);
}
});
$(window).resize(function () {
var h = $(window).height();
$(".tt-dropdown-menu").css('max-height', h - 100);
});
// tell the autocomplete to launch a new tab with the topic, map, or mapper you clicked on
$('.sidebarSearchField').bind('typeahead:select', self.handleResultClick);
// don't do it, if they clicked on a 'addToMap' button
$('.sidebarSearch button.addToMap').click(function (event) {
event.stopPropagation();
});
// make sure that when you click on 'limit to me' or 'toggle section' it works
$('.sidebarSearchField.tt-input').keyup(function(){
if ($('.sidebarSearchField.tt-input').val() === '') {
self.hideLoader();
} else {
self.showLoader();
}
});
},
handleResultClick: function (event, datum, dataset) {
var self = Metamaps.GlobalUI.Search;
self.hideLoader();
if (["topic", "map", "mapper"].indexOf(datum.rtype) !== -1) {
self.close(0, true);
var win;
if (datum.rtype == "topic") {
Metamaps.Router.topics(datum.id);
} else if (datum.rtype == "map") {
Metamaps.Router.maps(datum.id);
} else if (datum.rtype == "mapper") {
Metamaps.Router.explore("mapper", datum.id);
}
}
},
initSearchOptions: function () {
var self = Metamaps.GlobalUI.Search;
function toggleResultSet(set) {
var s = $('.tt-dataset-' + set + ' .tt-suggestion, .tt-dataset-' + set + ' .resultnoresult');
if (s.is(':visible')) {
s.hide();
$(this).removeClass('minimizeResults').addClass('maximizeResults');
} else {
s.show();
$(this).removeClass('maximizeResults').addClass('minimizeResults');
}
}
$('.limitToMe').unbind().bind("change", function (e) {
if ($(this).attr('id') == 'limitTopicsToMe') {
self.limitTopicsToMe = !self.limitTopicsToMe;
}
if ($(this).attr('id') == 'limitMapsToMe') {
self.limitMapsToMe = !self.limitMapsToMe;
}
// set the value of the search equal to itself to retrigger the
// autocomplete event
var searchQuery = $('.sidebarSearchField.tt-input').val();
$(".sidebarSearchField").typeahead('val', '')
.typeahead('val', searchQuery);
});
// when the user clicks minimize section, hide the results for that section
$('.minimizeMapperResults').unbind().click(function (e) {
toggleResultSet.call(this, 'mappers');
});
$('.minimizeTopicResults').unbind().click(function (e) {
toggleResultSet.call(this, 'topics');
});
$('.minimizeMapResults').unbind().click(function (e) {
toggleResultSet.call(this, 'maps');
});
},
hideLoader: function () {
$('#searchLoading').hide();
},
showLoader: function () {
$('#searchLoading').show();
}
};

View file

@ -1,324 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Import.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Backbone
* - Metamaps.Famous // TODO remove dependency
* - Metamaps.Map
* - Metamaps.Mappings
* - Metamaps.Metacodes
* - Metamaps.Synapses
* - Metamaps.Topics
*/
Metamaps.Import = {
// note that user is not imported
topicWhitelist: [
'id', 'name', 'metacode', 'x', 'y', 'description', 'link', 'permission'
],
synapseWhitelist: [
'topic1', 'topic2', 'category', 'desc', 'description', 'permission'
],
cidMappings: {}, // to be filled by import_id => cid mappings
init: function () {
var self = Metamaps.Import
$('body').bind('paste', function (e) {
if (e.target.tagName === 'INPUT') return
var text = e.originalEvent.clipboardData.getData('text/plain')
var results
if (text.trimLeft()[0] === '{') {
try {
results = JSON.parse(text)
} catch (e) {
results = false
}
} else {
results = self.parseTabbedString(text)
}
if (results === false) return
var topics = results.topics
var synapses = results.synapses
if (topics.length > 0 || synapses.length > 0) {
if (window.confirm('Are you sure you want to create ' + topics.length +
' new topics and ' + synapses.length + ' new synapses?')) {
self.importTopics(topics)
self.importSynapses(synapses)
} // if
} // if
})
},
abort: function (message) {
console.error(message)
},
simplify: function (string) {
return string
.replace(/(^\s*|\s*$)/g, '')
.toLowerCase()
},
parseTabbedString: function (text) {
var self = Metamaps.Import
// determine line ending and split lines
var delim = '\n'
if (text.indexOf('\r\n') !== -1) {
delim = '\r\n'
} else if (text.indexOf('\r') !== -1) {
delim = '\r'
} // if
var STATES = {
ABORT: -1,
UNKNOWN: 0,
TOPICS_NEED_HEADERS: 1,
SYNAPSES_NEED_HEADERS: 2,
TOPICS: 3,
SYNAPSES: 4
}
// state & lines determine parser behaviour
var state = STATES.UNKNOWN
var lines = text.split(delim)
var results = { topics: [], synapses: [] }
var topicHeaders = []
var synapseHeaders = []
lines.forEach(function (line_raw, index) {
var line = line_raw.split('\t')
var noblanks = line.filter(function (elt) {
return elt !== ''
})
switch (state) {
case STATES.UNKNOWN:
if (noblanks.length === 0) {
state = STATES.UNKNOWN
break
} else if (noblanks.length === 1 && self.simplify(line[0]) === 'topics') {
state = STATES.TOPICS_NEED_HEADERS
break
} else if (noblanks.length === 1 && self.simplify(line[0]) === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS
break
}
state = STATES.TOPICS_NEED_HEADERS
// FALL THROUGH - if we're not sure what to do, pretend
// we're on the TOPICS_NEED_HEADERS state and parse some headers
case STATES.TOPICS_NEED_HEADERS: // eslint-disable-line
if (noblanks.length < 2) {
self.abort('Not enough topic headers on line ' + index)
state = STATES.ABORT
}
topicHeaders = line.map(function (header, index) {
return header.toLowerCase().replace('description', 'desc')
})
state = STATES.TOPICS
break
case STATES.SYNAPSES_NEED_HEADERS:
if (noblanks.length < 2) {
self.abort('Not enough synapse headers on line ' + index)
state = STATES.ABORT
}
synapseHeaders = line.map(function (header, index) {
return header.toLowerCase().replace('description', 'desc')
})
state = STATES.SYNAPSES
break
case STATES.TOPICS:
if (noblanks.length === 0) {
state = STATES.UNKNOWN
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'topics') {
state = STATES.TOPICS_NEED_HEADERS
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS
} else {
var topic = {}
line.forEach(function (field, index) {
var header = topicHeaders[index]
if (self.topicWhitelist.indexOf(header) === -1) return
topic[header] = field
if (['id', 'x', 'y'].indexOf(header) !== -1) {
topic[header] = parseInt(topic[header])
} // if
})
results.topics.push(topic)
}
break
case STATES.SYNAPSES:
if (noblanks.length === 0) {
state = STATES.UNKNOWN
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'topics') {
state = STATES.TOPICS_NEED_HEADERS
} else if (noblanks.length === 1 && line[0].toLowerCase() === 'synapses') {
state = STATES.SYNAPSES_NEED_HEADERS
} else {
var synapse = {}
line.forEach(function (field, index) {
var header = synapseHeaders[index]
if (self.synapseWhitelist.indexOf(header) === -1) return
synapse[header] = field
if (['id', 'topic1', 'topic2'].indexOf(header) !== -1) {
synapse[header] = parseInt(synapse[header])
} // if
})
results.synapses.push(synapse)
}
break
case STATES.ABORT:
default:
self.abort('Invalid state while parsing import data. Check code.')
state = STATES.ABORT
}
})
if (state === STATES.ABORT) {
return false
} else {
return results
}
},
importTopics: function (parsedTopics) {
var self = Metamaps.Import
// up to 25 topics: scale 100
// up to 81 topics: scale 200
// up to 169 topics: scale 300
var scale = Math.floor((Math.sqrt(parsedTopics.length) - 1) / 4) * 100
if (scale < 100) scale = 100
var autoX = -scale
var autoY = -scale
parsedTopics.forEach(function (topic) {
var x, y
if (topic.x && topic.y) {
x = topic.x
y = topic.y
} else {
x = autoX
y = autoY
autoX += 50
if (autoX > scale) {
autoY += 50
autoX = -scale
}
}
self.createTopicWithParameters(
topic.name, topic.metacode, topic.permission,
topic.desc, topic.link, x, y, topic.id
)
})
},
importSynapses: function (parsedSynapses) {
var self = Metamaps.Import
parsedSynapses.forEach(function (synapse) {
// only createSynapseWithParameters once both topics are persisted
var topic1 = Metamaps.Topics.get(self.cidMappings[synapse.topic1])
var topic2 = Metamaps.Topics.get(self.cidMappings[synapse.topic2])
if (!topic1 || !topic2) {
console.error("One of the two topics doesn't exist!")
console.error(synapse)
return true
}
var synapse_created = false
topic1.once('sync', function () {
if (topic1.id && topic2.id && !synapse_created) {
synapse_created = true
self.createSynapseWithParameters(
synapse.desc, synapse.category, synapse.permission,
topic1, topic2
)
} // if
})
topic2.once('sync', function () {
if (topic1.id && topic2.id && !synapse_created) {
synapse_created = true
self.createSynapseWithParameters(
synapse.desc, synapse.category, synapse.permission,
topic1, topic2
)
} // if
})
})
},
createTopicWithParameters: function (name, metacode_name, permission, desc,
link, xloc, yloc, import_id) {
var self = Metamaps.Import
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
var metacode = Metamaps.Metacodes.where({name: metacode_name})[0] || null
if (metacode === null) return console.error('metacode not found')
var topic = new Metamaps.Backbone.Topic({
name: name,
metacode_id: metacode.id,
permission: permission || Metamaps.Active.Map.get('permission'),
desc: desc,
link: link
})
Metamaps.Topics.add(topic)
self.cidMappings[import_id] = topic.cid
var mapping = new Metamaps.Backbone.Mapping({
xloc: xloc,
yloc: yloc,
mappable_id: topic.cid,
mappable_type: 'Topic'
})
Metamaps.Mappings.add(mapping)
// this function also includes the creation of the topic in the database
Metamaps.Topic.renderTopic(mapping, topic, true, true)
Metamaps.Famous.viz.hideInstructions()
},
createSynapseWithParameters: function (description, category, permission,
topic1, topic2) {
var node1 = topic1.get('node')
var node2 = topic2.get('node')
if (!topic1.id || !topic2.id) {
console.error('missing topic id when creating synapse')
return
} // if
var synapse = new Metamaps.Backbone.Synapse({
desc: description,
category: category,
permission: permission,
node1_id: topic1.id,
node2_id: topic2.id
})
Metamaps.Synapses.add(synapse)
var mapping = new Metamaps.Backbone.Mapping({
mappable_type: 'Synapse',
mappable_id: synapse.cid
})
Metamaps.Mappings.add(mapping)
Metamaps.Synapse.renderSynapse(mapping, synapse, node1, node2, true)
}
}
module.exports = Metamaps.Import

File diff suppressed because it is too large Load diff

View file

@ -1,78 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Listeners.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Control
* - Metamaps.JIT
* - Metamaps.Visualize
*/
Metamaps.Listeners = {
init: function () {
$(document).on('keydown', function (e) {
if (!(Metamaps.Active.Map || Metamaps.Active.Topic)) return
switch (e.which) {
case 13: // if enter key is pressed
Metamaps.JIT.enterKeyHandler()
e.preventDefault()
break
case 27: // if esc key is pressed
Metamaps.JIT.escKeyHandler()
break
case 65: // if a or A is pressed
if (e.ctrlKey) {
Metamaps.Control.deselectAllNodes()
Metamaps.Control.deselectAllEdges()
e.preventDefault()
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
Metamaps.Control.selectNode(n, e)
})
Metamaps.Visualize.mGraph.plot()
}
break
case 69: // if e or E is pressed
if (e.ctrlKey) {
e.preventDefault()
if (Metamaps.Active.Map) {
Metamaps.JIT.zoomExtents(null, Metamaps.Visualize.mGraph.canvas)
}
}
break
case 77: // if m or M is pressed
if (e.ctrlKey) {
e.preventDefault()
Metamaps.Control.removeSelectedNodes()
Metamaps.Control.removeSelectedEdges()
}
break
case 68: // if d or D is pressed
if (e.ctrlKey) {
e.preventDefault()
Metamaps.Control.deleteSelected()
}
break
case 72: // if h or H is pressed
if (e.ctrlKey) {
e.preventDefault()
Metamaps.Control.hideSelectedNodes()
Metamaps.Control.hideSelectedEdges()
}
break
default:
break; // alert(e.which)
}
})
$(window).resize(function () {
if (Metamaps.Visualize && Metamaps.Visualize.mGraph) Metamaps.Visualize.mGraph.canvas.resize($(window).width(), $(window).height())
if ((Metamaps.Active.Map || Metamaps.Active.Topic) && Metamaps.Famous && Metamaps.Famous.maps.surf) Metamaps.Famous.maps.reposition()
if (Metamaps.Active.Map && Metamaps.Realtime.inConversation) Metamaps.Realtime.positionVideos()
})
}
}; // end Metamaps.Listeners

View file

@ -1,763 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Map.js.erb
*
* Dependencies:
* - Metamaps.Create
* - Metamaps.Erb
* - Metamaps.Filter
* - Metamaps.JIT
* - Metamaps.Loading
* - Metamaps.Maps
* - Metamaps.Realtime
* - Metamaps.Router
* - Metamaps.Selected
* - Metamaps.SynapseCard
* - Metamaps.TopicCard
* - Metamaps.Visualize
* - Metamaps.Active
* - Metamaps.Backbone
* - Metamaps.GlobalUI
* - Metamaps.Mappers
* - Metamaps.Mappings
* - Metamaps.Messages
* - Metamaps.Synapses
* - Metamaps.Topics
*
* Major sub-modules:
* - Metamaps.Map.CheatSheet
* - Metamaps.Map.InfoBox
*/
Metamaps.Map = {
events: {
editedByActiveMapper: 'Metamaps:Map:events:editedByActiveMapper'
},
nextX: 0,
nextY: 0,
sideLength: 1,
turnCount: 0,
nextXshift: 1,
nextYshift: 0,
timeToTurn: 0,
init: function () {
var self = Metamaps.Map
// prevent right clicks on the main canvas, so as to not get in the way of our right clicks
$('#center-container').bind('contextmenu', function (e) {
return false
})
$('.sidebarFork').click(function () {
self.fork()
})
Metamaps.GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html()
self.InfoBox.init()
self.CheatSheet.init()
$(document).on(Metamaps.Map.events.editedByActiveMapper, self.editedByActiveMapper)
},
launch: function (id) {
var bb = Metamaps.Backbone
var start = function (data) {
Metamaps.Active.Map = new bb.Map(data.map)
Metamaps.Mappers = new bb.MapperCollection(data.mappers)
Metamaps.Collaborators = new bb.MapperCollection(data.collaborators)
Metamaps.Topics = new bb.TopicCollection(data.topics)
Metamaps.Synapses = new bb.SynapseCollection(data.synapses)
Metamaps.Mappings = new bb.MappingCollection(data.mappings)
Metamaps.Messages = data.messages
Metamaps.Backbone.attachCollectionEvents()
var map = Metamaps.Active.Map
var mapper = Metamaps.Active.Mapper
// add class to .wrapper for specifying whether you can edit the map
if (map.authorizeToEdit(mapper)) {
$('.wrapper').addClass('canEditMap')
}
// add class to .wrapper for specifying if the map can
// be collaborated on
if (map.get('permission') === 'commons') {
$('.wrapper').addClass('commonsMap')
}
// set filter mapper H3 text
$('#filter_by_mapper h3').html('MAPPERS')
// build and render the visualization
Metamaps.Visualize.type = 'ForceDirected'
Metamaps.JIT.prepareVizData()
// update filters
Metamaps.Filter.reset()
// reset selected arrays
Metamaps.Selected.reset()
// set the proper mapinfobox content
Metamaps.Map.InfoBox.load()
// these three update the actual filter box with the right list items
Metamaps.Filter.checkMetacodes()
Metamaps.Filter.checkSynapses()
Metamaps.Filter.checkMappers()
Metamaps.Realtime.startActiveMap()
Metamaps.Loading.hide()
}
$.ajax({
url: '/maps/' + id + '/contains.json',
success: start
})
},
end: function () {
if (Metamaps.Active.Map) {
$('.wrapper').removeClass('canEditMap commonsMap')
Metamaps.Map.resetSpiral()
$('.rightclickmenu').remove()
Metamaps.TopicCard.hideCard()
Metamaps.SynapseCard.hideCard()
Metamaps.Create.newTopic.hide()
Metamaps.Create.newSynapse.hide()
Metamaps.Filter.close()
Metamaps.Map.InfoBox.close()
Metamaps.Realtime.endActiveMap()
}
},
fork: function () {
Metamaps.GlobalUI.openLightbox('forkmap')
var nodes_data = '',
synapses_data = ''
var nodes_array = []
var synapses_array = []
// collect the unfiltered topics
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
// if the opacity is less than 1 then it's filtered
if (n.getData('alpha') === 1) {
var id = n.getData('topic').id
nodes_array.push(id)
var x, y
if (n.pos.x && n.pos.y) {
x = n.pos.x
y = n.pos.y
} else {
var x = Math.cos(n.pos.theta) * n.pos.rho
var y = Math.sin(n.pos.theta) * n.pos.rho
}
nodes_data += id + '/' + x + '/' + y + ','
}
})
// collect the unfiltered synapses
Metamaps.Synapses.each(function (synapse) {
var desc = synapse.get('desc')
var descNotFiltered = Metamaps.Filter.visible.synapses.indexOf(desc) > -1
// make sure that both topics are being added, otherwise, it
// doesn't make sense to add the synapse
var topicsNotFiltered = nodes_array.indexOf(synapse.get('node1_id')) > -1
topicsNotFiltered = topicsNotFiltered && nodes_array.indexOf(synapse.get('node2_id')) > -1
if (descNotFiltered && topicsNotFiltered) {
synapses_array.push(synapse.id)
}
})
synapses_data = synapses_array.join()
nodes_data = nodes_data.slice(0, -1)
Metamaps.GlobalUI.CreateMap.topicsToMap = nodes_data
Metamaps.GlobalUI.CreateMap.synapsesToMap = synapses_data
},
leavePrivateMap: function () {
var map = Metamaps.Active.Map
Metamaps.Maps.Active.remove(map)
Metamaps.Maps.Featured.remove(map)
Metamaps.Router.home()
Metamaps.GlobalUI.notifyUser('Sorry! That map has been changed to Private.')
},
cantEditNow: function () {
Metamaps.Realtime.turnOff(true); // true is for 'silence'
Metamaps.GlobalUI.notifyUser('Map was changed to Public. Editing is disabled.')
Metamaps.Active.Map.trigger('changeByOther')
},
canEditNow: function () {
var confirmString = "You've been granted permission to edit this map. "
confirmString += 'Do you want to reload and enable realtime collaboration?'
var c = confirm(confirmString)
if (c) {
Metamaps.Router.maps(Metamaps.Active.Map.id)
}
},
editedByActiveMapper: function () {
if (Metamaps.Active.Mapper) {
Metamaps.Mappers.add(Metamaps.Active.Mapper)
}
},
getNextCoord: function () {
var self = Metamaps.Map
var nextX = self.nextX
var nextY = self.nextY
var DISTANCE_BETWEEN = 120
self.nextX = self.nextX + DISTANCE_BETWEEN * self.nextXshift
self.nextY = self.nextY + DISTANCE_BETWEEN * self.nextYshift
self.timeToTurn += 1
// if true, it's time to turn
if (self.timeToTurn === self.sideLength) {
self.turnCount += 1
// if true, it's time to increase side length
if (self.turnCount % 2 === 0) {
self.sideLength += 1
}
self.timeToTurn = 0
// going right? turn down
if (self.nextXshift == 1 && self.nextYshift == 0) {
self.nextXshift = 0
self.nextYshift = 1
}
// going down? turn left
else if (self.nextXshift == 0 && self.nextYshift == 1) {
self.nextXshift = -1
self.nextYshift = 0
}
// going left? turn up
else if (self.nextXshift == -1 && self.nextYshift == 0) {
self.nextXshift = 0
self.nextYshift = -1
}
// going up? turn right
else if (self.nextXshift == 0 && self.nextYshift == -1) {
self.nextXshift = 1
self.nextYshift = 0
}
}
return {
x: nextX,
y: nextY
}
},
resetSpiral: function () {
Metamaps.Map.nextX = 0
Metamaps.Map.nextY = 0
Metamaps.Map.nextXshift = 1
Metamaps.Map.nextYshift = 0
Metamaps.Map.sideLength = 1
Metamaps.Map.timeToTurn = 0
Metamaps.Map.turnCount = 0
},
exportImage: function () {
var canvas = {}
canvas.canvas = document.createElement('canvas')
canvas.canvas.width = 1880 // 960
canvas.canvas.height = 1260 // 630
canvas.scaleOffsetX = 1
canvas.scaleOffsetY = 1
canvas.translateOffsetY = 0
canvas.translateOffsetX = 0
canvas.denySelected = true
canvas.getSize = function () {
if (this.size) return this.size
var canvas = this.canvas
return this.size = {
width: canvas.width,
height: canvas.height
}
}
canvas.scale = function (x, y) {
var px = this.scaleOffsetX * x,
py = this.scaleOffsetY * y
var dx = this.translateOffsetX * (x - 1) / px,
dy = this.translateOffsetY * (y - 1) / py
this.scaleOffsetX = px
this.scaleOffsetY = py
this.getCtx().scale(x, y)
this.translate(dx, dy)
}
canvas.translate = function (x, y) {
var sx = this.scaleOffsetX,
sy = this.scaleOffsetY
this.translateOffsetX += x * sx
this.translateOffsetY += y * sy
this.getCtx().translate(x, y)
}
canvas.getCtx = function () {
return this.canvas.getContext('2d')
}
// center it
canvas.getCtx().translate(1880 / 2, 1260 / 2)
var mGraph = Metamaps.Visualize.mGraph
var id = mGraph.root
var root = mGraph.graph.getNode(id)
var T = !!root.visited
// pass true to avoid basing it on a selection
Metamaps.JIT.zoomExtents(null, canvas, true)
var c = canvas.canvas,
ctx = canvas.getCtx(),
scale = canvas.scaleOffsetX
// draw a grey background
ctx.fillStyle = '#d8d9da'
var xPoint = (-(c.width / scale) / 2) - (canvas.translateOffsetX / scale),
yPoint = (-(c.height / scale) / 2) - (canvas.translateOffsetY / scale)
ctx.fillRect(xPoint, yPoint, c.width / scale, c.height / scale)
// draw the graph
mGraph.graph.eachNode(function (node) {
var nodeAlpha = node.getData('alpha')
node.eachAdjacency(function (adj) {
var nodeTo = adj.nodeTo
if (!!nodeTo.visited === T && node.drawn && nodeTo.drawn) {
mGraph.fx.plotLine(adj, canvas)
}
})
if (node.drawn) {
mGraph.fx.plotNode(node, canvas)
}
if (!mGraph.labelsHidden) {
if (node.drawn && nodeAlpha >= 0.95) {
mGraph.labels.plotLabel(canvas, node)
} else {
mGraph.labels.hideLabel(node, false)
}
}
node.visited = !T
})
var imageData = {
encoded_image: canvas.canvas.toDataURL()
}
var map = Metamaps.Active.Map
var today = new Date()
var dd = today.getDate()
var mm = today.getMonth() + 1; // January is 0!
var yyyy = today.getFullYear()
if (dd < 10) {
dd = '0' + dd
}
if (mm < 10) {
mm = '0' + mm
}
today = mm + '/' + dd + '/' + yyyy
var mapName = map.get('name').split(' ').join([separator = '-'])
var downloadMessage = ''
downloadMessage += 'Captured map screenshot! '
downloadMessage += "<a href='" + imageData.encoded_image + "' "
downloadMessage += "download='metamap-" + map.id + '-' + mapName + '-' + today + ".png'>DOWNLOAD</a>"
Metamaps.GlobalUI.notifyUser(downloadMessage)
$.ajax({
type: 'POST',
dataType: 'json',
url: '/maps/' + Metamaps.Active.Map.id + '/upload_screenshot',
data: imageData,
success: function (data) {
console.log('successfully uploaded map screenshot')
},
error: function () {
console.log('failed to save map screenshot')
}
})
}
}
/*
*
* CHEATSHEET
*
*/
Metamaps.Map.CheatSheet = {
init: function () {
// tab the cheatsheet
$('#cheatSheet').tabs()
$('#quickReference').tabs().addClass('ui-tabs-vertical ui-helper-clearfix')
$('#quickReference .ui-tabs-nav li').removeClass('ui-corner-top').addClass('ui-corner-left')
// id = the id of a vimeo video
var switchVideo = function (element, id) {
$('.tutorialItem').removeClass('active')
$(element).addClass('active')
$('#tutorialVideo').attr('src', '//player.vimeo.com/video/' + id)
}
$('#gettingStarted').click(function () {
// switchVideo(this,'88334167')
})
$('#upYourSkillz').click(function () {
// switchVideo(this,'100118167')
})
$('#advancedMapping').click(function () {
// switchVideo(this,'88334167')
})
}
}; // end Metamaps.Map.CheatSheet
/*
*
* INFOBOX
*
*/
Metamaps.Map.InfoBox = {
isOpen: false,
changing: false,
selectingPermission: false,
changePermissionText: "<div class='tooltips'>As the creator, you can change the permission of this map, and the permission of all the topics and synapses you have authority to change will change as well.</div>",
nameHTML: '<span class="best_in_place best_in_place_name" id="best_in_place_map_{{id}}_name" data-url="/maps/{{id}}" data-object="map" data-attribute="name" data-type="textarea" data-activator="#mapInfoName">{{name}}</span>',
descHTML: '<span class="best_in_place best_in_place_desc" id="best_in_place_map_{{id}}_desc" data-url="/maps/{{id}}" data-object="map" data-attribute="desc" data-nil="Click to add description..." data-type="textarea" data-activator="#mapInfoDesc">{{desc}}</span>',
init: function () {
var self = Metamaps.Map.InfoBox
$('.mapInfoIcon').click(self.toggleBox)
$('.mapInfoBox').click(function (event) {
event.stopPropagation()
})
$('body').click(self.close)
self.attachEventListeners()
self.generateBoxHTML = Hogan.compile($('#mapInfoBoxTemplate').html())
},
toggleBox: function (event) {
var self = Metamaps.Map.InfoBox
if (self.isOpen) self.close()
else self.open()
event.stopPropagation()
},
open: function () {
var self = Metamaps.Map.InfoBox
$('.mapInfoIcon div').addClass('hide')
if (!self.isOpen && !self.changing) {
self.changing = true
$('.mapInfoBox').fadeIn(200, function () {
self.changing = false
self.isOpen = true
})
}
},
close: function () {
var self = Metamaps.Map.InfoBox
$('.mapInfoIcon div').removeClass('hide')
if (!self.changing) {
self.changing = true
$('.mapInfoBox').fadeOut(200, function () {
self.changing = false
self.isOpen = false
self.hidePermissionSelect()
$('.mapContributors .tip').hide()
})
}
},
load: function () {
var self = Metamaps.Map.InfoBox
var map = Metamaps.Active.Map
var obj = map.pick('permission', 'topic_count', 'synapse_count')
var isCreator = map.authorizePermissionChange(Metamaps.Active.Mapper)
var canEdit = map.authorizeToEdit(Metamaps.Active.Mapper)
var relevantPeople = map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
var shareable = map.get('permission') !== 'private'
obj['name'] = canEdit ? Hogan.compile(self.nameHTML).render({id: map.id, name: map.get('name')}) : map.get('name')
obj['desc'] = canEdit ? Hogan.compile(self.descHTML).render({id: map.id, desc: map.get('desc')}) : map.get('desc')
obj['map_creator_tip'] = isCreator ? self.changePermissionText : ''
obj['contributor_count'] = relevantPeople.length
obj['contributors_class'] = relevantPeople.length > 1 ? 'multiple' : ''
obj['contributors_class'] += relevantPeople.length === 2 ? ' mTwo' : ''
obj['contributor_image'] = relevantPeople.length > 0 ? relevantPeople.models[0].get('image') : Metamaps.Erb['user.png']
obj['contributor_list'] = self.createContributorList()
obj['user_name'] = isCreator ? 'You' : map.get('user_name')
obj['created_at'] = map.get('created_at_clean')
obj['updated_at'] = map.get('updated_at_clean')
var classes = isCreator ? 'yourMap' : ''
classes += canEdit ? ' canEdit' : ''
classes += shareable ? ' shareable' : ''
$('.mapInfoBox').removeClass('shareable yourMap canEdit')
.addClass(classes)
.html(self.generateBoxHTML.render(obj))
self.attachEventListeners()
},
attachEventListeners: function () {
var self = Metamaps.Map.InfoBox
$('.mapInfoBox.canEdit .best_in_place').best_in_place()
// because anyone who can edit the map can change the map title
var bipName = $('.mapInfoBox .best_in_place_name')
bipName.unbind('best_in_place:activate').bind('best_in_place:activate', function () {
var $el = bipName.find('textarea')
var el = $el[0]
$el.attr('maxlength', '140')
$('.mapInfoName').append('<div class="nameCounter forMap"></div>')
var callback = function (data) {
$('.nameCounter.forMap').html(data.all + '/140')
}
Countable.live(el, callback)
})
bipName.unbind('best_in_place:deactivate').bind('best_in_place:deactivate', function () {
$('.nameCounter.forMap').remove()
})
$('.mapInfoName .best_in_place_name').unbind('ajax:success').bind('ajax:success', function () {
var name = $(this).html()
Metamaps.Active.Map.set('name', name)
Metamaps.Active.Map.trigger('saved')
})
$('.mapInfoDesc .best_in_place_desc').unbind('ajax:success').bind('ajax:success', function () {
var desc = $(this).html()
Metamaps.Active.Map.set('desc', desc)
Metamaps.Active.Map.trigger('saved')
})
$('.yourMap .mapPermission').unbind().click(self.onPermissionClick)
// .yourMap in the unbind/bind is just a namespace for the events
// not a reference to the class .yourMap on the .mapInfoBox
$('.mapInfoBox.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect)
$('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap)
$('.mapContributors span, #mapContribs').unbind().click(function (event) {
$('.mapContributors .tip').toggle()
event.stopPropagation()
})
$('.mapContributors .tip').unbind().click(function (event) {
event.stopPropagation()
})
$('.mapContributors .tip li a').click(Metamaps.Router.intercept)
$('.mapInfoBox').unbind('.hideTip').bind('click.hideTip', function () {
$('.mapContributors .tip').hide()
})
self.addTypeahead()
},
addTypeahead: function () {
var self = Metamaps.Map.InfoBox
if (!Metamaps.Active.Map) return
// for autocomplete
var collaborators = {
name: 'collaborators',
limit: 9999,
display: function(s) { return s.label; },
templates: {
notFound: function(s) {
return Hogan.compile($('#collaboratorSearchTemplate').html()).render({
value: "No results",
label: "No results",
rtype: "noresult",
profile: Metamaps.Erb['user.png'],
});
},
suggestion: function(s) {
return Hogan.compile($('#collaboratorSearchTemplate').html()).render(s);
},
},
source: new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/search/mappers?term=%QUERY',
wildcard: '%QUERY',
},
})
}
// for adding map collaborators, who will have edit rights
if (Metamaps.Active.Mapper && Metamaps.Active.Mapper.id === Metamaps.Active.Map.get('user_id')) {
$('.collaboratorSearchField').typeahead(
{
highlight: false,
},
[collaborators]
)
$('.collaboratorSearchField').bind('typeahead:select', self.handleResultClick)
$('.mapContributors .removeCollaborator').click(function () {
self.removeCollaborator(parseInt($(this).data('id')))
})
}
},
removeCollaborator: function (collaboratorId) {
var self = Metamaps.Map.InfoBox
Metamaps.Collaborators.remove(Metamaps.Collaborators.get(collaboratorId))
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
$.post('/maps/' + Metamaps.Active.Map.id + '/access', { access: mapperIds })
self.updateNumbers()
},
addCollaborator: function (newCollaboratorId) {
var self = Metamaps.Map.InfoBox
if (Metamaps.Collaborators.get(newCollaboratorId)) {
Metamaps.GlobalUI.notifyUser('That user already has access')
return
}
function callback(mapper) {
Metamaps.Collaborators.add(mapper)
var mapperIds = Metamaps.Collaborators.models.map(function (mapper) { return mapper.id })
$.post('/maps/' + Metamaps.Active.Map.id + '/access', { access: mapperIds })
var name = Metamaps.Collaborators.get(newCollaboratorId).get('name')
Metamaps.GlobalUI.notifyUser(name + ' will be notified by email')
self.updateNumbers()
}
$.getJSON('/users/' + newCollaboratorId + '.json', callback)
},
handleResultClick: function (event, item) {
var self = Metamaps.Map.InfoBox
self.addCollaborator(item.id)
$('.collaboratorSearchField').typeahead('val', '')
},
updateNameDescPerm: function (name, desc, perm) {
$('.mapInfoName .best_in_place_name').html(name)
$('.mapInfoDesc .best_in_place_desc').html(desc)
$('.mapInfoBox .mapPermission').removeClass('commons public private').addClass(perm)
},
createContributorList: function () {
var self = Metamaps.Map.InfoBox
var relevantPeople = Metamaps.Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
var activeMapperIsCreator = Metamaps.Active.Mapper && Metamaps.Active.Mapper.id === Metamaps.Active.Map.get('user_id')
var string = ''
string += '<ul>'
relevantPeople.each(function (m) {
var isCreator = Metamaps.Active.Map.get('user_id') === m.get('id')
string += '<li><a href="/explore/mapper/' + m.get('id') + '">' + '<img class="rtUserImage" width="25" height="25" src="' + m.get('image') + '" />' + m.get('name')
if (isCreator) string += ' (creator)'
string += '</a>'
if (activeMapperIsCreator && !isCreator) string += '<span class="removeCollaborator" data-id="' + m.get('id') + '"></span>'
string += '</li>'
})
string += '</ul>'
if (activeMapperIsCreator) {
string += '<div class="collabSearchField"><span class="addCollab"></span><input class="collaboratorSearchField" placeholder="Add a collaborator!"></input></div>'
}
return string
},
updateNumbers: function () {
var self = Metamaps.Map.InfoBox
var mapper = Metamaps.Active.Mapper
var relevantPeople = Metamaps.Active.Map.get('permission') === 'commons' ? Metamaps.Mappers : Metamaps.Collaborators
var contributors_class = ''
if (relevantPeople.length === 2) contributors_class = 'multiple mTwo'
else if (relevantPeople.length > 2) contributors_class = 'multiple'
var contributors_image = Metamaps.Erb['user.png']
if (relevantPeople.length > 0) {
// get the first contributor and use their image
contributors_image = relevantPeople.models[0].get('image')
}
$('.mapContributors img').attr('src', contributors_image).removeClass('multiple mTwo').addClass(contributors_class)
$('.mapContributors span').text(relevantPeople.length)
$('.mapContributors .tip').html(self.createContributorList())
self.addTypeahead()
$('.mapContributors .tip').unbind().click(function (event) {
event.stopPropagation()
})
$('.mapTopics').text(Metamaps.Topics.length)
$('.mapSynapses').text(Metamaps.Synapses.length)
$('.mapEditedAt').html('<span>Last edited: </span>' + Metamaps.Util.nowDateFormatted())
},
onPermissionClick: function (event) {
var self = Metamaps.Map.InfoBox
if (!self.selectingPermission) {
self.selectingPermission = true
$(this).addClass('minimize') // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('commons')) {
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('public')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('private')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
}
$('.mapPermission .permissionSelect li').click(self.selectPermission)
event.stopPropagation()
}
},
hidePermissionSelect: function () {
var self = Metamaps.Map.InfoBox
self.selectingPermission = false
$('.mapPermission').removeClass('minimize') // this line flips the pull up arrow to a drop down arrow
$('.mapPermission .permissionSelect').remove()
},
selectPermission: function (event) {
var self = Metamaps.Map.InfoBox
self.selectingPermission = false
var permission = $(this).attr('class')
Metamaps.Active.Map.save({
permission: permission
})
Metamaps.Active.Map.updateMapWrapper()
shareable = permission === 'private' ? '' : 'shareable'
$('.mapPermission').removeClass('commons public private minimize').addClass(permission)
$('.mapPermission .permissionSelect').remove()
$('.mapInfoBox').removeClass('shareable').addClass(shareable)
event.stopPropagation()
},
deleteActiveMap: function () {
var confirmString = 'Are you sure you want to delete this map? '
confirmString += 'This action is irreversible. It will not delete the topics and synapses on the map.'
var doIt = confirm(confirmString)
var map = Metamaps.Active.Map
var mapper = Metamaps.Active.Mapper
var authorized = map.authorizePermissionChange(mapper)
if (doIt && authorized) {
Metamaps.Map.InfoBox.close()
Metamaps.Maps.Active.remove(map)
Metamaps.Maps.Featured.remove(map)
Metamaps.Maps.Mine.remove(map)
Metamaps.Maps.Shared.remove(map)
map.destroy()
Metamaps.Router.home()
Metamaps.GlobalUI.notifyUser('Map eliminated!')
}
else if (!authorized) {
alert("Hey now. We can't just go around willy nilly deleting other people's maps now can we? Run off and find something constructive to do, eh?")
}
}
}; // end Metamaps.Map.InfoBox

View file

@ -1,20 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Mapper.js.erb
*
* Dependencies: none!
*/
Metamaps.Mapper = {
// this function is to retrieve a mapper JSON object from the database
// @param id = the id of the mapper to retrieve
get: function (id, callback) {
return $.ajax({
url: '/users/' + id + '.json',
success: function (data) {
callback(new Metamaps.Backbone.Mapper(data))
}
})
}
}; // end Metamaps.Mapper

View file

@ -1,117 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Organize.js.erb
*
* Dependencies:
* - Metamaps.Visualize
*/
Metamaps.Organize = {
init: function () {},
arrange: function (layout, centerNode) {
// first option for layout to implement is 'grid', will do an evenly spaced grid with its center at the 0,0 origin
if (layout == 'grid') {
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes); // this will always be an integer, the # of nodes on your graph visualization
var numColumns = Math.floor(Math.sqrt(numNodes)) // the number of columns to make an even grid
var GRIDSPACE = 400
var row = 0
var column = 0
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (column == numColumns) {
column = 0
row += 1
}
var newPos = new $jit.Complex()
newPos.x = column * GRIDSPACE
newPos.y = row * GRIDSPACE
n.setPos(newPos, 'end')
column += 1
})
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
} else if (layout == 'grid_full') {
// this will always be an integer, the # of nodes on your graph visualization
var numNodes = _.size(Metamaps.Visualize.mGraph.graph.nodes)
// var numColumns = Math.floor(Math.sqrt(numNodes)) // the number of columns to make an even grid
// var GRIDSPACE = 400
var height = Metamaps.Visualize.mGraph.canvas.getSize(0).height
var width = Metamaps.Visualize.mGraph.canvas.getSize(0).width
var totalArea = height * width
var cellArea = totalArea / numNodes
var ratio = height / width
var cellWidth = sqrt(cellArea / ratio)
var cellHeight = cellArea / cellWidth
var row = floor(height / cellHeight)
var column = floor(width / cellWidth)
var totalCells = row * column
if (totalCells)
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (column == numColumns) {
column = 0
row += 1
}
var newPos = new $jit.Complex()
newPos.x = column * GRIDSPACE
newPos.y = row * GRIDSPACE
n.setPos(newPos, 'end')
column += 1
})
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
} else if (layout == 'radial') {
var centerX = centerNode.getPos().x
var centerY = centerNode.getPos().y
centerNode.setPos(centerNode.getPos(), 'end')
console.log(centerNode.adjacencies)
var lineLength = 200
var usedNodes = {}
usedNodes[centerNode.id] = centerNode
var radial = function (node, level, degree) {
if (level == 1) {
var numLinksTemp = _.size(node.adjacencies)
var angleTemp = 2 * Math.PI / numLinksTemp
} else {
angleTemp = 2 * Math.PI / 20
}
node.eachAdjacency(function (a) {
var isSecondLevelNode = (centerNode.adjacencies[a.nodeTo.id] != undefined && level > 1)
if (usedNodes[a.nodeTo.id] == undefined && !isSecondLevelNode) {
var newPos = new $jit.Complex()
newPos.x = level * lineLength * Math.sin(degree) + centerX
newPos.y = level * lineLength * Math.cos(degree) + centerY
a.nodeTo.setPos(newPos, 'end')
usedNodes[a.nodeTo.id] = a.nodeTo
radial(a.nodeTo, level + 1, degree)
degree += angleTemp
}
})
}
radial(centerNode, 1, 0)
Metamaps.Visualize.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
} else if (layout == 'center_viewport') {
var lowX = 0,
lowY = 0,
highX = 0,
highY = 0
var oldOriginX = Metamaps.Visualize.mGraph.canvas.translateOffsetX
var oldOriginY = Metamaps.Visualize.mGraph.canvas.translateOffsetY
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
if (n.id === 1) {
lowX = n.getPos().x
lowY = n.getPos().y
highX = n.getPos().x
highY = n.getPos().y
}
if (n.getPos().x < lowX) lowX = n.getPos().x
if (n.getPos().y < lowY) lowY = n.getPos().y
if (n.getPos().x > highX) highX = n.getPos().x
if (n.getPos().y > highY) highY = n.getPos().y
})
console.log(lowX, lowY, highX, highY)
var newOriginX = (lowX + highX) / 2
var newOriginY = (lowY + highY) / 2
} else alert('please call function with a valid layout dammit!')
}
}; // end Metamaps.Organize

File diff suppressed because it is too large Load diff

View file

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

View file

@ -1,169 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Synapse.js.erb
*
* Dependencies:
* - Metamaps.Backbone
* - Metamaps.Control
* - Metamaps.Create
* - Metamaps.JIT
* - Metamaps.Map
* - Metamaps.Mappings
* - Metamaps.Selected
* - Metamaps.Settings
* - Metamaps.Synapses
* - Metamaps.Topics
* - Metamaps.Visualize
*/
Metamaps.Synapse = {
// this function is to retrieve a synapse JSON object from the database
// @param id = the id of the synapse to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Synapses.get(id) == undefined) {
if (!callback) {
var e = $.ajax({
url: '/synapses/' + id + '.json',
async: false
})
Metamaps.Synapses.add($.parseJSON(e.responseText))
return Metamaps.Synapses.get(id)
} else {
return $.ajax({
url: '/synapses/' + id + '.json',
success: function (data) {
Metamaps.Synapses.add(data)
callback(Metamaps.Synapses.get(id))
}
})
}
} else {
if (!callback) {
return Metamaps.Synapses.get(id)
} else {
return callback(Metamaps.Synapses.get(id))
}
}
},
/*
*
*
*/
renderSynapse: function (mapping, synapse, node1, node2, createNewInDB) {
var self = Metamaps.Synapse
var edgeOnViz
var newedge = synapse.createEdge(mapping)
Metamaps.Visualize.mGraph.graph.addAdjacence(node1, node2, newedge.data)
edgeOnViz = Metamaps.Visualize.mGraph.graph.getAdjacence(node1.id, node2.id)
synapse.set('edge', edgeOnViz)
synapse.updateEdge() // links the synapse and the mapping to the edge
Metamaps.Control.selectEdge(edgeOnViz)
var mappingSuccessCallback = function (mappingModel, response) {
var newSynapseData = {
mappingid: mappingModel.id,
mappableid: mappingModel.get('mappable_id')
}
$(document).trigger(Metamaps.JIT.events.newSynapse, [newSynapseData])
}
var synapseSuccessCallback = function (synapseModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ mappable_id: synapseModel.id }, {
success: mappingSuccessCallback
})
}
}
if (!Metamaps.Settings.sandbox && createNewInDB) {
if (synapse.isNew()) {
synapse.save(null, {
success: synapseSuccessCallback,
error: function (model, response) {
console.log('error saving synapse to database')
}
})
} else if (!synapse.isNew() && Metamaps.Active.Map) {
mapping.save(null, {
success: mappingSuccessCallback
})
}
}
},
createSynapseLocally: function () {
var self = Metamaps.Synapse,
topic1,
topic2,
node1,
node2,
synapse,
mapping
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
// for each node in this array we will create a synapse going to the position2 node.
var synapsesToCreate = []
topic2 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic2id)
node2 = topic2.get('node')
var len = Metamaps.Selected.Nodes.length
if (len == 0) {
topic1 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic1id)
synapsesToCreate[0] = topic1.get('node')
} else if (len > 0) {
synapsesToCreate = Metamaps.Selected.Nodes
}
for (var i = 0; i < synapsesToCreate.length; i++) {
node1 = synapsesToCreate[i]
topic1 = node1.getData('topic')
synapse = new Metamaps.Backbone.Synapse({
desc: Metamaps.Create.newSynapse.description,
node1_id: topic1.isNew() ? topic1.cid : topic1.id,
node2_id: topic2.isNew() ? topic2.cid : topic2.id,
})
Metamaps.Synapses.add(synapse)
mapping = new Metamaps.Backbone.Mapping({
mappable_type: 'Synapse',
mappable_id: synapse.cid,
})
Metamaps.Mappings.add(mapping)
// this function also includes the creation of the synapse in the database
self.renderSynapse(mapping, synapse, node1, node2, true)
} // for each in synapsesToCreate
Metamaps.Create.newSynapse.hide()
},
getSynapseFromAutocomplete: function (id) {
var self = Metamaps.Synapse,
topic1,
topic2,
node1,
node2
var synapse = self.get(id)
var mapping = new Metamaps.Backbone.Mapping({
mappable_type: 'Synapse',
mappable_id: synapse.id,
})
Metamaps.Mappings.add(mapping)
topic1 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic1id)
node1 = topic1.get('node')
topic2 = Metamaps.Topics.get(Metamaps.Create.newSynapse.topic2id)
node2 = topic2.get('node')
Metamaps.Create.newSynapse.hide()
self.renderSynapse(mapping, synapse, node1, node2, true)
}
}; // end Metamaps.Synapse

View file

@ -1,363 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Topic.js.erb
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.Backbone
* - Metamaps.Backbone
* - Metamaps.Create
* - Metamaps.Creators
* - Metamaps.Famous
* - Metamaps.Filter
* - Metamaps.GlobalUI
* - Metamaps.JIT
* - Metamaps.Mappings
* - Metamaps.Selected
* - Metamaps.Settings
* - Metamaps.SynapseCard
* - Metamaps.Synapses
* - Metamaps.TopicCard
* - Metamaps.Topics
* - Metamaps.Util
* - Metamaps.Visualize
* - Metamaps.tempInit
* - Metamaps.tempNode
* - Metamaps.tempNode2
*/
Metamaps.Topic = {
// this function is to retrieve a topic JSON object from the database
// @param id = the id of the topic to retrieve
get: function (id, callback) {
// if the desired topic is not yet in the local topic repository, fetch it
if (Metamaps.Topics.get(id) == undefined) {
// console.log("Ajax call!")
if (!callback) {
var e = $.ajax({
url: '/topics/' + id + '.json',
async: false
})
Metamaps.Topics.add($.parseJSON(e.responseText))
return Metamaps.Topics.get(id)
} else {
return $.ajax({
url: '/topics/' + id + '.json',
success: function (data) {
Metamaps.Topics.add(data)
callback(Metamaps.Topics.get(id))
}
})
}
} else {
if (!callback) {
return Metamaps.Topics.get(id)
} else {
return callback(Metamaps.Topics.get(id))
}
}
},
launch: function (id) {
var bb = Metamaps.Backbone
var start = function (data) {
Metamaps.Active.Topic = new bb.Topic(data.topic)
Metamaps.Creators = new bb.MapperCollection(data.creators)
Metamaps.Topics = new bb.TopicCollection([data.topic].concat(data.relatives))
Metamaps.Synapses = new bb.SynapseCollection(data.synapses)
Metamaps.Backbone.attachCollectionEvents()
// set filter mapper H3 text
$('#filter_by_mapper h3').html('CREATORS')
// build and render the visualization
Metamaps.Visualize.type = 'RGraph'
Metamaps.JIT.prepareVizData()
// update filters
Metamaps.Filter.reset()
// reset selected arrays
Metamaps.Selected.reset()
// these three update the actual filter box with the right list items
Metamaps.Filter.checkMetacodes()
Metamaps.Filter.checkSynapses()
Metamaps.Filter.checkMappers()
}
$.ajax({
url: '/topics/' + id + '/network.json',
success: start
})
},
end: function () {
if (Metamaps.Active.Topic) {
$('.rightclickmenu').remove()
Metamaps.TopicCard.hideCard()
Metamaps.SynapseCard.hideCard()
Metamaps.Filter.close()
}
},
centerOn: function (nodeid) {
if (!Metamaps.Visualize.mGraph.busy) {
Metamaps.Visualize.mGraph.onClick(nodeid, {
hideLabels: false,
duration: 1000,
onComplete: function () {}
})
}
},
fetchRelatives: function (node, metacode_id) {
var topics = Metamaps.Topics.map(function (t) { return t.id })
var topics_string = topics.join()
var creators = Metamaps.Creators.map(function (t) { return t.id })
var creators_string = creators.join()
var topic = node.getData('topic')
var successCallback = function (data) {
if (data.creators.length > 0) Metamaps.Creators.add(data.creators)
if (data.topics.length > 0) Metamaps.Topics.add(data.topics)
if (data.synapses.length > 0) Metamaps.Synapses.add(data.synapses)
var topicColl = new Metamaps.Backbone.TopicCollection(data.topics)
topicColl.add(topic)
var synapseColl = new Metamaps.Backbone.SynapseCollection(data.synapses)
var graph = Metamaps.JIT.convertModelsToJIT(topicColl, synapseColl)[0]
Metamaps.Visualize.mGraph.op.sum(graph, {
type: 'fade',
duration: 500,
hideLabels: false
})
var i, l, t, s
Metamaps.Visualize.mGraph.graph.eachNode(function (n) {
t = Metamaps.Topics.get(n.id)
t.set({ node: n }, { silent: true })
t.updateNode()
n.eachAdjacency(function (edge) {
if (!edge.getData('init')) {
edge.setData('init', true)
l = edge.getData('synapseIDs').length
for (i = 0; i < l; i++) {
s = Metamaps.Synapses.get(edge.getData('synapseIDs')[i])
s.set({ edge: edge }, { silent: true })
s.updateEdge()
}
}
})
})
}
var paramsString = metacode_id ? 'metacode=' + metacode_id + '&' : ''
paramsString += 'network=' + topics_string + '&creators=' + creators_string
$.ajax({
type: 'Get',
url: '/topics/' + topic.id + '/relatives.json?' + paramsString,
success: successCallback,
error: function () {}
})
},
/*
*
*
*/
renderTopic: function (mapping, topic, createNewInDB, permitCreateSynapseAfter) {
var self = Metamaps.Topic
var nodeOnViz, tempPos
var newnode = topic.createNode()
var midpoint = {}, pixelPos
if (!$.isEmptyObject(Metamaps.Visualize.mGraph.graph.nodes)) {
Metamaps.Visualize.mGraph.graph.addNode(newnode)
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id)
topic.set('node', nodeOnViz, {silent: true})
topic.updateNode() // links the topic and the mapping to the node
nodeOnViz.setData('dim', 1, 'start')
nodeOnViz.setData('dim', 25, 'end')
if (Metamaps.Visualize.type === 'RGraph') {
tempPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
tempPos = tempPos.toPolar()
nodeOnViz.setPos(tempPos, 'current')
nodeOnViz.setPos(tempPos, 'start')
nodeOnViz.setPos(tempPos, 'end')
} else if (Metamaps.Visualize.type === 'ForceDirected') {
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'end')
}
if (Metamaps.Create.newTopic.addSynapse && permitCreateSynapseAfter) {
Metamaps.Create.newSynapse.topic1id = Metamaps.tempNode.getData('topic').id
// position the form
midpoint.x = Metamaps.tempNode.pos.getc().x + (nodeOnViz.pos.getc().x - Metamaps.tempNode.pos.getc().x) / 2
midpoint.y = Metamaps.tempNode.pos.getc().y + (nodeOnViz.pos.getc().y - Metamaps.tempNode.pos.getc().y) / 2
pixelPos = Metamaps.Util.coordsToPixels(midpoint)
$('#new_synapse').css('left', pixelPos.x + 'px')
$('#new_synapse').css('top', pixelPos.y + 'px')
// show the form
Metamaps.Create.newSynapse.open()
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function () {
Metamaps.tempNode = null
Metamaps.tempNode2 = null
Metamaps.tempInit = false
}
})
} else {
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas)
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function () {}
})
}
} else {
Metamaps.Visualize.mGraph.loadJSON(newnode)
nodeOnViz = Metamaps.Visualize.mGraph.graph.getNode(newnode.id)
topic.set('node', nodeOnViz, {silent: true})
topic.updateNode() // links the topic and the mapping to the node
nodeOnViz.setData('dim', 1, 'start')
nodeOnViz.setData('dim', 25, 'end')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'current')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'start')
nodeOnViz.setPos(new $jit.Complex(mapping.get('xloc'), mapping.get('yloc')), 'end')
Metamaps.Visualize.mGraph.fx.plotNode(nodeOnViz, Metamaps.Visualize.mGraph.canvas)
Metamaps.Visualize.mGraph.fx.animate({
modes: ['node-property:dim'],
duration: 500,
onComplete: function () {}
})
}
var mappingSuccessCallback = function (mappingModel, response) {
var newTopicData = {
mappingid: mappingModel.id,
mappableid: mappingModel.get('mappable_id')
}
$(document).trigger(Metamaps.JIT.events.newTopic, [newTopicData])
}
var topicSuccessCallback = function (topicModel, response) {
if (Metamaps.Active.Map) {
mapping.save({ mappable_id: topicModel.id }, {
success: mappingSuccessCallback,
error: function (model, response) {
console.log('error saving mapping to database')
}
})
}
if (Metamaps.Create.newTopic.addSynapse) {
Metamaps.Create.newSynapse.topic2id = topicModel.id
}
}
if (!Metamaps.Settings.sandbox && createNewInDB) {
if (topic.isNew()) {
topic.save(null, {
success: topicSuccessCallback,
error: function (model, response) {
console.log('error saving topic to database')
}
})
} else if (!topic.isNew() && Metamaps.Active.Map) {
mapping.save(null, {
success: mappingSuccessCallback
})
}
}
},
createTopicLocally: function () {
var self = Metamaps.Topic
if (Metamaps.Create.newTopic.name === '') {
Metamaps.GlobalUI.notifyUser('Please enter a topic title...')
return
}
// hide the 'double-click to add a topic' message
Metamaps.Famous.viz.hideInstructions()
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
var metacode = Metamaps.Metacodes.get(Metamaps.Create.newTopic.metacode)
var topic = new Metamaps.Backbone.Topic({
name: Metamaps.Create.newTopic.name,
metacode_id: metacode.id,
defer_to_map_id: Metamaps.Active.Map.id
})
Metamaps.Topics.add(topic)
var mapping = new Metamaps.Backbone.Mapping({
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
mappable_id: topic.cid,
mappable_type: 'Topic',
})
Metamaps.Mappings.add(mapping)
// these can't happen until the value is retrieved, which happens in the line above
Metamaps.Create.newTopic.hide()
self.renderTopic(mapping, topic, true, true) // this function also includes the creation of the topic in the database
},
getTopicFromAutocomplete: function (id) {
var self = Metamaps.Topic
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
Metamaps.Create.newTopic.hide()
var topic = self.get(id)
var mapping = new Metamaps.Backbone.Mapping({
xloc: Metamaps.Create.newTopic.x,
yloc: Metamaps.Create.newTopic.y,
mappable_type: 'Topic',
mappable_id: topic.id,
})
Metamaps.Mappings.add(mapping)
self.renderTopic(mapping, topic, true, true)
},
getTopicFromSearch: function (event, id) {
var self = Metamaps.Topic
$(document).trigger(Metamaps.Map.events.editedByActiveMapper)
var topic = self.get(id)
var nextCoords = Metamaps.Map.getNextCoord()
var mapping = new Metamaps.Backbone.Mapping({
xloc: nextCoords.x,
yloc: nextCoords.y,
mappable_type: 'Topic',
mappable_id: topic.id,
})
Metamaps.Mappings.add(mapping)
self.renderTopic(mapping, topic, true, true)
Metamaps.GlobalUI.notifyUser('Topic was added to your map!')
event.stopPropagation()
event.preventDefault()
return false
}
}; // end Metamaps.Topic

View file

@ -1,451 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.TopicCard.js
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.GlobalUI
* - Metamaps.Mapper
* - Metamaps.Metacodes
* - Metamaps.Router
* - Metamaps.Util
* - Metamaps.Visualize
*/
Metamaps.TopicCard = {
openTopicCard: null, // stores the topic that's currently open
authorizedToEdit: false, // stores boolean for edit permission for open topic card
init: function () {
var self = Metamaps.TopicCard
// initialize best_in_place editing
$('.authenticated div.permission.canEdit .best_in_place').best_in_place()
Metamaps.TopicCard.generateShowcardHTML = Hogan.compile($('#topicCardTemplate').html())
// initialize topic card draggability and resizability
$('.showcard').draggable({
handle: '.metacodeImage'
})
embedly('on', 'card.rendered', self.embedlyCardRendered)
},
/**
* Will open the Topic Card for the node that it's passed
* @param {$jit.Graph.Node} node
*/
showCard: function (node) {
var self = Metamaps.TopicCard
var topic = node.getData('topic')
self.openTopicCard = topic
self.authorizedToEdit = topic.authorizeToEdit(Metamaps.Active.Mapper)
// populate the card that's about to show with the right topics data
self.populateShowCard(topic)
$('.showcard').fadeIn('fast')
},
hideCard: function () {
var self = Metamaps.TopicCard
$('.showcard').fadeOut('fast')
self.openTopicCard = null
self.authorizedToEdit = false
},
embedlyCardRendered: function (iframe) {
var self = Metamaps.TopicCard
$('#embedlyLinkLoader').hide()
// means that the embedly call returned 404 not found
if ($('#embedlyLink')[0]) {
$('#embedlyLink').css('display', 'block').fadeIn('fast')
$('.embeds').addClass('nonEmbedlyLink')
}
$('.CardOnGraph').addClass('hasAttachment')
if (self.authorizedToEdit) {
$('.embeds').append('<div id="linkremove"></div>')
$('#linkremove').click(self.removeLink)
}
},
removeLink: function () {
var self = Metamaps.TopicCard
self.openTopicCard.save({
link: null
})
$('.embeds').empty().removeClass('nonEmbedlyLink')
$('#addLinkInput input').val('')
$('.attachments').removeClass('hidden')
$('.CardOnGraph').removeClass('hasAttachment')
},
bindShowCardListeners: function (topic) {
var self = Metamaps.TopicCard
var showCard = document.getElementById('showcard')
var authorized = self.authorizedToEdit
// get mapper image
var setMapperImage = function (mapper) {
$('.contributorIcon').attr('src', mapper.get('image'))
}
Metamaps.Mapper.get(topic.get('user_id'), setMapperImage)
// starting embed.ly
var resetFunc = function () {
$('#addLinkInput input').val('')
$('#addLinkInput input').focus()
}
var inputEmbedFunc = function (event) {
var element = this
setTimeout(function () {
var text = $(element).val()
if (event.type == 'paste' || (event.type == 'keyup' && event.which == 13)) {
// TODO evaluate converting this to '//' no matter what (infer protocol)
if (text.slice(0, 7) !== 'http://' &&
text.slice(0, 8) !== 'https://' &&
text.slice(0, 2) !== '//') {
text = '//' + text
}
topic.save({
link: text
})
var embedlyEl = $('<a/>', {
id: 'embedlyLink',
'data-card-description': '0',
href: text
}).html(text)
$('.attachments').addClass('hidden')
$('.embeds').append(embedlyEl)
$('.embeds').append('<div id="embedlyLinkLoader"></div>')
var loader = new CanvasLoader('embedlyLinkLoader')
loader.setColor('#4fb5c0'); // default is '#000000'
loader.setDiameter(28) // default is 40
loader.setDensity(41) // default is 40
loader.setRange(0.9); // default is 1.3
loader.show() // Hidden by default
var e = embedly('card', document.getElementById('embedlyLink'))
if (!e) {
self.handleInvalidLink()
}
}
}, 100)
}
$('#addLinkReset').click(resetFunc)
$('#addLinkInput input').bind('paste keyup', inputEmbedFunc)
// initialize the link card, if there is a link
if (topic.get('link') && topic.get('link') !== '') {
var loader = new CanvasLoader('embedlyLinkLoader')
loader.setColor('#4fb5c0'); // default is '#000000'
loader.setDiameter(28) // default is 40
loader.setDensity(41) // default is 40
loader.setRange(0.9); // default is 1.3
loader.show() // Hidden by default
var e = embedly('card', document.getElementById('embedlyLink'))
if (!e) {
self.handleInvalidLink()
}
}
var selectingMetacode = false
// attach the listener that shows the metacode title when you hover over the image
$('.showcard .metacodeImage').mouseenter(function () {
$('.showcard .icon').css('z-index', '4')
$('.showcard .metacodeTitle').show()
})
$('.showcard .linkItem.icon').mouseleave(function () {
if (!selectingMetacode) {
$('.showcard .metacodeTitle').hide()
$('.showcard .icon').css('z-index', '1')
}
})
var metacodeLiClick = function () {
selectingMetacode = false
var metacodeId = parseInt($(this).attr('data-id'))
var metacode = Metamaps.Metacodes.get(metacodeId)
$('.CardOnGraph').find('.metacodeTitle').html(metacode.get('name'))
.append('<div class="expandMetacodeSelect"></div>')
.attr('class', 'metacodeTitle mbg' + metacode.id)
$('.CardOnGraph').find('.metacodeImage').css('background-image', 'url(' + metacode.get('icon') + ')')
topic.save({
metacode_id: metacode.id
})
Metamaps.Visualize.mGraph.plot()
$('.metacodeSelect').hide().removeClass('onRightEdge onBottomEdge')
$('.metacodeTitle').hide()
$('.showcard .icon').css('z-index', '1')
}
var openMetacodeSelect = function (event) {
var windowWidth
var showcardLeft
var TOPICCARD_WIDTH = 300
var METACODESELECT_WIDTH = 404
var distanceFromEdge
var MAX_METACODELIST_HEIGHT = 270
var windowHeight
var showcardTop
var topicTitleHeight
var distanceFromBottom
if (!selectingMetacode) {
selectingMetacode = true
// this is to make sure the metacode
// select is accessible onscreen, when opened
// while topic card is close to the right
// edge of the screen
windowWidth = $(window).width()
showcardLeft = parseInt($('.showcard').css('left'))
distanceFromEdge = windowWidth - (showcardLeft + TOPICCARD_WIDTH)
if (distanceFromEdge < METACODESELECT_WIDTH) {
$('.metacodeSelect').addClass('onRightEdge')
}
// this is to make sure the metacode
// select is accessible onscreen, when opened
// while topic card is close to the bottom
// edge of the screen
windowHeight = $(window).height()
showcardTop = parseInt($('.showcard').css('top'))
topicTitleHeight = $('.showcard .title').height() + parseInt($('.showcard .title').css('padding-top')) + parseInt($('.showcard .title').css('padding-bottom'))
heightOfSetList = $('.showcard .metacodeSelect').height()
distanceFromBottom = windowHeight - (showcardTop + topicTitleHeight)
if (distanceFromBottom < MAX_METACODELIST_HEIGHT) {
$('.metacodeSelect').addClass('onBottomEdge')
}
$('.metacodeSelect').show()
event.stopPropagation()
}
}
var hideMetacodeSelect = function () {
selectingMetacode = false
$('.metacodeSelect').hide().removeClass('onRightEdge onBottomEdge')
$('.metacodeTitle').hide()
$('.showcard .icon').css('z-index', '1')
}
if (authorized) {
$('.showcard .metacodeTitle').click(openMetacodeSelect)
$('.showcard').click(hideMetacodeSelect)
$('.metacodeSelect > ul > li').click(function (event) {
event.stopPropagation()
})
$('.metacodeSelect li li').click(metacodeLiClick)
var bipName = $(showCard).find('.best_in_place_name')
bipName.bind('best_in_place:activate', function () {
var $el = bipName.find('textarea')
var el = $el[0]
$el.attr('maxlength', '140')
$('.showcard .title').append('<div class="nameCounter forTopic"></div>')
var callback = function (data) {
$('.nameCounter.forTopic').html(data.all + '/140')
}
Countable.live(el, callback)
})
bipName.bind('best_in_place:deactivate', function () {
$('.nameCounter.forTopic').remove()
})
// bind best_in_place ajax callbacks
bipName.bind('ajax:success', function () {
var name = Metamaps.Util.decodeEntities($(this).html())
topic.set('name', name)
topic.trigger('saved')
})
$(showCard).find('.best_in_place_desc').bind('ajax:success', function () {
this.innerHTML = this.innerHTML.replace(/\r/g, '')
var desc = $(this).html() === $(this).data('nil') ? '' : $(this).html()
topic.set('desc', desc)
topic.trigger('saved')
})
}
var permissionLiClick = function (event) {
selectingPermission = false
var permission = $(this).attr('class')
topic.save({
permission: permission,
defer_to_map_id: null
})
$('.showcard .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2))
$('.showcard .permissionSelect').remove()
event.stopPropagation()
}
var openPermissionSelect = function (event) {
if (!selectingPermission) {
selectingPermission = true
$(this).addClass('minimize') // this line flips the drop down arrow to a pull up arrow
if ($(this).hasClass('co')) {
$(this).append('<ul class="permissionSelect"><li class="public"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('pu')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="private"></li></ul>')
} else if ($(this).hasClass('pr')) {
$(this).append('<ul class="permissionSelect"><li class="commons"></li><li class="public"></li></ul>')
}
$('.showcard .permissionSelect li').click(permissionLiClick)
event.stopPropagation()
}
}
var hidePermissionSelect = function () {
selectingPermission = false
$('.showcard .yourTopic .mapPerm').removeClass('minimize') // this line flips the pull up arrow to a drop down arrow
$('.showcard .permissionSelect').remove()
}
// ability to change permission
var selectingPermission = false
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) {
$('.showcard .yourTopic .mapPerm').click(openPermissionSelect)
$('.showcard').click(hidePermissionSelect)
}
$('.links .mapCount').unbind().click(function (event) {
$('.mapCount .tip').toggle()
$('.showcard .hoverTip').toggleClass('hide')
event.stopPropagation()
})
$('.mapCount .tip').unbind().click(function (event) {
event.stopPropagation()
})
$('.showcard').unbind('.hideTip').bind('click.hideTip', function () {
$('.mapCount .tip').hide()
$('.showcard .hoverTip').removeClass('hide')
})
$('.mapCount .tip li a').click(Metamaps.Router.intercept)
var originalText = $('.showMore').html()
$('.mapCount .tip .showMore').unbind().toggle(
function (event) {
$('.extraText').toggleClass('hideExtra')
$('.showMore').html('Show less...')
},
function (event) {
$('.extraText').toggleClass('hideExtra')
$('.showMore').html(originalText)
})
$('.mapCount .tip showMore').unbind().click(function (event) {
event.stopPropagation()
})
},
handleInvalidLink: function () {
var self = Metamaps.TopicCard
self.removeLink()
Metamaps.GlobalUI.notifyUser('Invalid link')
},
populateShowCard: function (topic) {
var self = Metamaps.TopicCard
var showCard = document.getElementById('showcard')
$(showCard).find('.permission').remove()
var topicForTemplate = self.buildObject(topic)
var html = self.generateShowcardHTML.render(topicForTemplate)
if (topic.authorizeToEdit(Metamaps.Active.Mapper)) {
var perm = document.createElement('div')
var string = 'permission canEdit'
if (topic.authorizePermissionChange(Metamaps.Active.Mapper)) string += ' yourTopic'
perm.className = string
perm.innerHTML = html
showCard.appendChild(perm)
} else {
var perm = document.createElement('div')
perm.className = 'permission cannotEdit'
perm.innerHTML = html
showCard.appendChild(perm)
}
Metamaps.TopicCard.bindShowCardListeners(topic)
},
generateShowcardHTML: null, // will be initialized into a Hogan template within init function
// generateShowcardHTML
buildObject: function (topic) {
var self = Metamaps.TopicCard
var nodeValues = {}
var authorized = topic.authorizeToEdit(Metamaps.Active.Mapper)
if (!authorized) {
} else {
}
var desc_nil = 'Click to add description...'
nodeValues.attachmentsHidden = ''
if (topic.get('link') && topic.get('link') !== '') {
nodeValues.embeds = '<a href="' + topic.get('link') + '" id="embedlyLink" target="_blank" data-card-description="0">'
nodeValues.embeds += topic.get('link')
nodeValues.embeds += '</a><div id="embedlyLinkLoader"></div>'
nodeValues.attachmentsHidden = 'hidden'
nodeValues.hasAttachment = 'hasAttachment'
} else {
nodeValues.embeds = ''
nodeValues.hasAttachment = ''
}
if (authorized) {
nodeValues.attachments = '<div class="addLink"><div id="addLinkIcon"></div>'
nodeValues.attachments += '<div id="addLinkInput"><input placeholder="Enter or paste a link"></input>'
nodeValues.attachments += '<div id="addLinkReset"></div></div></div>'
} else {
nodeValues.attachmentsHidden = 'hidden'
nodeValues.attachments = ''
}
var inmapsAr = topic.get('inmaps')
var inmapsLinks = topic.get('inmapsLinks')
nodeValues.inmaps = ''
if (inmapsAr.length < 6) {
for (i = 0; i < inmapsAr.length; i++) {
var url = '/maps/' + inmapsLinks[i]
nodeValues.inmaps += '<li><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
}
} else {
for (i = 0; i < 5; i++) {
var url = '/maps/' + inmapsLinks[i]
nodeValues.inmaps += '<li><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
}
extra = inmapsAr.length - 5
nodeValues.inmaps += '<li><span class="showMore">See ' + extra + ' more...</span></li>'
for (i = 5; i < inmapsAr.length; i++) {
var url = '/maps/' + inmapsLinks[i]
nodeValues.inmaps += '<li class="hideExtra extraText"><a href="' + url + '">' + inmapsAr[i] + '</a></li>'
}
}
nodeValues.permission = topic.get('calculated_permission')
nodeValues.mk_permission = topic.get('calculated_permission').substring(0, 2)
nodeValues.map_count = topic.get('map_count').toString()
nodeValues.synapse_count = topic.get('synapse_count').toString()
nodeValues.id = topic.isNew() ? topic.cid : topic.id
nodeValues.metacode = topic.getMetacode().get('name')
nodeValues.metacode_class = 'mbg' + topic.get('metacode_id')
nodeValues.imgsrc = topic.getMetacode().get('icon')
nodeValues.name = topic.get('name')
nodeValues.userid = topic.get('user_id')
nodeValues.username = topic.get('user_name')
nodeValues.date = topic.getDate()
// the code for this is stored in /views/main/_metacodeOptions.html.erb
nodeValues.metacode_select = $('#metacodeOptions').html()
nodeValues.desc_nil = desc_nil
nodeValues.desc = (topic.get('desc') == '' && authorized) ? desc_nil : topic.get('desc')
return nodeValues
}
}; // end Metamaps.TopicCard

View file

@ -1,130 +0,0 @@
/* global Metamaps */
/*
* Metamaps.Util.js
*
* Dependencies:
* - Metamaps.Visualize
*/
Metamaps.Util = {
// helper function to determine how many lines are needed
// Line Splitter Function
// copyright Stephen Chapman, 19th April 2006
// you may copy this code but please keep the copyright notice as well
splitLine: function (st, n) {
var b = ''
var s = st ? st : ''
while (s.length > n) {
var c = s.substring(0, n)
var d = c.lastIndexOf(' ')
var e = c.lastIndexOf('\n')
if (e != -1) d = e
if (d == -1) d = n
b += c.substring(0, d) + '\n'
s = s.substring(d + 1)
}
return b + s
},
nowDateFormatted: function () {
var date = new Date(Date.now())
var month = (date.getMonth() + 1) < 10 ? '0' + (date.getMonth() + 1) : (date.getMonth() + 1)
var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate()
var year = date.getFullYear()
return month + '/' + day + '/' + year
},
decodeEntities: function (desc) {
var str, temp = document.createElement('p')
temp.innerHTML = desc // browser handles the topics
str = temp.textContent || temp.innerText
temp = null // delete the element
return str
}, // decodeEntities
getDistance: function (p1, p2) {
return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2))
},
coordsToPixels: function (coords) {
if (Metamaps.Visualize.mGraph) {
var canvas = Metamaps.Visualize.mGraph.canvas,
s = canvas.getSize(),
p = canvas.getPos(),
ox = canvas.translateOffsetX,
oy = canvas.translateOffsetY,
sx = canvas.scaleOffsetX,
sy = canvas.scaleOffsetY
var pixels = {
x: (coords.x / (1 / sx)) + p.x + s.width / 2 + ox,
y: (coords.y / (1 / sy)) + p.y + s.height / 2 + oy
}
return pixels
} else {
return {
x: 0,
y: 0
}
}
},
pixelsToCoords: function (pixels) {
var coords
if (Metamaps.Visualize.mGraph) {
var canvas = Metamaps.Visualize.mGraph.canvas,
s = canvas.getSize(),
p = canvas.getPos(),
ox = canvas.translateOffsetX,
oy = canvas.translateOffsetY,
sx = canvas.scaleOffsetX,
sy = canvas.scaleOffsetY
coords = {
x: (pixels.x - p.x - s.width / 2 - ox) * (1 / sx),
y: (pixels.y - p.y - s.height / 2 - oy) * (1 / sy),
}
} else {
coords = {
x: 0,
y: 0
}
}
return coords
},
getPastelColor: function () {
var r = (Math.round(Math.random() * 127) + 127).toString(16)
var g = (Math.round(Math.random() * 127) + 127).toString(16)
var b = (Math.round(Math.random() * 127) + 127).toString(16)
return Metamaps.Util.colorLuminance('#' + r + g + b, -0.4)
},
// darkens a hex value by 'lum' percentage
colorLuminance: function (hex, lum) {
// validate hex string
hex = String(hex).replace(/[^0-9a-f]/gi, '')
if (hex.length < 6) {
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2]
}
lum = lum || 0
// convert to decimal and change luminosity
var rgb = '#', c, i
for (i = 0; i < 3; i++) {
c = parseInt(hex.substr(i * 2, 2), 16)
c = Math.round(Math.min(Math.max(0, c + (c * lum)), 255)).toString(16)
rgb += ('00' + c).substr(c.length)
}
return rgb
},
generateOptionsList: function (data) {
var newlist = ''
for (var i = 0; i < data.length; i++) {
newlist = newlist + '<option value="' + data[i]['id'] + '">' + data[i]['1'][1] + '</option>'
}
return newlist
},
checkURLisImage: function (url) {
// when the page reloads the following regular expression will be screwed up
// please replace it with this one before you save: /*backslashhere*.(jpeg|jpg|gif|png)$/
return (url.match(/\.(jpeg|jpg|gif|png)$/) != null)
},
checkURLisYoutubeVideo: function (url) {
return (url.match(/^https?:\/\/(?:www\.)?youtube.com\/watch\?(?=[^?]*v=\w+)(?:[^\s?]+)?$/) != null)
}
}; // end Metamaps.Util

View file

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

View file

@ -1,210 +0,0 @@
/* global Metamaps, $ */
/*
* Metamaps.Visualize
*
* Dependencies:
* - Metamaps.Active
* - Metamaps.JIT
* - Metamaps.Loading
* - Metamaps.Metacodes
* - Metamaps.Router
* - Metamaps.Synapses
* - Metamaps.TopicCard
* - Metamaps.Topics
* - Metamaps.Touch
* - Metamaps.Visualize
*/
Metamaps.Visualize = {
mGraph: null, // a reference to the graph object.
cameraPosition: null, // stores the camera position when using a 3D visualization
type: 'ForceDirected', // the type of graph we're building, could be "RGraph", "ForceDirected", or "ForceDirected3D"
loadLater: false, // indicates whether there is JSON that should be loaded right in the offset, or whether to wait till the first topic is created
init: function () {
var self = Metamaps.Visualize
// disable awkward dragging of the canvas element that would sometimes happen
$('#infovis-canvas').on('dragstart', function (event) {
event.preventDefault()
})
// prevent touch events on the canvas from default behaviour
$('#infovis-canvas').bind('touchstart', function (event) {
event.preventDefault()
self.mGraph.events.touched = true
})
// prevent touch events on the canvas from default behaviour
$('#infovis-canvas').bind('touchmove', function (event) {
// Metamaps.JIT.touchPanZoomHandler(event)
})
// prevent touch events on the canvas from default behaviour
$('#infovis-canvas').bind('touchend touchcancel', function (event) {
lastDist = 0
if (!self.mGraph.events.touchMoved && !Metamaps.Touch.touchDragNode) Metamaps.TopicCard.hideCurrentCard()
self.mGraph.events.touched = self.mGraph.events.touchMoved = false
Metamaps.Touch.touchDragNode = false
})
},
computePositions: function () {
var self = Metamaps.Visualize,
mapping
if (self.type == 'RGraph') {
var i, l, startPos, endPos, topic, synapse
self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id)
topic.set({ node: n }, { silent: true })
topic.updateNode()
n.eachAdjacency(function (edge) {
if (!edge.getData('init')) {
edge.setData('init', true)
l = edge.getData('synapseIDs').length
for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i])
synapse.set({ edge: edge }, { silent: true })
synapse.updateEdge()
}
}
})
var pos = n.getPos()
pos.setc(-200, -200)
})
self.mGraph.compute('end')
} else if (self.type == 'ForceDirected') {
var i, l, startPos, endPos, topic, synapse
self.mGraph.graph.eachNode(function (n) {
topic = Metamaps.Topics.get(n.id)
topic.set({ node: n }, { silent: true })
topic.updateNode()
mapping = topic.getMapping()
n.eachAdjacency(function (edge) {
if (!edge.getData('init')) {
edge.setData('init', true)
l = edge.getData('synapseIDs').length
for (i = 0; i < l; i++) {
synapse = Metamaps.Synapses.get(edge.getData('synapseIDs')[i])
synapse.set({ edge: edge }, { silent: true })
synapse.updateEdge()
}
}
})
startPos = new $jit.Complex(0, 0)
endPos = new $jit.Complex(mapping.get('xloc'), mapping.get('yloc'))
n.setPos(startPos, 'start')
n.setPos(endPos, 'end')
})
} else if (self.type == 'ForceDirected3D') {
self.mGraph.compute()
}
},
/**
* render does the heavy lifting of creating the engine that renders the graph with the properties we desire
*
*/
render: function () {
var self = Metamaps.Visualize, RGraphSettings, FDSettings
if (self.type == 'RGraph' && (!self.mGraph || self.mGraph instanceof $jit.ForceDirected)) {
RGraphSettings = $.extend(true, {}, Metamaps.JIT.ForceDirected.graphSettings)
$jit.RGraph.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings)
$jit.RGraph.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings)
RGraphSettings.width = $(document).width()
RGraphSettings.height = $(document).height()
RGraphSettings.background = Metamaps.JIT.RGraph.background
RGraphSettings.levelDistance = Metamaps.JIT.RGraph.levelDistance
self.mGraph = new $jit.RGraph(RGraphSettings)
} else if (self.type == 'ForceDirected' && (!self.mGraph || self.mGraph instanceof $jit.RGraph)) {
FDSettings = $.extend(true, {}, Metamaps.JIT.ForceDirected.graphSettings)
$jit.ForceDirected.Plot.NodeTypes.implement(Metamaps.JIT.ForceDirected.nodeSettings)
$jit.ForceDirected.Plot.EdgeTypes.implement(Metamaps.JIT.ForceDirected.edgeSettings)
FDSettings.width = $('body').width()
FDSettings.height = $('body').height()
self.mGraph = new $jit.ForceDirected(FDSettings)
} else if (self.type == 'ForceDirected3D' && !self.mGraph) {
// init ForceDirected3D
self.mGraph = new $jit.ForceDirected3D(Metamaps.JIT.ForceDirected3D.graphSettings)
self.cameraPosition = self.mGraph.canvas.canvases[0].camera.position
} else {
self.mGraph.graph.empty()
}
if (self.type == 'ForceDirected' && Metamaps.Active.Mapper) $.post('/maps/' + Metamaps.Active.Map.id + '/events/user_presence')
function runAnimation () {
Metamaps.Loading.hide()
// load JSON data, if it's not empty
if (!self.loadLater) {
// load JSON data.
var rootIndex = 0
if (Metamaps.Active.Topic) {
var node = _.find(Metamaps.JIT.vizData, function (node) {
return node.id === Metamaps.Active.Topic.id
})
rootIndex = _.indexOf(Metamaps.JIT.vizData, node)
}
self.mGraph.loadJSON(Metamaps.JIT.vizData, rootIndex)
// compute positions and plot.
self.computePositions()
self.mGraph.busy = true
if (self.type == 'RGraph') {
self.mGraph.fx.animate(Metamaps.JIT.RGraph.animate)
} else if (self.type == 'ForceDirected') {
self.mGraph.animate(Metamaps.JIT.ForceDirected.animateSavedLayout)
} else if (self.type == 'ForceDirected3D') {
self.mGraph.animate(Metamaps.JIT.ForceDirected.animateFDLayout)
}
}
}
// hold until all the needed metacode images are loaded
// hold for a maximum of 80 passes, or 4 seconds of waiting time
var tries = 0
function hold () {
var unique = _.uniq(Metamaps.Topics.models, function (metacode) { return metacode.get('metacode_id'); }),
requiredMetacodes = _.map(unique, function (metacode) { return metacode.get('metacode_id'); }),
loadedCount = 0
_.each(requiredMetacodes, function (metacode_id) {
var metacode = Metamaps.Metacodes.get(metacode_id),
img = metacode ? metacode.get('image') : false
if (img && (img.complete || (typeof img.naturalWidth !== 'undefined' && img.naturalWidth !== 0))) {
loadedCount += 1
}
})
if (loadedCount === requiredMetacodes.length || tries > 80) runAnimation()
else setTimeout(function () { tries++; hold() }, 50)
}
hold()
// update the url now that the map is ready
clearTimeout(Metamaps.Router.timeoutId)
Metamaps.Router.timeoutId = setTimeout(function () {
var m = Metamaps.Active.Map
var t = Metamaps.Active.Topic
if (m && window.location.pathname !== '/maps/' + m.id) {
Metamaps.Router.navigate('/maps/' + m.id)
}
else if (t && window.location.pathname !== '/topics/' + t.id) {
Metamaps.Router.navigate('/topics/' + t.id)
}
}, 800)
}
}; // end Metamaps.Visualize

View file

@ -1,73 +0,0 @@
/* global Metamaps */
/*
* Metamaps.js.erb
*/
// TODO eliminate these 5 top-level variables
Metamaps.panningInt = null
Metamaps.tempNode = null
Metamaps.tempInit = false
Metamaps.tempNode2 = null
Metamaps.VERSION = '<%= METAMAPS_VERSION %>'
/* erb variables from rails */
Metamaps.Erb = {}
Metamaps.Erb['REALTIME_SERVER'] = '<%= ENV['REALTIME_SERVER'] %>'
Metamaps.Erb['junto_spinner_darkgrey.gif'] = '<%= asset_path('junto_spinner_darkgrey.gif') %>'
Metamaps.Erb['user.png'] = '<%= asset_path('user.png') %>'
Metamaps.Erb['icons/wildcard.png'] = '<%= asset_path('icons/wildcard.png') %>'
Metamaps.Erb['topic_description_signifier.png'] = '<%= asset_path('topic_description_signifier.png') %>'
Metamaps.Erb['topic_link_signifier.png'] = '<%= asset_path('topic_link_signifier.png') %>'
Metamaps.Erb['synapse16.png'] = '<%= asset_path('synapse16.png') %>'
Metamaps.Settings = {
embed: false, // indicates that the app is on a page that is optimized for embedding in iFrames on other web pages
sandbox: false, // puts the app into a mode (when true) where it only creates data locally, and isn't writing it to the database
colors: {
background: '#344A58',
synapses: {
normal: '#888888',
hover: '#888888',
selected: '#FFFFFF'
},
topics: {
selected: '#FFFFFF'
},
labels: {
background: '#18202E',
text: '#DDD'
}
},
}
Metamaps.Touch = {
touchPos: null, // this stores the x and y values of a current touch event
touchDragNode: null // this stores a reference to a JIT node that is being dragged
}
Metamaps.Mouse = {
didPan: false,
didBoxZoom: false,
changeInX: 0,
changeInY: 0,
edgeHoveringOver: false,
boxStartCoordinates: false,
boxEndCoordinates: false,
synapseStartCoordinates: [],
synapseEndCoordinates: null,
lastNodeClick: 0,
lastCanvasClick: 0,
DOUBLE_CLICK_TOLERANCE: 300
}
Metamaps.Selected = {
reset: function () {
var self = Metamaps.Selected
self.Nodes = []
self.Edges = []
},
Nodes: [],
Edges: []
}

View file

@ -1,15 +0,0 @@
// TODO document this user agent function
var labelType, useGradients, nativeTextSupport, animate
;(function () {
var ua = navigator.userAgent,
iStuff = ua.match(/iPhone/i) || ua.match(/iPad/i),
typeOfCanvas = typeof HTMLCanvasElement,
nativeCanvasSupport = (typeOfCanvas == 'object' || typeOfCanvas == 'function'),
textSupport = nativeCanvasSupport && (typeof document.createElement('canvas').getContext('2d').fillText == 'function')
// I'm setting this based on the fact that ExCanvas provides text support for IE
// and that as of today iPhone/iPad current text support is lame
labelType = (!nativeCanvasSupport || (textSupport && !iStuff)) ? 'Native' : 'HTML'
nativeTextSupport = labelType == 'Native'
useGradients = nativeCanvasSupport
animate = !(iStuff || !nativeCanvasSupport)
})()

View file

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

View file

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

View file

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

View file

@ -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
*/

View 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;
}

View file

@ -56,16 +56,15 @@
}
li.toggledOff {
opacity: 0.4;
opacity: 0.6;
}
}
.blackBox {
.centerContent {
width: 760px;
margin: 0 auto;
padding: 20px 0 60px 20px;
background: rgba(0, 0, 0, 0.4);
color: white;
padding: 80px 0 60px 20px;
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 {

View file

@ -78,11 +78,18 @@ html {
}
body {
background: #d8d9da url(<%= asset_data_uri('shattered_@2X.png') %>);
font-family: 'din-medium', helvetica, sans-serif;
color: #424242;
-moz-osx-font-smoothing: grayscale;
background: #d8d9da url(<%= asset_path('shattered_@2X.png') %>);
font-family: 'din-medium', helvetica, sans-serif;
color: #424242;
-moz-osx-font-smoothing: grayscale;
overflow-x: hidden;
&.controller-main,
&.controller-maps,
&.controller-topics,
&.controller-explore {
overflow-y: hidden;
}
}
h1,
h2,
@ -142,6 +149,7 @@ button.button.btn-no:hover {
.toast .toast-button {
margin-top: -10px;
margin-left: 10px;
margin-bottom: -10px;
}
/*
* Utility
@ -185,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,
@ -523,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;
@ -567,6 +573,26 @@ button.button.btn-no:hover {
.openMetacodeSwitcher:hover {
background-position: -16px 0;
}
.pinCarousel {
cursor: pointer;
display: block;
height: 16px;
width: 16px;
background-image: url(<%= asset_data_uri('pincarousel_sprite.png') %>);
position: absolute;
z-index: 2;
top: 20px;
right: 16px;
}
.pinCarousel:hover {
background-position: 0 -16px;
}
.pinCarousel.isPinned {
background-position: -16px 0;
}
.pinCarousel.isPinned:hover {
background-position: -16px -16px;
}
#metacodeImg {
height: 120px;
}
@ -642,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;
@ -745,9 +783,9 @@ label {
}
.sidebarAccountIcon img {
border-radius: 16px;
width: 32px;
}
.sidebarAccountBox {
display: none;
height: auto;
}
.authenticated .sidebarAccountBox {
@ -788,6 +826,7 @@ label {
font-size: 14px;
line-height: 14px;
color: #757575;
cursor: pointer;
}
.accountListItem:hover {
color: #424242;
@ -798,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;
@ -806,6 +845,9 @@ label {
.accountAdmin .accountIcon {
background-position: 0 -32px;
}
.accountApps .accountIcon {
background-position: 0 -32px;
}
.accountInvite .accountIcon {
background-position: 0 -64px;
}
@ -1006,7 +1048,6 @@ label[for="user_remember_me"] {
}
.sidebarFilterBox {
display:none;
width: 319px;
padding: 16px 0;
overflow-y: auto;
@ -1217,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;
}
@ -1246,11 +1287,12 @@ 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;
width: auto;
white-space: nowrap;
width: auto;
min-width: 5em;
}
.rightclickmenu .rc-metacode ul ul,
.rightclickmenu .rc-siblings ul ul {
@ -1504,9 +1546,8 @@ h3.filterBox {
background-image: url(<%= asset_data_uri('permissions32_sprite.png') %>);
}
/* map info box */
/* map info box */
.wrapper div.mapInfoBox {
.wrapper .mapInfoBox {
display: none;
position: absolute;
bottom: 40px;
@ -1514,12 +1555,74 @@ h3.filterBox {
background-color: #424242;
color: #F5F5F5;
border-radius: 2px;
box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0px 3px 3px rgba(0,0,0,0.16);
text-align: center;
font-style: normal;
}
.import-dialog{
button {
margin: 1em 0.5em;
}
.import-blue-button {
display: inline-block;
box-sizing: border-box;
margin: 0.75em;
padding: 0.75em;
padding-top: 0.85em;
height: 3em;
background-color: #AAB0FB;
border-radius: 0.3em;
color: white;
cursor: pointer;
}
.fileupload {
box-sizing: border-box;
margin: 0.75em;
padding: 0.75em;
height: 3em;
border: 3px dashed #AAB0FB;
width: 75%;
text-align: center;
cursor: pointer;
}
}
.wrapper .mapInfoBox {
width: 360px;
min-height: 300px;
padding: 0;
font-style: normal;
}
.requestTitle {
display: none;
position: absolute;
background: black;
text-align: center;
box-shadow: 0 3px 3px rgba(0,0,0,0.23), 0px 3px 3px rgba(0,0,0,0.16);
text-transform: none;
color: white;
border-radius: 2px;
font-family: din-regular;
line-height: 18px;
font-size: 15px;
padding: 3px 5px 2px;
white-space: nowrap;
font-style: normal;
left: 50%;
margin-left: -100px;
top: -15px;
}
.mapRequestTitle .requestTitle {
display: block;
}
.requestTitle:after {
content: '';
position: absolute;
top: 23px;
left: 50%;
margin-left: -8px;
width: 0;
height: 0;
border-top: 10px solid #000000;
border-left: 8px solid transparent;
border-right: 8px solid transparent;
}
.mapInfoName {
font-size: 18px;
@ -1577,7 +1680,7 @@ h3.filterBox {
.mapContributors {
position: relative;
height: 30px;
margin: 9px 0px 9px 56px;
margin: 9px 0px 9px 44px;
padding: 0;
width: 64px;
}
@ -1812,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;
@ -1920,6 +2019,7 @@ input.collaboratorSearchField {
position: relative;
cursor: pointer;
display: none;
padding: 0 2px;
}
.mapInfoShareIcon {
width: 24px;
@ -1959,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%;
@ -1973,17 +2110,17 @@ and it won't be important on password protected instances */
left: 0;
width: 100%;
height: 100%;
position: fixed;
position: absolute;
z-index: 1000000;
display: none;
}
#lightbox_main {
width: 800px;
height: auto;
margin: 0 auto;
z-index: 2;
position: relative;
top: 50%;
top: 5vh;
height: 90vh;
background-color: transparent;
color: black;
}
@ -2022,8 +2159,10 @@ and it won't be important on password protected instances */
background-position: center center;
}
#lightbox_content {
width: 552px;
height: 434px;
width: 800px;
max-height: 90vh;
box-sizing: border-box;
overflow-y: auto;
background-color: #e0e0e0;
padding: 64px 124px 64px 124px;
box-shadow: 0px 6px 3px rgba(0, 0, 0, 0.23), 10px 10px 10px rgba(0, 0, 0, 0.19);
@ -2105,41 +2244,34 @@ and it won't be important on password protected instances */
color: #00bcd4;
}
.lightbox_links .lightboxAboutIcon {
background-image: url(<%= asset_data_uri('about_sprite.png') %>);
background-repeat: no-repeat;
width:32px;
height:32px;
margin:10px auto;
}
#lightbox_metamapps .lightboxAboutIcon {
.icon_twitter .lightboxAboutIcon,
.icon_source_code .lightboxAboutIcon,
.icon_terms .lightboxAboutIcon {
background-image: url(<%= asset_data_uri('about_sprite.png') %>);
background-repeat: no-repeat;
background-position: 0 0;
}
#lightbox_community .lightboxAboutIcon {
background-position: -32px 0;
}
#lightbox_source .lightboxAboutIcon {
background-position: -64px 0;
}
#lightbox_blog .lightboxAboutIcon {
background-position: -96px 0;
}
#lightbox_term .lightboxAboutIcon {
background-position: -128px 0;
}
#lightbox_metamapps:hover .lightboxAboutIcon {
.icon_twitter .lightboxAboutIcon {
background-position: 0 0;
&:hover {
background-position: 0 -32px;
}
}
#lightbox_community:hover .lightboxAboutIcon {
background-position: -32px -32px;
}
#lightbox_source:hover .lightboxAboutIcon {
.icon_source_code .lightboxAboutIcon {
background-position: -64px 0;
&:hover {
background-position: -64px -32px;
}
}
#lightbox_blog:hover .lightboxAboutIcon {
background-position: -96px -32px;
}
#lightbox_term:hover .lightboxAboutIcon {
.icon_terms .lightboxAboutIcon {
background-position: -128px 0;
&:hover {
background-position: -128px -32px;
}
}
/* jquery ui tabs */
@ -2183,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;
@ -2190,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;
@ -2780,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 {
@ -2989,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;
}

View file

@ -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;
}

View file

@ -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,22 +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;
@ -39,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,6 +55,7 @@
#infovis {
width:100%;
height:100%;
position: absolute;
}
.showcard .permission {
@ -60,7 +67,6 @@
display:block;
position:relative;
width:100%;
min-height:360px;
z-index: 25;
}
.CardOnGraph.hasAttachment {
@ -68,11 +74,11 @@
}
.CardOnGraph .title {
font-size: 18px;
line-height: 22px;
word-break: break-word;
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;
@ -91,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;
@ -110,44 +115,76 @@
.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;
}
.CardOnGraph .desc h3 {
font-style:normal;
margin-top:5px;
/*
* Styling for Markdown in topic cards
*/
.CardOnGraph .desc {
p, ol, ul {
padding: 0.15em 0;
}
h1, h2, h3, h4, h5, h6 {
font-style: normal;
padding: 0.25em 0;
}
ol,
ul {
margin-left: 1em;
}
a:hover {
text-decoration: underline;
opacity: 0.9;
}
}
.CardOnGraph .best_in_place_desc {
/*
* End Markdown styling
*/
.CardOnGraph .riek_desc {
display:block;
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;
@ -159,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 {
@ -315,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;
@ -396,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;
@ -439,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;
@ -580,15 +609,14 @@ background-color: #E0E0E0;
position: relative;
}
.CardOnGraph .hoverForTip:hover .tip, .mapCard .hoverForTip:hover .tip, #mapContribs:hover .tip {
.CardOnGraph .hoverForTip:hover .tip, #mapContribs:hover .tip {
display:block;
}
.CardOnGraph .tip, .mapCard .tip {
display:none;
.CardOnGraph .tip {
position: absolute;
background: black;
background: $mid-gray;
top: 35px;
left: 0;
right: 0;
color: white;
border-radius: 4px;
font-size:15px !important;
@ -597,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;
@ -626,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;
@ -670,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;
@ -726,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;
}
@ -813,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;
}
@ -924,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;
@ -940,124 +964,14 @@ font-family: 'din-regular', helvetica, sans-serif;
background-position: 0 -24px;
}
/* Map Cards */
.map {
display:inline-block;
width:220px;
height:340px;
font-size: 12px;
text-align: left;
overflow: visible;
background: #424242;
border-radius:2px;
margin:16px 16px 16px 19px;
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
}
.mapCard {
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
display: -ms-flexbox; /* TWEENER - IE 10 */
display: -webkit-flex; /* NEW - Chrome */
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
-webkit-box-orient: vertical;
-moz-box-orient: vertical;
-webkit-box-direction: normal;
-moz-box-direction: normal;
-ms-flex-direction: column;
-webkit-flex-direction: column;
flex-direction: column;
position:relative;
width:100%;
height:308px;
padding: 16px 0;
color:#F5F5F5;
}
.mapCard .title {
word-wrap: break-word;
font-size:18px;
line-height:22px;
height: 44px;
display:block;
padding: 0 16px;
text-align: center;
-webkit-box-flex: none; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: none; /* OLD - Firefox 19- */
-webkit-flex: none; /* Chrome */
-ms-flex: none; /* IE 10 */
flex: none; /* NEW, Spec - Opera 12.1, Firefox 20+ */
font-family: 'din-regular', sans-serif;
}
.mapCard .mapScreenshot {
width: 188px;
height: 126px;
padding: 8px 16px;
}
.mapCard .mapScreenshot img {
width: 188px;
height: 126px;
border-radius: 2px;
}
.mapCard .scroll {
display:block;
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: 1; /* OLD - Firefox 19- */
-webkit-flex: 1; /* Chrome */
-ms-flex: 1; /* IE 10 */
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
padding:0 16px 8px;
font-family: helvetica, sans-serif;
font-style: italic;
font-size: 12px;
word-wrap: break-word;
}
.mCS_no_scrollbar {
padding-right: 5px;
}
.mapCard .mapMetadata {
font-family: 'din-regular', sans-serif;
font-size: 12px;
position:relative;
border-top: 1px solid #BDBDBD;
-webkit-box-flex: none; /* OLD - iOS 6-, Safari 3.1-6 */
-moz-box-flex: none; /* OLD - Firefox 19- */
-webkit-flex: none; /* Chrome */
-ms-flex: none; /* IE 10 */
flex: none; /* NEW, Spec - Opera 12.1, Firefox 20+ */
}
.mapCard .metadataSection {
padding: 8px 16px 0 16px;
width: 78px;
float: left;
}
.mapPermission {
font-family: 'din-medium', sans-serif;
}
.cCountColor {
font-family: 'din-medium', sans-serif;
color: #DB5D5D;
}
.tCountColor {
font-family: 'din-medium', sans-serif;
color: #4FC059;
}
.sCountColor {
font-family: 'din-medium', sans-serif;
color: #DAB539;
}
/* mapper card */
.mapper {
float: left;
display: inline-block;
vertical-align: bottom;
width:220px;
height:340px;
font-size: 12px;
@ -1065,7 +979,7 @@ font-family: 'din-regular', helvetica, sans-serif;
overflow: visible;
background: #E0E0E0;
border-radius:2px;
margin:16px 16px 16px 19px;
margin:16px;
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
}
@ -1089,10 +1003,10 @@ font-family: 'din-regular', helvetica, sans-serif;
font-size: 24px;
text-align: center;
margin-top: 24px;
padding: 0 16px;
padding: 0 5%;
white-space: nowrap;
text-overflow: ellipsis;
width: 189px;
width: 90%;
overflow: hidden;
}

View file

@ -24,21 +24,13 @@
backface-visibility: visible !important;
}
#famousOverlay {
position:absolute;
top: 0;
#yield {
position: absolute;
width: 100%;
height: 100%;
margin:0;
z-index: 0;
}
#yield {
display:none;
}
#toast {
display: none;
box-sizing: border-box;
padding-top: 92px;
overflow-y: auto;
}
/*.animations {
@ -55,16 +47,6 @@
transition-timing-function: ease-in-out;
}*/
.mapElement {
display: none;
}
.mapPage .mapElement, .topicPage .mapElement {
display: block;
}
.mapPage .mapElementHidden {
display:none;
}
/* loading */
#loading {
@ -120,8 +102,6 @@
top: 10px;
left: 24px;
z-index:3;
box-shadow: 0px 1px 1.5px rgba(0,0,0,0.12), 0 1px 1px rgba(0,0,0,0.24);
border-radius: 2px;
}
.explorePage .upperLeftUI {
box-shadow: none;
@ -131,23 +111,24 @@
display:none;
}
.homeButton {
width: 40px;
height: 32px;
background-color: #757575;
background-image: url(<%= asset_data_uri('home_light.png') %>);
background-repeat: no-repeat;
background-position: center center;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
float:left;
margin-right: 16px;
}
.homeButton:hover {
background-image: url(<%= asset_data_uri('home_light.png') %>);
}
.homeButton a {
display:block;
width: 40px;
height: 32px;
color: #747474;
font-family: "vinyl", sans-serif;
font-style: italic;
text-transform: uppercase;
font-weight: 400;
font-size: 30px;
line-height: 38px;
}
.homeButton a:hover {
color: #616161;
}
/* end upperLeftUI */
@ -187,43 +168,64 @@
}
.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 {
width: 32px;
height: 32px;
background-image: url(<%= asset_data_uri('topright_sprite.png') %>);
background-image: url(<%= asset_path('topright_sprite.png') %>);
background-repeat: no-repeat;
cursor: pointer;
}
.sidebarFilterIcon {
background-position: -64px 0;
background-position: -32px 0;
}
.sidebarForkIcon {
background-position: -96px 0;
background-position: -64px 0;
}
.addMap {
background-position: -96px 0;
}
.notificationsIcon {
background-position: -128px 0;
margin-right:10px;
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;
}
.sidebarFilterIcon:hover {
background-position: -64px -32px;
background-position: -32px -32px;
}
.sidebarForkIcon:hover {
background-position: -96px -32px;
background-position: -64px -32px;
}
.addMap:hover {
background-position: -128px -32px;
margin-right:10px;
background-position: -96px -32px;
}
/* end upperRightUI */
/* map wrapper */
.mapWrapper {
position:absolute;
width: 100%;
height: 100%;
}
/* end map wrapper */
/* yield */
@ -333,41 +335,26 @@
}
.fullWidthWrapper.withPartners {
background: url(<%= asset_data_uri('homepage_bg_fade.png') %>) no-repeat center -300px;
background: url(<%= asset_path('homepage_bg_fade.png') %>) no-repeat center -300px;
}
.homeWrapper.homePartners {
padding: 64px 0 280px;
height: 96px;
background: url(<%= asset_data_uri('partner_logos.png') %>) no-repeat 0 64px;
}
.github-fork-ribbon-wrapper {
display:none;
}
.homePage .github-fork-ribbon-wrapper {
display: block;
}
/* end home page */
/* infoAndHelp */
.mapPage .infoAndHelp, .topicPage .infoAndHelp {
right: 70px;
}
.mapPage .openCheatsheet .tooltipsAbove, .topicPage .openCheatsheet .tooltipsAbove {
left: 29px;
}
.unauthenticated .homePage .infoAndHelp {
display:none;
.openCheatsheet .tooltipsAbove {
right: 1px;
left: auto;
}
.infoAndHelp {
position: absolute;
bottom: 20px;
right: 20px;
right: 70px;
z-index: 3;
width: auto;
font-style: italic;
@ -380,7 +367,7 @@
cursor: pointer;
}
.openCheatsheet {
background-image: url(<%= asset_data_uri('help_sprite.png') %>);
background-image: url(<%= asset_path('help_sprite.png') %>);
background-repeat:no-repeat;
}
.openCheatsheet:hover {
@ -388,15 +375,27 @@
}
.mapInfoIcon {
position: relative;
top: 56px; /* puts it just offscreen */
background-image: url(<%= asset_data_uri('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') %>);
background-position: 0 0;
background-repeat: no-repeat;
width: 32px;
}
.starMap:hover {
background-position: 0 -32px !important;
}
.starMap.starred {
background-position: 0 -64px;
}
.starMap.starred:hover {
background-position: 0 0;
}
/* end infoAndHelp */
@ -407,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;
}
@ -432,31 +424,18 @@
z-index: 4;
}
.takeScreenshot {
margin-bottom: 5px;
border-radius: 2px;
background-image: url(<%= asset_data_uri 'screenshot_sprite.png' %>);
display: none;
}
.takeScreenshot:hover {
background-position: -32px 0;
}
.canEditMap .takeScreenshot {
display: block;
}
.zoomExtents {
margin-bottom:5px;
border-radius: 2px;
background-image: url(<%= asset_data_uri('extents_sprite.png') %>);
background-image: url(<%= asset_path('extents_sprite.png') %>);
}
.zoomExtents:hover {
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,
.mapInfoIcon:hover .tooltipsAbove, .openCheatsheet:hover .tooltipsAbove, .chat-button:hover .tooltips {
.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;
}
@ -512,14 +491,44 @@
font-style: normal;
}
.importDialog .tooltipsUnder {
left: -22px;
}
.sidebarFilterIcon .tooltipsUnder {
margin-left: -4px;
}
.notificationsIcon .tooltipsUnder {
left: -20px;
}
.sidebarForkIcon .tooltipsUnder {
margin-left: -34px;
}
.openMetacodeSwitcher .tooltipsAbove {
left: -50px;
top: -5px;
}
.pinCarousel .tooltipsAbove {
top: -5px;
}
.pinCarousel .tooltipsAbove.helpPin {
left: -24px;
}
.pinCarousel .tooltipsAbove.helpUnpin {
left: -14px;
}
.openMetacodeSwitcher .tooltipsAbove:after {
left: 50%;
}
.pinCarousel .tooltipsAbove.helpPin:after {
left: 46%;
}
.pinCarousel .tooltipsAbove.helpUnpin:after {
left: 42%;
}
.sidebarForkIcon div:after{
left: 45%;
}
@ -540,8 +549,11 @@
top: 10px;
}
.openCheatsheet .tooltipsAbove {
left: -4px;
.starMap .tooltipsAbove {
left: -2px;
}
.starMap.starred .tooltipsAbove {
left: -8px;
}
.sidebarAccountIcon .tooltipsUnder {
@ -549,7 +561,7 @@
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%;
@ -562,7 +574,12 @@
border-bottom: 5px solid transparent;
}
.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%;
@ -573,11 +590,17 @@
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 {
.mapInfoIcon div:after, .openCheatsheet div:after, .starMap div:after, .openMetacodeSwitcher div:after, .pinCarousel div:after {
content: '';
position: absolute;
top: 76%;
@ -591,7 +614,7 @@
}
.zoomIn {
background-image: url(<%= asset_data_uri('zoom_sprite.png') %>);
background-image: url(<%= asset_path('zoom_sprite.png') %>);
background-position: 0 /…0;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
@ -600,7 +623,7 @@
background-position: -32px 0;
}
.zoomOut {
background-image: url(<%= asset_data_uri('zoom_sprite.png') %>);
background-image: url(<%= asset_path('zoom_sprite.png') %>);
background-position:0 -32px;
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
@ -611,48 +634,84 @@
/* end mapControls */
/* explore maps */
.exploreMapsBar {
z-index:2;
background-color:#FAFAFA;
#react-app {
position: absolute;
height: 100%;
width: 100%;
overflow-y: auto;
}
.exploreMapsMenu {
display: block;
#exploreMaps {
position: absolute;
height: 100%;
width: 100%;
margin-top:52px;
height:42px;
background-color:#EEEEEE;
overflow-y: auto;
}
#exploreMaps > div {
margin: 110px auto 0 auto;
}
.button.loadMore {
margin: 10px auto 20px;
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);
}
.exploreMapsCenter {
z-index: 3 !important;
#navBar {
position: absolute;
width: 100%;
}
.exploreMapsButton {
color: #757575;
.navBarContainer {
z-index:2;
background-color:#FAFAFA;
height: 42px;
padding-top: 52px;
}
.navBarMenu {
display: block;
width: 100%;
height:42px;
background-color:#EEEEEE;
box-shadow: 0px 3px 3px rgba(0,0,0,0.23), 0 3px 3px rgba(0,0,0,0.16);
text-align: center;
}
.navBarCenter {
display: block;
}
.navBarButton {
color: #757575;
cursor: default;
font-weight: normal;
font-family: 'din-medium';
font-size: 14px;
height: 14px;
padding: 14px 16px 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;
}
@ -669,42 +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 .myMaps .exploreMapsIcon {
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: 0 0;
.navBarLinkText {
padding: 11px 0 12px 0;
display: inline-block;
}
.exploreMapsCenter .sharedMaps .exploreMapsIcon {
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: -96px 0;
}
.exploreMapsCenter .activeMaps .exploreMapsIcon {
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: -32px 0;
}
.exploreMapsCenter .featuredMaps .exploreMapsIcon {
background-image: url(<%= asset_data_uri 'exploremaps_sprite.png' %>);
background-position: -64px 0;
}
.myMaps:hover .exploreMapsIcon, .myMaps.active .exploreMapsIcon {
.navBarCenter .authedApps .navBarIcon {
background-image: url(<%= asset_path('user_sprite.png') %>);
background-position: 0 -32px;
}
.activeMaps:hover .exploreMapsIcon, .activeMaps.active .exploreMapsIcon {
.navBarCenter .myMaps .navBarIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -32px 0;
}
.navBarCenter .sharedMaps .navBarIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -128px 0;
}
.navBarCenter .activeMaps .navBarIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: 0 0;
}
.navBarCenter .featuredMaps .navBarIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -96px 0;
}
.navBarCenter .starredMaps .navBarIcon {
background-image: url(<%= asset_path 'exploremaps_sprite.png' %>);
background-position: -96px 0;
}
.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 .navBarIcon, .myMaps.active .navBarIcon {
background-position: -32px -32px;
}
.featuredMaps:hover .exploreMapsIcon, .featuredMaps.active .exploreMapsIcon {
background-position: -64px -32px;
.activeMaps:hover .navBarIcon, .activeMaps.active .navBarIcon {
background-position: 0 -32px;
}
.sharedMaps:hover .exploreMapsIcon, .sharedMaps.active .exploreMapsIcon {
.featuredMaps:hover .navBarIcon, .featuredMaps.active .navBarIcon {
background-position: -96px -32px;
}
.starredMaps:hover .navBarIcon, .starredMaps.active .navBarIcon {
background-position: -96px -32px;
}
.sharedMaps:hover .navBarIcon, .sharedMaps.active .navBarIcon {
background-position: -128px -32px;
}
.notificationsLink:hover .navBarIcon, .notificationsLink.active .navBarIcon {
background-position-y: -32px;
}
.mapsWrapper {
/*overflow-y: auto; */
@ -713,10 +801,31 @@
/* end explore maps */
/* instructions */
#instructions {
width: 220px;
height: 80px;
font-family: 'din-regular', helvetica, sans-serif;
font-size: 32px;
text-align: center;
color: #999999;
z-index: 0;
top: 50%;
position: absolute;
left: 50%;
margin-top: -40px;
margin-left: -110px;
}
/* end instructions */
/* toast */
.toast {
position: fixed;
bottom: 20px;
left: 20px;
background-color: #323232;
color: #F5F5F5;
padding: 16px;

View 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 }

View file

@ -1,77 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: mark@famo.us
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
html {
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
overflow: hidden;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
body {
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
padding: 0px;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-font-smoothing: antialiased;
-webkit-tap-highlight-color: transparent;
-webkit-perspective: 0;
perspective: none;
overflow: hidden;
}
.famous-container, .famous-group {
position: absolute;
top: 0px;
left: 0px;
bottom: 0px;
right: 0px;
overflow: visible;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
-webkit-backface-visibility: visible;
backface-visibility: visible;
pointer-events: none;
}
.famous-group {
width: 0px;
height: 0px;
margin: 0px;
padding: 0px;
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.famous-surface {
position: absolute;
-webkit-transform-origin: center center;
transform-origin: center center;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
-webkit-transform-style: flat;
transform-style: preserve-3d; /* performance */
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-tap-highlight-color: transparent;
pointer-events: auto;
}
.famous-container-group {
position: relative;
width: 100%;
height: 100%;
}

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