diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..67150012 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +## 2.5 + +- Initial release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..ffbf1223 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,92 @@ +# Contributing to Metamaps + +Active involvement from the community is essential to help make Metamaps as beneficial for communities as it can be. You can help by reporting bugs, fixing bugs, adding features, contributing new modules and by providing feedback. + + +## Reporting bugs and other issues + +If you think you've encountered a bug, do the following: + +1. Make sure you are working with the latest version of the Metamaps `master` branch. +2. Browse through the [issues][metamaps-issues] to check if + anyone else has already reported. If someone has, feel free to add more + information to that issue to help us solve it. +3. If no one has yet submitted the issue you are encountering, add it in! Please be sure + to include as much information as possible, include errors, warnings, + screenshots, links to a video showing the problem or code that can reproduce + the issue. + + +## Contributing code + +Metamaps is made possible by open source +contributors like you. We're very interested in getting help from the greater +community, but before you start it's important that you become acquainted with +our workflow. Following these guidelines below will make collaboration much +smoother and increase the chances that we will accept your pull request without +hiccups. + + +### Development Process + +Our development process is very similar to the approach +described in the well-known article [A Successful Git Branching Model by Vincent +Driessen][git-branching-model]. Here's an overview: + +* Our `master` branch is the branch upon which + Metamaps developers should be basing their work on. The `master` branch is not guaranteed to be stable. +* All commits intended for `master` should take place on your own personal + fork, and be submitted via pull request when ready. +* Only maintainers can accept pull requests from forks into the core Famo.us + repository. +* Please squash your commits into a single commit before making a pull request. + +### Getting started + +1. Make sure you have a [GitHub account](https://github.com/signup/free) +2. [Fork metamaps][fork-metamaps] +3. Keep your fork up to date. Metamaps is a fast moving project, and things are + changing all the time. It's important that any changes you make are based on + the most recent version of metamaps, since it's possible that something may + have changed that breaks your pull request or invalidates its need. +4. Make sure you have a [Contributor License Agreement][cla] on file. +5. Read on ... + + +### Contributor License Agreement + +Before we can accept any contributions to Metamaps, we first require that all +individuals or companies agree to our Contributor License Agreement (CLA). The e-mail +address used in the pull request will be used to check if a CLA has already been +filed, so be sure to list all email addresses that you might use to submit your +pull requests when filling it out. Our CLA can be found [here][cla]. + +### Testing and Linting + +TODO + + +### Branch grouping tokens + +All pull requests submitted to Famo.us should occur on a new branch. For these +branches, we at metamaps use a short token indicating the nature of the branch in +question followed by a solidus (`/`) and a kebab-cased string describing the +branch. We are using the following tokens: + + bug // bug fixes + wip // work in progress + feat // feature + +Bug fixes follow a [slightly different format](#bug-fixes). + +### Bug fixes + +If you'd like to contribute a fix for a bug you've encountered, first read up on +[how to report a bug](#reporting-bugs-and-other-issues) and report it so we are +aware of the issue. By filing the issue first, we may be able to provide you +with some insight that guides you in the right direction. + +[metamaps-issues]: https://github.com/Connoropolous/metamaps_gen002/issues +[git-branching-model]: http://nvie.com/posts/a-successful-git-branching-model/ +[fork-metamaps]: https://github.com/Connoropolous/metamaps_gen002/fork +[cla]: http://metamaps.cc/cla diff --git a/Gemfile b/Gemfile index 65988ca4..f720116a 100644 --- a/Gemfile +++ b/Gemfile @@ -1,12 +1,16 @@ source 'https://rubygems.org' +#ruby '1.9.3' gem 'rails', '3.2.17' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' +#gem 'watir' +#gem 'phantomjs' + gem 'devise' -gem 'redis' +gem 'redis', '2.2.2' gem 'pg' gem 'cancan' gem 'formula' @@ -14,6 +18,11 @@ gem 'formtastic' gem 'json' gem 'rails3-jquery-autocomplete' gem 'best_in_place' +gem 'kaminari' # pagination + +gem 'paperclip' +gem 'aws-sdk' + #gem 'therubyracer' #optional #gem 'rb-readline' @@ -29,6 +38,10 @@ group :assets do gem 'uglifier', '>= 1.0.3' end +group :production do #this is used on heroku + #gem 'rmagick' +end + gem 'jquery-rails', '2.1.2' # To use ActiveModel has_secure_password diff --git a/Gemfile.lock b/Gemfile.lock index 3346fa26..ee449288 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -29,6 +29,9 @@ GEM i18n (~> 0.6, >= 0.6.4) multi_json (~> 1.0) arel (3.0.3) + aws-sdk (1.44.0) + json (~> 1.4) + nokogiri (>= 1.4.4) bcrypt (3.1.7) bcrypt (3.1.7-x86-mingw32) best_in_place (2.1.0) @@ -36,6 +39,10 @@ GEM rails (~> 3.1) builder (3.0.4) cancan (1.6.10) + climate_control (0.0.3) + activesupport (>= 3.0) + cocaine (0.5.4) + climate_control (>= 0.0.3, < 1.0) coffee-rails (3.2.2) coffee-script (>= 2.2.0) railties (~> 3.2.0) @@ -64,12 +71,25 @@ GEM railties (>= 3.1.0, < 5.0) thor (~> 0.14) json (1.8.1) + kaminari (0.16.1) + actionpack (>= 3.0.0) + activesupport (>= 3.0.0) mail (2.5.4) mime-types (~> 1.16) treetop (~> 1.4.8) mime-types (1.25.1) + mini_portile (0.6.0) multi_json (1.10.0) + nokogiri (1.6.2.1) + mini_portile (= 0.6.0) + nokogiri (1.6.2.1-x86-mingw32) + mini_portile (= 0.6.0) orm_adapter (0.5.0) + paperclip (4.1.1) + activemodel (>= 3.0.0) + activesupport (>= 3.0.0) + cocaine (~> 0.5.3) + mime-types pg (0.17.1) pg (0.17.1-x86-mingw32) polyglot (0.3.4) @@ -100,7 +120,7 @@ GEM rake (10.3.2) rdoc (3.12.2) json (~> 1.4) - redis (3.0.7) + redis (2.2.2) sass (3.3.7) sass-rails (3.2.6) railties (~> 3.2.0) @@ -129,6 +149,7 @@ PLATFORMS x86-mingw32 DEPENDENCIES + aws-sdk best_in_place cancan coffee-rails (~> 3.2.1) @@ -138,9 +159,11 @@ DEPENDENCIES jbuilder (= 0.8.2) jquery-rails (= 2.1.2) json + kaminari + paperclip pg rails (= 3.2.17) rails3-jquery-autocomplete - redis + redis (= 2.2.2) sass-rails uglifier (>= 1.0.3) diff --git a/Gemfile~ b/Gemfile~ deleted file mode 100644 index 9e2acc35..00000000 --- a/Gemfile~ +++ /dev/null @@ -1,47 +0,0 @@ -source 'https://rubygems.org' - -gem 'rails', '3.2.17' - -# Bundle edge Rails instead: -# gem 'rails', :git => 'git://github.com/rails/rails.git' - -gem 'devise' -gem 'redis' -gem 'pg' -gem 'cancan' -gem 'formula' -gem 'formtastic' -gem 'json' -gem 'rails3-jquery-autocomplete' -gem 'best_in_place' -gem 'therubyracer' #optional -#gem 'rb-readline' - -# Gems used only for assets and not required -# in production environments by default. -group :assets do - gem 'sass-rails' - gem 'coffee-rails', '~> 3.2.1' - - # See https://github.com/sstephenson/execjs#readme for more supported runtimes - # gem 'therubyracer' - - gem 'uglifier', '>= 1.0.3' -end - -gem 'jquery-rails', '2.1.2' - -# To use ActiveModel has_secure_password -# gem 'bcrypt-ruby', '~> 3.0.0' - -# To use Jbuilder templates for JSON - gem 'jbuilder', '0.8.2' - -# Use unicorn as the web server -# gem 'unicorn' - -# Deploy with Capistrano -# gem 'capistrano' - -# To use debugger -# gem 'ruby-debug19', :require => 'ruby-debug' diff --git a/Metamaps AGPL License.txt b/LICENSE similarity index 93% rename from Metamaps AGPL License.txt rename to LICENSE index c5a113d7..58777e31 100644 --- a/Metamaps AGPL License.txt +++ b/LICENSE @@ -1,7 +1,7 @@ - GNU AFFERO GENERAL PUBLIC LICENSE +GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 - Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. @@ -617,4 +617,45 @@ Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS - + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/MacInstallation.md b/MacInstallation.md new file mode 100644 index 00000000..a6e47436 --- /dev/null +++ b/MacInstallation.md @@ -0,0 +1,40 @@ +install homebrew + + \curl -sSL https://get.rvm.io | bash -s stable --rails + + rvm install 1.9.3 --with-gcc=clang + + rvm use 1.9.3 + + gem install lunchy + +(http://www.moncefbelyamani.com/how-to-install-postgresql-on-a-mac-with-homebrew-and-lunchy/) + + + brew install postgresql + ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents + createuser metamaps -P -s -d + +set a password + + lunchy start postgres + + +cd into the metamaps directory + + bundle install + + +copy the database.yml.default file and rename it database.yml +make sure the username and password match the POSTGRES username and password you set + + +http://nodejs.org/ hit install, download, open, install + + + rake db:create + rake db:schema:load + rake db:fixtures:load + rails s + +( to start the server) diff --git a/README.md b/README.md new file mode 100644 index 00000000..af6e92c4 --- /dev/null +++ b/README.md @@ -0,0 +1,55 @@ +Metamaps +======= + +Welcome to the Metamaps GitHub repo. + +## About + +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 a private beta. + +Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter. + +To get connected with the community interested in Metamaps, join our [Google+ community][community]. + +## Installation + +Depending on which OS you are using, the instructions for getting set up with a local installation of the Metamaps software will vary. Because the software has both Node.js components, and RubyOnRails, getting set up with your local copy can take 1 to 2 hours. +- [For Windows][windows-installation] +- [For Ubuntu][ubuntu-installation] +- [For Mac][mac-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. + +## Documentation + +- TODO + +## Community + +- 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]. + +## 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) 2014 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/Connoropolous/metamaps_gen002/blob/master/LICENSE +[contributing]: https://github.com/Connoropolous/metamaps_gen002/blob/master/CONTRIBUTING.md +[contributing-issues]: https://github.com/Connoropolous/metamaps_gen002/blob/master/CONTRIBUTING.md#reporting-bugs-and-other-issues +[windows-installation]: https://github.com/Connoropolous/metamaps_gen002/blob/master/WindowsInstallation.md +[mac-installation]: https://github.com/Connoropolous/metamaps_gen002/blob/master/MacInstallation.md +[ubuntu-installation]: https://github.com/Connoropolous/metamaps_gen002/blob/master/UbuntuInstallation.md diff --git a/README.rdoc b/README.rdoc deleted file mode 100644 index c90f8df3..00000000 --- a/README.rdoc +++ /dev/null @@ -1,89 +0,0 @@ -== Metamaps -Metamaps is a free and open source technology for changemakers, innovators, educators and students. It enables individuals and communities to build and visualize their shared knowledge and unlock their collective intelligence. You can find out about more about the project at http://blog.metamaps.cc. - -You can find a version of this software running at http://metamaps.cc, where the technology is being beta tested in a private beta, if you're not up to the task of running your own version. - -Metamaps is created and maintained by a distributed, nomadic community comprised of technologists, artists and storytellers. You can get in touch with us at team@metamaps.cc or @metamapps on twitter. - -To get connected with the community interested in Metamaps, join our G+ community. https://plus.google.com/u/0/communities/115060009262157699234 - -To contribute to Metamaps, fork this repository, and submit a pull request! - -==Running Metamaps On Your Local Machine - -First off, Metamaps runs on Ruby On Rails. Ruby 1.9.3 and Rails 3.2. You'll need to get Ruby and Rails installed on your computer if you don't already have it. We recommend using the Rails Installer, which you can download from Mac or Windows at http://railsinstaller.org/en (see the notes below about Ubuntu). This will get you set up perfectly with the right versions of Ruby, and Rails for running your local version of Metamaps. - -It uses postgreSQL 9.2 as a database. You can install that for your computer from here: http://www.enterprisedb.com/products-services-training/pgdownload . During installation you can choose whatever database password you like. Make sure to note it down! - -Once you install those, open a 'command prompt with ruby and rails'. - -Navigate to the folder that you want to download the metamaps files to and run the following: (use your forked git repository address if it's different than this repo. You will also need to go to your Github account settings and add the SSH key that was placed in your clipboard earlier) - git clone git@github.com:Connoropolous/metamaps_gen002.git - cd metamaps_gen002 - -Now you're in the main directory. - -Install all the gems needed for Metamaps by running - $ bundle install - -Setting up the database: - -1) Copy /config/database.yml.default and rename the copy to /config/database.yml then edit database.yml with your text editor and set the password to whatever you chose when you set up the PostGres database. - -2) In a terminal: - $ rake db:create - $ rake db:schema:load - $ rake db:fixtures:load - -Running the server: - - $rails s #runs the server - -Navigate your browser to localhost:3000 once you have the server running - -Sign in with the default account - -email: user@user.com - -password: toolsplusconsciousness - -OR create a new account at /users/sign_up, and use access code 'qwertyui' - -Start mapping and programming! - - -==Installing on Ubuntu - -There can be trouble installing on Ubuntu - -Try installing postgresql and libpq-dev. - -It's also recommended using Ruby Version Manager (rvm) - $rvm reinstall ruby-1.9.3-p125 - -execjs might complain there is no runtime, if so add gem 'therubyracer' to the Gemfile - - -== Finding Your Way Around The Code - -Here are the important folders/files: - -config/database.yml: This file is your database configuration. If it doesn't exist, copy it from config/database.yml.default and then get it set up. config/database.yml is in .gitignore - -app/assets/javascripts/application.js: Global Javascript - -app/assets/javascripts/Jit/*: These files handle all code that uses the Javascript Infovis Toolkit, so realistically, most code for laying stuff out is in here. - -app/assets/controllers/*: These files define actions you can do on the different database objects. So for instance, what happens when you edit a Synapse? Check in app/assets/controllers/synapse_controller.rb, in the edit block - -app/assets/views/*.html.erb: Files in here define either html that is displayed when a certain action is called (like edit, or create) on a thing. E.G. app/assets/views/topic/new.html.erb would have a form for creating a new topic. We don't use that way very much anymore though. "Partial" views can be called elsewhere in ruby code and are prefixed with an underscore. So we focus more on the files starting with an underscore. Read through the comments at the top of each file to understand what they all do. - -app/assets/views/*.js.erb: Javascript that is called in response to, e.g., editing or creating a topic, synapse, etc. - - -== 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. - -You should have received a copy of the GNU Affero General Public License along with this program. If not, see http://www.gnu.org/licenses. diff --git a/Rakefile b/Rakefile index b21a66b9..30cf58f5 100644 --- a/Rakefile +++ b/Rakefile @@ -4,4 +4,4 @@ require File.expand_path('../config/application', __FILE__) -ISSAD::Application.load_tasks +Metamaps::Application.load_tasks diff --git a/Ubuntu README.md b/UbuntuInstallation.md similarity index 55% rename from Ubuntu README.md rename to UbuntuInstallation.md index beefc79f..348ad5c1 100644 --- a/Ubuntu README.md +++ b/UbuntuInstallation.md @@ -1,101 +1,109 @@ Firstly this walkthrough is done with a 14.04 32bit install of Ubuntu. -All Commands are quoted with "" which are not to be included in the command. - All commands that I could are terminal based. Lets check if all updates for the system are installed first in terminal type -"sudo apt-get update" + sudo apt-get update now we need to install git -"sudo apt-get install git" + sudo apt-get install git lets get our RVM installed (Ruby Version Manager) now this is fun because the package you will get from apt-get is outdated. so we are going to use CURL to get RVM -"sudo apt-get install curl" + sudo apt-get install curl then lets install RVM with curl like this -"curl -L get.rvm.io | bash -s stable" + curl -L get.rvm.io | bash -s stable -"PATH=$PATH:$HOME/.rvm/bin # Add RVM to PATH for scripting" + PATH=$PATH:$HOME/.rvm/bin # Add RVM to PATH for scripting -"[[ -s "$HOME/.profile" ]] && source "$HOME/.profile"" + [[ -s "$HOME/.profile" ]] && source "$HOME/.profile" -"[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"" + [[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm" -"source ~/.rvm/scripts/rvm" + source ~/.rvm/scripts/rvm now we can actually install RVM -"rvm requirements" + rvm requirements running this will check your system for requirements as well so you will need to put your system password in. alright now we can download metamaps from the master using git -"git clone https://github.com/Connoropolous/metamaps_gen002.git" + git clone https://github.com/Connoropolous/metamaps_gen002.git now there is a couple other things we are going to need which is nodejs, postgresql, libpq-dev and redis-server -"sudo apt-get install nodejs" + sudo apt-get install nodejs -"sudo apt-get install postgresql" + sudo apt-get install postgresql -"sudo apt-get install libpq-dev" + sudo apt-get install libpq-dev -"sudo apt-get install redis-server" + sudo apt-get install redis-server Install the specific version of ruby needed this will take some time *Note you will get a warning about this being an outdated version* -"rvm install ruby-1.9.3-p125" + rvm install ruby-1.9.3-p125 -Now we also need to rename your database file which is in ./config/database.yml.default to database.yml +Now we also need to rename your database file which is in ./config/database.default.yml to database.yml now run inside your metamaps_gen002 folder -"bundle install" + bundle install in your top lvl directory for metamaps this is a lengthy process so you might want to go and make a coffee or something :) alright now we need to make sure your postgres password is the same as it is listed in the DB file so we are going to set it by -"sudo -u postgres psql" + sudo -u postgres psql Select postgres like this -"\password postgres;" + \password postgres set the password to 3112 Then to quit -"\q;" + \q now we can run the rake install and db creation -"rake db:create" + rake db:create -"rake db:schema:load" + rake db:schema:load + + rake db:fixtures:load -"rake db:fixtures:load" - -Execute the server : "rails s" +Execute the server: + + rails s and dont forget to run realtime too open a new terminal navigate to ./realtime and run -"nodejs realtime-server.js" + nodejs realtime-server.js -Now your all set enjoy your personal server of metamaps :) +Now you're all set enjoy your personal server of metamaps :) +Navigate your browser to localhost:3000 once you have the server running +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! diff --git a/WindowsInstallation.md b/WindowsInstallation.md new file mode 100644 index 00000000..0e8dcd4e --- /dev/null +++ b/WindowsInstallation.md @@ -0,0 +1,42 @@ +First off, Metamaps runs on Ruby On Rails. Ruby 1.9.3 and Rails 3.2. You'll need to get Ruby and Rails installed on your computer if you don't already have it. We recommend using the Rails Installer, which you can download from Mac or Windows at http://railsinstaller.org/en (see the notes below about Ubuntu). This will get you set up perfectly with the right versions of Ruby, and Rails for running your local version of Metamaps. + +It uses postgreSQL 9.2 as a database. You can install that for your computer from here: http://www.enterprisedb.com/products-services-training/pgdownload . During installation you can choose whatever database password you like. Make sure to note it down! + +Once you install those, open a 'command prompt with ruby and rails'. + +Navigate to the folder that you want to download the metamaps files to and run the following: (use your forked git repository address if it's different than this repo. You will also need to go to your Github account settings and add the SSH key that was placed in your clipboard earlier) + + git clone https://github.com/Connoropolous/metamaps_gen002.git + cd metamaps_gen002 + +Now you're in the main directory. + +Install all the gems needed for Metamaps by running + + bundle install + +Setting up the database: + +1) Copy /config/database.yml.default and rename the copy to /config/database.yml then edit database.yml with your text editor and set the password to whatever you chose when you set up the PostGres database. + +2) In a terminal: + + rake db:create + rake db:schema:load + rake db:fixtures:load + +Running the server: + + rails s + +Navigate your browser to localhost:3000 once you have the server running + +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! diff --git a/app/assets/images/MMCCicon_add.png b/app/assets/images/MMCCicon_add.png deleted file mode 100644 index fdb4045f..00000000 Binary files a/app/assets/images/MMCCicon_add.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_add_map.png b/app/assets/images/MMCCicon_add_map.png deleted file mode 100644 index ded32adc..00000000 Binary files a/app/assets/images/MMCCicon_add_map.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_admin.png b/app/assets/images/MMCCicon_admin.png deleted file mode 100644 index a3b9a767..00000000 Binary files a/app/assets/images/MMCCicon_admin.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_center.png b/app/assets/images/MMCCicon_center.png deleted file mode 100644 index c009d99d..00000000 Binary files a/app/assets/images/MMCCicon_center.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_commons.png b/app/assets/images/MMCCicon_commons.png deleted file mode 100644 index 1eed3c5b..00000000 Binary files a/app/assets/images/MMCCicon_commons.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_commons_black.png b/app/assets/images/MMCCicon_commons_black.png deleted file mode 100644 index 4f06fed8..00000000 Binary files a/app/assets/images/MMCCicon_commons_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_delete_black.png b/app/assets/images/MMCCicon_delete_black.png deleted file mode 100644 index 017a1adf..00000000 Binary files a/app/assets/images/MMCCicon_delete_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_delete_grey.png b/app/assets/images/MMCCicon_delete_grey.png deleted file mode 100644 index 4ba2b136..00000000 Binary files a/app/assets/images/MMCCicon_delete_grey.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_edit_permission_black.png b/app/assets/images/MMCCicon_edit_permission_black.png deleted file mode 100644 index e87d006e..00000000 Binary files a/app/assets/images/MMCCicon_edit_permission_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_filter.png b/app/assets/images/MMCCicon_filter.png deleted file mode 100644 index afb23324..00000000 Binary files a/app/assets/images/MMCCicon_filter.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_filter2.png b/app/assets/images/MMCCicon_filter2.png deleted file mode 100644 index 5b50ffdd..00000000 Binary files a/app/assets/images/MMCCicon_filter2.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_go.png b/app/assets/images/MMCCicon_go.png deleted file mode 100644 index e35a0f87..00000000 Binary files a/app/assets/images/MMCCicon_go.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_help.png b/app/assets/images/MMCCicon_help.png deleted file mode 100644 index 16cd1894..00000000 Binary files a/app/assets/images/MMCCicon_help.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_hide.png b/app/assets/images/MMCCicon_hide.png deleted file mode 100644 index 80ea7276..00000000 Binary files a/app/assets/images/MMCCicon_hide.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_info.png b/app/assets/images/MMCCicon_info.png deleted file mode 100644 index 4594cba0..00000000 Binary files a/app/assets/images/MMCCicon_info.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_invite.png b/app/assets/images/MMCCicon_invite.png deleted file mode 100644 index 347ddc02..00000000 Binary files a/app/assets/images/MMCCicon_invite.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_left_arrow.png b/app/assets/images/MMCCicon_left_arrow.png deleted file mode 100644 index 23cd9559..00000000 Binary files a/app/assets/images/MMCCicon_left_arrow.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_link.png b/app/assets/images/MMCCicon_link.png deleted file mode 100644 index 8bd1ee24..00000000 Binary files a/app/assets/images/MMCCicon_link.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_logout.png b/app/assets/images/MMCCicon_logout.png deleted file mode 100644 index 5f22796f..00000000 Binary files a/app/assets/images/MMCCicon_logout.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_map.png b/app/assets/images/MMCCicon_map.png deleted file mode 100644 index e1a61d89..00000000 Binary files a/app/assets/images/MMCCicon_map.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_map_black.png b/app/assets/images/MMCCicon_map_black.png deleted file mode 100644 index abefa2a1..00000000 Binary files a/app/assets/images/MMCCicon_map_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_mapper.png b/app/assets/images/MMCCicon_mapper.png deleted file mode 100644 index 0e9c3207..00000000 Binary files a/app/assets/images/MMCCicon_mapper.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_mapper_black.png b/app/assets/images/MMCCicon_mapper_black.png deleted file mode 100644 index a324b3a9..00000000 Binary files a/app/assets/images/MMCCicon_mapper_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_maximize_arrow.png b/app/assets/images/MMCCicon_maximize_arrow.png deleted file mode 100644 index 1fe42d26..00000000 Binary files a/app/assets/images/MMCCicon_maximize_arrow.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_maximize_arrow_black.png b/app/assets/images/MMCCicon_maximize_arrow_black.png deleted file mode 100644 index 5196c38e..00000000 Binary files a/app/assets/images/MMCCicon_maximize_arrow_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_metacode_set.png b/app/assets/images/MMCCicon_metacode_set.png deleted file mode 100644 index 98aea34a..00000000 Binary files a/app/assets/images/MMCCicon_metacode_set.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_metacode_set_change.png b/app/assets/images/MMCCicon_metacode_set_change.png deleted file mode 100644 index 56279526..00000000 Binary files a/app/assets/images/MMCCicon_metacode_set_change.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_minimize_arrow.png b/app/assets/images/MMCCicon_minimize_arrow.png deleted file mode 100644 index 2aad516c..00000000 Binary files a/app/assets/images/MMCCicon_minimize_arrow.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_minimize_arrow_black.png b/app/assets/images/MMCCicon_minimize_arrow_black.png deleted file mode 100644 index cb1a83b7..00000000 Binary files a/app/assets/images/MMCCicon_minimize_arrow_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_pop-out.png b/app/assets/images/MMCCicon_pop-out.png deleted file mode 100644 index ca3ecd45..00000000 Binary files a/app/assets/images/MMCCicon_pop-out.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_pop-out_black.png b/app/assets/images/MMCCicon_pop-out_black.png deleted file mode 100644 index 7db39126..00000000 Binary files a/app/assets/images/MMCCicon_pop-out_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_private.png b/app/assets/images/MMCCicon_private.png deleted file mode 100644 index 50e98e18..00000000 Binary files a/app/assets/images/MMCCicon_private.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_private_black.png b/app/assets/images/MMCCicon_private_black.png deleted file mode 100644 index 076205f6..00000000 Binary files a/app/assets/images/MMCCicon_private_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_public.png b/app/assets/images/MMCCicon_public.png deleted file mode 100644 index e8b51410..00000000 Binary files a/app/assets/images/MMCCicon_public.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_public_black.png b/app/assets/images/MMCCicon_public_black.png deleted file mode 100644 index 950c49e4..00000000 Binary files a/app/assets/images/MMCCicon_public_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_realtime_blue.png b/app/assets/images/MMCCicon_realtime_blue.png deleted file mode 100644 index 98bd1982..00000000 Binary files a/app/assets/images/MMCCicon_realtime_blue.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_realtime_junto.png b/app/assets/images/MMCCicon_realtime_junto.png deleted file mode 100644 index 587065b4..00000000 Binary files a/app/assets/images/MMCCicon_realtime_junto.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_remove_from_map_black.png b/app/assets/images/MMCCicon_remove_from_map_black.png deleted file mode 100644 index 9ddc204f..00000000 Binary files a/app/assets/images/MMCCicon_remove_from_map_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_remove_from_map_grey.png b/app/assets/images/MMCCicon_remove_from_map_grey.png deleted file mode 100644 index 0e863158..00000000 Binary files a/app/assets/images/MMCCicon_remove_from_map_grey.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_right_arrow.png b/app/assets/images/MMCCicon_right_arrow.png deleted file mode 100644 index 5b57c191..00000000 Binary files a/app/assets/images/MMCCicon_right_arrow.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_save_layout.png b/app/assets/images/MMCCicon_save_layout.png deleted file mode 100644 index d163dfb5..00000000 Binary files a/app/assets/images/MMCCicon_save_layout.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_save_new_map.png b/app/assets/images/MMCCicon_save_new_map.png deleted file mode 100644 index ac6d5e95..00000000 Binary files a/app/assets/images/MMCCicon_save_new_map.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_settings.png b/app/assets/images/MMCCicon_settings.png deleted file mode 100644 index ae56c5a9..00000000 Binary files a/app/assets/images/MMCCicon_settings.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_synapse.png b/app/assets/images/MMCCicon_synapse.png deleted file mode 100644 index 9fea87f0..00000000 Binary files a/app/assets/images/MMCCicon_synapse.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_synapse_black.png b/app/assets/images/MMCCicon_synapse_black.png deleted file mode 100644 index 1f96a7e9..00000000 Binary files a/app/assets/images/MMCCicon_synapse_black.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_topic.png b/app/assets/images/MMCCicon_topic.png deleted file mode 100644 index 90457c0b..00000000 Binary files a/app/assets/images/MMCCicon_topic.png and /dev/null differ diff --git a/app/assets/images/MMCCicon_wand.png b/app/assets/images/MMCCicon_wand.png deleted file mode 100644 index 409d1948..00000000 Binary files a/app/assets/images/MMCCicon_wand.png and /dev/null differ diff --git a/app/assets/images/MMSocial-51.png b/app/assets/images/MMSocial-51.png deleted file mode 100644 index d31ecc9f..00000000 Binary files a/app/assets/images/MMSocial-51.png and /dev/null differ diff --git a/app/assets/images/MMSocial-52.png b/app/assets/images/MMSocial-52.png deleted file mode 100644 index 2396356a..00000000 Binary files a/app/assets/images/MMSocial-52.png and /dev/null differ diff --git a/app/assets/images/MMSocial-53.png b/app/assets/images/MMSocial-53.png deleted file mode 100644 index e78ab067..00000000 Binary files a/app/assets/images/MMSocial-53.png and /dev/null differ diff --git a/app/assets/images/about_sprite.png b/app/assets/images/about_sprite.png new file mode 100755 index 00000000..58eafff7 Binary files /dev/null and b/app/assets/images/about_sprite.png differ diff --git a/app/assets/images/addtopic_sprite.png b/app/assets/images/addtopic_sprite.png new file mode 100755 index 00000000..14213bf5 Binary files /dev/null and b/app/assets/images/addtopic_sprite.png differ diff --git a/app/assets/images/arrow_sprite.png b/app/assets/images/arrow_sprite.png new file mode 100755 index 00000000..d033c784 Binary files /dev/null and b/app/assets/images/arrow_sprite.png differ diff --git a/app/assets/images/arrowdown_sprite.png b/app/assets/images/arrowdown_sprite.png new file mode 100755 index 00000000..1353452d Binary files /dev/null and b/app/assets/images/arrowdown_sprite.png differ diff --git a/app/assets/images/arrowperms_sprite.png b/app/assets/images/arrowperms_sprite.png new file mode 100644 index 00000000..eff00341 Binary files /dev/null and b/app/assets/images/arrowperms_sprite.png differ diff --git a/app/assets/images/arrowright_sprite.png b/app/assets/images/arrowright_sprite.png new file mode 100755 index 00000000..5fb67803 Binary files /dev/null and b/app/assets/images/arrowright_sprite.png differ diff --git a/app/assets/images/background2-for-repeating.jpg b/app/assets/images/background2-for-repeating.jpg deleted file mode 100644 index 946cfa6b..00000000 Binary files a/app/assets/images/background2-for-repeating.jpg and /dev/null differ diff --git a/app/assets/images/background2.jpg b/app/assets/images/background2.jpg deleted file mode 100644 index 9d9a3c7c..00000000 Binary files a/app/assets/images/background2.jpg and /dev/null differ diff --git a/app/assets/images/beta_gen002.png b/app/assets/images/beta_gen002.png deleted file mode 100644 index 550e9e4b..00000000 Binary files a/app/assets/images/beta_gen002.png and /dev/null differ diff --git a/app/assets/images/bg.png b/app/assets/images/bg.png deleted file mode 100644 index 681d441c..00000000 Binary files a/app/assets/images/bg.png and /dev/null differ diff --git a/app/assets/images/compass_arrow.png b/app/assets/images/compass_arrow.png new file mode 100644 index 00000000..e688df79 Binary files /dev/null and b/app/assets/images/compass_arrow.png differ diff --git a/app/assets/images/context_sprite.png b/app/assets/images/context_sprite.png new file mode 100755 index 00000000..df724cb9 Binary files /dev/null and b/app/assets/images/context_sprite.png differ diff --git a/app/assets/images/edit.png b/app/assets/images/edit.png new file mode 100755 index 00000000..ead97a43 Binary files /dev/null and b/app/assets/images/edit.png differ diff --git a/app/assets/images/exploremaps_sprite.png b/app/assets/images/exploremaps_sprite.png new file mode 100755 index 00000000..16535918 Binary files /dev/null and b/app/assets/images/exploremaps_sprite.png differ diff --git a/app/assets/images/extents_sprite.png b/app/assets/images/extents_sprite.png new file mode 100755 index 00000000..583d2c7c Binary files /dev/null and b/app/assets/images/extents_sprite.png differ diff --git a/app/assets/images/feedback_sprite.png b/app/assets/images/feedback_sprite.png new file mode 100755 index 00000000..fc7998d3 Binary files /dev/null and b/app/assets/images/feedback_sprite.png differ diff --git a/app/assets/images/help_sprite.png b/app/assets/images/help_sprite.png new file mode 100755 index 00000000..da171b68 Binary files /dev/null and b/app/assets/images/help_sprite.png differ diff --git a/app/assets/images/home_dark.png b/app/assets/images/home_dark.png new file mode 100755 index 00000000..0008b5b4 Binary files /dev/null and b/app/assets/images/home_dark.png differ diff --git a/app/assets/images/home_light.png b/app/assets/images/home_light.png new file mode 100755 index 00000000..de4291da Binary files /dev/null and b/app/assets/images/home_light.png differ diff --git a/app/assets/images/junto24_sprite.png b/app/assets/images/junto24_sprite.png new file mode 100755 index 00000000..24e1a1af Binary files /dev/null and b/app/assets/images/junto24_sprite.png differ diff --git a/app/assets/images/labelCheckbox.png b/app/assets/images/labelCheckbox.png deleted file mode 100644 index 8f6a6e5e..00000000 Binary files a/app/assets/images/labelCheckbox.png and /dev/null differ diff --git a/app/assets/images/link_sprite.png b/app/assets/images/link_sprite.png new file mode 100755 index 00000000..fdfec698 Binary files /dev/null and b/app/assets/images/link_sprite.png differ diff --git a/app/assets/images/linkedmedia.png b/app/assets/images/linkedmedia.png new file mode 100755 index 00000000..2009b7a3 Binary files /dev/null and b/app/assets/images/linkedmedia.png differ diff --git a/app/assets/images/map.png b/app/assets/images/map.png deleted file mode 100644 index 1137c4ad..00000000 Binary files a/app/assets/images/map.png and /dev/null differ diff --git a/app/assets/images/map32_sprite.png b/app/assets/images/map32_sprite.png new file mode 100755 index 00000000..33c8ee6c Binary files /dev/null and b/app/assets/images/map32_sprite.png differ diff --git a/app/assets/images/mapInfoLine.png b/app/assets/images/mapInfoLine.png deleted file mode 100644 index e73a2339..00000000 Binary files a/app/assets/images/mapInfoLine.png and /dev/null differ diff --git a/app/assets/images/mapinfo_sprite.png b/app/assets/images/mapinfo_sprite.png new file mode 100755 index 00000000..9429ab30 Binary files /dev/null and b/app/assets/images/mapinfo_sprite.png differ diff --git a/app/assets/images/menu_icon_32.png b/app/assets/images/menu_icon_32.png deleted file mode 100644 index 811f4af3..00000000 Binary files a/app/assets/images/menu_icon_32.png and /dev/null differ diff --git a/app/assets/images/metacode-watermark.png b/app/assets/images/metacode-watermark.png deleted file mode 100644 index 2196e907..00000000 Binary files a/app/assets/images/metacode-watermark.png and /dev/null differ diff --git a/app/assets/images/metacodesettings_sprite.png b/app/assets/images/metacodesettings_sprite.png new file mode 100755 index 00000000..6b64c74e Binary files /dev/null and b/app/assets/images/metacodesettings_sprite.png differ diff --git a/app/assets/images/metamap16.png b/app/assets/images/metamap16.png new file mode 100755 index 00000000..923dbc4e Binary files /dev/null and b/app/assets/images/metamap16.png differ diff --git a/app/assets/images/metamap32c.png b/app/assets/images/metamap32c.png new file mode 100755 index 00000000..36c3282a Binary files /dev/null and b/app/assets/images/metamap32c.png differ diff --git a/app/assets/images/metamap36c.png b/app/assets/images/metamap36c.png new file mode 100755 index 00000000..5917fb6f Binary files /dev/null and b/app/assets/images/metamap36c.png differ diff --git a/app/assets/images/permissions32_sprite.png b/app/assets/images/permissions32_sprite.png new file mode 100755 index 00000000..dd1e175e Binary files /dev/null and b/app/assets/images/permissions32_sprite.png differ diff --git a/app/assets/images/permissions36_sprite.png b/app/assets/images/permissions36_sprite.png new file mode 100755 index 00000000..422022c5 Binary files /dev/null and b/app/assets/images/permissions36_sprite.png differ diff --git a/app/assets/images/permissions64sprite.png b/app/assets/images/permissions64sprite.png new file mode 100755 index 00000000..2f9d189d Binary files /dev/null and b/app/assets/images/permissions64sprite.png differ diff --git a/app/assets/images/photo.png b/app/assets/images/photo.png new file mode 100755 index 00000000..ba283a57 Binary files /dev/null and b/app/assets/images/photo.png differ diff --git a/app/assets/images/remove.png b/app/assets/images/remove.png new file mode 100755 index 00000000..9f44bea2 Binary files /dev/null and b/app/assets/images/remove.png differ diff --git a/app/assets/images/search.png b/app/assets/images/search.png new file mode 100755 index 00000000..b7e53cb7 Binary files /dev/null and b/app/assets/images/search.png differ diff --git a/app/assets/images/search_icon_32x32.png b/app/assets/images/search_icon_32x32.png deleted file mode 100644 index 00a6dc34..00000000 Binary files a/app/assets/images/search_icon_32x32.png and /dev/null differ diff --git a/app/assets/images/settings.png b/app/assets/images/settings.png deleted file mode 100644 index d3348a38..00000000 Binary files a/app/assets/images/settings.png and /dev/null differ diff --git a/app/assets/images/share_sprite.png b/app/assets/images/share_sprite.png new file mode 100755 index 00000000..5486daef Binary files /dev/null and b/app/assets/images/share_sprite.png differ diff --git a/app/assets/images/shattered_@2X.png b/app/assets/images/shattered_@2X.png new file mode 100644 index 00000000..19322777 Binary files /dev/null and b/app/assets/images/shattered_@2X.png differ diff --git a/app/assets/images/spinner.gif b/app/assets/images/spinner.gif deleted file mode 100644 index e17b93cd..00000000 Binary files a/app/assets/images/spinner.gif and /dev/null differ diff --git a/app/assets/images/synapse16.png b/app/assets/images/synapse16.png new file mode 100755 index 00000000..d88b0a06 Binary files /dev/null and b/app/assets/images/synapse16.png differ diff --git a/app/assets/images/synapse32.png b/app/assets/images/synapse32.png new file mode 100755 index 00000000..d56080eb Binary files /dev/null and b/app/assets/images/synapse32.png differ diff --git a/app/assets/images/synapse32_sprite.png b/app/assets/images/synapse32_sprite.png new file mode 100755 index 00000000..53c593d5 Binary files /dev/null and b/app/assets/images/synapse32_sprite.png differ diff --git a/app/assets/images/synapsedirectionleft_sprite.png b/app/assets/images/synapsedirectionleft_sprite.png new file mode 100755 index 00000000..df9f11ee Binary files /dev/null and b/app/assets/images/synapsedirectionleft_sprite.png differ diff --git a/app/assets/images/synapsedirectionright_sprite.png b/app/assets/images/synapsedirectionright_sprite.png new file mode 100755 index 00000000..8ecebd60 Binary files /dev/null and b/app/assets/images/synapsedirectionright_sprite.png differ diff --git a/app/assets/images/synapsestar.png b/app/assets/images/synapsestar.png new file mode 100755 index 00000000..ba9a7dd3 Binary files /dev/null and b/app/assets/images/synapsestar.png differ diff --git a/app/assets/images/topbg.png b/app/assets/images/topbg.png deleted file mode 100644 index f56313e3..00000000 Binary files a/app/assets/images/topbg.png and /dev/null differ diff --git a/app/assets/images/topbg2.png b/app/assets/images/topbg2.png deleted file mode 100644 index a433e648..00000000 Binary files a/app/assets/images/topbg2.png and /dev/null differ diff --git a/app/assets/images/topic16.png b/app/assets/images/topic16.png new file mode 100755 index 00000000..18f6ee7a Binary files /dev/null and b/app/assets/images/topic16.png differ diff --git a/app/assets/images/topic32.png b/app/assets/images/topic32.png new file mode 100755 index 00000000..53e34702 Binary files /dev/null and b/app/assets/images/topic32.png differ diff --git a/app/assets/images/topright_sprite.png b/app/assets/images/topright_sprite.png new file mode 100755 index 00000000..938c6a0b Binary files /dev/null and b/app/assets/images/topright_sprite.png differ diff --git a/vendor/assets/images/ui-bg_flat_0_aaaaaa_40x100.png b/app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png similarity index 100% rename from vendor/assets/images/ui-bg_flat_0_aaaaaa_40x100.png rename to app/assets/images/ui-bg_flat_0_aaaaaa_40x100.png diff --git a/vendor/assets/images/ui-bg_flat_75_ffffff_40x100.png b/app/assets/images/ui-bg_flat_75_ffffff_40x100.png similarity index 100% rename from vendor/assets/images/ui-bg_flat_75_ffffff_40x100.png rename to app/assets/images/ui-bg_flat_75_ffffff_40x100.png diff --git a/vendor/assets/images/ui-bg_glass_55_fbf9ee_1x400.png b/app/assets/images/ui-bg_glass_55_fbf9ee_1x400.png similarity index 100% rename from vendor/assets/images/ui-bg_glass_55_fbf9ee_1x400.png rename to app/assets/images/ui-bg_glass_55_fbf9ee_1x400.png diff --git a/vendor/assets/images/ui-bg_glass_65_ffffff_1x400.png b/app/assets/images/ui-bg_glass_65_ffffff_1x400.png similarity index 100% rename from vendor/assets/images/ui-bg_glass_65_ffffff_1x400.png rename to app/assets/images/ui-bg_glass_65_ffffff_1x400.png diff --git a/vendor/assets/images/ui-bg_glass_75_dadada_1x400.png b/app/assets/images/ui-bg_glass_75_dadada_1x400.png similarity index 100% rename from vendor/assets/images/ui-bg_glass_75_dadada_1x400.png rename to app/assets/images/ui-bg_glass_75_dadada_1x400.png diff --git a/vendor/assets/images/ui-bg_glass_75_e6e6e6_1x400.png b/app/assets/images/ui-bg_glass_75_e6e6e6_1x400.png similarity index 100% rename from vendor/assets/images/ui-bg_glass_75_e6e6e6_1x400.png rename to app/assets/images/ui-bg_glass_75_e6e6e6_1x400.png diff --git a/vendor/assets/images/ui-bg_glass_95_fef1ec_1x400.png b/app/assets/images/ui-bg_glass_95_fef1ec_1x400.png similarity index 100% rename from vendor/assets/images/ui-bg_glass_95_fef1ec_1x400.png rename to app/assets/images/ui-bg_glass_95_fef1ec_1x400.png diff --git a/vendor/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/app/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png similarity index 100% rename from vendor/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png rename to app/assets/images/ui-bg_highlight-soft_75_cccccc_1x100.png diff --git a/vendor/assets/images/ui-icons_222222_256x240.png b/app/assets/images/ui-icons_222222_256x240.png similarity index 100% rename from vendor/assets/images/ui-icons_222222_256x240.png rename to app/assets/images/ui-icons_222222_256x240.png diff --git a/vendor/assets/images/ui-icons_2e83ff_256x240.png b/app/assets/images/ui-icons_2e83ff_256x240.png similarity index 100% rename from vendor/assets/images/ui-icons_2e83ff_256x240.png rename to app/assets/images/ui-icons_2e83ff_256x240.png diff --git a/vendor/assets/images/ui-icons_454545_256x240.png b/app/assets/images/ui-icons_454545_256x240.png similarity index 100% rename from vendor/assets/images/ui-icons_454545_256x240.png rename to app/assets/images/ui-icons_454545_256x240.png diff --git a/vendor/assets/images/ui-icons_888888_256x240.png b/app/assets/images/ui-icons_888888_256x240.png similarity index 100% rename from vendor/assets/images/ui-icons_888888_256x240.png rename to app/assets/images/ui-icons_888888_256x240.png diff --git a/vendor/assets/images/ui-icons_cd0a0a_256x240.png b/app/assets/images/ui-icons_cd0a0a_256x240.png similarity index 100% rename from vendor/assets/images/ui-icons_cd0a0a_256x240.png rename to app/assets/images/ui-icons_cd0a0a_256x240.png diff --git a/app/assets/images/upload_sprite.png b/app/assets/images/upload_sprite.png new file mode 100755 index 00000000..563be4b4 Binary files /dev/null and b/app/assets/images/upload_sprite.png differ diff --git a/app/assets/images/user.png b/app/assets/images/user.png new file mode 100755 index 00000000..67239052 Binary files /dev/null and b/app/assets/images/user.png differ diff --git a/app/assets/images/user_sprite.png b/app/assets/images/user_sprite.png new file mode 100755 index 00000000..72bcafac Binary files /dev/null and b/app/assets/images/user_sprite.png differ diff --git a/app/assets/images/xlightbox.png b/app/assets/images/xlightbox.png new file mode 100755 index 00000000..48932848 Binary files /dev/null and b/app/assets/images/xlightbox.png differ diff --git a/app/assets/images/zoom_sprite.png b/app/assets/images/zoom_sprite.png new file mode 100755 index 00000000..b03bdeec Binary files /dev/null and b/app/assets/images/zoom_sprite.png differ diff --git a/app/assets/javascripts/Jit/excanvas.js b/app/assets/javascripts/Jit/excanvas.js deleted file mode 100644 index 00b316ca..00000000 --- a/app/assets/javascripts/Jit/excanvas.js +++ /dev/null @@ -1,1416 +0,0 @@ -// Copyright 2006 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - - -// Known Issues: -// -// * Patterns only support repeat. -// * Radial gradient are not implemented. The VML version of these look very -// different from the canvas one. -// * Clipping paths are not implemented. -// * Coordsize. The width and height attribute have higher priority than the -// width and height style values which isn't correct. -// * Painting mode isn't implemented. -// * Canvas width/height should is using content-box by default. IE in -// Quirks mode will draw the canvas using border-box. Either change your -// doctype to HTML5 -// (http://www.whatwg.org/specs/web-apps/current-work/#the-doctype) -// or use Box Sizing Behavior from WebFX -// (http://webfx.eae.net/dhtml/boxsizing/boxsizing.html) -// * Non uniform scaling does not correctly scale strokes. -// * Optimize. There is always room for speed improvements. - -// Only add this code if we do not already have a canvas implementation -if (!document.createElement('canvas').getContext) { - -(function() { - - // alias some functions to make (compiled) code shorter - var m = Math; - var mr = m.round; - var ms = m.sin; - var mc = m.cos; - var abs = m.abs; - var sqrt = m.sqrt; - - // this is used for sub pixel precision - var Z = 10; - var Z2 = Z / 2; - - var IE_VERSION = +navigator.userAgent.match(/MSIE ([\d.]+)?/)[1]; - - /** - * This funtion is assigned to the elements as element.getContext(). - * @this {HTMLElement} - * @return {CanvasRenderingContext2D_} - */ - function getContext() { - return this.context_ || - (this.context_ = new CanvasRenderingContext2D_(this)); - } - - var slice = Array.prototype.slice; - - /** - * Binds a function to an object. The returned function will always use the - * passed in {@code obj} as {@code this}. - * - * Example: - * - * g = bind(f, obj, a, b) - * g(c, d) // will do f.call(obj, a, b, c, d) - * - * @param {Function} f The function to bind the object to - * @param {Object} obj The object that should act as this when the function - * is called - * @param {*} var_args Rest arguments that will be used as the initial - * arguments when the function is called - * @return {Function} A new function that has bound this - */ - function bind(f, obj, var_args) { - var a = slice.call(arguments, 2); - return function() { - return f.apply(obj, a.concat(slice.call(arguments))); - }; - } - - function encodeHtmlAttribute(s) { - return String(s).replace(/&/g, '&').replace(/"/g, '"'); - } - - function addNamespace(doc, prefix, urn) { - if (!doc.namespaces[prefix]) { - doc.namespaces.add(prefix, urn, '#default#VML'); - } - } - - function addNamespacesAndStylesheet(doc) { - addNamespace(doc, 'g_vml_', 'urn:schemas-microsoft-com:vml'); - addNamespace(doc, 'g_o_', 'urn:schemas-microsoft-com:office:office'); - - // Setup default CSS. Only add one style sheet per document - if (!doc.styleSheets['ex_canvas_']) { - var ss = doc.createStyleSheet(); - ss.owningElement.id = 'ex_canvas_'; - ss.cssText = 'canvas{display:inline-block;overflow:hidden;' + - // default size is 300x150 in Gecko and Opera - 'text-align:left;width:300px;height:150px}'; - } - } - - // Add namespaces and stylesheet at startup. - addNamespacesAndStylesheet(document); - - var G_vmlCanvasManager_ = { - init: function(opt_doc) { - var doc = opt_doc || document; - // Create a dummy element so that IE will allow canvas elements to be - // recognized. - doc.createElement('canvas'); - doc.attachEvent('onreadystatechange', bind(this.init_, this, doc)); - }, - - init_: function(doc) { - // find all canvas elements - var els = doc.getElementsByTagName('canvas'); - for (var i = 0; i < els.length; i++) { - this.initElement(els[i]); - } - }, - - /** - * Public initializes a canvas element so that it can be used as canvas - * element from now on. This is called automatically before the page is - * loaded but if you are creating elements using createElement you need to - * make sure this is called on the element. - * @param {HTMLElement} el The canvas element to initialize. - * @return {HTMLElement} the element that was created. - */ - initElement: function(el) { - if (!el.getContext) { - el.getContext = getContext; - - // Add namespaces and stylesheet to document of the element. - addNamespacesAndStylesheet(el.ownerDocument); - - // Remove fallback content. There is no way to hide text nodes so we - // just remove all childNodes. We could hide all elements and remove - // text nodes but who really cares about the fallback content. - el.innerHTML = ''; - - // do not use inline function because that will leak memory - el.attachEvent('onpropertychange', onPropertyChange); - el.attachEvent('onresize', onResize); - - var attrs = el.attributes; - if (attrs.width && attrs.width.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setWidth_(attrs.width.nodeValue); - el.style.width = attrs.width.nodeValue + 'px'; - } else { - el.width = el.clientWidth; - } - if (attrs.height && attrs.height.specified) { - // TODO: use runtimeStyle and coordsize - // el.getContext().setHeight_(attrs.height.nodeValue); - el.style.height = attrs.height.nodeValue + 'px'; - } else { - el.height = el.clientHeight; - } - //el.getContext().setCoordsize_() - } - return el; - } - }; - - function onPropertyChange(e) { - var el = e.srcElement; - - switch (e.propertyName) { - case 'width': - el.getContext().clearRect(); - el.style.width = el.attributes.width.nodeValue + 'px'; - // In IE8 this does not trigger onresize. - el.firstChild.style.width = el.clientWidth + 'px'; - break; - case 'height': - el.getContext().clearRect(); - el.style.height = el.attributes.height.nodeValue + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - break; - } - } - - function onResize(e) { - var el = e.srcElement; - if (el.firstChild) { - el.firstChild.style.width = el.clientWidth + 'px'; - el.firstChild.style.height = el.clientHeight + 'px'; - } - } - - G_vmlCanvasManager_.init(); - - // precompute "00" to "FF" - var decToHex = []; - for (var i = 0; i < 16; i++) { - for (var j = 0; j < 16; j++) { - decToHex[i * 16 + j] = i.toString(16) + j.toString(16); - } - } - - function createMatrixIdentity() { - return [ - [1, 0, 0], - [0, 1, 0], - [0, 0, 1] - ]; - } - - function matrixMultiply(m1, m2) { - var result = createMatrixIdentity(); - - for (var x = 0; x < 3; x++) { - for (var y = 0; y < 3; y++) { - var sum = 0; - - for (var z = 0; z < 3; z++) { - sum += m1[x][z] * m2[z][y]; - } - - result[x][y] = sum; - } - } - return result; - } - - function copyState(o1, o2) { - o2.fillStyle = o1.fillStyle; - o2.lineCap = o1.lineCap; - o2.lineJoin = o1.lineJoin; - o2.lineWidth = o1.lineWidth; - o2.miterLimit = o1.miterLimit; - o2.shadowBlur = o1.shadowBlur; - o2.shadowColor = o1.shadowColor; - o2.shadowOffsetX = o1.shadowOffsetX; - o2.shadowOffsetY = o1.shadowOffsetY; - o2.strokeStyle = o1.strokeStyle; - o2.globalAlpha = o1.globalAlpha; - o2.font = o1.font; - o2.textAlign = o1.textAlign; - o2.textBaseline = o1.textBaseline; - o2.arcScaleX_ = o1.arcScaleX_; - o2.arcScaleY_ = o1.arcScaleY_; - o2.lineScale_ = o1.lineScale_; - } - - var colorData = { - aliceblue: '#F0F8FF', - antiquewhite: '#FAEBD7', - aquamarine: '#7FFFD4', - azure: '#F0FFFF', - beige: '#F5F5DC', - bisque: '#FFE4C4', - black: '#000000', - blanchedalmond: '#FFEBCD', - blueviolet: '#8A2BE2', - brown: '#A52A2A', - burlywood: '#DEB887', - cadetblue: '#5F9EA0', - chartreuse: '#7FFF00', - chocolate: '#D2691E', - coral: '#FF7F50', - cornflowerblue: '#6495ED', - cornsilk: '#FFF8DC', - crimson: '#DC143C', - cyan: '#00FFFF', - darkblue: '#00008B', - darkcyan: '#008B8B', - darkgoldenrod: '#B8860B', - darkgray: '#A9A9A9', - darkgreen: '#006400', - darkgrey: '#A9A9A9', - darkkhaki: '#BDB76B', - darkmagenta: '#8B008B', - darkolivegreen: '#556B2F', - darkorange: '#FF8C00', - darkorchid: '#9932CC', - darkred: '#8B0000', - darksalmon: '#E9967A', - darkseagreen: '#8FBC8F', - darkslateblue: '#483D8B', - darkslategray: '#2F4F4F', - darkslategrey: '#2F4F4F', - darkturquoise: '#00CED1', - darkviolet: '#9400D3', - deeppink: '#FF1493', - deepskyblue: '#00BFFF', - dimgray: '#696969', - dimgrey: '#696969', - dodgerblue: '#1E90FF', - firebrick: '#B22222', - floralwhite: '#FFFAF0', - forestgreen: '#228B22', - gainsboro: '#DCDCDC', - ghostwhite: '#F8F8FF', - gold: '#FFD700', - goldenrod: '#DAA520', - grey: '#808080', - greenyellow: '#ADFF2F', - honeydew: '#F0FFF0', - hotpink: '#FF69B4', - indianred: '#CD5C5C', - indigo: '#4B0082', - ivory: '#FFFFF0', - khaki: '#F0E68C', - lavender: '#E6E6FA', - lavenderblush: '#FFF0F5', - lawngreen: '#7CFC00', - lemonchiffon: '#FFFACD', - lightblue: '#ADD8E6', - lightcoral: '#F08080', - lightcyan: '#E0FFFF', - lightgoldenrodyellow: '#FAFAD2', - lightgreen: '#90EE90', - lightgrey: '#D3D3D3', - lightpink: '#FFB6C1', - lightsalmon: '#FFA07A', - lightseagreen: '#20B2AA', - lightskyblue: '#87CEFA', - lightslategray: '#778899', - lightslategrey: '#778899', - lightsteelblue: '#B0C4DE', - lightyellow: '#FFFFE0', - limegreen: '#32CD32', - linen: '#FAF0E6', - magenta: '#FF00FF', - mediumaquamarine: '#66CDAA', - mediumblue: '#0000CD', - mediumorchid: '#BA55D3', - mediumpurple: '#9370DB', - mediumseagreen: '#3CB371', - mediumslateblue: '#7B68EE', - mediumspringgreen: '#00FA9A', - mediumturquoise: '#48D1CC', - mediumvioletred: '#C71585', - midnightblue: '#191970', - mintcream: '#F5FFFA', - mistyrose: '#FFE4E1', - moccasin: '#FFE4B5', - navajowhite: '#FFDEAD', - oldlace: '#FDF5E6', - olivedrab: '#6B8E23', - orange: '#FFA500', - orangered: '#FF4500', - orchid: '#DA70D6', - palegoldenrod: '#EEE8AA', - palegreen: '#98FB98', - paleturquoise: '#AFEEEE', - palevioletred: '#DB7093', - papayawhip: '#FFEFD5', - peachpuff: '#FFDAB9', - peru: '#CD853F', - pink: '#FFC0CB', - plum: '#DDA0DD', - powderblue: '#B0E0E6', - rosybrown: '#BC8F8F', - royalblue: '#4169E1', - saddlebrown: '#8B4513', - salmon: '#FA8072', - sandybrown: '#F4A460', - seagreen: '#2E8B57', - seashell: '#FFF5EE', - sienna: '#A0522D', - skyblue: '#87CEEB', - slateblue: '#6A5ACD', - slategray: '#708090', - slategrey: '#708090', - snow: '#FFFAFA', - springgreen: '#00FF7F', - steelblue: '#4682B4', - tan: '#D2B48C', - thistle: '#D8BFD8', - tomato: '#FF6347', - turquoise: '#40E0D0', - violet: '#EE82EE', - wheat: '#F5DEB3', - whitesmoke: '#F5F5F5', - yellowgreen: '#9ACD32' - }; - - - function getRgbHslContent(styleString) { - var start = styleString.indexOf('(', 3); - var end = styleString.indexOf(')', start + 1); - var parts = styleString.substring(start + 1, end).split(','); - // add alpha if needed - if (parts.length != 4 || styleString.charAt(3) != 'a') { - parts[3] = 1; - } - return parts; - } - - function percent(s) { - return parseFloat(s) / 100; - } - - function clamp(v, min, max) { - return Math.min(max, Math.max(min, v)); - } - - function hslToRgb(parts){ - var r, g, b, h, s, l; - h = parseFloat(parts[0]) / 360 % 360; - if (h < 0) - h++; - s = clamp(percent(parts[1]), 0, 1); - l = clamp(percent(parts[2]), 0, 1); - if (s == 0) { - r = g = b = l; // achromatic - } else { - var q = l < 0.5 ? l * (1 + s) : l + s - l * s; - var p = 2 * l - q; - r = hueToRgb(p, q, h + 1 / 3); - g = hueToRgb(p, q, h); - b = hueToRgb(p, q, h - 1 / 3); - } - - return '#' + decToHex[Math.floor(r * 255)] + - decToHex[Math.floor(g * 255)] + - decToHex[Math.floor(b * 255)]; - } - - function hueToRgb(m1, m2, h) { - if (h < 0) - h++; - if (h > 1) - h--; - - if (6 * h < 1) - return m1 + (m2 - m1) * 6 * h; - else if (2 * h < 1) - return m2; - else if (3 * h < 2) - return m1 + (m2 - m1) * (2 / 3 - h) * 6; - else - return m1; - } - - var processStyleCache = {}; - - function processStyle(styleString) { - if (styleString in processStyleCache) { - return processStyleCache[styleString]; - } - - var str, alpha = 1; - - styleString = String(styleString); - if (styleString.charAt(0) == '#') { - str = styleString; - } else if (/^rgb/.test(styleString)) { - var parts = getRgbHslContent(styleString); - var str = '#', n; - for (var i = 0; i < 3; i++) { - if (parts[i].indexOf('%') != -1) { - n = Math.floor(percent(parts[i]) * 255); - } else { - n = +parts[i]; - } - str += decToHex[clamp(n, 0, 255)]; - } - alpha = +parts[3]; - } else if (/^hsl/.test(styleString)) { - var parts = getRgbHslContent(styleString); - str = hslToRgb(parts); - alpha = parts[3]; - } else { - str = colorData[styleString] || styleString; - } - return processStyleCache[styleString] = {color: str, alpha: alpha}; - } - - var DEFAULT_STYLE = { - style: 'normal', - variant: 'normal', - weight: 'normal', - size: 10, - family: 'sans-serif' - }; - - // Internal text style cache - var fontStyleCache = {}; - - function processFontStyle(styleString) { - if (fontStyleCache[styleString]) { - return fontStyleCache[styleString]; - } - - var el = document.createElement('div'); - var style = el.style; - try { - style.font = styleString; - } catch (ex) { - // Ignore failures to set to invalid font. - } - - return fontStyleCache[styleString] = { - style: style.fontStyle || DEFAULT_STYLE.style, - variant: style.fontVariant || DEFAULT_STYLE.variant, - weight: style.fontWeight || DEFAULT_STYLE.weight, - size: style.fontSize || DEFAULT_STYLE.size, - family: style.fontFamily || DEFAULT_STYLE.family - }; - } - - function getComputedStyle(style, element) { - var computedStyle = {}; - - for (var p in style) { - computedStyle[p] = style[p]; - } - - // Compute the size - var canvasFontSize = parseFloat(element.currentStyle.fontSize), - fontSize = parseFloat(style.size); - - if (typeof style.size == 'number') { - computedStyle.size = style.size; - } else if (style.size.indexOf('px') != -1) { - computedStyle.size = fontSize; - } else if (style.size.indexOf('em') != -1) { - computedStyle.size = canvasFontSize * fontSize; - } else if(style.size.indexOf('%') != -1) { - computedStyle.size = (canvasFontSize / 100) * fontSize; - } else if (style.size.indexOf('pt') != -1) { - computedStyle.size = fontSize / .75; - } else { - computedStyle.size = canvasFontSize; - } - - // Different scaling between normal text and VML text. This was found using - // trial and error to get the same size as non VML text. - computedStyle.size *= 0.981; - - return computedStyle; - } - - function buildStyle(style) { - return style.style + ' ' + style.variant + ' ' + style.weight + ' ' + - style.size + 'px ' + style.family; - } - - var lineCapMap = { - 'butt': 'flat', - 'round': 'round' - }; - - function processLineCap(lineCap) { - return lineCapMap[lineCap] || 'square'; - } - - /** - * This class implements CanvasRenderingContext2D interface as described by - * the WHATWG. - * @param {HTMLElement} canvasElement The element that the 2D context should - * be associated with - */ - function CanvasRenderingContext2D_(canvasElement) { - this.m_ = createMatrixIdentity(); - - this.mStack_ = []; - this.aStack_ = []; - this.currentPath_ = []; - - // Canvas context properties - this.strokeStyle = '#000'; - this.fillStyle = '#000'; - - this.lineWidth = 1; - this.lineJoin = 'miter'; - this.lineCap = 'butt'; - this.miterLimit = Z * 1; - this.globalAlpha = 1; - this.font = '10px sans-serif'; - this.textAlign = 'left'; - this.textBaseline = 'alphabetic'; - this.canvas = canvasElement; - - var cssText = 'width:' + canvasElement.clientWidth + 'px;height:' + - canvasElement.clientHeight + 'px;overflow:hidden;position:absolute'; - var el = canvasElement.ownerDocument.createElement('div'); - el.style.cssText = cssText; - canvasElement.appendChild(el); - - var overlayEl = el.cloneNode(false); - // Use a non transparent background. - overlayEl.style.backgroundColor = 'red'; - overlayEl.style.filter = 'alpha(opacity=0)'; - canvasElement.appendChild(overlayEl); - - this.element_ = el; - this.arcScaleX_ = 1; - this.arcScaleY_ = 1; - this.lineScale_ = 1; - } - - var contextPrototype = CanvasRenderingContext2D_.prototype; - contextPrototype.clearRect = function() { - if (this.textMeasureEl_) { - this.textMeasureEl_.removeNode(true); - this.textMeasureEl_ = null; - } - this.element_.innerHTML = ''; - }; - - contextPrototype.beginPath = function() { - // TODO: Branch current matrix so that save/restore has no effect - // as per safari docs. - this.currentPath_ = []; - }; - - contextPrototype.moveTo = function(aX, aY) { - var p = getCoords(this, aX, aY); - this.currentPath_.push({type: 'moveTo', x: p.x, y: p.y}); - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.lineTo = function(aX, aY) { - var p = getCoords(this, aX, aY); - this.currentPath_.push({type: 'lineTo', x: p.x, y: p.y}); - - this.currentX_ = p.x; - this.currentY_ = p.y; - }; - - contextPrototype.bezierCurveTo = function(aCP1x, aCP1y, - aCP2x, aCP2y, - aX, aY) { - var p = getCoords(this, aX, aY); - var cp1 = getCoords(this, aCP1x, aCP1y); - var cp2 = getCoords(this, aCP2x, aCP2y); - bezierCurveTo(this, cp1, cp2, p); - }; - - // Helper function that takes the already fixed cordinates. - function bezierCurveTo(self, cp1, cp2, p) { - self.currentPath_.push({ - type: 'bezierCurveTo', - cp1x: cp1.x, - cp1y: cp1.y, - cp2x: cp2.x, - cp2y: cp2.y, - x: p.x, - y: p.y - }); - self.currentX_ = p.x; - self.currentY_ = p.y; - } - - contextPrototype.quadraticCurveTo = function(aCPx, aCPy, aX, aY) { - // the following is lifted almost directly from - // http://developer.mozilla.org/en/docs/Canvas_tutorial:Drawing_shapes - - var cp = getCoords(this, aCPx, aCPy); - var p = getCoords(this, aX, aY); - - var cp1 = { - x: this.currentX_ + 2.0 / 3.0 * (cp.x - this.currentX_), - y: this.currentY_ + 2.0 / 3.0 * (cp.y - this.currentY_) - }; - var cp2 = { - x: cp1.x + (p.x - this.currentX_) / 3.0, - y: cp1.y + (p.y - this.currentY_) / 3.0 - }; - - bezierCurveTo(this, cp1, cp2, p); - }; - - contextPrototype.arc = function(aX, aY, aRadius, - aStartAngle, aEndAngle, aClockwise) { - aRadius *= Z; - var arcType = aClockwise ? 'at' : 'wa'; - - var xStart = aX + mc(aStartAngle) * aRadius - Z2; - var yStart = aY + ms(aStartAngle) * aRadius - Z2; - - var xEnd = aX + mc(aEndAngle) * aRadius - Z2; - var yEnd = aY + ms(aEndAngle) * aRadius - Z2; - - // IE won't render arches drawn counter clockwise if xStart == xEnd. - if (xStart == xEnd && !aClockwise) { - xStart += 0.125; // Offset xStart by 1/80 of a pixel. Use something - // that can be represented in binary - } - - var p = getCoords(this, aX, aY); - var pStart = getCoords(this, xStart, yStart); - var pEnd = getCoords(this, xEnd, yEnd); - - this.currentPath_.push({type: arcType, - x: p.x, - y: p.y, - radius: aRadius, - xStart: pStart.x, - yStart: pStart.y, - xEnd: pEnd.x, - yEnd: pEnd.y}); - - }; - - contextPrototype.rect = function(aX, aY, aWidth, aHeight) { - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - }; - - contextPrototype.strokeRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.stroke(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.fillRect = function(aX, aY, aWidth, aHeight) { - var oldPath = this.currentPath_; - this.beginPath(); - - this.moveTo(aX, aY); - this.lineTo(aX + aWidth, aY); - this.lineTo(aX + aWidth, aY + aHeight); - this.lineTo(aX, aY + aHeight); - this.closePath(); - this.fill(); - - this.currentPath_ = oldPath; - }; - - contextPrototype.createLinearGradient = function(aX0, aY0, aX1, aY1) { - var gradient = new CanvasGradient_('gradient'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - return gradient; - }; - - contextPrototype.createRadialGradient = function(aX0, aY0, aR0, - aX1, aY1, aR1) { - var gradient = new CanvasGradient_('gradientradial'); - gradient.x0_ = aX0; - gradient.y0_ = aY0; - gradient.r0_ = aR0; - gradient.x1_ = aX1; - gradient.y1_ = aY1; - gradient.r1_ = aR1; - return gradient; - }; - - contextPrototype.drawImage = function(image, var_args) { - var dx, dy, dw, dh, sx, sy, sw, sh; - - // to find the original width we overide the width and height - var oldRuntimeWidth = image.runtimeStyle.width; - var oldRuntimeHeight = image.runtimeStyle.height; - image.runtimeStyle.width = 'auto'; - image.runtimeStyle.height = 'auto'; - - // get the original size - var w = image.width; - var h = image.height; - - // and remove overides - image.runtimeStyle.width = oldRuntimeWidth; - image.runtimeStyle.height = oldRuntimeHeight; - - if (arguments.length == 3) { - dx = arguments[1]; - dy = arguments[2]; - sx = sy = 0; - sw = dw = w; - sh = dh = h; - } else if (arguments.length == 5) { - dx = arguments[1]; - dy = arguments[2]; - dw = arguments[3]; - dh = arguments[4]; - sx = sy = 0; - sw = w; - sh = h; - } else if (arguments.length == 9) { - sx = arguments[1]; - sy = arguments[2]; - sw = arguments[3]; - sh = arguments[4]; - dx = arguments[5]; - dy = arguments[6]; - dw = arguments[7]; - dh = arguments[8]; - } else { - throw Error('Invalid number of arguments'); - } - - var d = getCoords(this, dx, dy); - - var w2 = sw / 2; - var h2 = sh / 2; - - var vmlStr = []; - - var W = 10; - var H = 10; - - // For some reason that I've now forgotten, using divs didn't work - vmlStr.push(' ' , - '', - ''); - - this.element_.insertAdjacentHTML('BeforeEnd', vmlStr.join('')); - }; - - contextPrototype.stroke = function(aFill) { - var lineStr = []; - var lineOpen = false; - - var W = 10; - var H = 10; - - lineStr.push(''); - - if (!aFill) { - appendStroke(this, lineStr); - } else { - appendFill(this, lineStr, min, max); - } - - lineStr.push(''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - function appendStroke(ctx, lineStr) { - var a = processStyle(ctx.strokeStyle); - var color = a.color; - var opacity = a.alpha * ctx.globalAlpha; - var lineWidth = ctx.lineScale_ * ctx.lineWidth; - - // VML cannot correctly render a line if the width is less than 1px. - // In that case, we dilute the color to make the line look thinner. - if (lineWidth < 1) { - opacity *= lineWidth; - } - - lineStr.push( - '' - ); - } - - function appendFill(ctx, lineStr, min, max) { - var fillStyle = ctx.fillStyle; - var arcScaleX = ctx.arcScaleX_; - var arcScaleY = ctx.arcScaleY_; - var width = max.x - min.x; - var height = max.y - min.y; - if (fillStyle instanceof CanvasGradient_) { - // TODO: Gradients transformed with the transformation matrix. - var angle = 0; - var focus = {x: 0, y: 0}; - - // additional offset - var shift = 0; - // scale factor for offset - var expansion = 1; - - if (fillStyle.type_ == 'gradient') { - var x0 = fillStyle.x0_ / arcScaleX; - var y0 = fillStyle.y0_ / arcScaleY; - var x1 = fillStyle.x1_ / arcScaleX; - var y1 = fillStyle.y1_ / arcScaleY; - var p0 = getCoords(ctx, x0, y0); - var p1 = getCoords(ctx, x1, y1); - var dx = p1.x - p0.x; - var dy = p1.y - p0.y; - angle = Math.atan2(dx, dy) * 180 / Math.PI; - - // The angle should be a non-negative number. - if (angle < 0) { - angle += 360; - } - - // Very small angles produce an unexpected result because they are - // converted to a scientific notation string. - if (angle < 1e-6) { - angle = 0; - } - } else { - var p0 = getCoords(ctx, fillStyle.x0_, fillStyle.y0_); - focus = { - x: (p0.x - min.x) / width, - y: (p0.y - min.y) / height - }; - - width /= arcScaleX * Z; - height /= arcScaleY * Z; - var dimension = m.max(width, height); - shift = 2 * fillStyle.r0_ / dimension; - expansion = 2 * fillStyle.r1_ / dimension - shift; - } - - // We need to sort the color stops in ascending order by offset, - // otherwise IE won't interpret it correctly. - var stops = fillStyle.colors_; - stops.sort(function(cs1, cs2) { - return cs1.offset - cs2.offset; - }); - - var length = stops.length; - var color1 = stops[0].color; - var color2 = stops[length - 1].color; - var opacity1 = stops[0].alpha * ctx.globalAlpha; - var opacity2 = stops[length - 1].alpha * ctx.globalAlpha; - - var colors = []; - for (var i = 0; i < length; i++) { - var stop = stops[i]; - colors.push(stop.offset * expansion + shift + ' ' + stop.color); - } - - // When colors attribute is used, the meanings of opacity and o:opacity2 - // are reversed. - lineStr.push(''); - } else if (fillStyle instanceof CanvasPattern_) { - if (width && height) { - var deltaLeft = -min.x; - var deltaTop = -min.y; - lineStr.push(''); - } - } else { - var a = processStyle(ctx.fillStyle); - var color = a.color; - var opacity = a.alpha * ctx.globalAlpha; - lineStr.push(''); - } - } - - contextPrototype.fill = function() { - this.stroke(true); - }; - - contextPrototype.closePath = function() { - this.currentPath_.push({type: 'close'}); - }; - - function getCoords(ctx, aX, aY) { - var m = ctx.m_; - return { - x: Z * (aX * m[0][0] + aY * m[1][0] + m[2][0]) - Z2, - y: Z * (aX * m[0][1] + aY * m[1][1] + m[2][1]) - Z2 - }; - }; - - contextPrototype.save = function() { - var o = {}; - copyState(this, o); - this.aStack_.push(o); - this.mStack_.push(this.m_); - this.m_ = matrixMultiply(createMatrixIdentity(), this.m_); - }; - - contextPrototype.restore = function() { - if (this.aStack_.length) { - copyState(this.aStack_.pop(), this); - this.m_ = this.mStack_.pop(); - } - }; - - function matrixIsFinite(m) { - return isFinite(m[0][0]) && isFinite(m[0][1]) && - isFinite(m[1][0]) && isFinite(m[1][1]) && - isFinite(m[2][0]) && isFinite(m[2][1]); - } - - function setM(ctx, m, updateLineScale) { - if (!matrixIsFinite(m)) { - return; - } - ctx.m_ = m; - - if (updateLineScale) { - // Get the line scale. - // Determinant of this.m_ means how much the area is enlarged by the - // transformation. So its square root can be used as a scale factor - // for width. - var det = m[0][0] * m[1][1] - m[0][1] * m[1][0]; - ctx.lineScale_ = sqrt(abs(det)); - } - } - - contextPrototype.translate = function(aX, aY) { - var m1 = [ - [1, 0, 0], - [0, 1, 0], - [aX, aY, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.rotate = function(aRot) { - var c = mc(aRot); - var s = ms(aRot); - - var m1 = [ - [c, s, 0], - [-s, c, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), false); - }; - - contextPrototype.scale = function(aX, aY) { - this.arcScaleX_ *= aX; - this.arcScaleY_ *= aY; - var m1 = [ - [aX, 0, 0], - [0, aY, 0], - [0, 0, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.transform = function(m11, m12, m21, m22, dx, dy) { - var m1 = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, matrixMultiply(m1, this.m_), true); - }; - - contextPrototype.setTransform = function(m11, m12, m21, m22, dx, dy) { - var m = [ - [m11, m12, 0], - [m21, m22, 0], - [dx, dy, 1] - ]; - - setM(this, m, true); - }; - - /** - * The text drawing function. - * The maxWidth argument isn't taken in account, since no browser supports - * it yet. - */ - contextPrototype.drawText_ = function(text, x, y, maxWidth, stroke) { - var m = this.m_, - delta = 1000, - left = 0, - right = delta, - offset = {x: 0, y: 0}, - lineStr = []; - - var fontStyle = getComputedStyle(processFontStyle(this.font), - this.element_); - - var fontStyleString = buildStyle(fontStyle); - - var elementStyle = this.element_.currentStyle; - var textAlign = this.textAlign.toLowerCase(); - switch (textAlign) { - case 'left': - case 'center': - case 'right': - break; - case 'end': - textAlign = elementStyle.direction == 'ltr' ? 'right' : 'left'; - break; - case 'start': - textAlign = elementStyle.direction == 'rtl' ? 'right' : 'left'; - break; - default: - textAlign = 'left'; - } - - // 1.75 is an arbitrary number, as there is no info about the text baseline - switch (this.textBaseline) { - case 'hanging': - case 'top': - offset.y = fontStyle.size / 1.75; - break; - case 'middle': - break; - default: - case null: - case 'alphabetic': - case 'ideographic': - case 'bottom': - offset.y = -fontStyle.size / 2.25; - break; - } - - switch(textAlign) { - case 'right': - left = delta; - right = 0.05; - break; - case 'center': - left = right = delta / 2; - break; - } - - var d = getCoords(this, x + offset.x, y + offset.y); - - lineStr.push(''); - - if (stroke) { - appendStroke(this, lineStr); - } else { - // TODO: Fix the min and max params. - appendFill(this, lineStr, {x: -left, y: 0}, - {x: right, y: fontStyle.size}); - } - - var skewM = m[0][0].toFixed(3) + ',' + m[1][0].toFixed(3) + ',' + - m[0][1].toFixed(3) + ',' + m[1][1].toFixed(3) + ',0,0'; - - var skewOffset = mr(d.x / Z) + ',' + mr(d.y / Z); - - lineStr.push('', - '', - ''); - - this.element_.insertAdjacentHTML('beforeEnd', lineStr.join('')); - }; - - contextPrototype.fillText = function(text, x, y, maxWidth) { - this.drawText_(text, x, y, maxWidth, false); - }; - - contextPrototype.strokeText = function(text, x, y, maxWidth) { - this.drawText_(text, x, y, maxWidth, true); - }; - - contextPrototype.measureText = function(text) { - if (!this.textMeasureEl_) { - var s = ''; - this.element_.insertAdjacentHTML('beforeEnd', s); - this.textMeasureEl_ = this.element_.lastChild; - } - var doc = this.element_.ownerDocument; - this.textMeasureEl_.innerHTML = ''; - this.textMeasureEl_.style.font = this.font; - // Don't use innerHTML or innerText because they allow markup/whitespace. - this.textMeasureEl_.appendChild(doc.createTextNode(text)); - return {width: this.textMeasureEl_.offsetWidth}; - }; - - /******** STUBS ********/ - contextPrototype.clip = function() { - // TODO: Implement - }; - - contextPrototype.arcTo = function() { - // TODO: Implement - }; - - contextPrototype.createPattern = function(image, repetition) { - return new CanvasPattern_(image, repetition); - }; - - // Gradient / Pattern Stubs - function CanvasGradient_(aType) { - this.type_ = aType; - this.x0_ = 0; - this.y0_ = 0; - this.r0_ = 0; - this.x1_ = 0; - this.y1_ = 0; - this.r1_ = 0; - this.colors_ = []; - } - - CanvasGradient_.prototype.addColorStop = function(aOffset, aColor) { - aColor = processStyle(aColor); - this.colors_.push({offset: aOffset, - color: aColor.color, - alpha: aColor.alpha}); - }; - - function CanvasPattern_(image, repetition) { - assertImageIsValid(image); - switch (repetition) { - case 'repeat': - case null: - case '': - this.repetition_ = 'repeat'; - break - case 'repeat-x': - case 'repeat-y': - case 'no-repeat': - this.repetition_ = repetition; - break; - default: - throwException('SYNTAX_ERR'); - } - - this.src_ = image.src; - this.width_ = image.width; - this.height_ = image.height; - } - - function throwException(s) { - throw new DOMException_(s); - } - - function assertImageIsValid(img) { - if (!img || img.nodeType != 1 || img.tagName != 'IMG') { - throwException('TYPE_MISMATCH_ERR'); - } - if (img.readyState != 'complete') { - throwException('INVALID_STATE_ERR'); - } - } - - function DOMException_(s) { - this.code = this[s]; - this.message = s +': DOM Exception ' + this.code; - } - var p = DOMException_.prototype = new Error; - p.INDEX_SIZE_ERR = 1; - p.DOMSTRING_SIZE_ERR = 2; - p.HIERARCHY_REQUEST_ERR = 3; - p.WRONG_DOCUMENT_ERR = 4; - p.INVALID_CHARACTER_ERR = 5; - p.NO_DATA_ALLOWED_ERR = 6; - p.NO_MODIFICATION_ALLOWED_ERR = 7; - p.NOT_FOUND_ERR = 8; - p.NOT_SUPPORTED_ERR = 9; - p.INUSE_ATTRIBUTE_ERR = 10; - p.INVALID_STATE_ERR = 11; - p.SYNTAX_ERR = 12; - p.INVALID_MODIFICATION_ERR = 13; - p.NAMESPACE_ERR = 14; - p.INVALID_ACCESS_ERR = 15; - p.VALIDATION_ERR = 16; - p.TYPE_MISMATCH_ERR = 17; - - // set up externs - G_vmlCanvasManager = G_vmlCanvasManager_; - CanvasRenderingContext2D = CanvasRenderingContext2D_; - CanvasGradient = CanvasGradient_; - CanvasPattern = CanvasPattern_; - DOMException = DOMException_; -})(); - -} // if \ No newline at end of file diff --git a/app/assets/javascripts/Jit/filter.js b/app/assets/javascripts/Jit/filter.js deleted file mode 100644 index dc409f8c..00000000 --- a/app/assets/javascripts/Jit/filter.js +++ /dev/null @@ -1,183 +0,0 @@ -// create filters for maps - -function switchVisible(category, duration) { - if (categoryVisible[category] == true) { - hideCategory(category, duration); - } - else if (categoryVisible[category] == false) { - showCategory(category, duration); - } -} - -function hideCategory(category, duration) { - if (duration == null) duration = 500; - Mconsole.graph.eachNode( function (n) { - if (n.getData('metacode') == category) { - n.setData('alpha', 0.4, 'end'); - n.eachAdjacency(function(adj) { - adj.setData('alpha', 0.4, 'end'); - }); - } - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: duration - }); -} - -function showCategory(category, duration) { - if (duration == null) duration = 500; - Mconsole.graph.eachNode( function (n) { - if (n.getData('metacode') == category) { - n.setData('alpha', 1, 'end'); - n.eachAdjacency(function(adj) { - adj.setData('alpha', 1, 'end'); - }); - } - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: duration - }); -} - -// These functions toggle ALL nodes and synapses on the page -function hideAll(duration) { - if (duration == null) duration = 500; - Mconsole.graph.eachNode( function (n) { - n.setData('alpha', 0.4, 'end'); - n.eachAdjacency(function(adj) { - adj.setData('alpha', 0.2, 'end'); - }); - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: duration - }); -} -function showAll(duration) { - if (duration == null) duration = 500; - Mconsole.graph.eachNode( function (n) { - n.setData('alpha', 1, 'end'); - n.eachAdjacency(function(adj) { - adj.setData('alpha', 0.4, 'end'); - }); - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: duration - }); -} - -function filterTopicsByMap(mapID) { - Mconsole.graph.eachNode(function (n) { - if (n.getData('inmaps').indexOf(parseInt(mapID)) !== -1) { - n.setData('alpha', 1, 'end'); - } - else { - n.setData('alpha', 0.4, 'end'); - } - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 500 - }); - }); -} // filterTopicsByName - -function filterTopicsByMapper(mapperID) { - Mconsole.graph.eachNode(function (n) { - if (n.getData('userid').toString() == mapperID) { - n.setData('alpha', 1, 'end'); - } - else { - n.setData('alpha', 0.4, 'end'); - } - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 500 - }); - }); -} // filterTopicsByName - -function filterTopicsByName(searchQuery) { - Mconsole.graph.eachNode(function (n) { - nodeName = n.name.toLowerCase(); - if (nodeName.indexOf(searchQuery) !== -1 && searchQuery != "") { - n.setData('alpha', 1, 'end'); - } - else { - n.setData('alpha', 0.4, 'end'); - } - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 500 - }); - }); -} // filterTopicsByName - -function clearCanvas() { - Mconsole.graph.eachNode(function(n) { - Mconsole.graph.removeNode(n.id); - }); - Mconsole.plot(); -} - -function clearCanvasExceptRoot() { - var ids = new Array(); - Mconsole.graph.eachNode(function(n) { - ids.push(n.id); - }); - - var root = Mconsole.graph.nodes[Mconsole.root]; - ids.forEach(function(id, index) { - if (id != root.id) { - Mconsole.graph.removeNode(id); - } - }); - fetchRelatives(root); //also runs Mconsole.plot() -} - -/** - * Define all the dynamic interactions for the Filter By Metacode using Jquery - */ - -$(document).ready(function() { - $('.sidebarFilterBox .showAll').click(function(e) { - showAll(); - $('#filter_by_metacode ul li').removeClass('toggledOff'); - for (var catVis in categoryVisible) { - categoryVisible[catVis] = true; - } - }); - $('.sidebarFilterBox .hideAll').click(function(e) { - hideAll(); - $('#filter_by_metacode ul li').addClass('toggledOff'); - for (var catVis in categoryVisible) { - categoryVisible[catVis] = false; - } - }); - - // toggle visibility of topics with metacodes based on status in the filters list - $('#filter_by_metacode ul li').click(function(event) { - - var category = $(this).children('img').attr('alt'); - switchVisible(category); - - // toggle the image and the boolean array value - if (categoryVisible[category] == true) { - $(this).addClass('toggledOff'); - categoryVisible[category] = false; - } - else if (categoryVisible[category] == false) { - $(this).removeClass('toggledOff'); - categoryVisible[category] = true; - } - }); -}); \ No newline at end of file diff --git a/app/assets/javascripts/Jit/graphsettings-event-handlers.js b/app/assets/javascripts/Jit/graphsettings-event-handlers.js deleted file mode 100644 index 6b9c25fb..00000000 --- a/app/assets/javascripts/Jit/graphsettings-event-handlers.js +++ /dev/null @@ -1,631 +0,0 @@ -function selectEdgeOnClickHandler(adj, e) { - if (Mconsole.busy) return; - - // catch right click on mac, which is often like ctrl+click - if (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey) { - selectEdgeOnRightClickHandler(adj, e) - return; - } - - if (synapseWasDoubleClicked()) { - synapseDoubleClickHandler(adj, e); - return; - } - - var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(adj); - if (edgeIsSelected == -1) edgeIsSelected = false; - else if (edgeIsSelected != -1) edgeIsSelected = true; - - if (edgeIsSelected && e.shiftKey) { - //deselecting an edge with shift - deselectEdge(adj); - } else if (!edgeIsSelected && e.shiftKey) { - //selecting an edge with shift - selectEdge(adj); - } else if (edgeIsSelected && !e.shiftKey) { - //deselecting an edge without shift - unselect all - deselectAllEdges(); - } else if (!edgeIsSelected && !e.shiftKey) { - //selecting an edge without shift - unselect all but new one - deselectAllEdges(); - selectEdge(adj); - } - - Mconsole.plot(); -} //selectEdgeOnClickHandler - -function selectEdgeOnRightClickHandler(adj, e) { - // the 'node' variable is a JIT node, the one that was clicked on - // the 'e' variable is the click event - - e.preventDefault(); - e.stopPropagation(); - - if (Mconsole.busy) return; - - selectEdge(adj); - - // delete old right click menu - $('.rightclickmenu').remove(); - // create new menu for clicked on node - var rightclickmenu = document.createElement("div"); - rightclickmenu.className = "rightclickmenu"; - - // add the proper options to the menu - var menustring = '
    '; - - if (userid != null) menustring += '
  • Delete
  • '; - if (mapid && userid != null) menustring += '
  • Remove from map
  • '; - menustring += '
  • Hide until refresh
  • '; - if (userid) { - var options = '
    • commons
    • \ -
    • public
    • \ -
    • private
    • \ -
    '; - - menustring += '
  • Change permissions' + options + '
  • '; - } - - menustring += '
'; - rightclickmenu.innerHTML = menustring; - - // position the menu where the click happened - $(rightclickmenu).css({ - left: e.clientX, - top: e.clientY - }); - //add the menu to the page - $('#center-container').append(rightclickmenu); - - - // attach events to clicks on the list items - - // delete the selected things from the database - $('.rc-delete').click(function () { - $('.rightclickmenu').remove(); - var n = MetamapsModel.selectedNodes.length; - var e = MetamapsModel.selectedEdges.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 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) { - deleteSelectedEdges(); - deleteSelectedNodes(); - } - }); - - // remove the selected things from the map - $('.rc-remove').click(function () { - $('.rightclickmenu').remove(); - removeSelectedEdges(); - removeSelectedNodes(); - }); - - // hide selected nodes and synapses until refresh - $('.rc-hide').click(function () { - $('.rightclickmenu').remove(); - hideSelectedEdges(); - hideSelectedNodes(); - }); - - // change the permission of all the selected nodes and synapses that you were the originator of - $('.rc-permission li').click(function () { - $('.rightclickmenu').remove(); - // $(this).text() will be 'commons' 'public' or 'private' - updateSelectedPermissions($(this).text()); - }); - -} //selectEdgeOnRightClickHandler - - -function synapseDoubleClickHandler(adj, e) { - editEdge(adj, e); -} - -/* - * Returns a boolean saying if the synapse was double clicked in our understanding of the word - */ -function synapseWasDoubleClicked() { - //grab the timestamp of the click - var storedTime = MetamapsModel.lastSynapseClick; - var now = Date.now(); //not compatible with IE8 FYI - MetamapsModel.lastSynapseClick = now; - - if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) { - return true; - } else { - return false; - } -} //synapseWasDoubleClicked; - -function nodeDoubleClickHandler(node, e) { - openNodeShowcard(node); -} - -function enterKeyHandler(event) { - - //var selectedNodesCopy = MetamapsModel.selectedNodes.slice(0); - //var len = selectedNodesCopy.length; - //for (var i = 0; i < len; i += 1) { - // n = selectedNodesCopy[i]; - // keepFromCommons(n); - //}//for - //Mconsole.plot(); -} //enterKeyHandler - -function escKeyHandler() { - deselectAllEdges(); - deselectAllNodes(); -} //escKeyHandler - -/* - * Make a node "in the commons" (with a green circle) lose its - * green circle so it stays on the console/map/... - */ -function keepFromCommons(event, id) { - if (userid == null) { - return; - } - - $('#topic_addSynapse').val("false"); - $('#topic_x').val(0); - $('#topic_y').val(0); - $('#topic_grabTopic').val(id); - $('.new_topic').submit(); - - event.preventDefault(); - event.stopPropagation(); - return false; -} //doubleClickNodeHandler - -/* - * Returns a boolean saying if the node was double clicked in our understanding of the word - */ -function nodeWasDoubleClicked() { - //grab the timestamp of the click - var storedTime = MetamapsModel.lastNodeClick; - var now = Date.now(); //not compatible with IE8 FYI - MetamapsModel.lastNodeClick = now; - - if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) { - return true; - } else { - return false; - } -} //nodeWasDoubleClicked; - -function selectNodeOnClickHandler(node, e) { - if (Mconsole.busy) return; - - // catch right click on mac, which is often like ctrl+click - if (navigator.platform.indexOf("Mac") != -1 && e.ctrlKey) { - selectNodeOnRightClickHandler(node, e) - return; - } - - // if on a topic page, let alt+click center you on a new topic - if (!mapid && e.altKey) { - centerOn(node.id); - return; - } - - var check = nodeWasDoubleClicked(); - if (check) { - nodeDoubleClickHandler(node, e); - return; - } else { - // wait a certain length of time, then check again, then run this code - setTimeout(function () { - if (!nodeWasDoubleClicked()) { - if (!e.shiftKey) { - Mconsole.graph.eachNode(function (n) { - if (n.id != node.id) { - deselectNode(n); - } - }); - } - if (node.selected) { - deselectNode(node); - } else { - selectNode(node); - } - //trigger animation to final styles - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:color:alpha'], - duration: 500 - }); - Mconsole.plot(); - } - }, MetamapsModel.DOUBLE_CLICK_TOLERANCE); - } -} //selectNodeOnClickHandler - -function selectNodeOnRightClickHandler(node, e) { - // the 'node' variable is a JIT node, the one that was clicked on - // the 'e' variable is the click event - - e.preventDefault(); - e.stopPropagation(); - - if (Mconsole.busy) return; - - selectNode(node); - - // delete old right click menu - $('.rightclickmenu').remove(); - // create new menu for clicked on node - var rightclickmenu = document.createElement("div"); - rightclickmenu.className = "rightclickmenu"; - - // add the proper options to the menu - var menustring = '
    '; - - if (userid != null) menustring += '
  • Delete
  • '; - if (mapid && userid != null) menustring += '
  • Remove from map
  • '; - menustring += '
  • Hide until refresh
  • '; - - if (!mapid) menustring += '
  • Center this topic
  • '; - menustring += '
  • Open in new tab
  • '; - if (userid) { - var options = '
    • commons
    • \ -
    • public
    • \ -
    • private
    • \ -
    '; - - menustring += '
  • Change permissions' + options + '
  • '; - } - - menustring += '
'; - rightclickmenu.innerHTML = menustring; - - // position the menu where the click happened - $(rightclickmenu).css({ - left: e.clientX, - top: e.clientY - }); - //add the menu to the page - $('#center-container').append(rightclickmenu); - - - // attach events to clicks on the list items - - // delete the selected things from the database - $('.rc-delete').click(function () { - $('.rightclickmenu').remove(); - var n = MetamapsModel.selectedNodes.length; - var e = MetamapsModel.selectedEdges.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 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) { - deleteSelectedEdges(); - deleteSelectedNodes(); - } - }); - - // remove the selected things from the map - $('.rc-remove').click(function () { - $('.rightclickmenu').remove(); - removeSelectedEdges(); - removeSelectedNodes(); - }); - - // hide selected nodes and synapses until refresh - $('.rc-hide').click(function () { - $('.rightclickmenu').remove(); - hideSelectedEdges(); - hideSelectedNodes(); - }); - - // when in radial, center on the topic you picked - $('.rc-center').click(function () { - $('.rightclickmenu').remove(); - centerOn(node.id); - }); - - // open the entity in a new tab - $('.rc-popout').click(function () { - $('.rightclickmenu').remove(); - var win = window.open('/topics/' + node.id, '_blank'); - win.focus(); - }); - - // change the permission of all the selected nodes and synapses that you were the originator of - $('.rc-permission li').click(function () { - $('.rightclickmenu').remove(); - // $(this).text() will be 'commons' 'public' or 'private' - updateSelectedPermissions($(this).text()); - }); - -} //selectNodeOnRightClickHandler - -function canvasDoubleClickHandler(canvasLoc, e) { - - //grab the location and timestamp of the click - var storedTime = MetamapsModel.lastCanvasClick; - var now = Date.now(); //not compatible with IE8 FYI - MetamapsModel.lastCanvasClick = now; - - // if on a public map, disable topic creation - if (userid && (mapperm || !mapid)) { - if (now - storedTime < MetamapsModel.DOUBLE_CLICK_TOLERANCE) { - //pop up node creation :) - $('#topic_grabTopic').val("null"); - $('#topic_addSynapse').val("false"); - $('#new_topic').css('left', e.clientX + "px"); - $('#new_topic').css('top', e.clientY + "px"); - $('#topic_x').val(canvasLoc.x); - $('#topic_y').val(canvasLoc.y); - $('#new_topic').fadeIn('fast'); - $('#topic_name').typeahead('setQuery', '').focus(); - return; - } - } - - if (!MetamapsModel.didPan) { - $('#new_topic').fadeOut('fast'); - $('#new_synapse').fadeOut('fast'); - $('.rightclickmenu').remove(); - // reset the draw synapse positions to false - MetamapsModel.synapseStartCoord = false; - MetamapsModel.synapseEndCoord = false; - deselectAllNodes(); - tempInit = false; - tempNode = null; - tempNode2 = null; - Mconsole.plot(); - } -} //canvasDoubleClickHandler - -function handleSelectionBeforeDragging(node, e) { - // four cases: - // 1 nothing is selected, so pretend you aren't selecting - // 2 others are selected only and shift, so additionally select this one - // 3 others are selected only, no shift: drag only this one - // 4 this node and others were selected, so drag them (just return false) - //return value: deselect node again after? - if (MetamapsModel.selectedNodes.length == 0) { - selectNode(node); - return 'deselect'; - } - if (MetamapsModel.selectedNodes.indexOf(node) == -1) { - if (e.shiftKey) { - selectNode(node); - return 'nothing'; - } else { - return 'only-drag-this-one'; - } - } - return 'nothing'; //case 4? -} - -function onDragMoveTopicHandler(node, eventInfo, e) { - if (node && !node.nodeFrom) { - $('#new_synapse').fadeOut('fast'); - $('#new_topic').fadeOut('fast'); - var pos = eventInfo.getPos(); - var newPosComplex = new $jit.Complex(pos.x, pos.y); - // if it's a left click, or a touch, move the node - if (e.touches || (e.button == 0 && !e.altKey && (e.buttons == 0 || e.buttons == 1 || e.buttons == undefined))) { - //if the node dragged isn't already selected, select it - var whatToDo = handleSelectionBeforeDragging(node, e); - if (whatToDo == 'only-drag-this-one' || whatToDo == 'deselect') { - if (gType == "centered") { - var rho = Math.sqrt(pos.x * pos.x + pos.y * pos.y); - var theta = Math.atan2(pos.y, pos.x); - node.pos.setp(theta, rho); - } else { - node.setPos(newPosComplex, 'start'); - node.setPos(newPosComplex, 'current'); - node.setPos(newPosComplex, 'end'); - node.setData('xloc', pos.x); - node.setData('yloc', pos.y); - } - } else { - var len = MetamapsModel.selectedNodes.length; - - //first define offset for each node - var xOffset = new Array(); - var yOffset = new Array(); - for (var i = 0; i < len; i += 1) { - var n = MetamapsModel.selectedNodes[i]; - if (gType == "centered") { - xOffset[i] = n.pos.toComplex().x - node.pos.toComplex().x; - yOffset[i] = n.pos.toComplex().y - node.pos.toComplex().y; - } else { - xOffset[i] = n.pos.x - node.pos.x; - yOffset[i] = n.pos.y - node.pos.y; - } - } //for - - for (var i = 0; i < len; i += 1) { - var n = MetamapsModel.selectedNodes[i]; - if (gType == "centered") { - var x = pos.x + xOffset[i]; - var y = pos.y + yOffset[i]; - var rho = Math.sqrt(x * x + y * y); - var theta = Math.atan2(y, x); - n.pos.setp(theta, rho); - } else { - newPosComplex = new $jit.Complex(pos.x + xOffset[i], pos.y + yOffset[i]); - n.setPos(newPosComplex, 'start'); - n.setPos(newPosComplex, 'current'); - n.setPos(newPosComplex, 'end'); - n.setData('xloc', pos.x + xOffset[i]); - n.setData('yloc', pos.y + yOffset[i]); - } - } //for - } //if - - if (whatToDo == 'deselect') { - deselectNode(node); - } - dragged = node.id; - Mconsole.plot(); - } - // if it's a right click or holding down alt, start synapse creation ->third option is for firefox - else if ((e.button == 2 || (e.button == 0 && e.altKey) || e.buttons == 2) && userid != null) { - - // if on a public map, disable synapse creation - if (mapid && !mapperm) return; - - if (tempInit == false) { - tempNode = node; - tempInit = true; - // set the draw synapse start position - MetamapsModel.synapseStartCoord = { - x: node.pos.getc().x, - y: node.pos.getc().y - }; - } - // - temp = eventInfo.getNode(); - if (temp != false && temp.id != node.id) { // this means a Node has been returned - tempNode2 = temp; - - // set the draw synapse end position - MetamapsModel.synapseEndCoord = { - x: temp.pos.getc().x, - y: temp.pos.getc().y - }; - - Mconsole.plot(); - - // before making the highlighted one bigger, make sure all the others are regular size - Mconsole.graph.eachNode(function (n) { - n.setData('dim', 25, 'current'); - }); - temp.setData('dim', 35, 'current'); - Mconsole.fx.plotNode(tempNode, Mconsole.canvas); - Mconsole.fx.plotNode(temp, Mconsole.canvas); - } else if (!temp) { - tempNode2 = null; - Mconsole.graph.eachNode(function (n) { - n.setData('dim', 25, 'current'); - }); - //pop up node creation :) - $('#topic_grabTopic').val("null"); - var myX = e.clientX - 110; - var myY = e.clientY - 30; - $('#new_topic').css('left', myX + "px"); - $('#new_topic').css('top', myY + "px"); - $('#new_synapse').css('left', myX + "px"); - $('#new_synapse').css('top', myY + "px"); - $('#topic_x').val(eventInfo.getPos().x); - $('#topic_y').val(eventInfo.getPos().y); - // set the draw synapse end position - MetamapsModel.synapseEndCoord = { - x: eventInfo.getPos().x, - y: eventInfo.getPos().y - }; - Mconsole.plot(); - Mconsole.fx.plotNode(tempNode, Mconsole.canvas); - } - } - } -} - -var lastDist = 0; - -function getDistance(p1, p2) { - return Math.sqrt(Math.pow((p2.x - p1.x), 2) + Math.pow((p2.y - p1.y), 2)); -} - -function touchPanZoomHandler(eventInfo, e) { - if (e.touches.length == 1) { - var thispos = touchPos, - currentPos = eventInfo.getPos(), - canvas = Mconsole.canvas, - ox = canvas.translateOffsetX, - oy = canvas.translateOffsetY, - sx = canvas.scaleOffsetX, - sy = canvas.scaleOffsetY; - currentPos.x *= sx; - currentPos.y *= sy; - currentPos.x += ox; - currentPos.y += oy; - //var x = currentPos.x - thispos.x, - // y = currentPos.y - thispos.y; - var x = currentPos.x - thispos.x, - y = currentPos.y - thispos.y; - touchPos = currentPos; - Mconsole.canvas.translate(x * 1 / sx, y * 1 / sy); - } else if (e.touches.length == 2) { - var touch1 = e.touches[0]; - var touch2 = e.touches[1]; - - var dist = getDistance({ - x: touch1.clientX, - y: touch1.clientY - }, { - x: touch2.clientX, - y: touch2.clientY - }); - - if (!lastDist) { - lastDist = dist; - } - - var scale = dist / lastDist; - - console.log(scale); - - if (8 >= Mconsole.canvas.scaleOffsetX * scale && Mconsole.canvas.scaleOffsetX * scale >= 1) { - Mconsole.canvas.scale(scale, scale); - } - if (Mconsole.canvas.scaleOffsetX < 0.5) { - Mconsole.canvas.viz.labels.hideLabels(true); - } else if (Mconsole.canvas.scaleOffsetX > 0.5) { - Mconsole.canvas.viz.labels.hideLabels(false); - } - lastDist = dist; - } - -} - -function updateSelectedPermissions(permission) { - - - if ($('.notice.metamaps').length == 0) { - $('body').prepend('
'); - } - $('.notice.metamaps').hide().html('Working...').fadeIn('fast'); - - // 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 = MetamapsModel.selectedEdges.length; - for (var i = l - 1; i >= 0; i -= 1) { - var edge = MetamapsModel.selectedEdges[i]; - - if (edge.getData('userid') == userid) { - updateSynapsePermission(edge, permission); - sCount++; - } - } - - // change the permission of the selected topics, if logged in user is the original creator - var l = MetamapsModel.selectedNodes.length; - for (var i = l - 1; i >= 0; i -= 1) { - var node = MetamapsModel.selectedNodes[i]; - - if (node.getData('userid') == userid) { - updateTopicPermission(node, permission); - nCount++; - } - } - - var nString = nCount == 1 ? (nCount.toString() + ' topic and ') : (nCount.toString() + ' topics and '); - var sString = sCount == 1 ? (sCount.toString() + ' synapse') : (sCount.toString() + ' synapses'); - - $('.notice.metamaps').html(nString + sString + ' you created updated to ' + permission) - setTimeout(function () { - $('.notice.metamaps').fadeOut('fast'); - }, 8000); -} \ No newline at end of file diff --git a/app/assets/javascripts/Jit/graphsettings-model.js b/app/assets/javascripts/Jit/graphsettings-model.js deleted file mode 100644 index 5877e47b..00000000 --- a/app/assets/javascripts/Jit/graphsettings-model.js +++ /dev/null @@ -1,66 +0,0 @@ -/* - * @file - * This file holds the Model object that is referenced in other graphsettings - * files. It lists selected nodes, selected edges, and stores data about - * double clicks on the canvas - */ - -var MetamapsModel = new Object(); - -MetamapsModel.embed = false; - -// if you're on a map, this will be an object that has a reference to each user that has loaded the map, and whether they are -// in realtime or not -MetamapsModel.mappersOnMap = {}; - - -MetamapsModel.metacodeScrollerInit = false; // indicates whether the scrollbar in the custom metacode set space has been init - -MetamapsModel.selectedMetacodeSet = null; -MetamapsModel.selectedMetacodeSetIndex = null; - -MetamapsModel.selectedMetacodeNames = new Array(); -MetamapsModel.newSelectedMetacodeNames = new Array(); - -MetamapsModel.selectedMetacodes = new Array(); -MetamapsModel.newSelectedMetacodes = new Array(); - -//array of all selected edges, same for nodes -MetamapsModel.selectedEdges = new Array(); -MetamapsModel.selectedNodes = new Array(); - -//this stores a value that indicates whether the user panned or simply clicked without panning -// used for purposes of knowing whether to close the open card or not (don't if panned) -MetamapsModel.didPan = false; - -//is any showcard open right now? which one? -MetamapsModel.showcardInUse = null; -MetamapsModel.widthOfLabel = null; - -//is an edge card open right now? which one (the id)? -MetamapsModel.edgecardInUse = null; - -//is the mouse hovering over an edge? which one? -MetamapsModel.edgeHoveringOver = false; - -//coordinates of shift click for using box select -MetamapsModel.boxStartCoordinates = false; -MetamapsModel.boxEndCoordinates = false; - -//coordinates for drawing edge that's not created yet -MetamapsModel.synapseStartCoord = false; -MetamapsModel.synapseEndCoord = false; - -//double clicking of nodes or canvas -MetamapsModel.lastSynapseClick = 0; -MetamapsModel.lastNodeClick = 0; -MetamapsModel.lastCanvasClick = 0; -MetamapsModel.DOUBLE_CLICK_TOLERANCE = 300; - -//pop-up permission editors timers -MetamapsModel.edgePermTimer1 = null; -MetamapsModel.edgePermTimer2 = null; -MetamapsModel.edgePermSliding = false; -MetamapsModel.topicPermTimer1 = null; -MetamapsModel.topicPermTimer2 = null; -MetamapsModel.topicPermSliding = false; diff --git a/app/assets/javascripts/Jit/graphsettings.js b/app/assets/javascripts/Jit/graphsettings.js deleted file mode 100644 index 2593586c..00000000 --- a/app/assets/javascripts/Jit/graphsettings.js +++ /dev/null @@ -1,606 +0,0 @@ -/* - * @file - * This function defines all settings and event callbacks for the JIT graph. Some are found in other files - * First is the common settings (the same as arranged or chaotic) - * Then if it's a centred graph additional settings are added. - */ - -function graphSettings(type, embed) { - var t = { - //id of the visualization container - injectInto: 'infovis', - //Enable zooming and panning - //by scrolling and DnD - Navigation: { - enable: true, - //Enable panning events only if we're dragging the empty - //canvas (and not a node). - panning: 'avoid nodes', - zooming: 28 //zoom speed. higher is more sensible - }, - // Change node and edge styles such as - // color and width. - // These properties are also set per node - // with dollar prefixed data-properties in the - // JSON structure. - Node: { - overridable: true, - color: '#2D6A5D', - type: 'customNode', - dim: 25 - }, - Edge: { - overridable: true, - color: '#222222', - type: 'customEdge', - lineWidth: 2, - alpha: 0.4 - }, - //Native canvas text styling - Label: { - type: 'Native', //Native or HTML - size: 20, - family: 'arial', - textBaseline: 'hanging', - color: '#DDD' - //style: 'bold' - }, - //Add Tips - Tips: { - enable: false, - onShow: function (tip, node) {} - }, - // Add node events - Events: { - enable: true, - enableForEdges: true, - onMouseMove: function (node, eventInfo, e) { - onMouseMoveHandler(node, eventInfo, e); - }, - //Update node positions when dragged - onDragMove: function (node, eventInfo, e) { - onDragMoveTopicHandler(node, eventInfo, e); - }, - onDragEnd: function (node, eventInfo, e) { - onDragEndTopicHandler(node, eventInfo, e, false); - }, - onDragCancel: function (node, eventInfo, e) { - onDragCancelHandler(node, eventInfo, e, false); - }, - //Implement the same handler for touchscreens - onTouchStart: function (node, eventInfo, e) { - //$jit.util.event.stop(e); //stop default touchmove event - //Mconsole.events.onMouseDown(e, null, eventInfo); - Mconsole.events.touched = true; - touchPos = eventInfo.getPos(); - var canvas = Mconsole.canvas, - ox = canvas.translateOffsetX; - oy = canvas.translateOffsetY, - sx = canvas.scaleOffsetX, - sy = canvas.scaleOffsetY; - touchPos.x *= sx; - touchPos.y *= sy; - touchPos.x += ox; - touchPos.y += oy; - - touchDragNode = node; - }, - //Implement the same handler for touchscreens - onTouchMove: function (node, eventInfo, e) { - if (touchDragNode) onDragMoveTopicHandler(touchDragNode, eventInfo, e); - else { - touchPanZoomHandler(eventInfo, e); - Mconsole.labels.hideLabel(Mconsole.graph.getNode(MetamapsModel.showcardInUse)); - } - }, - //Implement the same handler for touchscreens - onTouchEnd: function (node, eventInfo, e) { - - }, - //Implement the same handler for touchscreens - onTouchCancel: function (node, eventInfo, e) { - - }, - //Add also a click handler to nodes - onClick: function (node, eventInfo, e) { - if (MetamapsModel.boxStartCoordinates) { - Mconsole.busy = false; - MetamapsModel.boxEndCoordinates = eventInfo.getPos(); - selectNodesWithBox(); - return; - } - - if (e.target.id != "infovis-canvas") return false; - - //clicking on a edge, node, or clicking on blank part of canvas? - if (node.nodeFrom) { - selectEdgeOnClickHandler(node, e); - } else if (node && !node.nodeFrom) { - selectNodeOnClickHandler(node, e); - } else { - //topic and synapse editing cards - if (!MetamapsModel.didPan) { - hideCards(); - } - canvasDoubleClickHandler(eventInfo.getPos(), e); - } //if - }, - onRightClick: function (node, eventInfo, e) { - e.preventDefault(); - e.stopPropagation(); - - if (node && !node.nodeFrom) { - selectNodeOnRightClickHandler(node, e); - } else if (node && node.nodeFrom) { // the variable 'node' is actually an edge/adjacency - // open right click menu - selectEdgeOnRightClickHandler(node, e); - } else { - // right click on open canvas, options here? - } - } - }, - //Number of iterations for the FD algorithm - iterations: 200, - //Edge length - levelDistance: 200 - }; - - if (embed) { - t.Edge.type = 'customEdgeEmbed'; - } - - if (type == "centered") { - t.background = { - CanvasStyles: { - strokeStyle: '#333', - lineWidth: 1.5 - } - }; - t.levelDistance = 280; - t.Events.enableForEdges = true; - t.Events.onDragEnd = function (node, eventInfo, e) { - //different because we can't go realtime - onDragEndTopicHandler(node, eventInfo, e, false); - }; - t.Events.onDragCancel = function (node, eventInfo, e) { - //different because we're centred - onDragCancelHandler(node, eventInfo, e, true); - }; - } //if - - return t; -} //graphSettings - -function hideCards() { - $('#edit_synapse').hide(); - MetamapsModel.edgecardInUse = null; - hideCurrentCard(); - // delete right click menu - $('.rightclickmenu').remove(); -} - -// defining code to draw edges with arrows pointing in one direction -var renderMidArrow = function (from, to, dim, swap, canvas, placement, newSynapse) { - var ctx = canvas.getCtx(); - // invert edge direction - if (swap) { - var tmp = from; - from = to; - to = tmp; - } - // vect represents a line from tip to tail of the arrow - var vect = new $jit.Complex(to.x - from.x, to.y - from.y); - // scale it - vect.$scale(dim / vect.norm()); - // compute the midpoint of the edge line - var newX = (to.x - from.x) * placement + from.x; - var newY = (to.y - from.y) * placement + from.y; - var midPoint = new $jit.Complex(newX, newY); - - // move midpoint by half the "length" of the arrow so the arrow is centered on the midpoint - var arrowPoint = new $jit.Complex((vect.x / 0.7) + midPoint.x, (vect.y / 0.7) + midPoint.y); - // compute the tail intersection point with the edge line - var intermediatePoint = new $jit.Complex(arrowPoint.x - vect.x, arrowPoint.y - vect.y); - // vector perpendicular to vect - var normal = new $jit.Complex(-vect.y / 2, vect.x / 2); - var v1 = intermediatePoint.add(normal); - var v2 = intermediatePoint.$add(normal.$scale(-1)); - - if (newSynapse) { - ctx.strokeStyle = "#222222"; - ctx.lineWidth = 2; - ctx.globalAlpha = 0.4; - } - ctx.beginPath(); - ctx.moveTo(from.x, from.y); - ctx.lineTo(to.x, to.y); - ctx.stroke(); - ctx.beginPath(); - ctx.moveTo(v1.x, v1.y); - ctx.lineTo(arrowPoint.x, arrowPoint.y); - ctx.lineTo(v2.x, v2.y); - ctx.stroke(); -}; - -// defining custom node type -var nodeSettings = { - 'customNode': { - 'render': function (node, canvas) { - var pos = node.pos.getc(true), - dim = node.getData('dim'), - cat = node.getData('metacode'), - whiteCircle = node.getData('whiteCircle'), - ctx = canvas.getCtx(); - - // if the topic is on the Canvas draw a white circle around it - if (whiteCircle) { - ctx.beginPath(); - ctx.arc(pos.x, pos.y, dim + 3, 0, 2 * Math.PI, false); - if (!MetamapsModel.embed) ctx.strokeStyle = 'white'; - if (MetamapsModel.embed) ctx.strokeStyle = '#999'; - ctx.lineWidth = 2; - ctx.stroke(); - } - ctx.drawImage(imgArray[cat], pos.x - dim, pos.y - dim, dim * 2, dim * 2); - - }, - 'contains': function (node, pos) { - var npos = node.pos.getc(true), - dim = node.getData('dim'); - return this.nodeHelper.circle.contains(npos, pos, dim); - } - } -} - -var renderEdgeArrows = function (edgeHelper, adj) { - var canvas = Mconsole.canvas; - var directionCat = adj.getData('category'); - var direction = adj.getData('direction'); - var pos = adj.nodeFrom.pos.getc(true); - var posChild = adj.nodeTo.pos.getc(true); - - //plot arrow edge - if (directionCat == "none") { - edgeHelper.line.render({ - x: pos.x, - y: pos.y - }, { - x: posChild.x, - y: posChild.y - }, canvas); - } else if (directionCat == "both") { - renderMidArrow({ - x: pos.x, - y: pos.y - }, { - x: posChild.x, - y: posChild.y - }, 13, true, canvas, 0.7); - renderMidArrow({ - x: pos.x, - y: pos.y - }, { - x: posChild.x, - y: posChild.y - }, 13, false, canvas, 0.7); - } else if (directionCat == "from-to") { - var direction = adj.data.$direction; - var inv = (direction && direction.length > 1 && direction[0] != adj.nodeFrom.id); - renderMidArrow({ - x: pos.x, - y: pos.y - }, { - x: posChild.x, - y: posChild.y - }, 13, inv, canvas, 0.7); - renderMidArrow({ - x: pos.x, - y: pos.y - }, { - x: posChild.x, - y: posChild.y - }, 13, inv, canvas, 0.3); - } - } //renderEdgeArrow - -// defining custom edges -var edgeSettings = { - 'customEdge': { - 'render': function (adj, canvas) { - //get nodes cartesian coordinates - var pos = adj.nodeFrom.pos.getc(true); - var posChild = adj.nodeTo.pos.getc(true); - - var directionCat = adj.getData("category"); - //label placement on edges - renderEdgeArrows(this.edgeHelper, adj); - - //check for edge label in data - var desc = adj.getData("desc"); - var showDesc = adj.getData("showDesc"); - if (desc != "" && showDesc) { - // '&' to '&' - desc = decodeEntities(desc); - - //now adjust the label placement - var ctx = canvas.getCtx(); - ctx.font = 'bold 14px arial'; - ctx.fillStyle = '#FFF'; - ctx.textBaseline = 'hanging'; - - // 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 - function splitLine(st, n) { - var b = ''; - var s = 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; - } - var arrayOfLabelLines = splitLine(desc, 30).split('\n'); - var index, lineWidths = []; - for (index = 0; index < arrayOfLabelLines.length; ++index) { - lineWidths.push(ctx.measureText(arrayOfLabelLines[index]).width) - } - var width = Math.max.apply(null, lineWidths) + 8; - var height = (16 * arrayOfLabelLines.length) + 8; - - var x = (pos.x + posChild.x - width) / 2; - var y = ((pos.y + posChild.y) / 2) - height / 2; - var radius = 5; - - //render background - ctx.beginPath(); - ctx.moveTo(x + radius, y); - ctx.lineTo(x + width - radius, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius); - ctx.lineTo(x + width, y + height - radius); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); - ctx.lineTo(x + radius, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius); - ctx.lineTo(x, y + radius); - ctx.quadraticCurveTo(x, y, x + radius, y); - ctx.closePath(); - ctx.fill(); - - //render text - ctx.fillStyle = '#222222'; - ctx.textAlign = 'center'; - for (index = 0; index < arrayOfLabelLines.length; ++index) { - ctx.fillText(arrayOfLabelLines[index], x + (width / 2), y + 5 + (16 * index)); - } - } - }, - 'contains': function (adj, pos) { - var from = adj.nodeFrom.pos.getc(true), - to = adj.nodeTo.pos.getc(true); - return this.edgeHelper.line.contains(from, to, pos, adj.Edge.epsilon); - } - } -} - -var edgeSettingsEmbed = { - 'customEdgeEmbed': { - 'render': function (adj, canvas) { - //get nodes cartesian coordinates - var pos = adj.nodeFrom.pos.getc(true); - var posChild = adj.nodeTo.pos.getc(true); - - var directionCat = adj.getData("category"); - //label placement on edges - renderEdgeArrows(this.edgeHelper, adj); - - //check for edge label in data - var desc = adj.getData("desc"); - var showDesc = adj.getData("showDesc"); - if (desc != "" && showDesc) { - // '&' to '&' - desc = decodeEntities(desc); - - //now adjust the label placement - var ctx = canvas.getCtx(); - var radius = canvas.getSize(); - var x = parseInt((pos.x + posChild.x - (desc.length * 5)) / 2); - var y = parseInt((pos.y + posChild.y) / 2); - ctx.font = 'bold 14px arial'; - - //render background - ctx.fillStyle = '#999'; - var margin = 5; - var height = 14 + margin; //font size + margin - var CURVE = height / 2; //offset for curvy corners - var width = ctx.measureText(desc).width + 2 * margin - 2 * CURVE - var labelX = x - margin + CURVE; - var labelY = y - height + margin; - ctx.fillRect(labelX, labelY, width, height); - - //curvy corners woo - circles in place of last CURVE pixels of rect - ctx.beginPath(); - ctx.arc(labelX, labelY + CURVE, CURVE, 0, 2 * Math.PI, false); - ctx.arc(labelX + width, labelY + CURVE, CURVE, 0, 2 * Math.PI, false); - ctx.fill(); - - //render text - ctx.fillStyle = '#000'; - ctx.fillText(desc, x, y); - } - }, - 'contains': function (adj, pos) { - var from = adj.nodeFrom.pos.getc(true), - to = adj.nodeTo.pos.getc(true); - return this.edgeHelper.line.contains(from, to, pos, adj.Edge.epsilon); - } - } -} - -function drawSelectBox(eventInfo, e) { - Mconsole.plot(); - var ctx = Mconsole.canvas.getCtx(); - - var startX = MetamapsModel.boxStartCoordinates.x, - startY = MetamapsModel.boxStartCoordinates.y, - currX = eventInfo.getPos().x, - currY = eventInfo.getPos().y; - - Mconsole.plot(); - ctx.beginPath(); - ctx.moveTo(startX, startY); - ctx.lineTo(startX, currY); - ctx.lineTo(currX, currY); - ctx.lineTo(currX, startY); - ctx.lineTo(startX, startY); - ctx.strokeStyle = "black"; - ctx.stroke(); -} - -function selectNodesWithBox() { - - var sX = MetamapsModel.boxStartCoordinates.x, - sY = MetamapsModel.boxStartCoordinates.y, - eX = MetamapsModel.boxEndCoordinates.x, - eY = MetamapsModel.boxEndCoordinates.y; - - - Mconsole.graph.eachNode(function (n) { - var x = gType == "centered" ? n.pos.toComplex().x : n.pos.x, - y = gType == "centered" ? n.pos.toComplex().y : n.pos.y; - - if ((sX < x && x < eX && sY < y && y < eY) || (sX > x && x > eX && sY > y && y > eY) || (sX > x && x > eX && sY < y && y < eY) || (sX < x && x < eX && sY > y && y > eY)) { - var nodeIsSelected = MetamapsModel.selectedNodes.indexOf(n); - if (nodeIsSelected == -1) selectNode(n); // the node is not selected, so select it - else if (nodeIsSelected != -1) deselectNode(n); // the node is selected, so deselect it - - } - }); - - MetamapsModel.boxStartCoordinates = false; - MetamapsModel.boxEndCoordinates = false; - Mconsole.plot(); -} - -function onMouseMoveHandler(node, eventInfo, e) { - - if (Mconsole.busy) return; - - var node = eventInfo.getNode(); - var edge = eventInfo.getEdge(); - - //if we're on top of a node object, act like there aren't edges under it - if (node != false) { - if (MetamapsModel.edgeHoveringOver) { - onMouseLeave(MetamapsModel.edgeHoveringOver); - } - $('canvas').css('cursor', 'pointer'); - return; - } - - if (edge == false && MetamapsModel.edgeHoveringOver != false) { - //mouse not on an edge, but we were on an edge previously - onMouseLeave(MetamapsModel.edgeHoveringOver); - } else if (edge != false && MetamapsModel.edgeHoveringOver == false) { - //mouse is on an edge, but there isn't a stored edge - onMouseEnter(edge); - } else if (edge != false && MetamapsModel.edgeHoveringOver != edge) { - //mouse is on an edge, but a different edge is stored - onMouseLeave(MetamapsModel.edgeHoveringOver) - onMouseEnter(edge); - } - - //could be false - MetamapsModel.edgeHoveringOver = edge; - - if (!node && !edge) { - $('canvas').css('cursor', 'default'); - } -} - -function onMouseEnter(edge) { - $('canvas').css('cursor', 'pointer'); - var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(edge); - //following if statement only executes if the edge being hovered over is not selected - if (edgeIsSelected == -1) { - edge.setData('showDesc', true, 'current'); - edge.setDataset('end', { - lineWidth: 4, - alpha: 1 - }); - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:color:alpha'], - duration: 100 - }); - Mconsole.plot(); - } -} - -function onMouseLeave(edge) { - $('canvas').css('cursor', 'default'); - var edgeIsSelected = MetamapsModel.selectedEdges.indexOf(edge); - //following if statement only executes if the edge being hovered over is not selected - if (edgeIsSelected == -1) { - edge.setData('showDesc', false, 'current'); - edge.setDataset('end', { - lineWidth: 2, - alpha: 0.4 - }); - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:color:alpha'], - duration: 100 - }); - } - Mconsole.plot(); -} - -function onDragEndTopicHandler(node, eventInfo, e, allowRealtime) { - if (tempInit && tempNode2 == null) { - $('#topic_addSynapse').val("true"); - $('#new_topic').fadeIn('fast'); - $('#topic_name').focus(); - } else if (tempInit && tempNode2 != null) { - $('#topic_addSynapse').val("false"); - $('#synapse_topic1id').val(tempNode.id); - $('#synapse_topic2id').val(tempNode2.id); - $('#new_synapse').fadeIn('fast'); - $('#synapse_desc').typeahead('setQuery', '').focus(); - tempNode = null; - tempNode2 = null; - tempInit = false; - } else if (dragged && dragged != 0 && goRealtime) { - saveLayout(dragged); - for (var i = 0; i < MetamapsModel.selectedNodes.length; i++) { - saveLayout(MetamapsModel.selectedNodes[i].id); - } - } -} //onDragEndTopicHandler - -function onDragCancelHandler(node, eventInfo, e, centred) { - tempNode = null; - tempNode2 = null; - tempInit = false; - - //not sure why this doesn't happen for centred graphs - if (!centred) { - $('#topic_addSynapse').val("false"); - $('#topic_topic1id').val(0); - $('#topic_topic2id').val(0); - } - Mconsole.plot(); -} - -// thanks to http://stackoverflow.com/questions/4338963/ -// convert-html-character-entities-back-to-regular-text-using-javascript -function decodeEntities(desc) { - var str, temp = document.createElement('p'); - temp.innerHTML = desc; //browser handles the entities - str = temp.textContent || temp.innerText; - temp = null; //delete the element; - return str; -} //decodeEntities \ No newline at end of file diff --git a/app/assets/javascripts/Jit/loadgraphs.js b/app/assets/javascripts/Jit/loadgraphs.js deleted file mode 100644 index 8a1c585b..00000000 --- a/app/assets/javascripts/Jit/loadgraphs.js +++ /dev/null @@ -1,143 +0,0 @@ -(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); -})(); - -// init custom node type -$jit.ForceDirected.Plot.NodeTypes.implement(nodeSettings); -//implement an edge type -$jit.ForceDirected.Plot.EdgeTypes.implement(edgeSettings); -$jit.ForceDirected.Plot.EdgeTypes.implement(edgeSettingsEmbed); -// end - -// init custom node type -$jit.RGraph.Plot.NodeTypes.implement(nodeSettings); -//implement an edge type -$jit.RGraph.Plot.EdgeTypes.implement(edgeSettings); -// end - -function initialize(type, loadLater, embed){ - - if (loadLater == null) { - loadlater = false; - } - if (embed == null) { - embed = false; - } - - viewMode = "graph"; - gType = type; - - if ( type == "centered") { - // init Rgraph - Mconsole = new $jit.RGraph(graphSettings(type)); - } - else if ( type == "arranged" || type == "chaotic" ) { - // init ForceDirected - Mconsole = new $jit.ForceDirected(graphSettings(type, embed)); - } - else { - alert("You didn't specify a type!"); - return false; - } - - // load JSON data. - if (!loadLater) { - Mconsole.busy = true; - Mconsole.loadJSON(json); - - // choose how to plot and animate the data onto the screen - var chooseAnimate; - - if ( type == "centered") { - // compute positions incrementally and animate. - //trigger small animation - Mconsole.graph.eachNode(function(n) { - var pos = n.getPos(); - pos.setc(-200, -200); - }); - Mconsole.compute('end'); - - chooseAnimate = { - modes:['polar'], - duration: 2000, - onComplete: function() { - Mconsole.busy = false; - } - }; - } - else if ( type == "arranged" ) { - // compute positions incrementally and animate. - Mconsole.graph.eachNode(function(n) { - var pos = n.getPos(); - pos.setc(0, 0); - var newPos = new $jit.Complex(); - newPos.x = n.data.$xloc; - newPos.y = n.data.$yloc; - n.setPos(newPos, 'end'); - }); - - chooseAnimate = { - modes: ['linear'], - transition: $jit.Trans.Quad.easeInOut, - duration: 2500, - onComplete: function() { - Mconsole.busy = false; - } - }; - } - else if ( type == "chaotic" ) { - // compute positions incrementally and animate. - Mconsole.compute(); - - chooseAnimate = { - modes: ['linear'], - transition: $jit.Trans.Elastic.easeOut, - duration: 2500, - onComplete: function() { - Mconsole.busy = false; - } - }; - } - - - $(document).ready(function() { - if ( type == "centered") { - Mconsole.fx.animate(chooseAnimate); - } - else if ( type == "arranged" || type == "chaotic") { - Mconsole.animate(chooseAnimate); - } - - // prevent touch events on the canvas from default behaviour - $("#infovis-canvas").bind('touchstart', function(event) { - event.preventDefault(); - Mconsole.events.touched = true; - }); - - // prevent touch events on the canvas from default behaviour - $("#infovis-canvas").bind('touchmove', function(event) { - //touchPanZoomHandler(event); - }); - - // prevent touch events on the canvas from default behaviour - $("#infovis-canvas").bind('touchend touchcancel', function(event) { - lastDist = 0; - if (!Mconsole.events.touchMoved && !touchDragNode) hideCurrentCard(); - Mconsole.events.touched = Mconsole.events.touchMoved = false; - touchDragNode = false; - }); - }); - // end - }// if not loadLater -} diff --git a/app/assets/javascripts/Jit/permissions.js b/app/assets/javascripts/Jit/permissions.js deleted file mode 100644 index 3c372dd3..00000000 --- a/app/assets/javascripts/Jit/permissions.js +++ /dev/null @@ -1,11 +0,0 @@ - -function authorizeToEdit(obj) { - if (userid && (obj.data.$permission == "commons" || obj.data.$userid == userid)) return true; - else return false; -} - -function mk_permission(obj) { - if (obj.getData("permission") == "commons") return "co"; - else if (obj.getData("permission") == "public") return "pu"; - else if (obj.getData("permission") == "private") return "pr"; -} \ No newline at end of file diff --git a/app/assets/javascripts/Jit/select-edit-delete-nodes-and-edges.js b/app/assets/javascripts/Jit/select-edit-delete-nodes-and-edges.js deleted file mode 100644 index 125c4020..00000000 --- a/app/assets/javascripts/Jit/select-edit-delete-nodes-and-edges.js +++ /dev/null @@ -1,439 +0,0 @@ -function centerOn(nodeid) { - if (!Mconsole.busy) { - var node = Mconsole.graph.getNode(nodeid); - $('div.index img').attr('src', imgArray[node.getData('metacode')].src); - $('div.index .mapName').html(node.name); - $(document).attr('title', node.name + ' | Metamaps'); - window.history.pushState(node.name, "Metamaps", "/topics/" + node.id); - Mconsole.onClick(node.id, { - hideLabels: false, - duration: 1000, - onComplete: function () { - fetchRelatives(node); - } - }); - } -} - -function editEdge(edge, e) { - //reset so we don't interfere with other edges, but first, save its x and y - var myX = $('#edit_synapse').css('left'); - var myY = $('#edit_synapse').css('top'); - $('#edit_synapse').remove(); - - //so label is missing while editing - deselectEdge(edge); - - //create the wrapper around the form elements, including permissions - //classes to make best_in_place happy - var edit_div = document.createElement('div'); - edit_div.setAttribute('id', 'edit_synapse'); - if (authorizeToEdit(edge)) { - edit_div.className = 'permission canEdit'; - edit_div.className += edge.getData('userid') === userid ? ' yourEdge' : ''; - } else { - edit_div.className = 'permission cannotEdit'; - } - $('.main .wrapper').append(edit_div); - - populateEditEdgeForm(edge); - - //drop it in the right spot, activate it - $('#edit_synapse').css('position', 'absolute'); - if (e) { - $('#edit_synapse').css('left', e.clientX); - $('#edit_synapse').css('top', e.clientY); - } else { - $('#edit_synapse').css('left', myX); - $('#edit_synapse').css('top', myY); - } - //$('#edit_synapse_name').click(); //required in case name is empty - //$('#edit_synapse_name input').focus(); - $('#edit_synapse').show(); - - MetamapsModel.edgecardInUse = edge.data.$id; -} - -function populateEditEdgeForm(edge) { - add_name_form(edge); - add_user_info(edge); - add_perms_form(edge); - if (authorizeToEdit(edge)) { - add_direction_form(edge); - } -} - -function add_name_form(edge) { - var data_nil = 'Click to add description.'; - //name editing form - $('#edit_synapse').append('
'); - $('#edit_synapse_name').attr('class', 'best_in_place best_in_place_desc'); - $('#edit_synapse_name').attr('data-object', 'synapse'); - $('#edit_synapse_name').attr('data-attribute', 'desc'); - $('#edit_synapse_name').attr('data-type', 'textarea'); - $('#edit_synapse_name').attr('data-nil', data_nil); - $('#edit_synapse_name').attr('data-url', '/synapses/' + edge.getData("id")); - $('#edit_synapse_name').html(edge.getData("desc")); - - //if edge data is blank or just whitespace, populate it with data_nil - if ($('#edit_synapse_name').html().trim() == '') { - $('#edit_synapse_name').html(data_nil); - } - - $('#edit_synapse_name').bind("ajax:success", function () { - var desc = $(this).html(); - if (desc == data_nil) { - edge.setData("desc", ''); - } else { - edge.setData("desc", desc); - } - selectEdge(edge); - Mconsole.plot(); - }); -} - -function add_user_info(edge) { - $('#edit_synapse').append('
Created by ' + edge.getData("username") + '
'); -} - -function add_perms_form(edge) { - //permissions - if owner, also allow permission editing - $('#edit_synapse').append('
'); - - // ability to change permission - var selectingPermission = false; - if (userid == edge.getData('userid')) { - $('#edit_synapse.yourEdge .mapPerm').click(function () { - 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('
'); - } else if ($(this).hasClass('pu')) { - $(this).append('
'); - } else if ($(this).hasClass('pr')) { - $(this).append('
'); - } - $('#edit_synapse .permissionSelect li').click(function (event) { - selectingPermission = false; - var permission = $(this).attr('class'); - updateSynapsePermission(edge, permission); - event.stopPropagation(); - }); - } else { - selectingPermission = false; - $(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow - $('#edit_synapse .permissionSelect').remove(); - } - }); - } -} //add_perms_form - -function add_direction_form(edge) { - //directionality checkboxes - $('#edit_synapse').append(''); - $('#edit_synapse').append(''); - $('#edit_synapse').append(''); - $('#edit_synapse').append(''); - - //determine which node is to the left and the right - //if directly in a line, top is left - if (edge.nodeFrom.pos.x < edge.nodeTo.pos.x || - edge.nodeFrom.pos.x == edge.nodeTo.pos.x && - edge.nodeFrom.pos.y < edge.nodeTo.pos.y) { - var left = edge.nodeTo; - var right = edge.nodeFrom; - } else { - var left = edge.nodeFrom; - var right = edge.nodeTo; - } - - /* - * One node is actually on the left onscreen. Call it left, & the other right. - * If category is from-to, and that node is first, check the 'right' checkbox. - * Else check the 'left' checkbox since the arrow is incoming. - */ - - var directionCat = edge.getData('category'); //both, none, from-to - if (directionCat == 'from-to') { - var from_to = edge.getData('direction'); - if (from_to[0] == left.id) { - //check left checkbox - $('#edit_synapse_left').prop('checked', true); - } else { - //check right checkbox - $('#edit_synapse_right').prop('checked', true); - } - } else if (directionCat == 'both') { - //check both checkboxes - $('#edit_synapse_left').prop('checked', true); - $('#edit_synapse_right').prop('checked', true); - } - $('#edit_synapse_left, #edit_synapse_right').click(function () { - var leftChecked = $('#edit_synapse_left').is(':checked'); - var rightChecked = $('#edit_synapse_right').is(':checked'); - - var dir = edge.getData('direction'); - var dirCat = 'none'; - if (leftChecked && rightChecked) { - dirCat = 'both'; - } else if (!leftChecked && rightChecked) { - dirCat = 'from-to'; - dir = [right.id, left.id]; - } else if (leftChecked && !rightChecked) { - dirCat = 'from-to'; - dir = [left.id, right.id]; - } - $.ajax({ - 'type': 'PUT', - 'url': '/synapses/' + edge.getData('id'), - 'data': { - synapse: { - category: dirCat - }, - node1_id: { - node1: dir[0] - }, - node2_id: { - node2: dir[1] - } - }, - 'success': function (data) { - updateEdgeDisplay(edge, dir, dirCat); - } - }); - }); -} //add_direction_form - -function updateEdgeDisplay(edge, dir, dirCat) { - edge.setData('category', dirCat); - edge.setData('direction', dir); - - //render mid arrow - //renderEdgeArrows(Mconsole.fx.edgeHelper, edge); - Mconsole.plot(); -} - -function deselectAllEdges() { - var l = MetamapsModel.selectedEdges.length; - for (var i = l - 1; i >= 0; i -= 1) { - var edge = MetamapsModel.selectedEdges[i]; - deselectEdge(edge); - } -} - -function deselectAllNodes() { - var l = MetamapsModel.selectedNodes.length; - for (var i = l - 1; i >= 0; i -= 1) { - var node = MetamapsModel.selectedNodes[i]; - deselectNode(node); - } -} - -// this is for hiding one topic from your canvas -function removeEdge(edge) { - var id = edge.getData("id"); - $.ajax({ - type: "DELETE", - url: "/synapses/" + id, - success: function () { - hideEdge(edge); - }, - }); -} - -function hideEdge(edge) { - var from = edge.nodeFrom.id; - var to = edge.nodeTo.id; - edge.setData('alpha', 0, 'end'); - Mconsole.fx.animate({ - modes: ['edge-property:alpha'], - duration: 1000 - }); - Mconsole.graph.removeAdjacence(from, to); - Mconsole.plot(); -} - -function hideSelectedEdges() { - var l = MetamapsModel.selectedEdges.length; - for (var i = l - 1; i >= 0; i -= 1) { - var edge = MetamapsModel.selectedEdges[i]; - hideEdge(edge); - } - MetamapsModel.selectedEdges = new Array(); -} - -function removeSelectedEdges() { - var l = MetamapsModel.selectedEdges.length; - for (var i = l - 1; i >= 0; i -= 1) { - if (mapid != null) { - var edge = MetamapsModel.selectedEdges[i]; - var id = edge.getData("id"); - //delete mapping of id mapid - $.ajax({ - type: "POST", - url: "/synapses/" + mapid + "/" + id + "/removefrommap", - }); - } - hideEdge(edge); - } - MetamapsModel.selectedEdges = new Array(); -} - -function deleteSelectedEdges() { - var l = MetamapsModel.selectedEdges.length; - for (var i = l - 1; i >= 0; i -= 1) { - var edge = MetamapsModel.selectedEdges[i]; - var id = edge.getData("id"); - $.ajax({ - type: "DELETE", - url: "/synapses/" + id, - }); - hideEdge(edge); - } - MetamapsModel.selectedEdges = new Array(); -} - -function selectNode(node) { - if (MetamapsModel.selectedNodes.indexOf(node) != -1) return; - node.selected = true; - node.setData('dim', 30, 'current'); - node.setData('whiteCircle', true); - node.eachAdjacency(function (adj) { - selectEdge(adj); - }); - MetamapsModel.selectedNodes.push(node); -} - -function deselectNode(node) { - delete node.selected; - node.setData('whiteCircle', false); - node.eachAdjacency(function (adj) { - deselectEdge(adj); - }); - node.setData('dim', 25, 'current'); - - //remove the node - MetamapsModel.selectedNodes.splice( - MetamapsModel.selectedNodes.indexOf(node), 1); -} - -function selectEdge(edge) { - if (MetamapsModel.selectedEdges.indexOf(edge) != -1) return; - edge.setData('showDesc', true, 'current'); - if (!MetamapsModel.embed) { - edge.setDataset('end', { - lineWidth: 4, - color: '#FFFFFF', - alpha: 1 - }); - } else if (MetamapsModel.embed) { - edge.setDataset('end', { - lineWidth: 4, - color: '#999', - alpha: 1 - }); - } - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:color:alpha'], - duration: 100 - }); - MetamapsModel.selectedEdges.push(edge); -} - -function deselectEdge(edge) { - edge.setData('showDesc', false, 'current'); - edge.setDataset('end', { - lineWidth: 2, - color: '#222222', - alpha: 0.4 - }); - - if (MetamapsModel.edgeHoveringOver == edge) { - edge.setData('showDesc', true, 'current'); - edge.setDataset('end', { - lineWidth: 4, - color: '#222222', - alpha: 1 - }); - } - - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:color:alpha'], - duration: 100 - }); - - //remove the edge - MetamapsModel.selectedEdges.splice( - MetamapsModel.selectedEdges.indexOf(edge), 1); -} - -// this is for hiding one topic from your canvas -function hideNode(nodeid) { - var node = Mconsole.graph.getNode(nodeid); - if (nodeid == Mconsole.root && gType == "centered") { - alert("You can't hide this topic, it is the root of your graph."); - return; - } - - deselectNode(node); - - node.setData('alpha', 0, 'end'); - node.eachAdjacency(function (adj) { - adj.setData('alpha', 0, 'end'); - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 1000 - }); - Mconsole.graph.removeNode(nodeid); -} - -function hideSelectedNodes() { - var l = MetamapsModel.selectedNodes.length; - for (var i = l - 1; i >= 0; i -= 1) { - var node = MetamapsModel.selectedNodes[i]; - hideNode(node.id); - } -} - -function removeNode(nodeid) { - var node = Mconsole.graph.getNode(nodeid); - deselectNode(node); - if (mapperm) { - $.ajax({ - type: "POST", - url: "/topics/" + mapid + "/" + nodeid + "/removefrommap", - }); - } -} - -function removeSelectedNodes() { - if (mapperm) { - var l = MetamapsModel.selectedNodes.length; - for (var i = l - 1; i >= 0; i -= 1) { - var node = MetamapsModel.selectedNodes[i]; - removeNode(node.id); - } - } -} - -function deleteNode(nodeid) { - if (nodeid == Mconsole.root && gType == "centered") { - alert("You can't delete this topic, it is the root of your graph."); - return; - } - $.ajax({ - type: "DELETE", - url: "/topics/" + nodeid, - }); -} - -function deleteSelectedNodes() { - var l = MetamapsModel.selectedNodes.length; - for (var i = l - 1; i >= 0; i -= 1) { - var node = MetamapsModel.selectedNodes[i]; - deleteNode(node.id); - } -} \ No newline at end of file diff --git a/app/assets/javascripts/Jit/topicCard.js b/app/assets/javascripts/Jit/topicCard.js deleted file mode 100644 index 577c73fa..00000000 --- a/app/assets/javascripts/Jit/topicCard.js +++ /dev/null @@ -1,213 +0,0 @@ -/* - * @file - * There is a lot of code that goes into creating the "label" of a node - * This includes editable cards with all node details, and some controls - * onCreateLabelHandler is the main function of this file, and the file - * also contains a bunch of helper functions - * - * html and littleHTML are potentially confusing variables - * html is the contents of the card shown when you click on a node's label. - * littleHTML creates little controls for removing/hiding nodes from the canvas - * - * This function features PHP-style variable substitution because the strings - * are so damn long. Values are identified by $_id_$, and then a regular - * expression is substituted in later (for html, in a separate function). - */ - -function buildCardWithHogan(node) { - var nodeValues = {}; - var authorized = authorizeToEdit(node); - - //link is rendered differently if user is logged out or in - var go_link, a_tag, close_a_tag; - if (!authorized) { - go_link = ''; - if (node.getData("link") != "") { - a_tag = ''; - close_a_tag = ''; - } else { - a_tag = ''; - close_a_tag = ''; - } - } else { - go_link = ''; - a_tag = ''; - close_a_tag = ''; - } - - var desc_nil = "Click to add description..."; - var link_nil = "Click to add link..."; - - nodeValues.permission = node.getData("permission"); - nodeValues.mk_permission = mk_permission(node); - nodeValues.map_count = node.getData("inmaps").length; - nodeValues.synapse_count = node.getData("synapseCount"); - nodeValues.id = node.id; - nodeValues.metacode = node.getData("metacode"); - nodeValues.metacode_class = 'mbg' + node.getData("metacode").replace(/\s/g, ''); - nodeValues.imgsrc = imgArray[node.getData("metacode")].src; - nodeValues.name = node.name; - nodeValues.userid = node.getData("userid"); - nodeValues.username = node.getData("username"); - nodeValues.date = node.getData("date"); - - // the code for this is stored in /views/main/_metacodeOptions.html.erb - nodeValues.metacode_select = $('#metacodeOptions').html(); - nodeValues.go_link = go_link; - nodeValues.a_tag = a_tag; - nodeValues.close_a_tag = close_a_tag; - nodeValues.link_nil = link_nil; - nodeValues.link = (node.getData("link") == "" && authorized) ? link_nil : node.getData("link"); - nodeValues.desc_nil = desc_nil; - nodeValues.desc = (node.getData("desc") == "" && authorized) ? desc_nil : node.getData("desc"); - - // the code for the template is stored in /views/layouts/_templates.html.erb - var hoganTemplate = Hogan.compile($('#topicCardTemplate').html()); - return hoganTemplate.render(nodeValues); -} - -function hideCurrentCard() { - if (MetamapsModel.showcardInUse) { - var node = Mconsole.graph.getNode(MetamapsModel.showcardInUse); - hideCard(node); - } -} - -function hideCard(node) { - var card = '.showcard'; - - $(card).fadeOut('fast', function () { - //node.setData('dim', 25, 'current'); - Mconsole.plot(); - }); - - MetamapsModel.showcardInUse = null; -} - -function populateShowCard(node) { - var showCard = document.getElementById('showcard'); - - $(showCard).find('.permission').remove(); - - var html = buildCardWithHogan(node); - - if (authorizeToEdit(node)) { - var perm = document.createElement('div'); - - var string = 'permission canEdit'; - if (userid == node.data.$userid) 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); - } - - 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'); - } - }); - - $('.showcard .metacodeTitle').click(function () { - if (!selectingMetacode) { - selectingMetacode = true; - $(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow - $('.metacodeSelect').show(); - // add the scroll bar to the list of metacode select options if it isn't already there - if (!$('.metacodeSelect ul').hasClass('mCustomScrollbar')) { - $('.metacodeSelect ul').mCustomScrollbar({ - mouseWheelPixels: 200, - advanced: { - updateOnContentResize: true - } - }); - - $('.metacodeSelect li').click(function () { - selectingMetacode = false; - var metacodeName = $(this).find('.mSelectName').text(); - updateMetacode(node, metacodeName); - }); - } - } else { - selectingMetacode = false; - $(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow - $('.metacodeSelect').hide(); - } - }); - - - // ability to change permission - var selectingPermission = false; - if (userid == node.data.$userid) { - $('.showcard .yourTopic .mapPerm').click(function () { - 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('
'); - } else if ($(this).hasClass('pu')) { - $(this).append('
'); - } else if ($(this).hasClass('pr')) { - $(this).append('
'); - } - $('.permissionSelect li').click(function (event) { - selectingPermission = false; - var permission = $(this).attr('class'); - updateTopicPermission(node, permission); - event.stopPropagation(); - }); - } else { - selectingPermission = false; - $(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow - $('.permissionSelect').remove(); - } - }); - } - - // when you're typing a description, resize the scroll box to have space - $('.best_in_place_desc textarea').bind('keyup', function () { - var s = $('.showcard').find('.scroll'); - s.height(s.height()).mCustomScrollbar('update'); - console.log('working'); - }); - - //bind best_in_place ajax callbacks - $(showCard).find('.best_in_place_name').bind("ajax:success", function () { - - var s = $('.showcard').find('.scroll'); - s.height(s.height()).mCustomScrollbar('update'); - - var name = $(this).html(); - node.name = decodeEntities(name); - Mconsole.plot(); - }); - - $(showCard).find('.best_in_place_desc').bind("ajax:success", function () { - this.innerHTML = this.innerHTML.replace(/\r/g, '') - - var s = $('.showcard').find('.scroll'); - s.height(s.height()).mCustomScrollbar('update'); - - var desc = $(this).html(); - node.setData("desc", desc); - }); - - $(showCard).find('.best_in_place_link').bind("ajax:success", function () { - var link = $(this).html(); - $(showCard).find('.go-link').attr('href', link); - node.setData("link", link); - }); - -} \ No newline at end of file diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 93cc4596..20672dd2 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,386 +10,16 @@ // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD // GO AFTER THE REQUIRES BELOW. // -// require autocomplete-rails-uncompressed -// //= require jquery //= require jquery-ui -//= require jquery.purr -//= require jquery.lettering -//= require jquery.textillate -//= require jquery.roundabout.min -//= require bip //= require jquery_ujs -//= require_tree . - -// other options are 'graph' -var viewMode = "list"; - -var labelType, useGradients, nativeTextSupport, animate, json, Mconsole = null, - gType, tempNode = null, - tempInit = false, - tempNode2 = null, - metacodeIMGinit = false, - goRealtime = false, - mapid = null, - mapperm = false, - touchPos, touchDragNode, mouseIsDown = false; - - -// this is to save the layout of a map -function saveLayoutAll() { - $('.sidebarSave .tip').html('Saving...'); - var coor = ""; - if (gType == "arranged" || gType == "chaotic") { - Mconsole.graph.eachNode(function (n) { - coor = coor + n.getData("mappingid") + '/' + n.pos.x + '/' + n.pos.y + ','; - }); - coor = coor.slice(0, -1); - $('#map_coordinates').val(coor); - $('#saveMapLayout').submit(); - } -} - -// this is to update the location coordinate of a single node on a map -function saveLayout(id) { - var n = Mconsole.graph.getNode(id); - $('#map_coordinates').val(n.getData("mappingid") + '/' + n.pos.x + '/' + n.pos.y); - $('#saveMapLayout').submit(); - dragged = 0; - //$('.wandSaveLayout').html('Saved!'); - //setTimeout(function(){$('.wandSaveLayout').html('Save Layout')},1500); -} - -// this is to save your console to a map -function saveToMap() { - var nodes_data = "", - synapses_data = ""; - var synapses_array = new Array(); - Mconsole.graph.eachNode(function (n) { - //don't add to the map if it was filtered out - if (categoryVisible[n.getData('metacode')] == false) { - return; - } - - 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 += n.id + '/' + x + '/' + y + ','; - n.eachAdjacency(function (adj) { - synapses_array.push(adj.getData("id")); - }); - }); - - //get unique values only - synapses_array = $.grep(synapses_array, function (value, key) { - return $.inArray(value, synapses_array) === key; - }); - - synapses_data = synapses_array.join(); - nodes_data = nodes_data.slice(0, -1); - - $('#map_topicsToMap').val(nodes_data); - $('#map_synapsesToMap').val(synapses_data); - openLightbox('forkmap'); -} - -function fetchRelatives(node) { - var myA = $.ajax({ - type: "Get", - url: "/topics/" + node.id + "?format=json", - success: function (data) { - if (gType == "centered") { - Mconsole.busy = true; - Mconsole.op.sum(data, { - type: 'fade', - duration: 500, - hideLabels: false - }); - Mconsole.graph.eachNode(function (n) { - n.eachAdjacency(function (a) { - if (!a.getData('showDesc')) { - a.setData('alpha', 0.4, 'start'); - a.setData('alpha', 0.4, 'current'); - a.setData('alpha', 0.4, 'end'); - } - }); - }); - Mconsole.busy = false; - } else { - Mconsole.op.sum(data, { - type: 'nothing', - }); - Mconsole.plot(); - } - }, - error: function () { - console.log('failed to recenter'); - } - }); -} - -// @param node = JIT node object -// @param metacode = STRING like "Idea", "Action", etc. -function updateMetacode(node, metacode) { - var mdata = { - "topic": { - "metacode": metacode - } - }; - $.ajax({ - type: "PUT", - dataType: 'json', - url: "/topics/" + node.id, - data: mdata, - success: function (data) { - $('.CardOnGraph').find('.metacodeTitle').text(metacode) - .attr('class', 'metacodeTitle mbg' + metacode.replace(/\s/g, '')); - $('.CardOnGraph').find('.metacodeImage').css('background-image', 'url(' + imgArray[metacode].src + ')'); - node.setData("metacode", metacode); - Mconsole.plot(); - $('.metacodeTitle').removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow - $('.metacodeSelect').hide(); - setTimeout(function () { - $('.metacodeTitle').hide(); - $('.showcard .icon').css('z-index', '1'); - }, 500); - }, - error: function () { - console.log('failed to update metacode'); - } - }); -} - -function updateTopicPermission(node, permission) { - var mdata = { - "topic": { - "permission": permission - } - }; - $.ajax({ - type: "PUT", - dataType: 'json', - url: "/topics/" + node.id, - data: mdata, - success: function (data) { - $('.showcard .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2)); - $('.permissionSelect').remove(); - node.setData("permission", permission); - }, - error: function () { - console.log('failed to update permission'); - } - }); -} - -function updateSynapsePermission(edge, permission) { - var mdata = { - "synapse": { - "permission": permission - } - }; - $.ajax({ - type: "PUT", - dataType: 'json', - url: "/synapses/" + edge.data.$id, - data: mdata, - success: function (data) { - $('#edit_synapse .mapPerm').removeClass('co pu pr minimize').addClass(permission.substring(0, 2)); - $('#edit_synapse .permissionSelect').remove(); - edge.setData("permission", permission); - }, - error: function () { - console.log('failed to update permission'); - } - }); -} - -function updateMapPermission(mapid, permission) { - var mdata = { - "map": { - "permission": permission - } - }; - $.ajax({ - type: "PUT", - dataType: 'json', - url: "/maps/" + mapid, - data: mdata, - success: function (data) { - $('.mapPermission').removeClass('commons public private minimize').addClass(permission); - $('.mapPermission .permissionSelect').remove(); - }, - error: function () { - console.log('failed to update permission'); - } - }); -} - -function updateMetacodeSet(set, index, custom) { - - if (custom && MetamapsModel.newSelectedMetacodes.length == 0) { - alert('Please select at least one metacode to use!'); - return false; - } - - var codesToSwitchTo; - MetamapsModel.selectedMetacodeSetIndex = index; - MetamapsModel.selectedMetacodeSet = "metacodeset-" + set; - - if (!custom) { - codesToSwitchTo = $('#metacodeSwitchTabs' + set).attr('data-metacodes').split(','); - $('.customMetacodeList li').addClass('toggledOff'); - MetamapsModel.selectedMetacodes = []; - MetamapsModel.selectedMetacodeNames = []; - MetamapsModel.newSelectedMetacodes = []; - MetamapsModel.newSelectedMetacodeNames = []; - } - if (custom) { - // uses .slice to avoid setting the two arrays to the same actual array - MetamapsModel.selectedMetacodes = MetamapsModel.newSelectedMetacodes.slice(0); - MetamapsModel.selectedMetacodeNames = MetamapsModel.newSelectedMetacodeNames.slice(0); - codesToSwitchTo = MetamapsModel.selectedMetacodeNames.slice(0); - } - - // sort by name - codesToSwitchTo.sort(); - codesToSwitchTo.reverse(); - - $('#metacodeImg, #metacodeImgTitle').empty(); - $('#metacodeImg').removeData('cloudcarousel'); - var newMetacodes = ""; - for (var i = 0; i < codesToSwitchTo.length; i++) { - newMetacodes += '' + codesToSwitchTo[i] + ''; - }; - $('#metacodeImg').empty().append(newMetacodes).CloudCarousel({ - titleBox: $('#metacodeImgTitle'), - yRadius: 40, - xPos: 150, - yPos: 40, - speed: 0.3, - mouseWheel: true, - bringToFront: true - }); - - $('#lightbox_overlay').hide(); - $('#topic_name').focus(); - - var mdata = { - "metacodes": { - "value": custom ? MetamapsModel.selectedMetacodes.toString() : MetamapsModel.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'); - } - }); -} - -function cancelMetacodeSetSwitch() { - if (MetamapsModel.selectedMetacodeSet != "metacodeset-custom") { - $('.customMetacodeList li').addClass('toggledOff'); - MetamapsModel.selectedMetacodes = []; - MetamapsModel.selectedMetacodeNames = []; - MetamapsModel.newSelectedMetacodes = []; - MetamapsModel.newSelectedMetacodeNames = []; - } else { // custom set is selected - // reset it to the current actual selection - $('.customMetacodeList li').addClass('toggledOff'); - for (var i = 0; i < MetamapsModel.selectedMetacodes.length; i++) { - $('#' + MetamapsModel.selectedMetacodes[i]).removeClass('toggledOff'); - }; - // uses .slice to avoid setting the two arrays to the same actual array - MetamapsModel.newSelectedMetacodeNames = MetamapsModel.selectedMetacodeNames.slice(0); - MetamapsModel.newSelectedMetacodes = MetamapsModel.selectedMetacodes.slice(0); - } - $('#metacodeSwitchTabs').tabs("select", MetamapsModel.selectedMetacodeSetIndex); - $('#topic_name').focus(); -} - -function MconsoleReset() { - - var tX = Mconsole.canvas.translateOffsetX; - var tY = Mconsole.canvas.translateOffsetY; - Mconsole.canvas.translate(-tX, -tY); - - var mX = Mconsole.canvas.scaleOffsetX; - var mY = Mconsole.canvas.scaleOffsetY; - Mconsole.canvas.scale((1 / mX), (1 / mY)); -} - -function openNodeShowcard(node) { - //populate the card that's about to show with the right topics data - populateShowCard(node); - - $('.showcard').fadeIn('fast'); - var s = $('.showcard').find('.scroll'); - s.height(s.height()).mCustomScrollbar({ - mouseWheelPixels: 200, - advanced: { - updateOnContentResize: true - } - }); - MetamapsModel.showcardInUse = node.id; -} - -function openLightbox(which) { - $('.lightboxContent').hide(); - $('#' + which).show(); - - $('#lightbox_overlay').show(); - $('#lightbox_main').css('margin-top', '-' + ($('#lightbox_main').height() / 2) + 'px'); - - if (!MetamapsModel.metacodeScrollerInit) { - $('.customMetacodeList, .metacodeSetList').mCustomScrollbar({ - mouseWheelPixels: 200, - advanced: { - updateOnContentResize: true - } - }); - MetamapsModel.metacodeScrollerInit = true; - } - if (which == "switchMetacodes") { - MetamapsModel.isSwitchingSet = true; - } -} - -function closeLightbox() { - $('#lightbox_overlay').hide(); - cancelMapCreate('fork_map'); - cancelMapCreate('new_map'); - if (MetamapsModel.isSwitchingSet) { - cancelMetacodeSetSwitch(); - MetamapsModel.isSwitchingSet = false; - } -} - -function cancelMapCreate(id) { - - var form = $('#' + id); - - form.find('#map_name').val(''); - form.find('#map_desc').val(''); - form.find('#map_permission').val('commons'); - - if (id == "fork_map") { - form.find('#map_topicsToMap').val('0'); - form.find('#map_synapsesToMap').val('0'); - } - form.find('.mapPermIcon').removeClass('selected'); - form.find('.mapCommonsIcon').addClass('selected'); - - return false; -} +//= require ./orderedLibraries/underscore +//= require ./orderedLibraries/backbone +//= require_directory ./lib +//= require ./src/Metamaps.GlobalUI +//= require ./src/Metamaps.Router +//= require ./src/Metamaps.Backbone +//= require ./src/Metamaps.Views +//= require ./src/JIT +//= require ./src/Metamaps +//= require ./src/Metamaps.JIT \ No newline at end of file diff --git a/app/assets/javascripts/jquery.textillate.js b/app/assets/javascripts/jquery.textillate.js deleted file mode 100644 index dc7f441d..00000000 --- a/app/assets/javascripts/jquery.textillate.js +++ /dev/null @@ -1,262 +0,0 @@ -/* - * textillate.js - * http://jschr.github.com/textillate - * MIT licensed - * - * Copyright (C) 2012-2013 Jordan Schroter - */ - -(function ($) { - "use strict"; - - function isInEffect (effect) { - return /In/.test(effect) || $.inArray(effect, $.fn.textillate.defaults.inEffects) >= 0; - }; - - function isOutEffect (effect) { - return /Out/.test(effect) || $.inArray(effect, $.fn.textillate.defaults.outEffects) >= 0; - }; - - // custom get data api method - function getData (node) { - var attrs = node.attributes || [] - , data = {}; - - if (!attrs.length) return data; - - $.each(attrs, function (i, attr) { - if (/^data-in-*/.test(attr.nodeName)) { - data.in = data.in || {}; - data.in[attr.nodeName.replace(/data-in-/, '')] = attr.nodeValue; - } else if (/^data-out-*/.test(attr.nodeName)) { - data.out = data.out || {}; - data.out[attr.nodeName.replace(/data-out-/, '')] = attr.nodeValue; - } else if (/^data-*/.test(attr.nodeName)) { - data[attr.nodeName] = attr.nodeValue; - } - }) - - return data; - } - - function shuffle (o) { - for (var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x); - return o; - } - - function animate ($c, effect, cb) { - $c.addClass('animated ' + effect) - .css('visibility', 'visible') - .show(); - - $c.one('animationend webkitAnimationEnd oAnimationEnd', function () { - $c.removeClass('animated ' + effect); - cb && cb(); - }); - } - - function animateChars ($chars, options, cb) { - var that = this - , count = $chars.length; - - if (!count) { - cb && cb(); - return; - } - - if (options.shuffle) $chars = shuffle($chars); - if (options.reverse) $chars = $chars.toArray().reverse(); - - $.each($chars, function (i, c) { - var $char = $(c); - - function complete () { - if (isInEffect(options.effect)) { - $char.css('visibility', 'visible'); - } else if (isOutEffect(options.effect)) { - $char.css('visibility', 'hidden'); - } - count -= 1; - if (!count && cb) cb(); - } - - var delay = options.sync ? options.delay : options.delay * i * options.delayScale; - - $char.text() ? - setTimeout(function () { animate($char, options.effect, complete) }, delay) : - complete(); - }); - }; - - var Textillate = function (element, options) { - var base = this - , $element = $(element); - - base.init = function () { - base.$texts = $element.find(options.selector); - - if (!base.$texts.length) { - base.$texts = $('
  • ' + $element.html() + '
'); - $element.html(base.$texts); - } - - base.$texts.hide(); - - base.$current = $('') - .text(base.$texts.find(':first-child').html()) - .prependTo($element); - - if (isInEffect(options.effect)) { - base.$current.css('visibility', 'hidden'); - } else if (isOutEffect(options.effect)) { - base.$current.css('visibility', 'visible'); - } - - base.setOptions(options); - - setTimeout(function () { - base.options.autoStart && base.start(); - }, base.options.initialDelay) - }; - - base.setOptions = function (options) { - base.options = options; - }; - - base.triggerEvent = function (name) { - var e = $.Event(name + '.tlt', { data: base }); - $element.trigger(e); - return e; - }; - - base.in = function (index, cb) { - index = index || 0; - - var $elem = base.$texts.find(':nth-child(' + (index + 1) + ')') - , options = $.extend({}, base.options, getData($elem)) - , $chars; - - base.triggerEvent('inAnimationBegin'); - - base.$current - .text($elem.html()) - .lettering('words'); - - base.$current.find('[class^="word"]') - .css({ - 'display': 'inline-block', - // fix for poor ios performance - '-webkit-transform': 'translate3d(0,0,0)', - '-moz-transform': 'translate3d(0,0,0)', - '-o-transform': 'translate3d(0,0,0)', - 'transform': 'translate3d(0,0,0)' - }) - .each(function () { $(this).lettering() }); - - $chars = base.$current - .find('[class^="char"]') - .css('display', 'inline-block'); - - if (isInEffect(options.in.effect)) { - $chars.css('visibility', 'hidden'); - } else if (isOutEffect(options.in.effect)) { - $chars.css('visibility', 'visible'); - } - - base.currentIndex = index; - - animateChars($chars, options.in, function () { - base.triggerEvent('inAnimationEnd'); - if (options.in.callback) options.in.callback(); - if (cb) cb(base); - }); - }; - - base.out = function (cb) { - var $elem = base.$texts.find(':nth-child(' + (base.currentIndex + 1) + ')') - , $chars = base.$current.find('[class^="char"]') - , options = $.extend({}, base.options, getData($elem)); - - base.triggerEvent('outAnimationBegin'); - - animateChars($chars, options.out, function () { - base.triggerEvent('outAnimationEnd'); - if (options.out.callback) options.out.callback(); - if (cb) cb(base); - }); - }; - - base.start = function (index) { - base.triggerEvent('start'); - - (function run (index) { - base.in(index, function () { - var length = base.$texts.children().length; - - index += 1; - - if (!base.options.loop && index >= length) { - if (base.options.callback) base.options.callback(); - base.triggerEvent('end'); - } else { - index = index % length; - - setTimeout(function () { - base.out(function () { - run(index) - }); - }, base.options.minDisplayTime); - } - }); - }(index || 0)); - }; - - base.init(); - } - - $.fn.textillate = function (settings, args) { - return this.each(function () { - var $this = $(this) - , data = $this.data('textillate') - , options = $.extend(true, {}, $.fn.textillate.defaults, getData(this), typeof settings == 'object' && settings); - - if (!data) { - $this.data('textillate', (data = new Textillate(this, options))); - } else if (typeof settings == 'string') { - data[settings].apply(data, [].concat(args)); - } else { - data.setOptions.call(data, options); - } - }) - }; - - $.fn.textillate.defaults = { - selector: '.texts', - loop: false, - minDisplayTime: 2000, - initialDelay: 0, - in: { - effect: 'fadeInLeftBig', - delayScale: 1.5, - delay: 50, - sync: false, - reverse: false, - shuffle: false, - callback: function () {} - }, - out: { - effect: 'hinge', - delayScale: 1.5, - delay: 50, - sync: false, - reverse: false, - shuffle: false, - callback: function () {} - }, - autoStart: true, - inEffects: [], - outEffects: [ 'hinge' ], - callback: function () {} - }; - -}(jQuery)); diff --git a/app/assets/javascripts/jquery/AllMappingPages.js b/app/assets/javascripts/jquery/AllMappingPages.js deleted file mode 100644 index 3848b068..00000000 --- a/app/assets/javascripts/jquery/AllMappingPages.js +++ /dev/null @@ -1,98 +0,0 @@ -/* AllMappingPages means: -1. being logged in or logged out and, -2. either - a. being on a Map page, or - b. being on a Topic page - - -*/ - -$(document).ready(function () { - - // initialize topic card draggability and resizability - $('.showcard').draggable({ - handle: ".metacodeImage" - }); - $('#showcard').resizable({ - maxHeight: 500, - maxWidth: 500, - minHeight: 320, - minWidth: 226, - resize: function (event, ui) { - var p = $('#showcard').find('.scroll'); - p.height(p.height()).mCustomScrollbar('update'); - } - }).css({ - display: 'none', - top: '300px', - left: '100px' - }); - - function bindFilterHover() { - - var filterIsOpen = false; - - // controls the sliding hover of the bottom left menu - var sliding1 = false; - var lT; - - var closeFilter = function () { - lT = setTimeout(function () { - if (!sliding1) { - sliding1 = true; - $('.sidebarFilterIcon').css('background-color', '#0F1519'); - $('.sidebarFilterBox').fadeOut(200, function () { - sliding1 = false; - filterIsOpen = false; - }); - } - }, 300); - } - - var openFilter = function () { - clearTimeout(lT); - if (!sliding1) { - sliding1 = true; - - // hide the other two - $('.sidebarAccountBox').hide(); - $('.sidebarCollaborateBox').hide(); - $('.sidebarAccountIcon').css('background-color', '#0F1519'); - $('.sidebarCollaborateIcon').css('background-color', '#0F1519'); - - $('.sidebarFilterIcon').css('background-color', '#000'); - $('.sidebarFilterBox').fadeIn(200, function () { - sliding1 = false; - filterIsOpen = true; - }); - } - } - // bind the hover events - $(".sidebarFilter").hover(openFilter, closeFilter); - - } // end bindFilterHover - - bindFilterHover(); - - // initialize scroll bar for filter by metacode, then hide it and position it correctly again - $("#filter_by_metacode").mCustomScrollbar({ - mouseWheelPixels: 200, - advanced: { - updateOnContentResize: true - } - }); - $('.sidebarFilterBox').hide().css({ - position: 'absolute', - top: '35px', - right: '-36px' - }); - - // 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; - }); - - // tab the cheatsheet - $('#cheatSheet').tabs().addClass("ui-tabs-vertical ui-helper-clearfix"); - $("#cheatSheet .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left"); -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/AuthAllMappingPages.js b/app/assets/javascripts/jquery/AuthAllMappingPages.js deleted file mode 100644 index a3e23df2..00000000 --- a/app/assets/javascripts/jquery/AuthAllMappingPages.js +++ /dev/null @@ -1,19 +0,0 @@ -/* AuthAllMappingPages means: -1. being logged in and, -2. either - a. being on a Map page, or - b. being on a Topic page - - -*/ - -$(document).ready(function () { - - $('.sidebarFork').click(function () { - saveToMap(); - }); - - // initialize best_in_place editing - $('.authenticated div.permission.canEdit .best_in_place').best_in_place(); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/AuthCanEditMapPage.js b/app/assets/javascripts/jquery/AuthCanEditMapPage.js deleted file mode 100644 index 6c79ffb3..00000000 --- a/app/assets/javascripts/jquery/AuthCanEditMapPage.js +++ /dev/null @@ -1,97 +0,0 @@ -/* authCanEditMapPage means: -1. being logged in and, -2. being on a Map page and having edit permissions (your map, or commons map) - - -*/ - -$(document).ready(function () { - - function bindRealtimeHover() { - - var realtimeIsOpen = false - - // controls the sliding hover of the bottom left menu - var sliding1 = false; - var lT; - - var closeRealtime = function () { - lT = setTimeout(function () { - if (!sliding1) { - sliding1 = true; - $('.sidebarCollaborateIcon').css('background-color', '#0F1519'); - $('.sidebarCollaborateBox').fadeOut(200, function () { - sliding1 = false; - realtimeIsOpen = false; - }); - } - }, 300); - } - - var openRealtime = function () { - clearTimeout(lT); - if (!sliding1) { - sliding1 = true; - - // hide the other two - $('.sidebarFilterBox').hide(); - $('.sidebarAccountBox').hide(); - $('.sidebarFilterIcon').css('background-color', '#0F1519'); - $('.sidebarAccountIcon').css('background-color', '#0F1519'); - - $('.sidebarCollaborateIcon').css('background-color', '#000'); - $('.sidebarCollaborateBox').fadeIn(200, function () { - sliding1 = false; - realtimeIsOpen = true; - }); - } - } - // bind the hover events - $(".sidebarCollaborate").hover(openRealtime, closeRealtime); - } // end bindRealtimeHover - - function bindSaveHover() { - var closeSave = function () { - - } - - var openSave = function () { - // hide the other three - $('.sidebarFilterBox, .sidebarAccountBox, .sidebarCollaborateBox').hide(); - $('.sidebarFilterIcon, .sidebarAccountIcon, .sidebarCollaborateIcon').css('background-color', '#0F1519'); - } - // bind the hover events - $(".sidebarSave").hover(openSave, closeSave); - } // end bindSaveHover - - // bind hover events - bindRealtimeHover(); - bindSaveHover(); - - // because anyone who can edit the map can collaborate on it in realtime - $(".realtimeOnOff").click(function (event) { - if (!goRealtime) { - window.realtime.sendRealtimeOn(); - $(this).html('ON').removeClass('rtOff').addClass('rtOn'); - $(".rtMapperSelf").removeClass('littleRtOff').addClass('littleRtOn'); - } else { - window.realtime.sendRealtimeOff(); - $(this).html('OFF').removeClass('rtOn').addClass('rtOff'); - $(".rtMapperSelf").removeClass('littleRtOn').addClass('littleRtOff'); - } - goRealtime = !goRealtime; - $(".sidebarCollaborateIcon").toggleClass("blue"); - }); - - // because anyone who can edit the map can save a new map layout - $('.sidebarSave').click(function () { - saveLayoutAll(); - }); - - // because anyone who can edit the map can change the map title - $('.mapInfoName .best_in_place_name').bind("ajax:success", function () { - var name = $(this).html(); - $('.mapName').html(name); - }); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/AuthCanEditMappingPages.js b/app/assets/javascripts/jquery/AuthCanEditMappingPages.js deleted file mode 100644 index 4ec0f72d..00000000 --- a/app/assets/javascripts/jquery/AuthCanEditMappingPages.js +++ /dev/null @@ -1,176 +0,0 @@ -/* authCanEditMappingPages means: -1. being logged in and, -2. either - a. being on a Map page and having edit permissions (your map, or commons map) or, - b. being on a Topic page - -this code adds required jQuery for creating, or pulling in, topics and synapses -*/ - -$(document).ready(function () { - - function bindForkHover() { - var closeFork = function () { - - } - - var openFork = function () { - // hide the other three - $('.sidebarFilterBox, .sidebarAccountBox, .sidebarCollaborateBox').hide(); - $('.sidebarFilterIcon, .sidebarAccountIcon, .sidebarCollaborateIcon').css('background-color', '#0F1519'); - } - // bind the hover events - $(".sidebarFork").hover(openFork, closeFork); - } // end bindForkHover - - // bind hover events - bindForkHover(); - - ////// - ////// - //// TOPIC CREATION - - // initialize the autocomplete results for the metacode spinner - $('#topic_name').typeahead([ - { - name: 'topic_autocomplete', - limit: 8, - template: $('#topicAutocompleteTemplate').html(), - remote: { - url: '/topics/autocomplete_topic?term=%QUERY' - }, - engine: Hogan - } - ]); - - var topicTypeahead = false; - // tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete - $('#topic_name').bind('typeahead:selected', function (event, datum, dataset) { - $('#topic_grabTopic').val(datum.id); - event.preventDefault(); - event.stopPropagation(); - $('.new_topic').submit(); - topicTypeahead = true; - }); - $('#topic_name').bind('typeahead:opened', function () { - topicTypeahead = false; - }); - - // bind keyboard handlers - $('#topic_name').bind('keyup', function (e) { - switch (e.which) { - case 13: - if (!topicTypeahead) $('.new_topic').submit(); - break; - default: - break; - } - }); - - // initialize metacode spinner and then hide it - $("#metacodeImg").CloudCarousel({ - titleBox: $('#metacodeImgTitle'), - yRadius: 40, - xPos: 150, - yPos: 40, - speed: 0.3, - mouseWheel: true, - bringToFront: true - }); - $('.new_topic').hide(); - - - ////// - ////// - //// SYNAPSE CREATION - - // initialize the autocomplete results for synapse creation - $('#synapse_desc').typeahead([ - { - name: 'synapse_autocomplete', - template: "
{{label}}
", - remote: { - url: '/search/synapses?term=%QUERY' - }, - engine: Hogan - }, - { - name: 'existing_synapses', - limit: 50, - template: $('#synapseAutocompleteTemplate').html(), - remote: { - url: '/search/synapses', - replace: function () { - var q = '/search/synapses?topic1id=' + $('#synapse_topic1id').val() + '&topic2id=' + $('#synapse_topic2id').val(); - return q; - } - }, - engine: Hogan, - header: "

Existing Synapses

" - }, - ]); - - var synapseTypeahead = false; - // tell the autocomplete to submit the form with the topic you clicked on if you pick from the autocomplete - $('#synapse_desc').bind('typeahead:selected', function (event, datum, dataset) { - if (datum.id) { // if they clicked on an existing synapse get it - $('#synapse_grabSynapse').val(datum.id); - } - event.preventDefault(); - event.stopPropagation(); - $('.new_synapse').submit(); - synapseTypeahead = true; - }); - $('#synapse_desc').bind('typeahead:opened', function () { - synapseTypeahead = false; - }); - // bind keyboard handlers - $('#synapse_desc').bind('keyup', function (e) { - switch (e.which) { - case 13: - if (!synapseTypeahead) $('.new_synapse').submit(); - break; - default: - break; - } - }); - - - ////// - ////// - //// TOPIC AND SYNAPSE CREATION - - // when either form submits, don't leave the page - $('.new_topic, .new_synapse').bind('submit', function (event, data) { - event.preventDefault(); - }); - - // disable right click events on the new topic and new synapse input fields - $('#new_topic, #new_synapse').bind('contextmenu', function (e) { - return false; - }); - - ////// - ////// - //// SWITCHING METACODE SETS - - $('#metacodeSwitchTabs').tabs({ - selected: MetamapsModel.selectedMetacodeSetIndex - }).addClass("ui-tabs-vertical ui-helper-clearfix"); - $("#metacodeSwitchTabs .ui-tabs-nav li").removeClass("ui-corner-top").addClass("ui-corner-left"); - $('.customMetacodeList li').click(function () { - if ($(this).attr('class') != 'toggledOff') { - $(this).addClass('toggledOff'); - var value_to_remove = $(this).attr('id'); - var name_to_remove = $(this).attr('data-name'); - MetamapsModel.newSelectedMetacodes.splice(MetamapsModel.newSelectedMetacodes.indexOf(value_to_remove), 1); - MetamapsModel.newSelectedMetacodeNames.splice(MetamapsModel.newSelectedMetacodeNames.indexOf(name_to_remove), 1); - } else if ($(this).attr('class') == 'toggledOff') { - $(this).removeClass('toggledOff'); - MetamapsModel.newSelectedMetacodes.push($(this).attr('id')); - MetamapsModel.newSelectedMetacodeNames.push($(this).attr('data-name')); - } - }); - - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/AuthEveryPage.js b/app/assets/javascripts/jquery/AuthEveryPage.js deleted file mode 100644 index ef08d5d5..00000000 --- a/app/assets/javascripts/jquery/AuthEveryPage.js +++ /dev/null @@ -1,16 +0,0 @@ -/* authEveryPage means: -1. being logged in and on any page on metamaps - -this code adds required jQuery for the create map lightBox that can be used from any page on metamaps -*/ - -$(document).ready(function () { - - // bind permission changer events on the createMap form - $('.permIcon').click(function () { - $(this).siblings('#map_permission').val($(this).attr('data-permission')); - $(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected'); - $(this).find('.mapPermIcon').addClass('selected'); - }); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/AuthMapCreatorMapPage.js b/app/assets/javascripts/jquery/AuthMapCreatorMapPage.js deleted file mode 100644 index e9db036d..00000000 --- a/app/assets/javascripts/jquery/AuthMapCreatorMapPage.js +++ /dev/null @@ -1,36 +0,0 @@ -/* AuthMapCreatorMapPage means: -1. being on a Map page -2. being the original creator of that map - - -*/ - -$(document).ready(function () { - - // ability to change permission of the map - var selectingPermission = false; - $('.yourMap .mapPermission').click(function () { - if (!selectingPermission) { - selectingPermission = true; - $(this).addClass('minimize'); // this line flips the drop down arrow to a pull up arrow - if ($(this).hasClass('commons')) { - $(this).append('
'); - } else if ($(this).hasClass('public')) { - $(this).append('
'); - } else if ($(this).hasClass('private')) { - $(this).append('
'); - } - $('.mapPermission .permissionSelect li').click(function (event) { - selectingPermission = false; - var permission = $(this).attr('class'); - updateMapPermission(mapid, permission); - event.stopPropagation(); - }); - } else { - selectingPermission = false; - $(this).removeClass('minimize'); // this line flips the pull up arrow to a drop down arrow - $('.mapPermission .permissionSelect').remove(); - } - }); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/EveryPage.js b/app/assets/javascripts/jquery/EveryPage.js deleted file mode 100644 index 376e0ead..00000000 --- a/app/assets/javascripts/jquery/EveryPage.js +++ /dev/null @@ -1,426 +0,0 @@ -// everything in this document.ready function is here because it is needed on every single page on metamaps -$(document).ready(function () { - - function bindMainMenuHover() { - - var menuIsOpen = false - - // controls the sliding hover of the bottom left menu - var sliding1 = false; - var lT; - - var closeMenu = function () { - lT = setTimeout(function () { - if (!sliding1) { - sliding1 = true; - // $('.footer .menu').animate({ - // height: '0px' - // }, 300, function() { - // sliding1 = false; - // menuIsOpen = false; - // }); - $('.footer').css('border-top-right-radius', '5px'); - $('.logo').animate({ - 'background-position-x': '-10px' - }, 200); - $('.footer .menu').fadeOut(200, function () { - sliding1 = false; - menuIsOpen = false; - }); - } - }, 500); - } - - var openMenu = function () { - clearTimeout(lT); - if (!sliding1) { - sliding1 = true; - - // $('.footer .menu').animate({ - // height: listLength + 'px' - // }, 300, function() { - // sliding1 = false; - // }); - $('.footer').css('border-top-right-radius', '0'); - $('.logo').animate({ - 'background-position-x': '-7px' - }, 200); - $('.footer .menu').fadeIn(200, function () { - sliding1 = false; - }); - } - } - // bind the hover events - $(".logo").hover(openMenu, closeMenu); - - // when on touch screen, make touching on the logo do what hovering does on desktop - $("#mainTitle a").bind('touchend', function (evt) { - if (!menuIsOpen) { - openMenu(); - evt.preventDefault(); - evt.stopPropagation(); - } - }); - } - - function bindSearchHover() { - - var searchIsOpen = false - - // controls the sliding hover of the search - var sliding1 = false; - var lT; - - var openSearch = function () { - clearTimeout(lT); - if (!sliding1 && !searchIsOpen) { - hideCards(); - sliding1 = true; - $('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({ - width: '200px' - }, 200, function () { - $('.sidebarSearchField, .sidebarSearch .tt-hint').css({ - padding: '5px 10px', - width: '180px' - }); - $('.sidebarSearchField').focus(); - sliding1 = false - searchIsOpen = true; - }); - } - } - var closeSearch = function (closeAfter, bypass) { - lT = setTimeout(function () { - if (!sliding1 && searchIsOpen && (bypass || $('.sidebarSearchField').val() == '')) { - sliding1 = true; - $('.sidebarSearchField, .sidebarSearch .tt-hint').css({ - padding: '5px 0', - width: '200px' - }); - $('.sidebarSearch .twitter-typeahead, .sidebarSearch .tt-hint, .sidebarSearchField').animate({ - width: '0' - }, 200, function () { - $('.sidebarSearchField').typeahead('setQuery', ''); - $('.sidebarSearchField').blur(); - sliding1 = false; - searchIsOpen = false; - }); - } - }, closeAfter); - } - - // bind the hover events - $(".sidebarSearch").hover(function () { - openSearch() - }, function () { - closeSearch(800, false) - }); - - $('.sidebarSearchIcon').click(function (e) { - $('.sidebarSearchField').focus(); - }); - $('.sidebarSearch').click(function (e) { - e.stopPropagation(); - }); - $('body').click(function (e) { - closeSearch(0, false); - }); - - // if the search is closed and user hits ctrl+/ - // close if they hit ESC - $('body').bind('keydown', function (e) { - switch (e.which) { - case 191: - if (e.ctrlKey && !searchIsOpen) { - openSearch(); - } - break; - case 27: - if (searchIsOpen) { - closeSearch(0, true); - } - break; - default: - break; //console.log(e.which); - } - }); - - // initialize the search box autocomplete results - var mapheader = userid ? '

Maps

' : '

Maps

'; - var topicheader = userid ? '

Topics

' : '

Topics

'; - $('.sidebarSearchField').typeahead([ - { - name: 'topics', - limit: 9999, - dupChecker: function (datum1, datum2) { - return false; - }, - template: $('#topicSearchTemplate').html(), - remote: { - url: '/search/topics?term=%QUERY', - replace: function () { - var q = '/search/topics?term=' + $('.sidebarSearchField').val(); - if ($("#limitTopicsToMe").is(':checked')) { - q += "&user=" + userid.toString(); - } - return q; - }, - filter: function (dataset) { - if (dataset.length == 0) { - dataset.push({ - value: "No results", - label: "No results", - typeImageURL: "/assets/icons/wildcard.png", - rtype: "noresult" - }); - } - return dataset; - } - }, - engine: Hogan, - header: topicheader - }, - { - name: 'maps', - limit: 9999, - dupChecker: function (datum1, datum2) { - return false; - }, - template: $('#mapSearchTemplate').html(), - remote: { - url: '/search/maps?term=%QUERY', - replace: function () { - var q = '/search/maps?term=' + $('.sidebarSearchField').val(); - if ($("#limitMapsToMe").is(':checked')) { - q += "&user=" + userid.toString(); - } - return q; - }, - filter: function (dataset) { - if (dataset.length == 0) { - dataset.push({ - value: "No results", - label: "No results", - rtype: "noresult" - }); - } - return dataset; - } - }, - engine: Hogan, - header: mapheader - }, - { - name: 'mappers', - limit: 9999, - dupChecker: function (datum1, datum2) { - return false; - }, - template: $('#mapperSearchTemplate').html(), - remote: { - url: '/search/mappers?term=%QUERY', - filter: function (dataset) { - if (dataset.length == 0) { - dataset.push({ - value: "No results", - label: "No results", - rtype: "noresult" - }); - } - return dataset; - } - }, - engine: Hogan, - header: '

Mappers

' - } - ]); - - //Set max height of the search results box to prevent it from covering bottom left footer - $('.sidebarSearchField').bind('typeahead:opened', function (event) { - var h = $(window).height(); - $(".tt-dropdown-menu").css('max-height', h - 100); - }); - $(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:selected', function (event, datum, dataset) { - console.log(event); - if (datum.rtype != "noresult") { - var win; - if (dataset == "topics") { - win = window.open('/topics/' + datum.id, '_blank'); - } else if (dataset == "maps") { - win = window.open('/maps/' + datum.id, '_blank'); - } else if (dataset == "mappers") { - win = window.open('/maps/mappers/' + datum.id, '_blank'); - } - win.focus(); - closeSearch(0); - } - }); - - - var checkboxChangeInit = false, - minimizeInit = false; - - $('.sidebarSearchField').bind('keyup', function () { - - // when the user selects 'added by me' resend the query with their userid attached - if (!checkboxChangeInit) { - $('.limitToMe').bind("change", function (e) { - // set the value of the search equal to itself to retrigger the autocomplete event - searchIsOpen = false; - $('.sidebarSearchField').typeahead('setQuery', $('.sidebarSearchField').val()); - setTimeout(function () { - searchIsOpen = true; - }, 2000); - }); - checkboxChangeInit = true; - } - - // when the user clicks minimize section, hide the results for that section - if (!minimizeInit) { - $('.minimizeMapperResults').click(function (e) { - var s = $('.tt-dataset-mappers .tt-suggestions'); - console.log(s.css('height')); - if (s.css('height') == '0px') { - $('.tt-dataset-mappers .tt-suggestions').css({ - 'height': 'auto', - 'overflow': 'visible' - }); - $(this).removeClass('maximizeResults').addClass('minimizeResults'); - } else { - $('.tt-dataset-mappers .tt-suggestions').css({ - 'height': '0', - 'overflow': 'hidden' - }); - $(this).removeClass('minimizeResults').addClass('maximizeResults'); - } - }); - $('.minimizeTopicResults').click(function (e) { - var s = $('.tt-dataset-topics .tt-suggestions'); - console.log(s.css('height')); - if (s.css('height') == '0px') { - s.css({ - 'height': 'auto', - 'border-top': 'none', - 'overflow': 'visible' - }); - $(this).removeClass('maximizeResults').addClass('minimizeResults'); - } else { - s.css({ - 'height': '0', - 'border-top': '1px solid rgb(56, 56, 56)', - 'overflow': 'hidden' - }); - $(this).removeClass('minimizeResults').addClass('maximizeResults'); - } - }); - $('.minimizeMapResults').click(function (e) { - var s = $('.tt-dataset-maps .tt-suggestions'); - console.log(s.css('height')); - if (s.css('height') == '0px') { - s.css({ - 'height': 'auto', - 'border-top': 'none', - 'overflow': 'visible' - }); - $(this).removeClass('maximizeResults').addClass('minimizeResults'); - } else { - s.css({ - 'height': '0', - 'border-top': '1px solid rgb(56, 56, 56)', - 'overflow': 'hidden' - }); - $(this).removeClass('minimizeResults').addClass('maximizeResults'); - } - }); - minimizeInit = true; - } - }); - - // - - $('.sidebarSearch button.addToMap').click(function (event) { - event.stopPropagation(); - }); - } // end bindSearchHover - - function bindAccountHover() { - - var accountIsOpen = false - - // controls the sliding hover of the bottom left menu - var sliding1 = false; - var lT; - - var closeAccount = function () { - lT = setTimeout(function () { - if (!sliding1) { - sliding1 = true; - $('.sidebarAccountIcon').css('background-color', '#0F1519'); - $('.sidebarAccountBox').fadeOut(200, function () { - sliding1 = false; - accountIsOpen = false; - }); - } - }, 300); - } - - var openAccount = function () { - clearTimeout(lT); - if (!sliding1) { - sliding1 = true; - - // hide the other two - $('.sidebarFilterBox').hide(); - $('.sidebarCollaborateBox').hide(); - $('.sidebarFilterIcon').css('background-color', '#0F1519'); - $('.sidebarCollaborateIcon').css('background-color', '#0F1519'); - - $('.sidebarAccountIcon').css('background-color', '#000'); - $('.sidebarAccountBox').fadeIn(200, function () { - sliding1 = false; - accountIsOpen = true; - }); - } - } - // bind the hover events - $(".sidebarAccount").hover(openAccount, closeAccount); - } // end bindAccountHover - - // bind hover events - bindMainMenuHover(); - bindSearchHover(); - bindAccountHover(); - - // hide notices after 10 seconds - $('.notice.metamaps').delay(10000).fadeOut('fast'); - $('.alert.metamaps').delay(10000).fadeOut('fast'); - - //bind lightbox clicks - $('.openLightbox').click(function (event) { - openLightbox($(this).attr('data-open')); - event.preventDefault(); - return false; - }); - - // bind keyboard handlers - $('body').bind('keyup', function (e) { - switch (e.which) { - case 13: - enterKeyHandler(e); - break; - case 27: - escKeyHandler(); - break; - default: - break; //console.log(e.which); - } - }); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/jquery/MapPage.js b/app/assets/javascripts/jquery/MapPage.js deleted file mode 100644 index 2a9336d0..00000000 --- a/app/assets/javascripts/jquery/MapPage.js +++ /dev/null @@ -1,48 +0,0 @@ -/* MapPage means: -1. being on a Map page - - -*/ - -$(document).ready(function () { - - function bindInfoHover() { - - var infoIsOpen = false; - - // controls the sliding hover of the bottom left menu - var sliding1 = false; - var lT; - - var closeInfo = function () { - lT = setTimeout(function () { - if (!sliding1) { - sliding1 = true; - $('.mapInfoBox').fadeOut(200, function () { - sliding1 = false; - infoIsOpen = false; - }); - } - }, 300); - } - - var openInfo = function (event) { - clearTimeout(lT); - if (!sliding1 && event.target.className != "openCheatsheet openLightbox") { - sliding1 = true; - - $('.mapInfoBox').fadeIn(200, function () { - sliding1 = false; - infoIsOpen = true; - }); - } - } - // bind the hover events - $("div.index").hover(openInfo, closeInfo); - - - } // end bindInfoHover - - bindInfoHover(); - -}); // end document.ready \ No newline at end of file diff --git a/app/assets/javascripts/lib/Countable.js b/app/assets/javascripts/lib/Countable.js new file mode 100644 index 00000000..524c4ff8 --- /dev/null +++ b/app/assets/javascripts/lib/Countable.js @@ -0,0 +1,379 @@ +/** + * Countable is a script to allow for live paragraph-, word- and character- + * counting on an HTML element. + * + * @author Sacha Schmid () + * @version 2.0.2 + * @license MIT + * @see + */ + +/** + * Note: For the purpose of this internal documentation, arguments of the type + * {Nodes} are to be interpreted as either {NodeList} or {Element}. + */ + +;(function (global) { + 'use strict' + + /** + * @private + * + * `_liveElements` holds all elements that have the live-counting + * functionality bound to them. + * + * `_event` holds the event to handle the live counting, based on the + * browser's capabilities. + */ + + var _liveElements = [], + _event = 'oninput' in document ? 'input' : 'keyup' + + /** + * `String.trim()` polyfill for non-supporting browsers. This is the + * recommended polyfill on MDN. + * + * @see + * @see + * + * @return {String} The original string with leading and trailing whitespace + * removed. + */ + + if (!String.prototype.trim) { + String.prototype.trim = function () { + return this.replace(/^\s+|\s+$/g, '') + } + } + + /** + * `ucs2decode` function from the punycode.js library. + * + * Creates an array containing the decimal code points of each Unicode + * character in the string. While JavaScript uses UCS-2 internally, this + * function will convert a pair of surrogate halves (each of which UCS-2 + * exposes as separate characters) into a single code point, matching + * UTF-16. + * + * @see + * @see + * + * @param {String} string The Unicode input string (UCS-2). + * + * @return {Array} The new array of code points. + */ + + function _decode (string) { + var output = [], + counter = 0, + length = string.length, + value, extra + + while (counter < length) { + value = string.charCodeAt(counter++) + + if ((value & 0xF800) == 0xD800 && counter < length) { + + // High surrogate, and there is a next character. + + extra = string.charCodeAt(counter++) + + if ((extra & 0xFC00) == 0xDC00) { + + // Low surrogate. + + output.push(((value & 0x3FF) << 10) + (extra & 0x3FF) + 0x10000) + } else { + output.push(value, extra) + } + } else { + output.push(value) + } + } + + return output + } + + /** + * `_validateArguments` validates the arguments given to each function call. + * Errors are logged to the console as warnings, but Countable fails silently. + * + * @private + * + * @param {Nodes} elements The (collection of) element(s) to + * validate. + * + * @param {Function} callback The callback function to validate. + * + * @return {Boolean} Returns whether all arguments are vaild. + */ + + function _validateArguments (elements, callback) { + var elementsValid = elements && ((Object.prototype.toString.call(elements) === '[object NodeList]' && elements.length) || (elements.nodeType === 1)), + callbackValid = callback && typeof callback === 'function' + + if ('console' in window && 'warn' in console) { + if (!elementsValid) console.warn('Countable: No valid elements were found') + if (!callbackValid) console.warn('Countable: "' + callback + '" is not a valid callback function') + } + + return elementsValid && callbackValid + } + + /** + * `_extendDefaults` is a function to extend a set of default options with the + * ones given in the function call. Available options are described below. + * + * {Boolean} hardReturns Use two returns to seperate a paragraph instead + * of one. + * {Boolean} stripTags Strip HTML tags before counting the values. + * {Boolean} ignoreReturns Ignore returns when calculating the `all` + * property. + * + * @private + * + * @param {Object} options Countable allows the options described above. + * They can be used in a function call to override + * the default behaviour. + * + * @return {Object} The new options object. + */ + + function _extendDefaults (options) { + var defaults = { hardReturns: false, stripTags: false, ignoreReturns: false } + + for (var prop in options) { + if (defaults.hasOwnProperty(prop)) defaults[prop] = options[prop] + } + + return defaults + } + + /** + * `_count` trims an element's value, optionally strips HTML tags and counts + * paragraphs, words, characters and characters plus spaces. + * + * @private + * + * @param {Element} element The element whose value is to be counted. + * + * @param {Object} options The options to use for the counting. + * + * @return {Object} The object containing the number of paragraphs, + * words, characters and characters plus spaces. + */ + + function _count (element, options) { + var original = 'value' in element ? element.value : element.innerText || element.textContent, + trimmed + + /** + * The initial implementation to allow for HTML tags stripping was created + * @craniumslows while the current one was created by @Rob--W. + * + * @see + * @see + */ + + if (options.stripTags) original = original.replace(/<\/?[a-z][^>]*>/gi, '') + + trimmed = original.trim() + + /** + * Most of the performance improvements are based on the works of @epmatsw. + * + * @see + */ + + return { + paragraphs: trimmed ? (trimmed.match(options.hardReturns ? /\n{2,}/g : /\n+/g) || []).length + 1 : 0, + words: trimmed ? (trimmed.replace(/['";:,.?¿\-!¡]+/g, '').match(/\S+/g) || []).length : 0, + characters: trimmed ? _decode(trimmed.replace(/\s/g, '')).length : 0, + all: _decode(options.ignoreReturns ? original.replace(/[\n\r]/g, '') : original).length + } + } + + /** + * `_loop` is a helper function to iterate over a collection, e.g. a NodeList + * or an Array. The callback receives the current element as the single + * parameter. + * + * @private + * + * @param {Array} which The collection to iterate over. + * + * @param {Function} callback The callback function to call on each + * iteration. + */ + + function _loop (which, callback) { + var len = which.length + + if (typeof len !== 'undefined') { + while (len--) { + callback(which[len]) + } + } else { + callback(which) + } + } + + /** + * This is the main object that will later be exposed to other scripts. It + * holds all the public methods that can be used to enable the Countable + * functionality. + */ + + var Countable = { + + /** + * The `live` method binds the counting handler to all given elements. The + * event is either `oninput` or `onkeydown`, based on the capabilities of + * the browser. + * + * @param {Nodes} elements All elements that should receive the + * Countable functionality. + * + * @param {Function} callback The callback to fire whenever the + * element's value changes. The callback is + * called with the relevant element bound to + * `this` and the counted values as the + * single parameter. + * + * @param {Object} [options] An object to modify Countable's + * behaviour. Refer to `_extendDefaults` for + * a list of available options. + * + * @return {Object} Returns the Countable object to allow for chaining. + */ + + live: function (elements, callback, options) { + var ops = _extendDefaults(options), + bind = function (element) { + var handler = function () { + callback.call(element, _count(element, ops)) + } + + _liveElements.push({ element: element, handler: handler }) + + handler() + + if (element.addEventListener) { + element.addEventListener(_event, handler, false) + } else if (element.attachEvent) { + element.attachEvent('on' + _event, handler) + } + } + + if (!_validateArguments(elements, callback)) return + + if (elements.length) { + _loop(elements, bind) + } else { + bind(elements) + } + + return this + }, + + /** + * The `die` method removes the Countable functionality from all given + * elements. + * + * @param {Nodes} elements All elements whose Countable functionality + * should be unbound. + * + * @return {Object} Returns the Countable object to allow for chaining. + */ + + die: function (elements) { + if (!_validateArguments(elements, function () {})) return + + _loop(elements, function (element) { + var liveElement + + _loop(_liveElements, function (live) { + if (live.element === element) liveElement = live + }) + + if (!liveElement) return + + if (element.removeEventListener) { + element.removeEventListener(_event, liveElement.handler, false) + } else if (element.detachEvent) { + element.detachEvent('on' + _event, liveElement.handler) + } + + _liveElements.splice(_liveElements.indexOf(liveElement), 1) + }) + + return this + }, + + /** + * The `once` method works mostly like the `live` method, but no events are + * bound, the functionality is only executed once. + * + * @param {Nodes} elements All elements that should receive the + * Countable functionality. + * + * @param {Function} callback The callback to fire whenever the + * element's value changes. The callback is + * called with the relevant element bound to + * `this` and the counted values as the + * single parameter. + * + * @param {Object} [options] An object to modify Countable's + * behaviour. Refer to `_extendDefaults` + * for a list of available options. + * + * @return {Object} Returns the Countable object to allow for chaining. + */ + + once: function (elements, callback, options) { + if (!_validateArguments(elements, callback)) return + + _loop(elements, function (element) { + callback.call(element, _count(element, _extendDefaults(options))) + }) + + return this + }, + + /** + * The `enabled` method checks if the live-counting functionality is bound + * to an element. + * + * @param {Element} element A single Element. + * + * @return {Boolean} A boolean value representing whether Countable + * functionality is bound to the given element. + */ + + enabled: function (element) { + var isEnabled = false + + if (element && element.nodeType === 1) { + _loop(_liveElements, function (live) { + if (live.element === element) isEnabled = true + }) + } + + return isEnabled + } + + } + + /** + * Expose Countable depending on the module system used across the + * application. (Node / CommonJS, AMD, global) + */ + + if (typeof exports === 'object') { + module.exports = Countable + } else if (typeof define === 'function' && define.amd) { + define(function () { return Countable }) + } else { + global.Countable = Countable + } +}(this)) diff --git a/app/assets/javascripts/WebSocketMain.swf b/app/assets/javascripts/lib/WebSocketMain.swf similarity index 100% rename from app/assets/javascripts/WebSocketMain.swf rename to app/assets/javascripts/lib/WebSocketMain.swf diff --git a/app/assets/javascripts/WebSocketMainInsecure.swf b/app/assets/javascripts/lib/WebSocketMainInsecure.swf similarity index 100% rename from app/assets/javascripts/WebSocketMainInsecure.swf rename to app/assets/javascripts/lib/WebSocketMainInsecure.swf diff --git a/app/assets/javascripts/bip.js b/app/assets/javascripts/lib/bip.js similarity index 100% rename from app/assets/javascripts/bip.js rename to app/assets/javascripts/lib/bip.js diff --git a/app/assets/javascripts/lib/canvasloader.min.js b/app/assets/javascripts/lib/canvasloader.min.js new file mode 100644 index 00000000..a17ee48a --- /dev/null +++ b/app/assets/javascripts/lib/canvasloader.min.js @@ -0,0 +1,12 @@ +(function(w){var k=function(b,c){typeof c=="undefined"&&(c={});this.init(b,c)},a=k.prototype,o,p=["canvas","vml"],f=["oval","spiral","square","rect","roundRect"],x=/^\#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,v=navigator.appVersion.indexOf("MSIE")!==-1&&parseFloat(navigator.appVersion.split("MSIE")[1])===8?true:false,y=!!document.createElement("canvas").getContext,q=true,n=function(b,c,a){var b=document.createElement(b),d;for(d in a)b[d]=a[d];typeof c!=="undefined"&&c.appendChild(b);return b},m=function(b, +c){for(var a in c)b.style[a]=c[a];return b},t=function(b,c){for(var a in c)b.setAttribute(a,c[a]);return b},u=function(b,c,a,d){b.save();b.translate(c,a);b.rotate(d);b.translate(-c,-a);b.beginPath()};a.init=function(b,c){if(typeof c.safeVML==="boolean")q=c.safeVML;try{this.mum=document.getElementById(b)!==void 0?document.getElementById(b):document.body}catch(a){this.mum=document.body}c.id=typeof c.id!=="undefined"?c.id:"canvasLoader";this.cont=n("div",this.mum,{id:c.id});if(y)o=p[0],this.can=n("canvas", +this.cont),this.con=this.can.getContext("2d"),this.cCan=m(n("canvas",this.cont),{display:"none"}),this.cCon=this.cCan.getContext("2d");else{o=p[1];if(typeof k.vmlSheet==="undefined"){document.getElementsByTagName("head")[0].appendChild(n("style"));k.vmlSheet=document.styleSheets[document.styleSheets.length-1];var d=["group","oval","roundrect","fill"],e;for(e in d)k.vmlSheet.addRule(d[e],"behavior:url(#default#VML); position:absolute;")}this.vml=n("group",this.cont)}this.setColor(this.color);this.draw(); +m(this.cont,{display:"none"})};a.cont={};a.can={};a.con={};a.cCan={};a.cCon={};a.timer={};a.activeId=0;a.diameter=40;a.setDiameter=function(b){this.diameter=Math.round(Math.abs(b));this.redraw()};a.getDiameter=function(){return this.diameter};a.cRGB={};a.color="#000000";a.setColor=function(b){this.color=x.test(b)?b:"#000000";this.cRGB=this.getRGB(this.color);this.redraw()};a.getColor=function(){return this.color};a.shape=f[0];a.setShape=function(b){for(var c in f)if(b===f[c]){this.shape=b;this.redraw(); +break}};a.getShape=function(){return this.shape};a.density=40;a.setDensity=function(b){this.density=q&&o===p[1]?Math.round(Math.abs(b))<=40?Math.round(Math.abs(b)):40:Math.round(Math.abs(b));if(this.density>360)this.density=360;this.activeId=0;this.redraw()};a.getDensity=function(){return this.density};a.range=1.3;a.setRange=function(b){this.range=Math.abs(b);this.redraw()};a.getRange=function(){return this.range};a.speed=2;a.setSpeed=function(b){this.speed=Math.round(Math.abs(b))};a.getSpeed=function(){return this.speed}; +a.fps=24;a.setFPS=function(b){this.fps=Math.round(Math.abs(b));this.reset()};a.getFPS=function(){return this.fps};a.getRGB=function(b){b=b.charAt(0)==="#"?b.substring(1,7):b;return{r:parseInt(b.substring(0,2),16),g:parseInt(b.substring(2,4),16),b:parseInt(b.substring(4,6),16)}};a.draw=function(){var b=0,c,a,d,e,h,k,j,r=this.density,s=Math.round(r*this.range),l,i,q=0;i=this.cCon;var g=this.diameter;if(o===p[0]){i.clearRect(0,0,1E3,1E3);t(this.can,{width:g,height:g});for(t(this.cCan,{width:g,height:g});b< +r;){l=b<=s?1-1/s*b:l=0;k=270-360/r*b;j=k/180*Math.PI;i.fillStyle="rgba("+this.cRGB.r+","+this.cRGB.g+","+this.cRGB.b+","+l.toString()+")";switch(this.shape){case f[0]:case f[1]:c=g*0.07;e=g*0.47+Math.cos(j)*(g*0.47-c)-g*0.47;h=g*0.47+Math.sin(j)*(g*0.47-c)-g*0.47;i.beginPath();this.shape===f[1]?i.arc(g*0.5+e,g*0.5+h,c*l,0,Math.PI*2,false):i.arc(g*0.5+e,g*0.5+h,c,0,Math.PI*2,false);break;case f[2]:c=g*0.12;e=Math.cos(j)*(g*0.47-c)+g*0.5;h=Math.sin(j)*(g*0.47-c)+g*0.5;u(i,e,h,j);i.fillRect(e,h-c*0.5, +c,c);break;case f[3]:case f[4]:a=g*0.3,d=a*0.27,e=Math.cos(j)*(d+(g-d)*0.13)+g*0.5,h=Math.sin(j)*(d+(g-d)*0.13)+g*0.5,u(i,e,h,j),this.shape===f[3]?i.fillRect(e,h-d*0.5,a,d):(c=d*0.55,i.moveTo(e+c,h-d*0.5),i.lineTo(e+a-c,h-d*0.5),i.quadraticCurveTo(e+a,h-d*0.5,e+a,h-d*0.5+c),i.lineTo(e+a,h-d*0.5+d-c),i.quadraticCurveTo(e+a,h-d*0.5+d,e+a-c,h-d*0.5+d),i.lineTo(e+c,h-d*0.5+d),i.quadraticCurveTo(e,h-d*0.5+d,e,h-d*0.5+d-c),i.lineTo(e,h-d*0.5+c),i.quadraticCurveTo(e,h-d*0.5,e+c,h-d*0.5))}i.closePath();i.fill(); +i.restore();++b}}else{m(this.cont,{width:g,height:g});m(this.vml,{width:g,height:g});switch(this.shape){case f[0]:case f[1]:j="oval";c=140;break;case f[2]:j="roundrect";c=120;break;case f[3]:case f[4]:j="roundrect",c=300}a=d=c;e=500-d;for(h=-d*0.5;b=1;)b.removeChild(b.firstChild)}};a.redraw=function(){this.clean();this.draw()};a.reset=function(){typeof this.timer=== +"number"&&(this.hide(),this.show())};a.tick=function(b){var a=this.con,f=this.diameter;b||(this.activeId+=360/this.density*this.speed);o===p[0]?(a.clearRect(0,0,f,f),u(a,f*0.5,f*0.5,this.activeId/180*Math.PI),a.drawImage(this.cCan,0,0,f,f),a.restore()):(this.activeId>=360&&(this.activeId-=360),m(this.vml,{rotation:this.activeId}))};a.show=function(){if(typeof this.timer!=="number"){var a=this;this.timer=self.setInterval(function(){a.tick()},Math.round(1E3/this.fps));m(this.cont,{display:"block"})}}; +a.hide=function(){typeof this.timer==="number"&&(clearInterval(this.timer),delete this.timer,m(this.cont,{display:"none"}))};a.kill=function(){var a=this.cont;typeof this.timer==="number"&&this.hide();o===p[0]?(a.removeChild(this.can),a.removeChild(this.cCan)):a.removeChild(this.vml);for(var c in this)delete this[c]};w.CanvasLoader=k})(window); \ No newline at end of file diff --git a/app/assets/javascripts/carousel/cloud-carousel.1.0.5.js b/app/assets/javascripts/lib/cloudcarousel.js similarity index 93% rename from app/assets/javascripts/carousel/cloud-carousel.1.0.5.js rename to app/assets/javascripts/lib/cloudcarousel.js index 467ae3c4..31a9aa7a 100644 --- a/app/assets/javascripts/carousel/cloud-carousel.1.0.5.js +++ b/app/assets/javascripts/lib/cloudcarousel.js @@ -177,10 +177,20 @@ jQuery.browser = browser; // You will need this plugin for the mousewheel to work: http://plugins.jquery.com/project/mousewheel if (options.mouseWheel) { + // START METAMAPS CODE + $('body').bind('mousewheel',this,function(event, delta) { + if (Metamaps.Create.newTopic.beingCreated && !Metamaps.Create.isSwitchingSet) { + event.data.rotate(delta); + return false; + } + }); + // END METAMAPS CODE + /* ORIGINAL CODE $(container).bind('mousewheel',this,function(event, delta) { event.data.rotate(delta); return false; }); + */ } $(container).bind('mouseover click',this,function(event){ @@ -198,7 +208,7 @@ jQuery.browser = browser; { $(options.titleBox).html( ($(event.target).attr('title') )); // METAMAPS CODE - $('#topic_metacode').val($(event.target).attr('title')); + Metamaps.Create.newTopic.metacode = $(event.target).attr('title'); // NOT METAMAPS CODE var idx = $(event.target).data('itemIndex'); var frontIndex = event.data.frontIndex; @@ -236,7 +246,7 @@ jQuery.browser = browser; { if ( items[this.frontIndex] === undefined ) { return; } // Images might not have loaded yet. // METAMAPS CODE - $('#topic_metacode').val($(items[this.frontIndex].image).attr('title')); + Metamaps.Create.newTopic.metacode = $(items[this.frontIndex].image).attr('title'); //$('img.cloudcarousel').css({"background":"none", "width":"","height":""}); //$(items[this.frontIndex].image).css({"width":"45px","height":"45px"}); // NOT METAMAPS CODE diff --git a/app/assets/javascripts/lib/embedly.js b/app/assets/javascripts/lib/embedly.js new file mode 100644 index 00000000..65b52d0f --- /dev/null +++ b/app/assets/javascripts/lib/embedly.js @@ -0,0 +1,2 @@ +!function(){var a=function b(c,d,e){function f(h,i){if(!d[h]){if(!c[h]){var j="function"==typeof a&&a;if(!i&&j)return j(h,!0);if(g)return g(h,!0);throw new Error("Cannot find module '"+h+"'")}var k=d[h]={exports:{}};c[h][0].call(k.exports,function(a){var b=c[h][1][a];return f(b?b:a)},k,k.exports,b,c,d,e)}return d[h].exports}for(var g="function"==typeof a&&a,h=0;ha};0>k&&(l=function(b){return a>b});var m=function(){clearInterval(c),g.console.log("duration",(new Date).getTime()-i),d.detachEvent("scroll",e)};c=setInterval(function(){return f+=k,l(f)?(m(),!1):(window.scrollTo(0,f),void(j=!0))},10),e=function(){j&&f!==g.window.scrollY()&&m()},d.addEvent("scroll",e)},b.exports=g},{"./dom.js":5,"./urlparse.js":14,"./utils.js":15,conf:"AqyHQT"}],3:[function(a,b){var c=!1,d=/xyz/.test(function(){})?/\b_super\b/:/.*/,e=function(){};e.extend=function(a){function b(){!c&&this.init&&this.init.apply(this,arguments)}var e=this.prototype;c=!0;var f=new this;c=!1;for(var g in a)f[g]="function"==typeof a[g]&&"function"==typeof e[g]&&d.test(a[g])?function(a,b){return function(){var c=this._super;this._super=e[a];var d=b.apply(this,arguments);return this._super=c,d}}(g,a[g]):a[g];return b.prototype=f,b.prototype.constructor=b,b.extend=arguments.callee,b},b.exports=e},{}],4:[function(a,b){var c=a("./iframe.js"),d=a("./utils.js"),e={started:!1,instance:null};e.EVENTS=["xcomm.stats.access","xcomm.stats.card.realtime","xcomm.stats.card.week","xcomm.stats.media.realtime","xcomm.stats.media.week","xcomm.stats.media.recommend","xcomm.user.set","xcomm.user.get","xcomm.user.remove","xcomm.page.progress"],e.clear=function(){e.instance&&(e.instance.remove(),e.instance=null),e.started=!1},e.connect=function(a){if(!a||e.started)return!1;e.started=!0;var b=c.createComm(a);return d.each(e.EVENTS,function(c){b.on(c,function(b){a.notify(c+".response",b)}),a.on(c,function(a){b.send(c,a)})}),b.on("xcomm.ready",function(b){a.notify("xcomm.ready",b)}),e.instance=b,b},b.exports=e},{"./iframe.js":6,"./utils.js":15}],5:[function(a,b){var c=a("./utils.js"),d={};d.toArray=function(a){return c.map(a,function(a){return a})},d.all=function(a){var b=[];return document.querySelectorAll?d.toArray(document.querySelectorAll(a)):b},d.one=function(a,b){var c=d.all(a,b);return 0===c.length?null:c[0]},d.create=function(a,b,e,f){if(!a||!c.isString(a))return null;c.isString(b)&&c.isNone(e)&&(e=b,b={});var g;return g=f?document.createElementNS("http://www.w3.org/2000/svg",a):document.createElement(a),c.each(b,function(a,b){g.setAttribute(b,a)}),e&&d.text(g,e),g},d.set=function(a,b,e){if(!a||!c.isString(a))return null;c.isString(b)&&c.isNone(e)&&(e=b,b={});var f=d.one(a);return f?(c.each(b,function(a,b){f.setAttribute(b,a)}),c.isNone(e)||d.text(f,e),f):null},d.replace=function(a,b){c.assert(c.isElement(a),"replace requires an element to be replaced"),c.assert(c.isElement(b),"replace requires an element to replace with."),a.parentNode.replaceChild(b,a)},d.remove=function(a){return c.isElement(a)&&c.isElement(a.parentNode)?void a.parentNode.removeChild(a):!1},d.hide=function(a){return c.isString(a)&&(a=d.one(a)),c.isElement(a)&&(a.style.display="none"),a},d.show=function(a,b){return c.isString(a)&&(a=d.one(a)),c.isElement(a)&&(a.style.display=b?"inline-block":"block"),a},d.svg=function(a,b,c){return d.create(a,b,c,"http://www.w3.org/2000/svg")},d.children=function(a,b){return c.isElement(a)?c.reduce(a.childNodes,function(a,d){if(c.isElement(d)){if(!c.isNone(b))if(d.namespaceURI&&"http://www.w3.org/2000/svg"===d.namespaceURI){if(d.nodeName!==b)return a}else if(b.toUpperCase()!==d.nodeName)return a;a.push(d)}return a},[]):[]},d.child=function(a,b){var c=d.children(a,b);return 0!==c.length?c[0]:null},d.text=function(a,b){if(!a||!c.isElement(a))return null;if(c.isNone(b))return a.innerText||a.textContent;var d=void 0===a.textContent?"innerText":"textContent";a[d]=b},d.hasClass=function(a,b){if(c.isString(a)&&(a=d.one(a)),!c.isElement(a)||!c.isString(b)||!b)return!1;var e=a.getAttribute("class");return c.isNone(e)?!1:(" "+e+" ").indexOf(" "+b+" ")>-1?!0:!1},d.addClass=function(a,b){if(c.isString(a)&&(a=d.one(a)),!c.isElement(a)||!c.isString(b)||!b)return!1;if(d.hasClass(a,b))return!1;var e=a.getAttribute("class");if(c.isNone(e))return a.setAttribute("class",b),!0;var f=e.split(" "),g=[];return c.map(f,function(a){var b=c.trim(a);""!==b&&g.push(b)}),g.push(b),a.setAttribute("class",g.join(" ")),!0},d.removeClass=function(a,b){if(c.isString(a)&&(a=d.one(a)),!c.isElement(a)||!c.isString(b)||!b)return!1;var e=a.getAttribute("class");if(c.isNone(e))return!1;var f=!1,g=c.reduce(e.split(" "),function(a,d){var e=c.trim(d);return e?e===b?(f=!0,a):(a.push(e),a):a},[]);return a.setAttribute("class",g.join(" ")),f},d.data=function(a,b,d){c.assert(a&&c.isElement(a),"dom.data needs an element."),c.assert(b&&c.isString(b),"dom.data needs an attr.");var e=c.camelCase(b);return c.isNone(d)?c.isNone(a.dataset)?a.getAttribute("data-"+b):c.isNone(a.dataset[e])?null:a.dataset[e]:void(c.isNone(a.dataset)?a.setAttribute("data-"+b,d):a.dataset[e]=d)},d.attrize=function(a){return a&&c.isObject(a)?c.map(a,function(a,b){return b+'="'+a+'"'}).sort().join(" "):""},d.event=function(a){var b=c.extend({},a||window.event);return b.target||(b.target=b.srcElement||document),3===b.target.nodeType&&(b.target=b.target.parentNode),!a.metaKey&&a.ctrlKey&&(b.metaKey=b.ctrlKey),b.stop=function(){a.preventDefault?a.preventDefault():a.returnValue=!1},b.pageX||b.pageY||!b.clientX&&!b.clientY||(b.pageX=b.clientX+document.body.scrollLeft+document.documentElement.scrollLeft,b.pageY=b.clientY+document.body.scrollTop+document.documentElement.scrollTop),b},d.addEvent=function(a,b,d){c.isNone(a)||(a.addEventListener?a.addEventListener(b,d,!1):a.attachEvent?a.attachEvent("on"+b,d):a["on"+b]=d)},d.detachEvent=function(a,b,d){c.isNone(a)||(a.removeEventListener?a.removeEventListener(b,d,!1):a.detachEvent?a.detachEvent("on"+b,d):a["on"+b]=null)},d.trigger=function(a,b){c.assert(c.contains(["click"],b),"Not a valid event");var d;a.dispatchEvent?(d=document.createEvent("MouseEvents"),d.initEvent(b,!0,!0),a.dispatchEvent(d,!0)):(d=document.createEventObject(),a.fireEvent("on"+b,d))},d.rect=function(a){try{return a.getBoundingClientRect()}catch(b){}return!1},b.exports=d},{"./utils.js":15}],6:[function(a,b){var c=a("./utils.js"),d=a("./dom.js"),e=a("./urlparse.js"),f=a("./browser.js"),g=a("./class.js"),h=a("./json.js"),i=a("./a.js"),j=a("conf"),k={};k.connect=function(a,b){if(!a||!c.isElement(a.elem))return!1;var d=new i,g=[],j=a.elem.src,k=!1,l=e.getOrigin(j);a.on=function(a,b,c){d.on(a,b,c)},a.one=function(a,b,c){d.one(a,b,c)},a.off=function(a,b){d.off(a,b)},a.send=function(b,d){if(c.isNone(d)&&(d={}),c.isString(d)&&(d={msg:d}),d.method=b,k===!1)return f.console.log("Iframe.queue",d),g.push(d),!1;a.sid&&(d.sid=a.sid),f.console.log("iframe.send",d);var e=h.stringify(d);a.elem.contentWindow&&a.elem.contentWindow.postMessage&&a.elem.contentWindow.postMessage(e,l)},a.ready=function(){k||(f.console.log("iframe.ready",a.name),k=!0,c.each(g,function(b){a.send(b.method,b)}))};var m=function(b,c){if(b.origin===l){if(f.console.log("iframe.message",c),!c.src&&!c.sid&&!c.listener)return!1;if(a.sid&&c.sid!==a.sid)return!1;if(c.src&&c.src!==j)return!1;if(c.listener&&c.listener!==j)return!1;"resize"===c.method&&a.resize&&a.resize(c),!c.method&&c.event&&c.listener?d.notify(c.event,c):c.method&&d.notify(c.method,c)}};return b.on("window.message",m),a._remove=function(){b.off("window.message",m)},a},k.rendering=function(a){return"1"===d.data(a,"rendering")?!0:(d.data(a,"rendering","1"),!1)};var l=g.extend({secure:null,rendered:!1,init:function(a,b){this.sid=c.getUUID(),this.query=a,this.create(b)},getSrc:function(){var a="";return a=this.secure===!0||j.EMB_HTTPS?j.EMB_SECURE_FRAME_SRC:/https?:\/\/sulia\.com\/embed/.test(this.query.url)?"http://embed.sulia.com/widgets/":j.EMB_FRAME_SRC,a+=this.name+".html?"+e.createQuery(this.query)+"#sid="+this.sid},create:function(a){var b=c.extend({},this.attrs);return this.src=this.getSrc(),b.src=this.src,b.id="emb_"+(this.query&&this.query.url?c.hash(this.query.url):this.sid),b["class"]="embedly-"+this.name,this.elem=d.create("iframe",b),c.each(this.style,function(a,b){this.elem.style[b]=a},this),k.connect(this,a),this.after(),this.elem},after:function(){},replace:function(a){d.replace(a,this.elem)},append:function(a){a.appendChild(this.elem)},resize:function(a){a.width&&this.elem.setAttribute("width",a.width),a.height&&this.elem.setAttribute("height",a.height)},remove:function(){d.remove(this.elem),this._remove&&this._remove()}}),m=l.extend({name:"card",attrs:{frameborder:"0",scrolling:"no",allowtransparency:"true",allowfullscreen:"true"},style:{width:"1px",height:"0px",border:"none",position:"absolute",visibility:"hidden"}});k.createCard=function(a,b,f){if(!j.EMB_POST_MESSAGE)return null;if(!c.isElement(a)||!c.isElement(a.parentNode))return null;if(k.rendering(a))return null;var g={};if(b&&c.isFunction(b.off)&&(f=b,b=null),!c.isNone(b)&&b.url)g=b;else if(c.each(["type","via","chrome","theme","image","description","embed","controls","analytics"],function(b){var e=d.data(a,"card-"+b);c.isNone(e)||(g[b]=e)}),"BLOCKQUOTE"===a.nodeName){var h,i=d.child(a,"h4"),l=d.child(a,"p");if(c.isNone(i)){if(!l)return!1;var n=a.getElementsByTagName("a");if(0===n.length)return!1;h=n[n.length-1],g.url=h.getAttribute("href")}else h=d.child(i,"a"),g.url=h.getAttribute("href"),g.title=d.text(h),g.description=c.isNone(l)?"0":d.text(l)}else"A"===a.nodeName&&(g.url=a.getAttribute("href"));var o,p,q;if(c.each(document.getElementsByTagName("meta"),function(a){q=[a.getAttribute("name"),a.getAttribute("property")],c.contains(q,"twitter:site")?p=a.getAttribute("content"):c.contains(q,"twitter:creator")&&(o=a.getAttribute("content"))}),o?g.twitter_via=o:p&&(g.twitter_via=p),!g.url)return null;var r=e.parse(g.url);if(!r.valid())return null;g.url=r.url;var s={url:g.url};c.isNone(g.type)||(s.type=g.type);var t=new m(s,f);t.send("card.content",g);var u=a.parentNode;return u&&u.offsetWidth&&(t.elem.style.width=u.offsetWidth>600?"600px":u.offsetWidth+"px"),u.insertBefore(t.elem,a),t.on("card.repeat",function(a){var b={url:a.url,via:document.location.toString()};a.embed&&(b.embed=a.embed),k.createCardModal(b,f)}),t.on("modal.stats",function(a){k.createStatsModal(a,f)}),t.on("card.ready",function(){t.ready()}),t.on("card.rendered",function(e){return"error"===e.name?(t.remove(),!1):b&&c.isArray(b.types)&&b.types.length>0&&!c.contains(b.types,e.type)?(t.remove(),!1):(t.rendered=!0,t.elem.style.display="block",t.elem.style.margin="10px auto",t.elem.style.visibility="visible",t.elem.style.position="relative",t.elem.width="600",t.elem.height=e.height?e.height:"300",t.elem.style.width=null,t.elem.style.height=null,t.elem.style.maxWidth="99%",t.elem.style.minWidth="200px",void d.remove(a))}),t};var n=l.extend({name:"button",attrs:{frameborder:"0",scrolling:"no",allowtransparency:"true",height:"20",width:"80"},style:{border:"none"}});k.createButton=function(a,b){if(!c.isElement(a))return null;if(k.rendering(a))return null;var e=d.data(a,"url");c.isNone(e)&&(e=document.location.toString());var g,h={url:e};c.each(["theme","target","lang"],function(b){g=d.data(a,b),c.isNone(g)||(h[b]=g)});var i=f.window.center(635,500);h.left=i.left,h.top=i.top;var j=new n({url:e},b);return j.replace(a),j.on("button.click",c.bind(function(){f.window.innerWidth()<=768||f.mobile()?window.location="http://embed.ly/code?url="+encodeURIComponent(h.url):k.createCardModal(this,b)},h)),j.send("button.data",h),j.on("button.ready",function(){j.ready()}),j};var o=l.extend({name:"modal",attrs:{frameborder:"0",allowtransparency:"true"},style:{border:"none",position:"fixed",top:"0",left:"0",zIndex:"2147483647"},after:function(){this.elem.style.width=f.window.innerWidth()+"px",this.elem.style.height=f.window.innerHeight()+"px"}});k.createCardModal=function(a,b){if(c.isNone(a)&&(a={url:document.location.toString()}),c.isNone(a.url)&&(a.url=document.location.toString()),"window"===a.target)return f.open("http://cdn.embedly.com/widgets/embed?url="+encodeURIComponent(a.url),"Embed Code",635,500),!1;a.t="card";var e=new o(a,b);return e.append(document.body),d.addEvent(window,"resize",function(){e.elem.style.width=f.window.innerWidth()+"px",e.elem.style.height=f.window.innerHeight()+"px"}),e.on("modal.close",function(){document.body.removeChild(e.elem)}),e.on("modal.ready",function(){e.ready()}),e},k.createStatsModal=function(a,b){a.t="stats";var c=new o(a,b);c.append(document.body),c.on("modal.close",function(){document.body.removeChild(c.elem)}),c.on("modal.ready",function(){c.ready()}),d.addEvent(window,"resize",function(){c.elem.style.width=f.window.innerWidth()+"px",c.elem.style.height=f.window.innerHeight()+"px"})};var p=l.extend({name:"xcomm",attrs:{frameborder:"0",allowtransparency:"true"},style:{border:"none",position:"absolute",top:"-9999em",width:"10px",height:"10px"},secure:!0});k.createComm=function(a){var b=new p({},a);return b.append(document.body),b.on("xcomm.ready",function(){b.ready()}),b},b.exports=k},{"./a.js":1,"./browser.js":2,"./class.js":3,"./dom.js":5,"./json.js":7,"./urlparse.js":14,"./utils.js":15,conf:"AqyHQT"}],7:[function(a,b){var c=a("./browser.js");b.exports=function(a){function b(a){return 10>a?"0"+a:a}function c(a){return h.lastIndex=0,h.test(a)?'"'+a.replace(h,function(a){var b=i[a];return"string"==typeof b?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function d(a,e){var h,i,j,k,l,m=f,n=e[a];switch(n&&"[object Date]"===Object.prototype.toString.call(n)&&(n=isFinite(this.valueOf())?this.getUTCFullYear()+"-"+b(this.getUTCMonth()+1)+"-"+b(this.getUTCDate())+"T"+b(this.getUTCHours())+":"+b(this.getUTCMinutes())+":"+b(this.getUTCSeconds())+"Z":null),typeof n){case"string":return c(n);case"number":return isFinite(n)?String(n):"null";case"boolean":case"null":return String(n);case"object":if(!n)return"null";if(f+=g,l=[],"[object Array]"===Object.prototype.toString.apply(n)){for(k=n.length,h=0;k>h;h+=1)l[h]=d(h,n)||"null";return j=0===l.length?"[]":f?"[\n"+f+l.join(",\n"+f)+"\n"+m+"]":"["+l.join(",")+"]",f=m,j}for(i in n)Object.prototype.hasOwnProperty.call(n,i)&&(j=d(i,n),j&&l.push(c(i)+(f?": ":":")+j));return j=0===l.length?"{}":f?"{\n"+f+l.join(",\n"+f)+"\n"+m+"}":"{"+l.join(",")+"}",f=m,j}}var e={};if(window.JSON&&JSON.parse&&JSON.stringify)return window.JSON;var f,g,h=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,i={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"};return e.stringify=function(a,b){var c;if(f="",g="","number"==typeof b)for(c=0;b>c;c+=1)g+=" ";else"string"==typeof b&&(g=b);return d("",{"":a})},e.parse=function(){var b,c,d,e,f={'"':'"',"\\":"\\","/":"/",b:"\b",f:"\f",n:"\n",r:"\r",t:" "},g=function(c){a.console.error({name:"SyntaxError",message:c,at:b,text:d})},h=function(a){return a&&a!==c&&g("Expected '"+a+"' instead of '"+c+"'"),c=d.charAt(b),b+=1,c},i=function(){var a,b="";for("-"===c&&(b="-",h("-"));c>="0"&&"9">=c;)b+=c,h();if("."===c)for(b+=".";h()&&c>="0"&&"9">=c;)b+=c;if("e"===c||"E"===c)for(b+=c,h(),("-"===c||"+"===c)&&(b+=c,h());c>="0"&&"9">=c;)b+=c,h();return a=+b,isFinite(a)?a:void g("Bad number")},j=function(){var a,b,d,e="";if('"'===c)for(;h();){if('"'===c)return h(),e;if("\\"===c)if(h(),"u"===c){for(d=0,b=0;4>b&&(a=parseInt(h(),16),isFinite(a));b+=1)d=16*d+a;e+=String.fromCharCode(d)}else{if("string"!=typeof f[c])break;e+=f[c]}else e+=c}g("Bad string")},k=function(){for(;c&&" ">=c;)h()},l=function(){switch(c){case"t":return h("t"),h("r"),h("u"),h("e"),!0;case"f":return h("f"),h("a"),h("l"),h("s"),h("e"),!1;case"n":return h("n"),h("u"),h("l"),h("l"),null}g("Unexpected '"+c+"'")},m=function(){var a=[];if("["===c){if(h("["),k(),"]"===c)return h("]"),a;for(;c;){if(a.push(e()),k(),"]"===c)return h("]"),a;h(","),k()}}g("Bad array")},n=function(){var a,b={};if("{"===c){if(h("{"),k(),"}"===c)return h("}"),b;for(;c;){if(a=j(),k(),h(":"),Object.hasOwnProperty.call(b,a)&&g('Duplicate key "'+a+'"'),b[a]=e(),k(),"}"===c)return h("}"),b;h(","),k()}}g("Bad object")};return e=function(){switch(k(),c){case"{":return n();case"[":return m();case'"':return j();case"-":return i();default:return c>="0"&&"9">=c?i():l()}},function(a){var f;return d=a,b=0,c=" ",f=e(),k(),c&&g("Syntax error"),f}}(),e}(c)},{"./browser.js":2}],8:[function(a,b){var c=a("./browser.js"),d=a("./utils.js"),e=a("./dom.js"),f={_data:null};f.COOKIE_NAME="em_p_uid",f.format=function(a){return a&&d.isObject(a)?d.map(a,function(a,b){return b+":"+a}).sort().join("|"):null},f.parse=function(a){if(!a)return null;var b;return d.reduce(a.split("|"),function(a,c){return null===a?null:(b=c.split(":"),2!==b.length?null:(a[b[0]]=b[1],a))},{})},f.timestamp=function(a){var b;try{b=parseInt(a,10)}catch(c){return!1}return b},f.get=function(){var a=c.cookie.get(f.COOKIE_NAME);if(d.isNone(a))return f.set();var b=f.parse(a),e=f.timestamp(b.t);return e===!1?f.set():d.getTimestamp()-e>15552e6?f.set({u:b.u,l:b.l}):b},f.set=function(a){var b={u:d.getUUID(),t:d.getTimestamp(),l:0};a&&(b=d.extend(b,a));var e=f.format(b);return c.cookie.set(f.COOKIE_NAME,e,365,"https:"===window.location.protocol),e=c.cookie.get(f.COOKIE_NAME),d.isNone(e)?null:f.parse(e)},f.update=function(a){var b=f.get();return b?(b=d.extend(b,a),f.set(b)):!1},f.data=function(){if(f._data)return f._data;var a={mt:d.getTimestamp(),mr:document.referrer,msw:c.window.innerWidth(),msh:c.window.innerHeight()},b=f.get();return b?(a.muu=b.u,a.mut=b.t,a.mul=b.l):a.muu=0,f._data=a,f.update({l:d.getTimestamp()}),f._data},f.send=function(a,b){if(!b||!d.isElement(b.elem))return!1;var c=d.extend(f.data(),{}),g=e.rect(b.elem);g&&(c.mft=g.top,c.mfl=g.left,c.mfw=g.width,c.mfh=g.height),b.send(a,c)},b.exports=f},{"./browser.js":2,"./dom.js":5,"./utils.js":15}],9:[function(a,b){var c=a("./dom.js"),d=a("./utils"),e={_event:null,_observer:null};e.nodeNames=["iframe","a","blockquote"],e.html=function(){var a=document.getElementsByTagName("html");return 0===a.length?null:a[0]},e.recurse=function(a){var b=[];return d.isElement(a)&&b.push(a),d.reduce(a.childNodes,function(a,b){return d.isElement(b)?a.concat(e.recurse(b)):a},b)},e.observer=function(a){var b=e.html();if(null===b)return!1;if(!window.MutationObserver)return!1;e._observer=new window.MutationObserver(function(b){d.each(b,function(b){if("childList"===b.type&&b.addedNodes){var c=Array.prototype.slice.call(b.addedNodes);d.each(c,function(b){d.each(e.recurse(b),function(b){b.nodeName&&d.contains(e.nodeNames,b.nodeName.toLowerCase())&&a.notify("mutation.insert."+b.nodeName.toLowerCase(),b)})})}})});var c={childList:!0,subtree:!0};return e._observer.observe(b,c),!0},e.events=function(a){var b=e.html();return null===b?!1:(e._event=function(b){d.each(e.recurse(b.target),function(b){b.nodeName&&d.contains(e.nodeNames,b.nodeName.toLowerCase())&&a.notify("mutation.insert."+b.nodeName.toLowerCase(),b)})},c.addEvent(b,"DOMNodeInserted",e._event),!0)},e.stop=function(){var a=e.html();return null===a?!1:(e._event&&(c.detachEvent(a,"DOMNodeInserted",e._event),e._event=null),void(e._observer&&(e._observer.disconnect(),e._observer=null)))},e.connect=function(a){return e._event||e._observer?!1:void(e.observer(a)||e.events(a))},b.exports=e},{"./dom.js":5,"./utils":15}],10:[function(a,b){var c=a("./utils.js"),d=a("./urlparse.js"),e=a("./comms.js"),f=a("conf"),g={started:!1};g.connect=function(a,b){var h=d.getDomain(document.location.toString());if(!b&&f.PAGE_PROGRESS_DOMAINS&&!c.contains(f.PAGE_PROGRESS_DOMAINS,h))return!1;if(g.started)return!1;g.started=!0;var i=function(){a.notify("xcomm.page.progress")};e.started?i():(e.connect(a),a.one("xcomm.ready",i))},b.exports=g},{"./comms.js":4,"./urlparse.js":14,"./utils.js":15,conf:"AqyHQT"}],11:[function(a,b){var c=a("./utils.js"),d=a("./dom.js"),e=function(){this.init()};e.prototype.init=function(){var a=this;document.addEventListener?document.addEventListener("DOMContentLoaded",function(){document.removeEventListener("DOMContentLoaded",arguments.callee,!1),a.ready()},!1):document.attachEvent&&(document.attachEvent("onreadystatechange",function(){"complete"===document.readyState&&(document.detachEvent("onreadystatechange",arguments.callee),a.ready())}),document.documentElement.doScroll&&window===window.top&&!function(){if(!a.isReady){try{document.documentElement.doScroll("left")}catch(b){return void setTimeout(arguments.callee,0)}a.ready()}}()),d.addEvent(window,"load",a.ready)},e.prototype.ready=function(){return this.isReady?!1:(this.isReady=!1,void(this.callback&&this.callback()))},e.prototype.bind=function(a){this.isReady&&a(),this.callback=a},e.prototype.elem=function(a,b,c){var e=!1,f=function(){e===!1&&(e=!0,b.call(c))};a.onload=f,d.addEvent(a,"load",f),a.onreadystatechange=function(){var b=a.readyState;("loaded"===b||"complete"===b)&&(a.onreadystatechange=null,f())}},e.prototype.firstNode=function(){var a=document.getElementsByTagName("head")[0],b=d.child(a,"link");if(b)return b;var c=d.child(a,"style");if(c)return c;var e=d.child(a,"script");return e?e:null},e.prototype.script=function(a,b,d,e){var f=this.firstNode(),g=document.createElement("script");g.type="text/javascript",g.src=a,c.isNone(e)||(g.async=1),this.elem(g,b,d),f.parentNode.insertBefore(g,f)},e.prototype.css=function(a,b,c){var d=this.firstNode(),e=document.createElement("link");e.type="text/css",e.rel="stylesheet",e.href=a,this.elem(e,b,c),d.parentNode.insertBefore(e,d)},b.exports=new e},{"./dom.js":5,"./utils.js":15}],12:[function(a,b){var c=a("./urlparse.js"),d={data:{},results:{},enabled:!1};d.show=function(a){var b=d.data[a],c=d.results[a];d.hub.notify("recommend.show",b,c)},d.add=function(a){var b=c.getQuery(a.elem.src);d.data[b.url]=a,d.enabled&&(a.on("media.stats.recommend",function(c){d.results[c.url]=c.results,a.on("pause",function(){d.show(b.url)}),a.send("addEventListener",{context:"player.js",version:"0.0.8",method:"addEventListener",value:"pause",listener:a.elem.src})}),a.send("media.stats.recommend",{key:b.key,url:b.url}))},d.connect=function(a){a.on("recommend",function(){d.enabled=!0}),a.on("recommend.add",function(a){d.add(a)}),d.hub=a},b.exports=d},{"./urlparse.js":14}],13:[function(a,b){var c=a("./utils.js"),d=a("./urlparse.js"),e=a("conf"),f={};f.youtube={schema:"youtube",re:/youtube\.com\/embed\/([^\/?#]+)/i,url:function(a){var b=f.youtube.re.exec(a);return 2!==b.length?a:"http://www.youtube.com/watch?v="+b[1]}},f.vimeo={schema:"vimeo",re:/player\.vimeo\.com\/video\/([^\/?#]+)/i,url:function(a){var b=f.vimeo.re.exec(a);return 2!==b.length?a:"http://vimeo.com/"+b[1]}},f.soundcloud={schema:"soundcloud",re:/w\.soundcloud\.com\/player\/\?/,url:function(a){var b=d.getQuery(a);if(b.url){var c=/api\.soundcloud\.com\/tracks\/([^\/?#]+)/.exec(b.url);if(2===c.length)return"https://soundcloud.com/track/"+c[1]}return a}},f.providers=[f.youtube,f.vimeo,f.soundcloud],f.provider=function(a){return c.reduce(f.providers,function(b,c){return c.re.test(a)?c:b},null)},f.replace=function(a,b){if(c.isNone(a)||!c.isElement(a))return null;if("IFRAME"!==a.nodeName)return null;if(!a.src||!c.isString(a.src))return null;if(!b.key)return!1;var g=a.src;g=g.replace(/&/g,"&");var h=f.provider(g);if(null===h)return null;var i="https:"===window.location.protocol?"https:":"http:";"file://"===g.substr(0,7)&&(g=g.substr(5)),"//"===g.substr(0,2)&&(g=i+g);var j=c.extend({},b,{url:h.url(g),src:g,schema:h.schema,type:"text/html"}),k=i+"//cdn.embedly.com/widgets/";e.EMB_DEBUG&&(k=e.EMB_FRAME_SRC);var l=k+"media.html?"+d.createQuery(j);return a.src=l,a},b.exports=f},{"./urlparse.js":14,"./utils.js":15,conf:"AqyHQT"}],14:[function(a,b){var c=a("./utils.js"),d={};d.createQuery=function(a){var b=[],d="";return a&&c.isObject(a)&&!c.isEmptyObject(a)?(c.each(a,function(a,c){b.push(encodeURIComponent(c)+"="+encodeURIComponent(a))}),b.sort(),b.join("&")):d},d.parseQuery=function(a){var b={};if(!a||!c.isString(a))return b;("#"===a.substr(0,1)||"?"===a.substr(0,1))&&(a=a.substr(1));var d=a.split("&");return c.each(d,function(a){if(!a)return!0;var c=a.split("="),d=decodeURIComponent(c[0]);b[d]=1===c.length?"":decodeURIComponent(2===c.length?c[1]:c.slice(1).join("="))}),b},d.getQuery=function(a){if(!a||!c.isString(a))return{};var b=a.split("?");return 2===b.length?d.parseQuery(b[1]):b.length>2?d.parseQuery(b.slice(1).join("?")):{}},d.appendQuery=function(a,b){if(!a||!c.isString(a))return null;var e=a.split("?"),f=e[0];if(!b||!c.isObject(b)||c.isEmptyObject(b))return a;var g=d.getQuery(a);return g=c.extend(g,b),c.isEmptyObject(g)?a:[f,d.createQuery(g)].join("?")},d.removeQuery=function(a,b){if(!a||!c.isString(a))return null;var e=a.split("?"),f=e[0],g=d.getQuery(a);return g.hasOwnProperty(b)&&delete g[b],c.isEmptyObject(g)?f:[f,d.createQuery(g)].join("?")},d.getOrigin=function(a){if(!a||!c.isString(a))return null;if(!/^https?:\/\//.test(a))return null;var b=a.split("/").slice(0,3).join("/");return-1===b.indexOf(".")?null:b},d.getDomain=function(a){var b=d.getOrigin(a);return b?b.replace(/^https?:\/\//,""):null},d.Parsed=function(a,b){this.init(a,b)},d.Parsed.prototype.init=function(a,b){this.original=a,this.url=b,this._valid=!1,this.url=b},d.Parsed.prototype.valid=function(a){return(a===!0||a===!1)&&(this._valid=a),this._valid},d.parse=function(a){var b=a,e="https:"===window.location.protocol?"https:":"http:";a=a?c.trim(a):a;var f=new d.Parsed(b,a);return a?/^https?:\/\/[^\/]+\.[^\/]/i.test(a)?(f.valid(!0),f):/^\w+:/i.test(a)?f:"#"===a[0]?f:/^\/\/[^\/]+\.[^\/]/i.test(a)?(f.valid(!0),f.url=e+a,f):/^\/([^\/]+|$)/i.test(a)?(f.valid(!0),f.url=d.getOrigin(window.location.toString())+a,f):/^[^\/]+\.[^\/]/i.test(a)?(f.valid(!0),f.url="http://"+a,f):f:f},d.addHash=function(a,b){return-1===a.indexOf("#")?a+"#"+b:a+"&"+b},b.exports=d},{"./utils.js":15}],15:[function(a,b){var c=a("conf"),d={},e={},f=Array.prototype,g=Object.prototype,h=Function.prototype,i=(f.push,f.slice),j=(f.concat,g.toString),k=f.forEach,l=(f.map,f.reduce),m=(f.reduceRight,f.filter,f.every),n=(f.some,f.indexOf),o=(f.lastIndexOf,Array.isArray,Object.keys,h.bind);d.identity=function(a){return a},d.each=function(a,b,c){if(null!=a)if(k&&a.forEach===k)a.forEach(b,c);else if(a.length===+a.length){for(var d=0,f=a.length;f>d;d++)if(d in a&&b.call(c,a[d],d,a)===e)return}else for(var h in a)if(g.hasOwnProperty.call(a,h)&&b.call(c,a[h],h,a)===e)return},d.map=function(a,b,c){var e=[];return null==a?e:Array.prototype.map&&a.map===Array.prototype.map?a.map(b,c):(d.each(a,function(a,d,f){e[e.length]=b.call(c,a,d,f)}),e)},d.reduce=function(a,b,c,e){var f=arguments.length>2;if(null==a&&(a=[]),l&&a.reduce===l)return e&&(b=d.bind(b,e)),f?a.reduce(b,c):a.reduce(b); +if(d.each(a,function(a,d,g){f?c=b.call(e,c,a,d,g):(c=a,f=!0)}),!f)throw new TypeError("Reduce of empty array with no initial value");return c},d.zip=function(a){return d.map(a[0],function(b,c){return b.map(a,function(a){return a[c]})})},d.extend=function(a){return d.each(Array.prototype.slice.call(arguments,1),function(b){for(var c in b)void 0!==b[c]&&(a[c]=b[c])}),a},d.contains=function(a,b){if(!n){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return!0;return!1}return a.indexOf(b)>-1},d.every=function(a,b,c){b||(b=d.identity);var f=!0;return null==a?f:m&&a.every===m?a.every(b,c):(d.each(a,function(a,d,g){return(f=f&&b.call(c,a,d,g))?void 0:e}),!!f)},d.indexOf=function(a,b){if(null==a)return-1;var c=0,d=a.length;if(n&&a.indexOf===n)return a.indexOf(b);for(;d>c;c++)if(a[c]===b)return c;return-1};var p=function(){};d.bind=function(a,b){var c,e;if(o&&a.bind===o)return o.apply(a,i.call(arguments,1));if(!d.isFunction(a))throw new TypeError;return c=i.call(arguments,2),e=function(){if(!(this instanceof e))return a.apply(b,c.concat(i.call(arguments)));p.prototype=a.prototype;var d=new p;p.prototype=null;var f=a.apply(d,c.concat(i.call(arguments)));return Object(f)===f?f:d}},d.get=function(a,b,c){if(c=d.isNone(c)?null:c,d.isNone(b)||!d.isString(b)||!a)return c;if(""===b)return a;var e=b.split("."),f=e.splice(0,1)[0];return a.hasOwnProperty(f)?d.get(a[f],e.join("."),c):c},d.isFunction=function(a){try{return/^\s*\bfunction\b/.test(a)}catch(b){return!1}},d.isNone=function(a){return null===a||void 0===a},d.isString=function(a){return"[object String]"===j.call(a)},d.isNumber=function(a){return"[object Number]"===j.call(a)},d.isDate=function(a){return"[object Date]"===j.call(a)},d.isObject=function(a){return"[object Object]"===j.call(a)},d.isArray=function(a){return"[object Array]"===j.call(a)},d.isElement=function(a){return!d.isNone(a)&&!d.isNone(a.nodeType)&&1===a.nodeType},d.isEmptyObject=function(a){if(d.isObject(a)){for(var b in a)if(g.hasOwnProperty.call(a,b))return!1;return!0}return!1},d.bool=function(a){return d.isNone(a)?null:"true"===a||"1"===a||1===a||a===!0?!0:"false"===a||"0"===a||0===a||a===!1?!1:null},d.assert=function(a,b){if(!a)throw b||"Assertion Failed"},d.getUUID=function(){return"xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx".replace(/[xy]/g,function(a){var b=16*Math.random()|0,c="x"===a?b:3&b|8;return c.toString(16)})},d.getTimestamp=function(){var a=new Date;return a.getTime()},d.trim=function(a){return a.replace(/^\s+|\s+$/g,"")},d.capitalize=function(a){return a.charAt(0).toUpperCase()+a.substr(1)},d.camelCase=function(a){var b=a.split("-");return b.length>1&&(a=b[0],a+=d.map(b.slice(1),function(a){return a[0].toUpperCase()+a.substr(1)}).join("")),a},d.truncate=function(a,b){return a?(b=b?b:50,a.lengthc;c++)b=31*b+a.charCodeAt(c)<<0;return(Math.pow(2,31)+b).toString()},d.rgbToHex=function(a,b,c){return"#"+((1<<24)+(a<<16)+(b<<8)+c).toString(16).slice(1)},c.EMB_DEBUG===!0&&(window._=d),b.exports=d},{conf:"AqyHQT"}],16:[function(a,b){var c=a("./utils.js"),d=a("./dom.js"),e=a("./browser.js"),f=function(){this.init()};f.prototype.init=function(){this._elements=[],this._listening=!1},f.prototype.viewable=function(a){if(!a.getBoundingClientRect)return!0;var b;try{b=a.getBoundingClientRect()}catch(c){return!1}return b.bottom>=0&&b.right>=0&&b.top<=(window.innerHeight||document.documentElement.clientHeight)&&b.left<=(window.innerWidth||document.documentElement.clientWidth)},f.prototype.check=function(){this.freeze=!0;var a=[];c.each(this._elements,c.bind(function(b,c){if(this.viewable(b.elem)){try{b.func.call(this)}catch(d){e.console.log(d)}a.push(c)}},this)),c.each(a,function(a){this._elements.splice(a,1)},this),0===this._elements.length&&this.stop(),this.freeze=!1},f.prototype.stop=function(){try{d.detachEvent(window,"DOMContentLoaded",this.handler),d.detachEvent(window,"load",this.handler),d.detachEvent(window,"resize",this.handler),d.detachEvent(window,"scroll",this.handler)}catch(a){}this.handler=null,this._listening=!1},f.prototype.listen=function(){return this._listening?!1:(this._listening=!0,this.handler=c.bind(function(){!this.freeze&&this._elements.length&&this.check()},this),d.addEvent(window,"DOMContentLoaded",this.handler),d.addEvent(window,"load",this.handler),d.addEvent(window,"resize",this.handler),void d.addEvent(window,"scroll",this.handler))},f.prototype.on=function(a,b,c){"viewable"===a&&(this._elements.push({elem:b,func:c}),this.listen(),this.check())},b.exports=f},{"./browser.js":2,"./dom.js":5,"./utils.js":15}],conf:[function(a,b){b.exports=a("AqyHQT")},{}],AqyHQT:[function(a,b){!function(a){a.EMB_DEBUG=!1,a.EMB_HTTPS="https:"===window.location.protocol?!0:!1,a.EMB_ORIGIN=(a.EMB_HTTPS?"https":"http")+"://cdn.embedly.com",a.EMB_FRAME_SRC=a.EMB_ORIGIN+"/widgets/",a.EMB_SECURE_FRAME_SRC="https://cdn.embedly.com/widgets/",a.EMB_POST_MESSAGE=!!window.postMessage,a.EMB_PROGRESS=!0,a.EMB_APP_API="https://app.embed.ly",a.EMB_API_KEY="fd92ebbc52fc43fb98f69e50e7893c13";var b=window.location.pathname.split(".")[0].split("/");a.EMB_GROUP=b[b.length-1].toLowerCase(),a.PAGE_PROGRESS_DOMAINS=[]}("undefined"==typeof b?this.conf={}:b.exports)},{}],19:[function(a){if(window.embedly&&window.embedly.look)return window.embedly.look(),!1;var b=a("./common/iframe.js"),c=a("./common/browser.js"),d=a("./common/utils.js"),e=a("./common/a.js"),f=a("./common/dom.js"),g=a("./common/ready.js"),h=a("./common/mutations.js"),i=a("./common/swap.js"),j=a("./common/meta.js"),k=a("./common/json.js"),l=a("./common/viewport.js"),m=a("./common/page.js"),n=a("./common/recommend.js"),o=new e,p=new l;n.connect(o);var q=function(){var a=/emb_(\d+)/.exec(c.location.hash());return a?a[1]:null},r={cardSelectors:[{selector:".embedly-card"}],buttonSelectors:[".embedly-button"],analytics:null,recommend:!1,shared:q()},s=function(a){var b;try{b=k.parse(a.data)}catch(d){return c.console.error(d),!1}o.notify("window.message",a,b)};f.addEvent(window,"message",s);var t=function(a,c,e){var f;if(d.isFunction(c)&&(e=c,c={}),d.isString(a))return".embedly-card"===a?!1:(r.cardSelectors.push({selector:a}),B(),!0);if(!d.isElement(a)&&d.isObject(a)){if(!a.selector&&!a.types)return!1;var g={};if(d.isArray(a.types)&&a.types.length>0&&(g.types=a.types),a.selector)g.selector=a.selector,r.cardSelectors.push(g);else{var h=r.cardSelectors.reduce(function(a,b){return".embedly-card"===b.selector?b:a},{});if(!h)return!1;h.types=g.types}}return!d.isElement(a)||"a"!==a.nodeName.toLowerCase()&&"blockquote"!==a.nodeName.toLowerCase()||(f=b.createCard(a,c,o)),f&&(f.one("card.rendered",function(){o.notify("card.rendered",f.elem,f),p.on("viewable",f.elem,function(){f.send("card.view")})}),f.on("resize",function(){o.notify("card.resize",f.elem,f)})),d.isFunction(e)&&e.call(f,f),o.notify("card.created",f),f},u=function(a){var c;return d.isString(a)?(r.buttonSelectors.push(a),B(),!0):(d.isElement(a)&&"a"===a.nodeName.toLowerCase()&&(c=b.createButton(a,o)),o.notify("button.created",c),c)},v=function(a,c){var e;e=d.isString(a)?{url:a}:a;var f=b.createCardModal(e,o);return d.isFunction(c)&&c.call(f,f),f},w=function(a){if("1"===f.data(a,"connected"))return!1;f.data(a,"connected","1");var c=b.connect({elem:a},o);c.one("media.ready",function(){c.ready(),p.on("viewable",c.elem,function(){c.send("media.view")}),o.notify("recommend.add",c),o.notify("media.ready",c)}),c.send("media.ready")},x=function(a){return a&&a.key?(r.analytics=a,void B()):!1},y=function(){o.notify("recommend"),B()},z=function(a,b){return"."===a.substr(0,1)?f.hasClass(b,a.substr(1))?!0:!1:d.contains(f.all(a),b)?!0:!1},A=function(a){if(("A"===a.nodeName||"BLOCKQUOTE"===a.nodeName)&&d.each(r.cardSelectors,function(b){z(b.selector,a)&&t(a,b)}),"A"===a.nodeName&&d.each(r.buttonSelectors,function(b){z(b,a)&&u(a)}),"IFRAME"===a.nodeName)if("embedly-embed"===a.className)w(a);else if(a.src&&/\/\/cdn\.embedly\.com\/widgets\/media\.html/.test(a.src))w(a);else if(null!==r.analytics&&r.analytics.replace){var b=i.replace(a,r.analytics);null!==b&&w(b)}},B=function(){d.each(r.cardSelectors,function(a){d.each(f.all(a.selector),function(a){A(a)})}),d.each(r.buttonSelectors,function(a){d.each(f.all(a),function(a){A(a)})}),d.each(f.all("iframe"),function(a){A(a)}),o.notify("look.done")};o.on("mutation.insert.a",A),o.on("mutation.insert.blockquote",A),o.on("mutation.insert.iframe",A),o.on("media.ready",function(a){j.send("media.meta",a)}),o.on("card.rendered",function(a,b){j.send("card.meta",b)}),o.on("card.rendered",function(a,b){if(!r.shared)return!1;if(!b.query||!b.query.url)return!1;var e=d.hash(b.query.url);return e!==r.shared?!1:(r.shared=null,void setTimeout(function(){var a=f.rect(b.elem);return a&&a.top?void c.animateScroll(a.top-5,500):!1},500))});var C=function(a,b){o.on(a,b)},D=function(a,b){o.off(a,b)},E=function(){f.detachEvent(window,"message",s),h.stop(),o.data={},window.embedly=null},F=function(){var a=Array.prototype.slice.call(arguments,0);if(0===a.length)return null;var b=a.splice(0,1)[0];switch(b){case"card":return t.apply(window,a);case"button":return u.apply(window,a);case"modal":return v.apply(window,a);case"look":return B.apply(window,a);case"on":return C.apply(window,a);case"off":return D.apply(window,a);case"kill":return E.apply(window,a);case"analytics":return x.apply(window,a);case"recommend":return y.apply(window,a)}return null},G=[];window.embedly&&d.isFunction(window.embedly)&&d.isArray(window.embedly.q)&&(G=window.embedly.q),window.embedly=function(){return F.apply(window,arguments)},window.embedly.card=function(a){return t(a)},window.embedly.button=function(a){return u(a)},window.embedly.modal=function(a){return v(a)},window.embedly.look=function(a){return B(a)},d.each(G,function(a){window.embedly.apply(window,a)}),h.connect(o),m.connect(o),g.bind(B),B(),d.isFunction(window.onEmbedlyReady)&&window.onEmbedlyReady.apply(this,[window.embedly])},{"./common/a.js":1,"./common/browser.js":2,"./common/dom.js":5,"./common/iframe.js":6,"./common/json.js":7,"./common/meta.js":8,"./common/mutations.js":9,"./common/page.js":10,"./common/ready.js":11,"./common/recommend.js":12,"./common/swap.js":13,"./common/utils.js":15,"./common/viewport.js":16}]},{},[19])}(); \ No newline at end of file diff --git a/app/assets/javascripts/hogan-2.0.0.js b/app/assets/javascripts/lib/hogan-2.0.0.js similarity index 100% rename from app/assets/javascripts/hogan-2.0.0.js rename to app/assets/javascripts/lib/hogan-2.0.0.js diff --git a/app/assets/javascripts/scroll/jquery-ui-1.8.23.custom.min.js b/app/assets/javascripts/lib/jquery-ui-1.8.23.custom.min.js similarity index 100% rename from app/assets/javascripts/scroll/jquery-ui-1.8.23.custom.min.js rename to app/assets/javascripts/lib/jquery-ui-1.8.23.custom.min.js diff --git a/app/assets/javascripts/jquery.lettering.js b/app/assets/javascripts/lib/jquery.lettering.js similarity index 100% rename from app/assets/javascripts/jquery.lettering.js rename to app/assets/javascripts/lib/jquery.lettering.js diff --git a/app/assets/javascripts/scroll/jquery.mCustomScrollbar.min.js b/app/assets/javascripts/lib/jquery.mCustomScrollbar.min.js similarity index 100% rename from app/assets/javascripts/scroll/jquery.mCustomScrollbar.min.js rename to app/assets/javascripts/lib/jquery.mCustomScrollbar.min.js diff --git a/app/assets/javascripts/scroll/jquery.mousewheel.min.js b/app/assets/javascripts/lib/jquery.mousewheel.min.js similarity index 100% rename from app/assets/javascripts/scroll/jquery.mousewheel.min.js rename to app/assets/javascripts/lib/jquery.mousewheel.min.js diff --git a/app/assets/javascripts/jquery.purr.js b/app/assets/javascripts/lib/jquery.purr.js similarity index 100% rename from app/assets/javascripts/jquery.purr.js rename to app/assets/javascripts/lib/jquery.purr.js diff --git a/app/assets/javascripts/jquery.roundabout.min.js b/app/assets/javascripts/lib/jquery.roundabout.min.js similarity index 100% rename from app/assets/javascripts/jquery.roundabout.min.js rename to app/assets/javascripts/lib/jquery.roundabout.min.js diff --git a/app/assets/javascripts/typing/jquery.typing-0.2.0.min.js b/app/assets/javascripts/lib/jquery.typing-0.2.0.min.js similarity index 100% rename from app/assets/javascripts/typing/jquery.typing-0.2.0.min.js rename to app/assets/javascripts/lib/jquery.typing-0.2.0.min.js diff --git a/app/assets/images/mCSB_buttons.png b/app/assets/javascripts/lib/mCSB_buttons.png similarity index 100% rename from app/assets/images/mCSB_buttons.png rename to app/assets/javascripts/lib/mCSB_buttons.png diff --git a/app/assets/javascripts/socket.io.js b/app/assets/javascripts/lib/socket.io.js similarity index 100% rename from app/assets/javascripts/socket.io.js rename to app/assets/javascripts/lib/socket.io.js diff --git a/app/assets/javascripts/typeahead.js b/app/assets/javascripts/lib/typeahead.js similarity index 100% rename from app/assets/javascripts/typeahead.js rename to app/assets/javascripts/lib/typeahead.js diff --git a/app/assets/javascripts/orderedLibraries/backbone.js b/app/assets/javascripts/orderedLibraries/backbone.js new file mode 100644 index 00000000..a0726ee4 --- /dev/null +++ b/app/assets/javascripts/orderedLibraries/backbone.js @@ -0,0 +1,1571 @@ +// Backbone.js 1.0.0 + +// (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc. +// Backbone may be freely distributed under the MIT license. +// For all details and documentation: +// http://backbonejs.org + +(function(){ + + // Initial Setup + // ------------- + + // Save a reference to the global object (`window` in the browser, `exports` + // on the server). + var root = this; + + // Save the previous value of the `Backbone` variable, so that it can be + // restored later on, if `noConflict` is used. + var previousBackbone = root.Backbone; + + // Create local references to array methods we'll want to use later. + var array = []; + var push = array.push; + var slice = array.slice; + var splice = array.splice; + + // The top-level namespace. All public Backbone classes and modules will + // be attached to this. Exported for both the browser and the server. + var Backbone; + if (typeof exports !== 'undefined') { + Backbone = exports; + } else { + Backbone = root.Backbone = {}; + } + + // Current version of the library. Keep in sync with `package.json`. + Backbone.VERSION = '1.0.0'; + + // Require Underscore, if we're on the server, and it's not already present. + var _ = root._; + if (!_ && (typeof require !== 'undefined')) _ = require('underscore'); + + // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns + // the `$` variable. + Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$; + + // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable + // to its previous owner. Returns a reference to this Backbone object. + Backbone.noConflict = function() { + root.Backbone = previousBackbone; + return this; + }; + + // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option + // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and + // set a `X-Http-Method-Override` header. + Backbone.emulateHTTP = false; + + // Turn on `emulateJSON` to support legacy servers that can't deal with direct + // `application/json` requests ... will encode the body as + // `application/x-www-form-urlencoded` instead and will send the model in a + // form param named `model`. + Backbone.emulateJSON = false; + + // Backbone.Events + // --------------- + + // A module that can be mixed in to *any object* in order to provide it with + // custom events. You may bind with `on` or remove with `off` callback + // functions to an event; `trigger`-ing an event fires all callbacks in + // succession. + // + // var object = {}; + // _.extend(object, Backbone.Events); + // object.on('expand', function(){ alert('expanded'); }); + // object.trigger('expand'); + // + var Events = Backbone.Events = { + + // Bind an event to a `callback` function. Passing `"all"` will bind + // the callback to all events fired. + on: function(name, callback, context) { + if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this; + this._events || (this._events = {}); + var events = this._events[name] || (this._events[name] = []); + events.push({callback: callback, context: context, ctx: context || this}); + return this; + }, + + // Bind an event to only be triggered a single time. After the first time + // the callback is invoked, it will be removed. + once: function(name, callback, context) { + if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this; + var self = this; + var once = _.once(function() { + self.off(name, once); + callback.apply(this, arguments); + }); + once._callback = callback; + return this.on(name, once, context); + }, + + // Remove one or many callbacks. If `context` is null, removes all + // callbacks with that function. If `callback` is null, removes all + // callbacks for the event. If `name` is null, removes all bound + // callbacks for all events. + off: function(name, callback, context) { + var retain, ev, events, names, i, l, j, k; + if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this; + if (!name && !callback && !context) { + this._events = {}; + return this; + } + + names = name ? [name] : _.keys(this._events); + for (i = 0, l = names.length; i < l; i++) { + name = names[i]; + if (events = this._events[name]) { + this._events[name] = retain = []; + if (callback || context) { + for (j = 0, k = events.length; j < k; j++) { + ev = events[j]; + if ((callback && callback !== ev.callback && callback !== ev.callback._callback) || + (context && context !== ev.context)) { + retain.push(ev); + } + } + } + if (!retain.length) delete this._events[name]; + } + } + + return this; + }, + + // Trigger one or many events, firing all bound callbacks. Callbacks are + // passed the same arguments as `trigger` is, apart from the event name + // (unless you're listening on `"all"`, which will cause your callback to + // receive the true name of the event as the first argument). + trigger: function(name) { + if (!this._events) return this; + var args = slice.call(arguments, 1); + if (!eventsApi(this, 'trigger', name, args)) return this; + var events = this._events[name]; + var allEvents = this._events.all; + if (events) triggerEvents(events, args); + if (allEvents) triggerEvents(allEvents, arguments); + return this; + }, + + // Tell this object to stop listening to either specific events ... or + // to every object it's currently listening to. + stopListening: function(obj, name, callback) { + var listeners = this._listeners; + if (!listeners) return this; + var deleteListener = !name && !callback; + if (typeof name === 'object') callback = this; + if (obj) (listeners = {})[obj._listenerId] = obj; + for (var id in listeners) { + listeners[id].off(name, callback, this); + if (deleteListener) delete this._listeners[id]; + } + return this; + } + + }; + + // Regular expression used to split event strings. + var eventSplitter = /\s+/; + + // Implement fancy features of the Events API such as multiple event + // names `"change blur"` and jQuery-style event maps `{change: action}` + // in terms of the existing API. + var eventsApi = function(obj, action, name, rest) { + if (!name) return true; + + // Handle event maps. + if (typeof name === 'object') { + for (var key in name) { + obj[action].apply(obj, [key, name[key]].concat(rest)); + } + return false; + } + + // Handle space separated event names. + if (eventSplitter.test(name)) { + var names = name.split(eventSplitter); + for (var i = 0, l = names.length; i < l; i++) { + obj[action].apply(obj, [names[i]].concat(rest)); + } + return false; + } + + return true; + }; + + // A difficult-to-believe, but optimized internal dispatch function for + // triggering events. Tries to keep the usual cases speedy (most internal + // Backbone events have 3 arguments). + var triggerEvents = function(events, args) { + var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2]; + switch (args.length) { + case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return; + case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return; + case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return; + case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return; + default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args); + } + }; + + var listenMethods = {listenTo: 'on', listenToOnce: 'once'}; + + // Inversion-of-control versions of `on` and `once`. Tell *this* object to + // listen to an event in another object ... keeping track of what it's + // listening to. + _.each(listenMethods, function(implementation, method) { + Events[method] = function(obj, name, callback) { + var listeners = this._listeners || (this._listeners = {}); + var id = obj._listenerId || (obj._listenerId = _.uniqueId('l')); + listeners[id] = obj; + if (typeof name === 'object') callback = this; + obj[implementation](name, callback, this); + return this; + }; + }); + + // Aliases for backwards compatibility. + Events.bind = Events.on; + Events.unbind = Events.off; + + // Allow the `Backbone` object to serve as a global event bus, for folks who + // want global "pubsub" in a convenient place. + _.extend(Backbone, Events); + + // Backbone.Model + // -------------- + + // Backbone **Models** are the basic data object in the framework -- + // frequently representing a row in a table in a database on your server. + // A discrete chunk of data and a bunch of useful, related methods for + // performing computations and transformations on that data. + + // Create a new model with the specified attributes. A client id (`cid`) + // is automatically generated and assigned for you. + var Model = Backbone.Model = function(attributes, options) { + var defaults; + var attrs = attributes || {}; + options || (options = {}); + this.cid = _.uniqueId('c'); + this.attributes = {}; + _.extend(this, _.pick(options, modelOptions)); + if (options.parse) attrs = this.parse(attrs, options) || {}; + if (defaults = _.result(this, 'defaults')) { + attrs = _.defaults({}, attrs, defaults); + } + this.set(attrs, options); + this.changed = {}; + this.initialize.apply(this, arguments); + }; + + // A list of options to be attached directly to the model, if provided. + var modelOptions = ['url', 'urlRoot', 'collection']; + + // Attach all inheritable methods to the Model prototype. + _.extend(Model.prototype, Events, { + + // A hash of attributes whose current and previous value differ. + changed: null, + + // The value returned during the last failed validation. + validationError: null, + + // The default name for the JSON `id` attribute is `"id"`. MongoDB and + // CouchDB users may want to set this to `"_id"`. + idAttribute: 'id', + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Return a copy of the model's `attributes` object. + toJSON: function(options) { + return _.clone(this.attributes); + }, + + // Proxy `Backbone.sync` by default -- but override this if you need + // custom syncing semantics for *this* particular model. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Get the value of an attribute. + get: function(attr) { + return this.attributes[attr]; + }, + + // Get the HTML-escaped value of an attribute. + escape: function(attr) { + return _.escape(this.get(attr)); + }, + + // Returns `true` if the attribute contains a value that is not null + // or undefined. + has: function(attr) { + return this.get(attr) != null; + }, + + // Set a hash of model attributes on the object, firing `"change"`. This is + // the core primitive operation of a model, updating the data and notifying + // anyone who needs to know about the change in state. The heart of the beast. + set: function(key, val, options) { + var attr, attrs, unset, changes, silent, changing, prev, current; + if (key == null) return this; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + options || (options = {}); + + // Run validation. + if (!this._validate(attrs, options)) return false; + + // Extract attributes and options. + unset = options.unset; + silent = options.silent; + changes = []; + changing = this._changing; + this._changing = true; + + if (!changing) { + this._previousAttributes = _.clone(this.attributes); + this.changed = {}; + } + current = this.attributes, prev = this._previousAttributes; + + // Check for changes of `id`. + if (this.idAttribute in attrs) this.id = attrs[this.idAttribute]; + + // For each `set` attribute, update or delete the current value. + for (attr in attrs) { + val = attrs[attr]; + if (!_.isEqual(current[attr], val)) changes.push(attr); + if (!_.isEqual(prev[attr], val)) { + this.changed[attr] = val; + } else { + delete this.changed[attr]; + } + unset ? delete current[attr] : current[attr] = val; + } + + // Trigger all relevant attribute changes. + if (!silent) { + if (changes.length) this._pending = true; + for (var i = 0, l = changes.length; i < l; i++) { + this.trigger('change:' + changes[i], this, current[changes[i]], options); + } + } + + // You might be wondering why there's a `while` loop here. Changes can + // be recursively nested within `"change"` events. + if (changing) return this; + if (!silent) { + while (this._pending) { + this._pending = false; + this.trigger('change', this, options); + } + } + this._pending = false; + this._changing = false; + return this; + }, + + // Remove an attribute from the model, firing `"change"`. `unset` is a noop + // if the attribute doesn't exist. + unset: function(attr, options) { + return this.set(attr, void 0, _.extend({}, options, {unset: true})); + }, + + // Clear all attributes on the model, firing `"change"`. + clear: function(options) { + var attrs = {}; + for (var key in this.attributes) attrs[key] = void 0; + return this.set(attrs, _.extend({}, options, {unset: true})); + }, + + // Determine if the model has changed since the last `"change"` event. + // If you specify an attribute name, determine if that attribute has changed. + hasChanged: function(attr) { + if (attr == null) return !_.isEmpty(this.changed); + return _.has(this.changed, attr); + }, + + // Return an object containing all the attributes that have changed, or + // false if there are no changed attributes. Useful for determining what + // parts of a view need to be updated and/or what attributes need to be + // persisted to the server. Unset attributes will be set to undefined. + // You can also pass an attributes object to diff against the model, + // determining if there *would be* a change. + changedAttributes: function(diff) { + if (!diff) return this.hasChanged() ? _.clone(this.changed) : false; + var val, changed = false; + var old = this._changing ? this._previousAttributes : this.attributes; + for (var attr in diff) { + if (_.isEqual(old[attr], (val = diff[attr]))) continue; + (changed || (changed = {}))[attr] = val; + } + return changed; + }, + + // Get the previous value of an attribute, recorded at the time the last + // `"change"` event was fired. + previous: function(attr) { + if (attr == null || !this._previousAttributes) return null; + return this._previousAttributes[attr]; + }, + + // Get all of the attributes of the model at the time of the previous + // `"change"` event. + previousAttributes: function() { + return _.clone(this._previousAttributes); + }, + + // Fetch the model from the server. If the server's representation of the + // model differs from its current attributes, they will be overridden, + // triggering a `"change"` event. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + if (!model.set(model.parse(resp, options), options)) return false; + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Set a hash of model attributes, and sync the model to the server. + // If the server returns an attributes hash that differs, the model's + // state will be `set` again. + save: function(key, val, options) { + var attrs, method, xhr, attributes = this.attributes; + + // Handle both `"key", value` and `{key: value}` -style arguments. + if (key == null || typeof key === 'object') { + attrs = key; + options = val; + } else { + (attrs = {})[key] = val; + } + + // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`. + if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false; + + options = _.extend({validate: true}, options); + + // Do not persist invalid models. + if (!this._validate(attrs, options)) return false; + + // Set temporary attributes if `{wait: true}`. + if (attrs && options.wait) { + this.attributes = _.extend({}, attributes, attrs); + } + + // After a successful server-side save, the client is (optionally) + // updated with the server-side state. + if (options.parse === void 0) options.parse = true; + var model = this; + var success = options.success; + options.success = function(resp) { + // Ensure attributes are restored during synchronous saves. + model.attributes = attributes; + var serverAttrs = model.parse(resp, options); + if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs); + if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) { + return false; + } + if (success) success(model, resp, options); + model.trigger('sync', model, resp, options); + }; + wrapError(this, options); + + method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update'); + if (method === 'patch') options.attrs = attrs; + xhr = this.sync(method, this, options); + + // Restore attributes. + if (attrs && options.wait) this.attributes = attributes; + + return xhr; + }, + + // Destroy this model on the server if it was already persisted. + // Optimistically removes the model from its collection, if it has one. + // If `wait: true` is passed, waits for the server to respond before removal. + destroy: function(options) { + options = options ? _.clone(options) : {}; + var model = this; + var success = options.success; + + var destroy = function() { + model.trigger('destroy', model, model.collection, options); + }; + + options.success = function(resp) { + if (options.wait || model.isNew()) destroy(); + if (success) success(model, resp, options); + if (!model.isNew()) model.trigger('sync', model, resp, options); + }; + + if (this.isNew()) { + options.success(); + return false; + } + wrapError(this, options); + + var xhr = this.sync('delete', this, options); + if (!options.wait) destroy(); + return xhr; + }, + + // Default URL for the model's representation on the server -- if you're + // using Backbone's restful methods, override this to change the endpoint + // that will be called. + url: function() { + var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError(); + if (this.isNew()) return base; + return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id); + }, + + // **parse** converts a response into the hash of attributes to be `set` on + // the model. The default implementation is just to pass the response along. + parse: function(resp, options) { + return resp; + }, + + // Create a new model with identical attributes to this one. + clone: function() { + return new this.constructor(this.attributes); + }, + + // A model is new if it has never been saved to the server, and lacks an id. + isNew: function() { + return this.id == null; + }, + + // Check if the model is currently in a valid state. + isValid: function(options) { + return this._validate({}, _.extend(options || {}, { validate: true })); + }, + + // Run validation against the next complete set of model attributes, + // returning `true` if all is well. Otherwise, fire an `"invalid"` event. + _validate: function(attrs, options) { + if (!options.validate || !this.validate) return true; + attrs = _.extend({}, this.attributes, attrs); + var error = this.validationError = this.validate(attrs, options) || null; + if (!error) return true; + this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error})); + return false; + } + + }); + + // Underscore methods that we want to implement on the Model. + var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit']; + + // Mix in each Underscore method as a proxy to `Model#attributes`. + _.each(modelMethods, function(method) { + Model.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.attributes); + return _[method].apply(_, args); + }; + }); + + // Backbone.Collection + // ------------------- + + // If models tend to represent a single row of data, a Backbone Collection is + // more analagous to a table full of data ... or a small slice or page of that + // table, or a collection of rows that belong together for a particular reason + // -- all of the messages in this particular folder, all of the documents + // belonging to this particular author, and so on. Collections maintain + // indexes of their models, both in order, and for lookup by `id`. + + // Create a new **Collection**, perhaps to contain a specific type of `model`. + // If a `comparator` is specified, the Collection will maintain + // its models in sort order, as they're added and removed. + var Collection = Backbone.Collection = function(models, options) { + options || (options = {}); + if (options.url) this.url = options.url; + if (options.model) this.model = options.model; + if (options.comparator !== void 0) this.comparator = options.comparator; + this._reset(); + this.initialize.apply(this, arguments); + if (models) this.reset(models, _.extend({silent: true}, options)); + }; + + // Default options for `Collection#set`. + var setOptions = {add: true, remove: true, merge: true}; + var addOptions = {add: true, merge: false, remove: false}; + + // Define the Collection's inheritable methods. + _.extend(Collection.prototype, Events, { + + // The default model for a collection is just a **Backbone.Model**. + // This should be overridden in most cases. + model: Model, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // The JSON representation of a Collection is an array of the + // models' attributes. + toJSON: function(options) { + return this.map(function(model){ return model.toJSON(options); }); + }, + + // Proxy `Backbone.sync` by default. + sync: function() { + return Backbone.sync.apply(this, arguments); + }, + + // Add a model, or list of models to the set. + add: function(models, options) { + return this.set(models, _.defaults(options || {}, addOptions)); + }, + + // Remove a model, or a list of models from the set. + remove: function(models, options) { + models = _.isArray(models) ? models.slice() : [models]; + options || (options = {}); + var i, l, index, model; + for (i = 0, l = models.length; i < l; i++) { + model = this.get(models[i]); + if (!model) continue; + delete this._byId[model.id]; + delete this._byId[model.cid]; + index = this.indexOf(model); + this.models.splice(index, 1); + this.length--; + if (!options.silent) { + options.index = index; + model.trigger('remove', model, this, options); + } + this._removeReference(model); + } + return this; + }, + + // Update a collection by `set`-ing a new list of models, adding new ones, + // removing models that are no longer present, and merging models that + // already exist in the collection, as necessary. Similar to **Model#set**, + // the core operation for updating the data contained by the collection. + set: function(models, options) { + options = _.defaults(options || {}, setOptions); + if (options.parse) models = this.parse(models, options); + if (!_.isArray(models)) models = models ? [models] : []; + var i, l, model, attrs, existing, sort; + var at = options.at; + var sortable = this.comparator && (at == null) && options.sort !== false; + var sortAttr = _.isString(this.comparator) ? this.comparator : null; + var toAdd = [], toRemove = [], modelMap = {}; + + // Turn bare objects into model references, and prevent invalid models + // from being added. + for (i = 0, l = models.length; i < l; i++) { + if (!(model = this._prepareModel(models[i], options))) continue; + + // If a duplicate is found, prevent it from being added and + // optionally merge it into the existing model. + if (existing = this.get(model)) { + if (options.remove) modelMap[existing.cid] = true; + if (options.merge) { + existing.set(model.attributes, options); + if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true; + } + + // This is a new model, push it to the `toAdd` list. + } else if (options.add) { + toAdd.push(model); + + // Listen to added models' events, and index models for lookup by + // `id` and by `cid`. + model.on('all', this._onModelEvent, this); + this._byId[model.cid] = model; + if (model.id != null) this._byId[model.id] = model; + } + } + + // Remove nonexistent models if appropriate. + if (options.remove) { + for (i = 0, l = this.length; i < l; ++i) { + if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model); + } + if (toRemove.length) this.remove(toRemove, options); + } + + // See if sorting is needed, update `length` and splice in new models. + if (toAdd.length) { + if (sortable) sort = true; + this.length += toAdd.length; + if (at != null) { + splice.apply(this.models, [at, 0].concat(toAdd)); + } else { + push.apply(this.models, toAdd); + } + } + + // Silently sort the collection if appropriate. + if (sort) this.sort({silent: true}); + + if (options.silent) return this; + + // Trigger `add` events. + for (i = 0, l = toAdd.length; i < l; i++) { + (model = toAdd[i]).trigger('add', model, this, options); + } + + // Trigger `sort` if the collection was sorted. + if (sort) this.trigger('sort', this, options); + return this; + }, + + // When you have more items than you want to add or remove individually, + // you can reset the entire set with a new list of models, without firing + // any granular `add` or `remove` events. Fires `reset` when finished. + // Useful for bulk operations and optimizations. + reset: function(models, options) { + options || (options = {}); + for (var i = 0, l = this.models.length; i < l; i++) { + this._removeReference(this.models[i]); + } + options.previousModels = this.models; + this._reset(); + this.add(models, _.extend({silent: true}, options)); + if (!options.silent) this.trigger('reset', this, options); + return this; + }, + + // Add a model to the end of the collection. + push: function(model, options) { + model = this._prepareModel(model, options); + this.add(model, _.extend({at: this.length}, options)); + return model; + }, + + // Remove a model from the end of the collection. + pop: function(options) { + var model = this.at(this.length - 1); + this.remove(model, options); + return model; + }, + + // Add a model to the beginning of the collection. + unshift: function(model, options) { + model = this._prepareModel(model, options); + this.add(model, _.extend({at: 0}, options)); + return model; + }, + + // Remove a model from the beginning of the collection. + shift: function(options) { + var model = this.at(0); + this.remove(model, options); + return model; + }, + + // Slice out a sub-array of models from the collection. + slice: function(begin, end) { + return this.models.slice(begin, end); + }, + + // Get a model from the set by id. + get: function(obj) { + if (obj == null) return void 0; + return this._byId[obj.id != null ? obj.id : obj.cid || obj]; + }, + + // Get the model at the given index. + at: function(index) { + return this.models[index]; + }, + + // Return models with matching attributes. Useful for simple cases of + // `filter`. + where: function(attrs, first) { + if (_.isEmpty(attrs)) return first ? void 0 : []; + return this[first ? 'find' : 'filter'](function(model) { + for (var key in attrs) { + if (attrs[key] !== model.get(key)) return false; + } + return true; + }); + }, + + // Return the first model with matching attributes. Useful for simple cases + // of `find`. + findWhere: function(attrs) { + return this.where(attrs, true); + }, + + // Force the collection to re-sort itself. You don't need to call this under + // normal circumstances, as the set will maintain sort order as each item + // is added. + sort: function(options) { + if (!this.comparator) throw new Error('Cannot sort a set without a comparator'); + options || (options = {}); + + // Run sort based on type of `comparator`. + if (_.isString(this.comparator) || this.comparator.length === 1) { + this.models = this.sortBy(this.comparator, this); + } else { + this.models.sort(_.bind(this.comparator, this)); + } + + if (!options.silent) this.trigger('sort', this, options); + return this; + }, + + // Figure out the smallest index at which a model should be inserted so as + // to maintain order. + sortedIndex: function(model, value, context) { + value || (value = this.comparator); + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _.sortedIndex(this.models, model, iterator, context); + }, + + // Pluck an attribute from each model in the collection. + pluck: function(attr) { + return _.invoke(this.models, 'get', attr); + }, + + // Fetch the default set of models for this collection, resetting the + // collection when they arrive. If `reset: true` is passed, the response + // data will be passed through the `reset` method instead of `set`. + fetch: function(options) { + options = options ? _.clone(options) : {}; + if (options.parse === void 0) options.parse = true; + var success = options.success; + var collection = this; + options.success = function(resp) { + var method = options.reset ? 'reset' : 'set'; + collection[method](resp, options); + if (success) success(collection, resp, options); + collection.trigger('sync', collection, resp, options); + }; + wrapError(this, options); + return this.sync('read', this, options); + }, + + // Create a new instance of a model in this collection. Add the model to the + // collection immediately, unless `wait: true` is passed, in which case we + // wait for the server to agree. + create: function(model, options) { + options = options ? _.clone(options) : {}; + if (!(model = this._prepareModel(model, options))) return false; + if (!options.wait) this.add(model, options); + var collection = this; + var success = options.success; + options.success = function(resp) { + if (options.wait) collection.add(model, options); + if (success) success(model, resp, options); + }; + model.save(null, options); + return model; + }, + + // **parse** converts a response into a list of models to be added to the + // collection. The default implementation is just to pass it through. + parse: function(resp, options) { + return resp; + }, + + // Create a new collection with an identical list of models as this one. + clone: function() { + return new this.constructor(this.models); + }, + + // Private method to reset all internal state. Called when the collection + // is first initialized or reset. + _reset: function() { + this.length = 0; + this.models = []; + this._byId = {}; + }, + + // Prepare a hash of attributes (or other model) to be added to this + // collection. + _prepareModel: function(attrs, options) { + if (attrs instanceof Model) { + if (!attrs.collection) attrs.collection = this; + return attrs; + } + options || (options = {}); + options.collection = this; + var model = new this.model(attrs, options); + if (!model._validate(attrs, options)) { + this.trigger('invalid', this, attrs, options); + return false; + } + return model; + }, + + // Internal method to sever a model's ties to a collection. + _removeReference: function(model) { + if (this === model.collection) delete model.collection; + model.off('all', this._onModelEvent, this); + }, + + // Internal method called every time a model in the set fires an event. + // Sets need to update their indexes when models change ids. All other + // events simply proxy through. "add" and "remove" events that originate + // in other collections are ignored. + _onModelEvent: function(event, model, collection, options) { + if ((event === 'add' || event === 'remove') && collection !== this) return; + if (event === 'destroy') this.remove(model, options); + if (model && event === 'change:' + model.idAttribute) { + delete this._byId[model.previous(model.idAttribute)]; + if (model.id != null) this._byId[model.id] = model; + } + this.trigger.apply(this, arguments); + } + + }); + + // Underscore methods that we want to implement on the Collection. + // 90% of the core usefulness of Backbone Collections is actually implemented + // right here: + var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl', + 'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select', + 'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke', + 'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest', + 'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf', + 'isEmpty', 'chain']; + + // Mix in each Underscore method as a proxy to `Collection#models`. + _.each(methods, function(method) { + Collection.prototype[method] = function() { + var args = slice.call(arguments); + args.unshift(this.models); + return _[method].apply(_, args); + }; + }); + + // Underscore methods that take a property name as an argument. + var attributeMethods = ['groupBy', 'countBy', 'sortBy']; + + // Use attributes instead of properties. + _.each(attributeMethods, function(method) { + Collection.prototype[method] = function(value, context) { + var iterator = _.isFunction(value) ? value : function(model) { + return model.get(value); + }; + return _[method](this.models, iterator, context); + }; + }); + + // Backbone.View + // ------------- + + // Backbone Views are almost more convention than they are actual code. A View + // is simply a JavaScript object that represents a logical chunk of UI in the + // DOM. This might be a single item, an entire list, a sidebar or panel, or + // even the surrounding frame which wraps your whole app. Defining a chunk of + // UI as a **View** allows you to define your DOM events declaratively, without + // having to worry about render order ... and makes it easy for the view to + // react to specific changes in the state of your models. + + // Creating a Backbone.View creates its initial element outside of the DOM, + // if an existing element is not provided... + var View = Backbone.View = function(options) { + this.cid = _.uniqueId('view'); + this._configure(options || {}); + this._ensureElement(); + this.initialize.apply(this, arguments); + this.delegateEvents(); + }; + + // Cached regex to split keys for `delegate`. + var delegateEventSplitter = /^(\S+)\s*(.*)$/; + + // List of view options to be merged as properties. + var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events']; + + // Set up all inheritable **Backbone.View** properties and methods. + _.extend(View.prototype, Events, { + + // The default `tagName` of a View's element is `"div"`. + tagName: 'div', + + // jQuery delegate for element lookup, scoped to DOM elements within the + // current view. This should be prefered to global lookups where possible. + $: function(selector) { + return this.$el.find(selector); + }, + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // **render** is the core function that your view should override, in order + // to populate its element (`this.el`), with the appropriate HTML. The + // convention is for **render** to always return `this`. + render: function() { + return this; + }, + + // Remove this view by taking the element out of the DOM, and removing any + // applicable Backbone.Events listeners. + remove: function() { + this.$el.remove(); + this.stopListening(); + return this; + }, + + // Change the view's element (`this.el` property), including event + // re-delegation. + setElement: function(element, delegate) { + if (this.$el) this.undelegateEvents(); + this.$el = element instanceof Backbone.$ ? element : Backbone.$(element); + this.el = this.$el[0]; + if (delegate !== false) this.delegateEvents(); + return this; + }, + + // Set callbacks, where `this.events` is a hash of + // + // *{"event selector": "callback"}* + // + // { + // 'mousedown .title': 'edit', + // 'click .button': 'save' + // 'click .open': function(e) { ... } + // } + // + // pairs. Callbacks will be bound to the view, with `this` set properly. + // Uses event delegation for efficiency. + // Omitting the selector binds the event to `this.el`. + // This only works for delegate-able events: not `focus`, `blur`, and + // not `change`, `submit`, and `reset` in Internet Explorer. + delegateEvents: function(events) { + if (!(events || (events = _.result(this, 'events')))) return this; + this.undelegateEvents(); + for (var key in events) { + var method = events[key]; + if (!_.isFunction(method)) method = this[events[key]]; + if (!method) continue; + + var match = key.match(delegateEventSplitter); + var eventName = match[1], selector = match[2]; + method = _.bind(method, this); + eventName += '.delegateEvents' + this.cid; + if (selector === '') { + this.$el.on(eventName, method); + } else { + this.$el.on(eventName, selector, method); + } + } + return this; + }, + + // Clears all callbacks previously bound to the view with `delegateEvents`. + // You usually don't need to use this, but may wish to if you have multiple + // Backbone views attached to the same DOM element. + undelegateEvents: function() { + this.$el.off('.delegateEvents' + this.cid); + return this; + }, + + // Performs the initial configuration of a View with a set of options. + // Keys with special meaning *(e.g. model, collection, id, className)* are + // attached directly to the view. See `viewOptions` for an exhaustive + // list. + _configure: function(options) { + if (this.options) options = _.extend({}, _.result(this, 'options'), options); + _.extend(this, _.pick(options, viewOptions)); + this.options = options; + }, + + // Ensure that the View has a DOM element to render into. + // If `this.el` is a string, pass it through `$()`, take the first + // matching element, and re-assign it to `el`. Otherwise, create + // an element from the `id`, `className` and `tagName` properties. + _ensureElement: function() { + if (!this.el) { + var attrs = _.extend({}, _.result(this, 'attributes')); + if (this.id) attrs.id = _.result(this, 'id'); + if (this.className) attrs['class'] = _.result(this, 'className'); + var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs); + this.setElement($el, false); + } else { + this.setElement(_.result(this, 'el'), false); + } + } + + }); + + // Backbone.sync + // ------------- + + // Override this function to change the manner in which Backbone persists + // models to the server. You will be passed the type of request, and the + // model in question. By default, makes a RESTful Ajax request + // to the model's `url()`. Some possible customizations could be: + // + // * Use `setTimeout` to batch rapid-fire updates into a single request. + // * Send up the models as XML instead of JSON. + // * Persist models via WebSockets instead of Ajax. + // + // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests + // as `POST`, with a `_method` parameter containing the true HTTP method, + // as well as all requests with the body as `application/x-www-form-urlencoded` + // instead of `application/json` with the model in a param named `model`. + // Useful when interfacing with server-side languages like **PHP** that make + // it difficult to read the body of `PUT` requests. + Backbone.sync = function(method, model, options) { + var type = methodMap[method]; + + // Default options, unless specified. + _.defaults(options || (options = {}), { + emulateHTTP: Backbone.emulateHTTP, + emulateJSON: Backbone.emulateJSON + }); + + // Default JSON-request options. + var params = {type: type, dataType: 'json'}; + + // Ensure that we have a URL. + if (!options.url) { + params.url = _.result(model, 'url') || urlError(); + } + + // Ensure that we have the appropriate request data. + if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) { + params.contentType = 'application/json'; + params.data = JSON.stringify(options.attrs || model.toJSON(options)); + } + + // For older servers, emulate JSON by encoding the request into an HTML-form. + if (options.emulateJSON) { + params.contentType = 'application/x-www-form-urlencoded'; + params.data = params.data ? {model: params.data} : {}; + } + + // For older servers, emulate HTTP by mimicking the HTTP method with `_method` + // And an `X-HTTP-Method-Override` header. + if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) { + params.type = 'POST'; + if (options.emulateJSON) params.data._method = type; + var beforeSend = options.beforeSend; + options.beforeSend = function(xhr) { + xhr.setRequestHeader('X-HTTP-Method-Override', type); + if (beforeSend) return beforeSend.apply(this, arguments); + }; + } + + // Don't process data on a non-GET request. + if (params.type !== 'GET' && !options.emulateJSON) { + params.processData = false; + } + + // If we're sending a `PATCH` request, and we're in an old Internet Explorer + // that still has ActiveX enabled by default, override jQuery to use that + // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8. + if (params.type === 'PATCH' && window.ActiveXObject && + !(window.external && window.external.msActiveXFilteringEnabled)) { + params.xhr = function() { + return new ActiveXObject("Microsoft.XMLHTTP"); + }; + } + + // Make the request, allowing the user to override any Ajax options. + var xhr = options.xhr = Backbone.ajax(_.extend(params, options)); + model.trigger('request', model, xhr, options); + return xhr; + }; + + // Map from CRUD to HTTP for our default `Backbone.sync` implementation. + var methodMap = { + 'create': 'POST', + 'update': 'PUT', + 'patch': 'PATCH', + 'delete': 'DELETE', + 'read': 'GET' + }; + + // Set the default implementation of `Backbone.ajax` to proxy through to `$`. + // Override this if you'd like to use a different library. + Backbone.ajax = function() { + return Backbone.$.ajax.apply(Backbone.$, arguments); + }; + + // Backbone.Router + // --------------- + + // Routers map faux-URLs to actions, and fire events when routes are + // matched. Creating a new one sets its `routes` hash, if not set statically. + var Router = Backbone.Router = function(options) { + options || (options = {}); + if (options.routes) this.routes = options.routes; + this._bindRoutes(); + this.initialize.apply(this, arguments); + }; + + // Cached regular expressions for matching named param parts and splatted + // parts of route strings. + var optionalParam = /\((.*?)\)/g; + var namedParam = /(\(\?)?:\w+/g; + var splatParam = /\*\w+/g; + var escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; + + // Set up all inheritable **Backbone.Router** properties and methods. + _.extend(Router.prototype, Events, { + + // Initialize is an empty function by default. Override it with your own + // initialization logic. + initialize: function(){}, + + // Manually bind a single named route to a callback. For example: + // + // this.route('search/:query/p:num', 'search', function(query, num) { + // ... + // }); + // + route: function(route, name, callback) { + if (!_.isRegExp(route)) route = this._routeToRegExp(route); + if (_.isFunction(name)) { + callback = name; + name = ''; + } + if (!callback) callback = this[name]; + var router = this; + Backbone.history.route(route, function(fragment) { + var args = router._extractParameters(route, fragment); + callback && callback.apply(router, args); + router.trigger.apply(router, ['route:' + name].concat(args)); + router.trigger('route', name, args); + Backbone.history.trigger('route', router, name, args); + }); + return this; + }, + + // Simple proxy to `Backbone.history` to save a fragment into the history. + navigate: function(fragment, options) { + Backbone.history.navigate(fragment, options); + return this; + }, + + // Bind all defined routes to `Backbone.history`. We have to reverse the + // order of the routes here to support behavior where the most general + // routes can be defined at the bottom of the route map. + _bindRoutes: function() { + if (!this.routes) return; + this.routes = _.result(this, 'routes'); + var route, routes = _.keys(this.routes); + while ((route = routes.pop()) != null) { + this.route(route, this.routes[route]); + } + }, + + // Convert a route string into a regular expression, suitable for matching + // against the current location hash. + _routeToRegExp: function(route) { + route = route.replace(escapeRegExp, '\\$&') + .replace(optionalParam, '(?:$1)?') + .replace(namedParam, function(match, optional){ + return optional ? match : '([^\/]+)'; + }) + .replace(splatParam, '(.*?)'); + return new RegExp('^' + route + '$'); + }, + + // Given a route, and a URL fragment that it matches, return the array of + // extracted decoded parameters. Empty or unmatched parameters will be + // treated as `null` to normalize cross-browser behavior. + _extractParameters: function(route, fragment) { + var params = route.exec(fragment).slice(1); + return _.map(params, function(param) { + return param ? decodeURIComponent(param) : null; + }); + } + + }); + + // Backbone.History + // ---------------- + + // Handles cross-browser history management, based on either + // [pushState](http://diveintohtml5.info/history.html) and real URLs, or + // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange) + // and URL fragments. If the browser supports neither (old IE, natch), + // falls back to polling. + var History = Backbone.History = function() { + this.handlers = []; + _.bindAll(this, 'checkUrl'); + + // Ensure that `History` can be used outside of the browser. + if (typeof window !== 'undefined') { + this.location = window.location; + this.history = window.history; + } + }; + + // Cached regex for stripping a leading hash/slash and trailing space. + var routeStripper = /^[#\/]|\s+$/g; + + // Cached regex for stripping leading and trailing slashes. + var rootStripper = /^\/+|\/+$/g; + + // Cached regex for detecting MSIE. + var isExplorer = /msie [\w.]+/; + + // Cached regex for removing a trailing slash. + var trailingSlash = /\/$/; + + // Has the history handling already been started? + History.started = false; + + // Set up all inheritable **Backbone.History** properties and methods. + _.extend(History.prototype, Events, { + + // The default interval to poll for hash changes, if necessary, is + // twenty times a second. + interval: 50, + + // Gets the true hash value. Cannot use location.hash directly due to bug + // in Firefox where location.hash will always be decoded. + getHash: function(window) { + var match = (window || this).location.href.match(/#(.*)$/); + return match ? match[1] : ''; + }, + + // Get the cross-browser normalized URL fragment, either from the URL, + // the hash, or the override. + getFragment: function(fragment, forcePushState) { + if (fragment == null) { + if (this._hasPushState || !this._wantsHashChange || forcePushState) { + fragment = this.location.pathname; + var root = this.root.replace(trailingSlash, ''); + if (!fragment.indexOf(root)) fragment = fragment.substr(root.length); + } else { + fragment = this.getHash(); + } + } + return fragment.replace(routeStripper, ''); + }, + + // Start the hash change handling, returning `true` if the current URL matches + // an existing route, and `false` otherwise. + start: function(options) { + if (History.started) throw new Error("Backbone.history has already been started"); + History.started = true; + + // Figure out the initial configuration. Do we need an iframe? + // Is pushState desired ... is it available? + this.options = _.extend({}, {root: '/'}, this.options, options); + this.root = this.options.root; + this._wantsHashChange = this.options.hashChange !== false; + this._wantsPushState = !!this.options.pushState; + this._hasPushState = !!(this.options.pushState && this.history && this.history.pushState); + var fragment = this.getFragment(); + var docMode = document.documentMode; + var oldIE = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7)); + + // Normalize root to always include a leading and trailing slash. + this.root = ('/' + this.root + '/').replace(rootStripper, '/'); + + if (oldIE && this._wantsHashChange) { + this.iframe = Backbone.$(' + +
+ + + +<% elsif authenticated? %> + <% content_for :title, "My Maps | Metamaps" %> + +<% end %> \ No newline at end of file diff --git a/app/views/main/paq.html.erb b/app/views/main/paq.html.erb deleted file mode 100644 index 76d0ec5e..00000000 --- a/app/views/main/paq.html.erb +++ /dev/null @@ -1,80 +0,0 @@ -<%# - # @file - # Located at / - # Shows 3 most recently created topics, synapses, and maps. - #%> - -<% content_for :title, "Possibly Asked Questions | Metamaps" %> - -

- P(ossibly)AQ -

- -
- -
Who may use Metamaps.cc?
-

You! We are currently in "beta" mode, meaning that the application is undergoing continuous testing and refinement. During this time, we welcome participants of all ages in this trial process with the understanding that things are evolving, and may hold a few surprises! Request an invite if you'd like to explore and build with us - feedback is always welcome.

- -
What does it take to learn to Metamap?
-

While the interface may not seem familiar at first, we've designed it to be both intuitive and empowering after a bit of practice. There are only a handful of basic functions, like adding topics and drawing "synapse" connections, that are needed get you going! A handy cheat sheet is available on the canvas for reference while mapping, and we also have an online manual and video tutorials to grasp more advanced functionality. But overall - the best way to learn is to start mapping, and to connect with other mappers in our online community.

- -
What is the platform being used for currently?
-

Firstly, check out our featured maps! At a basic level, metamaps are great for laying out complex ideas and scenarios. We're seeing maps of creative brainstorms, product design, personal research and learning, project management, and narrative storylines. Some users have been capturing live workshop event documentation, or organizing study groups. We're using it ourselves to organize collaboration and develop strategies for the project. We'd love to see what else you can come up with.

- -
Who made this up? Why?
-

The Metamaps.cc project was launched as an emergent collaboration between designer Gavin Keech, architect Ishan Shapiro, and web developer Connor Turland over the years 2010-12, with input and inspiration from many other peers and projects. Its design draws from the fields of computational cognition, collective intelligence, and human-computer interaction. We continue to design and develop optimal, novel ways to connect people and ideas through visual information.

- -
How is MM different from other "mind mapping" apps?
-

First and foremost, metamaps bring people together into a shared knowledge environment. Topics and maps "in the commons" invite collaborative editing and shared insight. As new content and connections are made throughout the system, all users benefit from collective intelligence. Other distinguishing factors on the platform include a focus on real-time collaboration, a flexible visual categorization system via metacode icons, no built-in structural biases, and an intuitive search tool to find content. As the project evolves, we will be building in powerful network and graph analysis techniques which are not currently offered in other mind mapping apps.

- -
Is this an open source project?
-

One of the core principles of our work is the enhancement of the pool of commons resources such as open source technology and shared knowledge. Our basic application framework is licensed as GPL open source on Github for anyone to build on, and this public platform is freely accessible online.

- -
How can I find out more about the project?
-

Reading here is a great first step. We also suggest browsing our blog, visiting the Google+ community, or getting in touch by submitting feedback through the site. We occasionally host online and in person meetups where you can interact with other mappers and see how people are using the platform. The story continues to unfold, and we'd be glad for you to take part.

- -
How can I participate, or support the project?
-

We welcome contributions in many forms. One of the easiest and best things you can do is to keep on mapping your ideas into the commons on the platform! If you're a developer interested in advancing the technology, contact us and take a look around our Github. Designers and others with professional skills can get in touch about opportunities for freelance collaboration through our innovative Open Value Network organizational structure for business development opportunities. Financial contributions are greatly appreciated in support of our work, and can be made by supporting us on Flattr or donating BitCoin. All financial contributions are transparently recorded in our value accounting system.

-

One of the core principles of our work is the enhancement of the pool of commons resources such as open source technology and shared knowledge. Our basic application framework is licensed as GPL open source on Github for anyone to build on, and this public platform is freely accessible online.

- -
How can I find out more about the project?
-

Reading here is a great first step. We also suggest browsing our blog, visiting the Google+ community, or getting in touch by submitting feedback through the site. We occasionally host online and in person meetups where you can interact with other mappers and see how people are using the platform. The story continues to unfold, and we'd be glad for you to take part.

- -
How can I participate, or support the project?
-

We welcome contributions in many forms. One of the easiest and best things you can do is to keep on mapping your ideas into the commons on the platform! If you're a developer interested in advancing the technology, contact us and take a look around our Github. Designers and others with professional skills can get in touch about opportunities for freelance collaboration through our innovative Open Value Network organizational structure for business development opportunities. Financial contributions are greatly appreciated in support of our work, and can be made by supporting us on Flattr or donating BitCoin. All financial contributions are transparently recorded in our value accounting system.

- -
Are you making money from it? Do you plan to?
-

The Metamaps.cc project has been bootstrapped through our own pockets, lots of time, and more recently, a couple of small grants which are going into supporting our small team to bring it to the next level. Some of us have used Metamaps.cc as a tool for our own freelance consulting practice, and we are looking at creating hosted and customized instances for different clients as one potential business model. We realize that in order to get the free and open public platform to where we want it to be, we have to be able to support ourselves to continue doing this work.

- -
I'd like to have a new / different feature. Where can I make suggestions and requests?
-

New features and functions are continually added to the platform as we seek to optimize the experience there for all users. If you find that something is calling out for addition or improvement, send us a note via feedback form or in the online community. The more detail and context you can provide, the better!

- -
I made a cool map...want to check it out?
-

Yes! Send us the link via feedback form or flag us on social media. We're always curious what mappers are able to do with the platform, and we'd love to pass great examples around so that others can see.

- -
Someone else changed my cool map (or favorite topic) without asking me...sad face :(
-

If your map / topic was set to Commons permission for editing, than any other logged-in user on the site will be able to make changes. We consider this a feature, not a bug, which encourages collaborative maps and an evolving collective knowledge garden. You can easily avoid unwanted changes by setting your permissions to Public, which others may still view and copy to another version if they wish. Courtesy, care, and the benefit of the doubt will go a long ways towards maintaining a happy, healthy, and productive communal atmosphere on Metamaps.cc

- -
- - diff --git a/app/views/main/requestinvite.html.erb b/app/views/main/requestinvite.html.erb index 6900cdc3..2b147db0 100644 --- a/app/views/main/requestinvite.html.erb +++ b/app/views/main/requestinvite.html.erb @@ -6,15 +6,6 @@ <% content_for :title, "Request Invite | Metamaps" %> +
- -

- Request Invite -

- - +
diff --git a/app/views/mappings/create.js.erb b/app/views/mappings/create.js.erb deleted file mode 100644 index ef8b6089..00000000 --- a/app/views/mappings/create.js.erb +++ /dev/null @@ -1,4 +0,0 @@ -/* - * @file - * This javascript is returned and executed when you create a new mapping. - */ diff --git a/app/views/mappings/destroy.js.erb b/app/views/mappings/destroy.js.erb deleted file mode 100644 index a8653340..00000000 --- a/app/views/mappings/destroy.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -/* - * @file - * The javascript returned when destroy is called in the mappings controller - * Unused - */ diff --git a/app/views/mappings/edit.html.erb b/app/views/mappings/edit.html.erb deleted file mode 100644 index 0151d668..00000000 --- a/app/views/mappings/edit.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%# - # @file - # This code renders the edit form for mappings. Unused. - #%> diff --git a/app/views/mappings/index.html.erb b/app/views/mappings/index.html.erb deleted file mode 100644 index 17643309..00000000 --- a/app/views/mappings/index.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%# - # @file - # This view could show an index of all mappings, but is unused. - #%> diff --git a/app/views/mappings/new.html.erb b/app/views/mappings/new.html.erb deleted file mode 100644 index 39dd3eb1..00000000 --- a/app/views/mappings/new.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%# - # @file - # This file is a form for creating new mappings. Unused. - #%> diff --git a/app/views/mappings/show.html.erb b/app/views/mappings/show.html.erb deleted file mode 100644 index 14785fb4..00000000 --- a/app/views/mappings/show.html.erb +++ /dev/null @@ -1,4 +0,0 @@ -<%# - # @file - # This would show a mapping but instead is unused. - #%> diff --git a/app/views/maps/_fork.html.erb b/app/views/maps/_fork.html.erb deleted file mode 100644 index 2ec5fa82..00000000 --- a/app/views/maps/_fork.html.erb +++ /dev/null @@ -1,69 +0,0 @@ -<%# - # @file - # Partial view, renders a form that creates a new map. - #%> -
-<%= form_for Map.new, url: maps_url, remote: true, html: { class: "new_map", id: "fork_map" } do |form|%> - - <% if controller_name == "maps" %> -

Save To New Map

- <% elsif controller_name == "topics" %> -

Save As New Map

- <% end %> - -
- - <%= form.text_field :name %> -
-
- -
- - <%= form.text_area :desc, class: "description", :rows => 5, :cols => 43 %> -
-
- -
- - -
-
-
- Collaborate with other mappers on editing this map. Those without accounts can view this map. -
-
-

COMMONS

-
-
-
-
- Anyone, with or without an account, can view this map but not edit anything. -
-
-

PUBLIC

-
-
-
-
- Only you can view or edit this map. -
-
-

PRIVATE

-
- - <%= form.hidden_field :permission, :value => "commons" %> -
-
- -

*new topics and synapses take on the same permission as the map they are created on

- -
- - <%= form.submit "Create!", class: "add" %> -
- - <%= form.hidden_field :topicsToMap, :value => 0 %> - <%= form.hidden_field :synapsesToMap, :value => 0 %> -
-<% end %> -
diff --git a/app/views/maps/_homemap.html.erb b/app/views/maps/_homemap.html.erb deleted file mode 100644 index 554783b6..00000000 --- a/app/views/maps/_homemap.html.erb +++ /dev/null @@ -1,32 +0,0 @@ -<%# - # @file - # Shows a map as a card. - # Any list of maps uses this rendering. - #%> -
"> - -
- -
- - <%= map.name %> - - -
- <%= map.desc %> -
-
- <%= pluralize(map.topics.count, 'topic') %> - <%= pluralize(map.synapses.count, 'synapse') %> -
-
- -
-
-
diff --git a/app/views/maps/_map.html.erb b/app/views/maps/_map.html.erb deleted file mode 100644 index e1daaf22..00000000 --- a/app/views/maps/_map.html.erb +++ /dev/null @@ -1,36 +0,0 @@ -<%# - # @file - # Shows a map as a card. - # Any list of maps uses this rendering. - #%> -<%= div_for map do %> -
"> - -
- - <%= best_in_place map, :name, :type => :textarea, :classes => 'best_in_place_name' %> - - -
-
- <%= best_in_place map, :desc, :type => :textarea, :nil => "Click to add description.", :classes => 'best_in_place_desc' %> -
-
-
-
-
- -
-<% end %> diff --git a/app/views/maps/_mapinfobox.html (copy).erb b/app/views/maps/_mapinfobox.html (copy).erb new file mode 100644 index 00000000..1c808a4e --- /dev/null +++ b/app/views/maps/_mapinfobox.html (copy).erb @@ -0,0 +1,52 @@ +<%# + # Partial rendering form for a new topic on a map + # This code is called when viewing a metamap in show.html.erb in the views/maps folder + #%> +
<%= @map.authorize_to_edit(user) ? " canEdit" : "" %>"> + +
<%= best_in_place @map, :name, :type => :input, :classes => 'best_in_place_name' %>
+ +
+
+ <%= @map.contributors.count %> + <% contributorList = '' + @map.contributors.each_with_index do |c, index| + comma = (index+1) == @map.contributors.count ? '' : ', ' + contributorList += c.name + comma + end + if @map.contributors.count == 0 + contributorList = 'No one has added anything yet.' + end %> +
<%= contributorList %>
+
+
+ <%= @map.topics.count %> +
+
+ <%= @map.synapses.count %> +
+
+ <% if @map.user == user %> +
As the creator, you can change the permission of this map, but the permissions of the topics and synapses on it must be changed independently.
+ <% end %> +
+
+
+ + <% if (authenticated? && @map.authorize_to_edit(user)) || (!authenticated? && @map.desc != "" && @map.desc != nil )%> +
+ <%= best_in_place @map, :desc, :type => :textarea, :nil => "Click to add description.", :classes => 'best_in_place_desc' %> +
+ <% end %> + +
+

Created by <%= @map.user == user ? "you" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %>

+

Last edited <%= @map.updated_at.strftime("%m/%d/%Y") %>

+
+ +
+ <% if @map.user == user %> + <%= link_to 'Delete', map_path(@map), :class => 'delete', :confirm => 'Delete this map (nodes and synapses will remain)?', :method => :delete %> + <% end %> +
+
diff --git a/app/views/maps/_mapinfobox.html.erb b/app/views/maps/_mapinfobox.html.erb index 1c808a4e..da339a02 100644 --- a/app/views/maps/_mapinfobox.html.erb +++ b/app/views/maps/_mapinfobox.html.erb @@ -2,8 +2,9 @@ # Partial rendering form for a new topic on a map # This code is called when viewing a metamap in show.html.erb in the views/maps folder #%> -
<%= @map.authorize_to_edit(user) ? " canEdit" : "" %>"> +
<%= @map && @map.authorize_to_edit(user) ? " canEdit" : "" %>"> + <% if @map %>
<%= best_in_place @map, :name, :type => :input, :classes => 'best_in_place_name' %>
@@ -40,13 +41,15 @@ <% end %>
-

Created by <%= @map.user == user ? "you" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %>

-

Last edited <%= @map.updated_at.strftime("%m/%d/%Y") %>

+

Created by <%= @map.user == user ? "you" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %>

+

Last edited <%= @map.updated_at.strftime("%m/%d/%Y") %>

<% if @map.user == user %> - <%= link_to 'Delete', map_path(@map), :class => 'delete', :confirm => 'Delete this map (nodes and synapses will remain)?', :method => :delete %> + <%= link_to 'Delete', map_path(@map), :class => 'delete', :confirm => 'Delete this map (nodes and synapses will remain)?', :method => :delete, + :data => { :bypass => 'true'} %> <% end %>
-
+ <% end %> +
\ No newline at end of file diff --git a/app/views/maps/_new.html.erb b/app/views/maps/_new.html.erb deleted file mode 100644 index 10b1c1ce..00000000 --- a/app/views/maps/_new.html.erb +++ /dev/null @@ -1,62 +0,0 @@ -<%# - # @file - # Partial view, renders a form that creates a new map. - #%> -
-<%= form_for Map.new, url: maps_url, remote: true, html: { class: "new_map", id: "new_map" } do |form|%> -

Create A New Map

- -
- - <%= form.text_field :name %> -
-
- -
- - <%= form.text_area :desc, class: "description", :rows => 5, :cols => 43 %> -
-
- -
- - -
-
-
- Collaborate with other mappers on editing this map. Those without accounts can view this map. -
-
-

COMMONS

-
-
-
-
- Anyone, with or without an account, can view this map but not edit anything. -
-
-

PUBLIC

-
-
-
-
- Only you can view or edit this map. -
-
-

PRIVATE

-
- - <%= form.hidden_field :permission, :value => "commons" %> -
-
- -

*new topics and synapses take on the same permission as the map they are created on

- -
- - <%= form.submit "Create!", class: "add" %> -
- -
-<% end %> -
diff --git a/app/views/maps/_newsynapse.html.erb b/app/views/maps/_newsynapse.html.erb index d32b7398..1c190324 100644 --- a/app/views/maps/_newsynapse.html.erb +++ b/app/views/maps/_newsynapse.html.erb @@ -1,16 +1,3 @@ -<%# - # @file - # partial generating a new synapse - # TODO: Where is this code used? - #%> -
- <%= form_for Synapse.new, url: synapses_url, remote: true do |form| %> - <%= form.text_field :desc, :placeholder => "describe the connection..." %> - <%= form.hidden_field :topic1id, :value => 0 %> - <%= form.hidden_field :topic2id, :value => 0 %> - <%= form.hidden_field :grabSynapse, :value => "null" %> - <% if (@map.permission == "commons" && authenticated?) || @map.user == user %> - <%= form.hidden_field :map, :value => @map.id %> - <% end %> - <% end %> -
+<%= form_for Synapse.new, url: synapses_url, remote: true do |form| %> +<%= form.text_field :desc, :placeholder => "describe the connection..." %> +<% end %> diff --git a/app/views/maps/_newtopic.html.erb b/app/views/maps/_newtopic.html.erb index 8ba65f32..048f453f 100644 --- a/app/views/maps/_newtopic.html.erb +++ b/app/views/maps/_newtopic.html.erb @@ -1,8 +1,3 @@ -<%# - # Partial rendering form for a new topic on a map - # This code is called when viewing a metamap in show.html.erb in the views/maps folder - #%> -
<%= form_for Topic.new, url: topics_url, remote: true do |form| %>
@@ -22,25 +17,16 @@ <% end %>
<%= form.text_field :name, :maxlength => 140, :placeholder => "title..." %> - <%= form.hidden_field :metacode, :value => "Action" %> - <%= form.hidden_field :x, :value => 0 %> - <%= form.hidden_field :y, :value => 0 %> - <% if (@map.permission == "commons" && authenticated?) || @map.user == user %> - <%= form.hidden_field :map, :value => @map.id %> - <% end %> - <%= form.hidden_field :grabTopic, :value => "null" %> - <%= form.hidden_field :addSynapse, :value => false %>
<% end %> -
diff --git a/app/views/maps/create.js.erb b/app/views/maps/create.js.erb deleted file mode 100644 index dc8a1937..00000000 --- a/app/views/maps/create.js.erb +++ /dev/null @@ -1,41 +0,0 @@ -/* - * @file - * Javascript run on creation of a new map - */ - - -$('#map_name').val(''); -$('#map_desc').val(''); -$('#map_permission').val('commons'); - -<% if @forked %> - $('#map_topicsToMap').val('0'); - $('#map_synapsesToMap').val('0'); - - var form = $('#fork_map'); -<% else %> - var form = $('#new_map'); -<% end %> -form.find('.mapPermIcon').removeClass('selected'); -form.find('.mapCommonsIcon').addClass('selected'); - - -var tempForm = form.html(); -if (mapid == null) { - form.html("Success! Do you want to
' + "'>Go to your new map?
or
Stay on this page?"); -} -else if (mapid != null) { - form.html("Success! Do you want to
' + "'>Go to your new map?
or
Stay on this map?"); -} -$('#lightbox_main').css('margin-top', '-' + ($('#lightbox_main').height() / 2) + 'px' ); - -function closeIt() { - $('#lightbox_overlay').hide(); - form.html(tempForm); - // bind permission changer events - form.find('.permIcon').click(function() { - $(this).siblings('#map_permission').val( $(this).attr('data-permission') ); - $(this).siblings('.permIcon').find('.mapPermIcon').removeClass('selected'); - $(this).find('.mapPermIcon').addClass('selected'); - }); -} diff --git a/app/views/maps/destroy.js.erb b/app/views/maps/destroy.js.erb deleted file mode 100644 index 851efd3a..00000000 --- a/app/views/maps/destroy.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -/* - * @file - * Javascript run on destruction of a map. Fades it out from map index. - */ -$('#<%= dom_id(@map) %>').fadeOut('slow'); diff --git a/app/views/maps/embed.html.erb b/app/views/maps/embed.html.erb index 4fc98a5d..de875ae2 100644 --- a/app/views/maps/embed.html.erb +++ b/app/views/maps/embed.html.erb @@ -1,63 +1,83 @@ <%# - # @file - # Code to display a map - # /maps/:id - #%> +# @file +# Code to display a map +# /maps/:id +#%> -<% content_for :title, @map.name + " | Metamaps" %> - -
- <% if authenticated? %> - <% if (@map.permission == "commons" && authenticated?) || @map.user == user %> - - <% end %> - - <% if (@map.permission == "commons" && authenticated?) || @map.user == user %> - <%= form_for @map, :url => savelayout_path(@map), :html => { :class => "saveMapLayout", :id => "saveMapLayout"}, remote: true do |form| %> - <%= form.hidden_field "coordinates", :value => "" %> - <%= form.submit "Save Layout", class: "saveLayout", id: "saveLayout" %> - <% end %> - <% end %> - <% end %> +<% content_for :title, @map.name + " | Metamaps" %> + +
+
-
-
-
-
-
+ +<% if authenticated? %> +
+
+
+
+
+<% if @map.permission == "commons" || @map.user == user %> +
+
+
+

Realtime:

+ ON +
+
+
    +
  • + <%= user.name %> (me) +
  • +
+
+
+
+<% end %> +<% end %> +
+
+
+

Filter By Metacode

allnone +
+ <%= render :partial => 'shared/filterbymetacode' %> +
+
+ +
+
+ +
+ <%= render :partial => 'maps/mapinfobox' %> +
+ +
+
+
+
+
<% if authenticated? %> - <%= render :partial => 'newtopic' %> - <%= render :partial => 'newsynapse' %> + +<% # add these if you have edit permissions on the map %> +<% if @map.permission == "commons" || @map.user == user %> +<% # for creating and pulling in topics and synapses %> +<%= render :partial => 'newtopic' %> +<%= render :partial => 'newsynapse' %> <% end %> - - + +<% # for populating the change metacode list on the topic card %> +<%= render :partial => 'shared/metacodeoptions' %> +<% end %> + + Metamaps.Active.Map = <%= @map.to_json.html_safe %>; + Metamaps.Metacodes = <%= @allmetacodes.to_json.html_safe %>; + Metamaps.Topics = <%= @alltopics.to_json.html_safe %>; + Metamaps.Synapses = <%= @allsynapses.to_json.html_safe %>; + Metamaps.Mappings = <%= @allmappings.to_json.html_safe %>; + Metamaps.Settings.embed = true; + \ No newline at end of file diff --git a/app/views/maps/index.html.erb b/app/views/maps/index.html.erb index a7984a60..928a2511 100644 --- a/app/views/maps/index.html.erb +++ b/app/views/maps/index.html.erb @@ -5,63 +5,16 @@ #%> <% content_for :title, "Explore Maps | Metamaps" %> - -

Explore Maps

- - -
- Displaying: -
- <% if @request == "other" %> - By <%= @user.name %> / - <% end %> - <% if @request == "topic" %> - Maps Containing Topic <%= @topic.id.to_s %>: "<%= @topic.name.truncate(30) %>" - <% end %> - - <% if @request != "topic" %> - ">Recently Active / - ">Featured / - ">Newest First - <% if authenticated? %> - / ">Yours - <% end %> - <% end %> -
-
-
- -
-
- <% @maps.each do |map| %> - <%= render map %> - <% end %> -
-
-
diff --git a/app/views/maps/realtime.js.erb b/app/views/maps/realtime.js.erb deleted file mode 100644 index 588faa8e..00000000 --- a/app/views/maps/realtime.js.erb +++ /dev/null @@ -1,94 +0,0 @@ -/* - * @file - * Javascript code for realtime callbacks - * TODO: Connor, could you explain this code sometime? - */ -var tempForT, tempForS, tempForM; - -<% @topics.each do |topic| %> - var topic = <%= topic.selfonmap_as_json(@map.id).html_safe %>; - tempForT = Mconsole.graph.getNode(topic.id); - if (tempForT === undefined) { - Mconsole.graph.addNode(topic); - var tempForT = Mconsole.graph.getNode(topic.id); - tempForT.setData('dim', 1, 'start'); - tempForT.setData('dim', 25, 'end'); - var newPos = new $jit.Complex(); - newPos.x = tempForT.data.$xloc; - newPos.y = tempForT.data.$yloc; - tempForT.setPos(newPos, 'start'); - tempForT.setPos(newPos, 'current'); - tempForT.setPos(newPos, 'end'); - Mconsole.fx.plotNode(tempForT, Mconsole.canvas); - Mconsole.labels.plotLabel(Mconsole.canvas, tempForT, Mconsole.config); - } - else { - var label = Mconsole.labels.getLabel(topic.id); - tempForT.setData('dim', 25, 'start'); - tempForT.setData('dim', 25, 'current'); - tempForT.setData('dim', 25, 'end'); - if (tempForT.name != topic.name) { - tempForT.name = topic.name; - $(label).find('.best_in_place_name').html(topic.name); - $(label).find('.label').html(topic.name); - } - if (tempForT.data.$metacode != topic.data.$metacode) { - $(label).find('.best_in_place_metacode').html(topic.data.$metacode); - $(label).find('img.icon').attr('alt', topic.data.$metacode); - $(label).find('img.icon').attr('src', imgArray[topic.data.$metacode].src); - } - if (tempForT.data.$desc != topic.data.$desc) { - $(label).find('.best_in_place_desc').html(topic.data.$desc); - } - if (tempForT.data.$link != topic.data.$link) { - $(label).find('.best_in_place_link').html(topic.data.$link); - $(label).find('.link').attr('href',topic.data.$link); - } - tempForT.data = topic.data; - } -<% end %> - -<% @synapses.each do |synapse| %> - var Node1 = Mconsole.graph.getNode(<%= synapse.topic1.id %>); - var Node2 = Mconsole.graph.getNode(<%= synapse.topic2.id %>); - Mconsole.graph.addAdjacence(Node1, Node2, {}); - tempForS = Mconsole.graph.getAdjacence(Node1.id, Node2.id); - tempForS.setDataset('start', { - lineWidth: 0.4 - }); - tempForS.setDataset('end', { - lineWidth: 2 - }); - var d = new Array(<%= synapse.node1_id.to_s() %>, <%= synapse.node2_id.to_s() %>); - tempForS.setDataset('current', { - desc: '<%= synapse.desc %>', - showDesc: false, - category: '<%= synapse.category %>', - id: '<%= synapse.id %>', - userid: '<%= synapse.user.id %>', - username: '<%= synapse.user.name %>' - }); - tempForS.data.$direction = d; - Mconsole.fx.plotLine(tempForS, Mconsole.canvas); -<% end %> - -<% @mappings.each do |mapping| %> - tempForM = Mconsole.graph.getNode(<%= mapping.topic_id %>); - tempForM.data.$xloc = <%= mapping.xloc %>; - tempForM.data.$yloc = <%= mapping.yloc %>; - var newPos = new $jit.Complex(); - newPos.x = tempForM.data.$xloc; - newPos.y = tempForM.data.$yloc; - tempForM.setPos(newPos, 'start'); - tempForM.setPos(newPos, 'current'); - tempForM.setPos(newPos, 'end'); -<% end %> - -<% if @topics.length > 0 || @synapses.length > 0 || @mappings.length > 0 %> - $('#map_time').val(Math.round((new Date()).getTime() / 1000)); - Mconsole.fx.animate({ - modes: ['linear','node-property:dim','edge-property:lineWidth'], - transition: $jit.Trans.Quad.easeInOut, - duration: 500 - }); -<% end %> diff --git a/app/views/maps/savelayout.js.erb b/app/views/maps/savelayout.js.erb deleted file mode 100644 index 3372a417..00000000 --- a/app/views/maps/savelayout.js.erb +++ /dev/null @@ -1,6 +0,0 @@ -/* - * @file - * Javascript executed when you save the layout of a map. - */ -$('.sidebarSave .tip').html('Saved!'); -setTimeout(function(){ $('.sidebarSave .tip').html('Save Layout') },1500); diff --git a/app/views/maps/show.html.erb b/app/views/maps/show.html.erb index 474a6c1a..0c5e4f97 100644 --- a/app/views/maps/show.html.erb +++ b/app/views/maps/show.html.erb @@ -1,133 +1,17 @@ <%# - # @file - # Code to display a map - # /maps/:id - #%> - +# @file +# Code to display a map +# /maps/:id +#%> + <% content_for :title, @map.name + " | Metamaps" %> - -
- -
- - -<% if authenticated? %> - <% if @map.permission == "commons" || @map.user == user %> -
-
-
Save Layout
-
-
-
- <% end %> -
-
-
Save To New Map
-
-
-
- <% if @map.permission == "commons" || @map.user == user %> -
-
-
-

Realtime:

- OFF -
-
-
    -
  • - <%= user.name %> (me) -
  • -
-
-
-
- <% end %> -<% end %> -
-
-
-

Filter By Metacode

allnone -
- <%= render :partial => 'main/filterbymetacode' %> -
-
- -
-
- - <%= @map.name %> - -
- <%= render :partial => 'maps/mapinfobox' %> -
- -
-
-
-
-
-
-
- -<% if authenticated? %> - - <% # add these if you have edit permissions on the map %> - <% if @map.permission == "commons" || @map.user == user %> - - <% # for creating and pulling in topics and synapses %> - <%= render :partial => 'newtopic' %> - <%= render :partial => 'newsynapse' %> - - <% # for saving the layout of the map %> - <%= form_for @map, :url => savelayout_path(@map), :html => { :class => "saveMapLayout", :id => "saveMapLayout"}, remote: true do |form| %> - <%= form.hidden_field "coordinates", :value => "" %> - <% end %> - - <% end %> - - <% # for populating the change metacode list on the topic card %> - <%= render :partial => 'main/metacodeoptions' %> -<% end %> - - \ No newline at end of file + Metamaps.currentSection = "map"; + Metamaps.currentPage = <%= @map.id.to_s %>; + Metamaps.Active.Map = <%= @map.to_json.html_safe %>; + Metamaps.Mappers = <%= @allmappers.to_json.html_safe %>; + Metamaps.Topics = <%= @alltopics.to_json.html_safe %>; + Metamaps.Synapses = <%= @allsynapses.to_json.html_safe %>; + Metamaps.Mappings = <%= @allmappings.to_json.html_safe %>; + Metamaps.Visualize.type = "ForceDirected"; + diff --git a/app/views/metacode_sets/_form.html.erb b/app/views/metacode_sets/_form.html.erb index 22815b60..3a5089b9 100644 --- a/app/views/metacode_sets/_form.html.erb +++ b/app/views/metacode_sets/_form.html.erb @@ -25,14 +25,18 @@

Choose Metacodes

-
Select AllUnselect All
-
+
+ Select All + Unselect All +
+
    <% $i = 0 %> <% @m = Metacode.order("name").all %> <% while $i < (Metacode.all.length / 4) do %> -
  • class="toggledOff"<% end %> > +
  • class="toggledOff"<% end %> + onclick="Metamaps.Admin.liClickHandler.call(this);"> <%= @m[$i].name %>

    <%= @m[$i].name.downcase %>

    @@ -42,7 +46,8 @@
    <% while $i < (Metacode.all.length / 4 * 2) do %> -
  • class="toggledOff"<% end %> > +
  • class="toggledOff"<% end %> + onclick="Metamaps.Admin.liClickHandler.call(this);"> <%= @m[$i].name %>

    <%= @m[$i].name.downcase %>

    @@ -52,7 +57,8 @@
    <% while $i < (Metacode.all.length / 4 * 3) do %> -
  • class="toggledOff"<% end %> > +
  • class="toggledOff"<% end %> + onclick="Metamaps.Admin.liClickHandler.call(this);"> <%= @m[$i].name %>

    <%= @m[$i].name.downcase %>

    @@ -62,7 +68,8 @@
    <% while $i < Metacode.all.length do %> -
  • class="toggledOff"<% end %> > +
  • class="toggledOff"<% end %> + onclick="Metamaps.Admin.liClickHandler.call(this);"> <%= @m[$i].name %>

    <%= @m[$i].name.downcase %>

    @@ -75,7 +82,8 @@
    - <%= link_to 'Cancel', metacode_sets_path, { :class => 'button' }%> - <%= f.submit :class => 'add' %> + <%= link_to 'Cancel', metacode_sets_path, + { :class => 'button', 'data-bypass' => 'true' } %> + <%= f.submit :class => 'add', :onclick => "return Metamaps.Admin.validate();" %>
    <% end %> \ No newline at end of file diff --git a/app/views/metacode_sets/edit.html.erb b/app/views/metacode_sets/edit.html.erb index 1c472eb6..5377cba8 100644 --- a/app/views/metacode_sets/edit.html.erb +++ b/app/views/metacode_sets/edit.html.erb @@ -1,57 +1,14 @@ -

    - Edit -

    - -
    -<%= render 'form' %> +
    +
    + <%= render 'form' %> +
    diff --git a/app/views/metacode_sets/index.html.erb b/app/views/metacode_sets/index.html.erb index a3df5c3e..7a93d97f 100644 --- a/app/views/metacode_sets/index.html.erb +++ b/app/views/metacode_sets/index.html.erb @@ -1,44 +1,37 @@ -

    - Metacode Sets -

    +
    +
    + <%= render :partial => 'admin/adminpanel' %> +
    + + + + + + -
    -<%= render :partial => 'admin/adminpanel' %> -
    -
    NameDescriptionMetacodes
    - - - - - - -<% @metacode_sets.each do |metacode_set| %> - - - - + + + - -<% end %> -
    NameDescriptionMetacodes
    - <%= metacode_set.name %>
    - <%= link_to 'Edit', edit_metacode_set_path(metacode_set) %>
    - <%= link_to 'Delete', metacode_set, method: :delete, data: { confirm: 'Are you sure?' } %> -
    <%= metacode_set.desc %> - <% metacode_set.metacodes.each_with_index do |metacode, index| %> - - <% if (index+1)%4 == 0 %> -
    + <% @metacode_sets.each do |metacode_set| %> +
    + <%= metacode_set.name %>
    + <%= link_to 'Edit', + edit_metacode_set_path(metacode_set), :data => { :bypass => 'true'} %> +
    + <%= link_to 'Delete', + metacode_set, method: :delete, + data: { confirm: 'Are you sure?', bypass: 'true' } %> +
    <%= metacode_set.desc %> + <% metacode_set.metacodes.each_with_index do |metacode, index| %> + + <% if (index+1)%4 == 0 %> +
    + <% end %> <% end %> - <% end %> -
    -
    -
    - - \ No newline at end of file +
    + + + <% end %> + +
    +
    \ No newline at end of file diff --git a/app/views/metacode_sets/new.html.erb b/app/views/metacode_sets/new.html.erb index 6fbb8218..1ff5e852 100644 --- a/app/views/metacode_sets/new.html.erb +++ b/app/views/metacode_sets/new.html.erb @@ -1,58 +1,14 @@ -

    - New Metacode Set -

    - -
    -<%= render 'form' %> +
    +
    + <%= render 'form' %> +
    \ No newline at end of file diff --git a/app/views/metacode_sets/show.html.erb b/app/views/metacode_sets/show.html.erb deleted file mode 100644 index ab449dc1..00000000 --- a/app/views/metacode_sets/show.html.erb +++ /dev/null @@ -1,19 +0,0 @@ -

    - <%= @metacode_set.name %> -

    - -
    -

    - Name: - <%= @metacode_set.name %> -

    - -

    - Description: - <%= @metacode_set.desc %> -

    - - -<%= link_to 'Edit', edit_metacode_set_path(@metacode_set) %> | -<%= link_to 'Back', metacode_sets_path %> -
    \ No newline at end of file diff --git a/app/views/metacodes/_form.html.erb b/app/views/metacodes/_form.html.erb index b41f409d..de815bbc 100644 --- a/app/views/metacodes/_form.html.erb +++ b/app/views/metacodes/_form.html.erb @@ -22,7 +22,7 @@
    - <%= link_to 'Cancel', metacodes_path, { :class => 'button' }%> + <%= link_to 'Cancel', metacodes_path, { :class => 'button', 'data-bypass' => 'true' } %> <%= f.submit :class => 'add' %>
    <% end %> diff --git a/app/views/metacodes/edit.html.erb b/app/views/metacodes/edit.html.erb index bfb27aa0..de8c85c1 100644 --- a/app/views/metacodes/edit.html.erb +++ b/app/views/metacodes/edit.html.erb @@ -1,7 +1,5 @@ -

    - Edit -

    - -
    -<%= render 'form' %> +
    +
    + <%= render 'form' %> +
    \ No newline at end of file diff --git a/app/views/metacodes/index.html.erb b/app/views/metacodes/index.html.erb index ea063b92..36901d56 100644 --- a/app/views/metacodes/index.html.erb +++ b/app/views/metacodes/index.html.erb @@ -1,34 +1,23 @@ -

    - Metacodes -

    +
    +
    + <%= render :partial => 'admin/adminpanel' %> +
    + + + + + + + -
    -<%= render :partial => 'admin/adminpanel' %> -
    -
    NameIcon
    - - - - - - - -<% @metacodes.each do |metacode| %> - - - - - - -<% end %> -
    NameIcon
    <%= metacode.name %><%= metacode.icon %><%= link_to 'Edit', edit_metacode_path(metacode) %>
    -
    - - \ No newline at end of file + <% @metacodes.each do |metacode| %> + + <%= metacode.name %> + <%= metacode.icon %> + + <%= link_to 'Edit', edit_metacode_path(metacode), :data => { :bypass => 'true'} %> + + <% end %> + +
    +
    \ No newline at end of file diff --git a/app/views/metacodes/new.html.erb b/app/views/metacodes/new.html.erb index ccd6fd1d..8520bb6c 100644 --- a/app/views/metacodes/new.html.erb +++ b/app/views/metacodes/new.html.erb @@ -1,7 +1,5 @@ -

    - New Metacode -

    - -
    -<%= render 'form' %> +
    +
    + <%= render 'form' %> +
    \ No newline at end of file diff --git a/app/views/metacodes/show.html.erb b/app/views/metacodes/show.html.erb deleted file mode 100644 index d987a575..00000000 --- a/app/views/metacodes/show.html.erb +++ /dev/null @@ -1,19 +0,0 @@ -

    - <%= @metacode.name %> -

    - -
    -

    - Name: - <%= @metacode.name %> -

    - -

    - Icon: - <%= @metacode.icon %> -

    - - -<%= link_to 'Edit', edit_metacode_path(@metacode) %> | -<%= link_to 'Back', metacodes_path %> -
    \ No newline at end of file diff --git a/app/views/layouts/_cheatsheet.html.erb b/app/views/shared/_cheatsheet.html.erb similarity index 73% rename from app/views/layouts/_cheatsheet.html.erb rename to app/views/shared/_cheatsheet.html.erb index 97cbf8ee..e55f1e91 100644 --- a/app/views/layouts/_cheatsheet.html.erb +++ b/app/views/shared/_cheatsheet.html.erb @@ -3,44 +3,33 @@ # The inner HTML of the cheatsheet #%> -

    Quick Reference Guide

    - +

    HELP

    +
    + + +
      - <% if controller_name == "topics" && action_name == "show" %>
    • Topic View
    • - <% end %> - <% if authenticated? && controller_name == "maps" && action_name == "show" %>
    • Creating Topics
    • - <% end %> - <% if authenticated? && (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    • Editing Topics
    • - <% end %> - <% if authenticated? && controller_name == "maps" && action_name == "show" %>
    • Creating Synapses
    • - <% end %> - <% if authenticated? && (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    • Editing Synapses
    • - <% end %> - <% if (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    • Navigation
    • Selection
    • - <% end %>
    • Search
    • -
    - <% if controller_name == "topics" && action_name == "show" %>
    -

    Topic View

    Alt + click on topic icon: recenter topics around chosen topic
    Right-click + 'center this topic': recenter topics around chosen topic
    - <% end %> - <% if authenticated? && controller_name == "maps" && action_name == "show" %>
    -

    Creating Topics

    Double-click on canvas: Bring up the metacode spinner
    Scroll: change metacode spinner selection
    Tab: rotate spinner counter-clockwise
    @@ -49,11 +38,8 @@
    Enter: create a new topic
    Gear Icon: open up metacode settings
    - <% end %> - <% if authenticated? && (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    -

    Editing Topics

    Open topic card: double-click on topic icon
    @@ -83,11 +69,8 @@
    *Hide/Remove/Delete topic within context menu
    - <% end %> - <% if authenticated? && controller_name == "maps" && action_name == "show" %>
    -

    Creating Synapses

    Right-click & drag from one topic to another: open create synapse prompt
    Enter: Create synapse
    *You do not have to add a description
    @@ -95,11 +78,8 @@
    Enter: Create topic
    Enter: Create synapse
    - <% end %> - <% if authenticated? && (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    -

    Editing Synapses

    Open synapse card:double-click on synapse
    Edit synapse description: click on current description text
    Save synapse description: hit enter
    @@ -108,18 +88,14 @@
    Right-click on synapse: open context menu
    *Hide/Remove/Delete synapse within context menu
    - <% end %> - <% if (controller_name == "maps" || controller_name == "topics" ) && action_name == "show" %>
    -

    Navigation

    Click + drag: move around canvas
    Scroll: zoom in/out
    Refresh page: center map
    -

    Selection

    Click on topic icon: select/deselect topic
    Click on synapse: select/deselect synapse
    Shift + click: select multiple topics / synapses
    @@ -130,10 +106,8 @@
    Click on background: deselect all topics & synapses
    Esc: deselect all topics & synapses
    - <% end %>
    -

    Search

    Ctrl + /: open search prompt
    Esc: close search prompt
    Type into the search prompt: search for topics, maps, & mappers
    @@ -147,4 +121,56 @@
    -
    +
    + +
    1. GETTING STARTED
    +
    2. UP YOUR SKILLZ
    +
    3. ADVANCED MAPPING
    +
    + +
    +

    For more information about Metamaps.cc, visit our Knowledge Base or skip directly to a section by clicking on one of the categories below.

    + + +
    + + +
    \ No newline at end of file diff --git a/app/views/shared/_filterBox.html.erb b/app/views/shared/_filterBox.html.erb new file mode 100644 index 00000000..4ba9b91a --- /dev/null +++ b/app/views/shared/_filterBox.html.erb @@ -0,0 +1,93 @@ +<%# + # @file + # this code generates the list of icons in the filter box in the upper right menu area + #%> + +<% + @mappers = [] + @synapses = [] + @metacodes = [] + @metacodelist = '' + @mapperlist = '' + @synapselist = '' +# There are essentially three functions happening here one to fill data to +#@mappers with all people who have mapped on the selected map, which +#actually gets checked twice once for topics or within @metacodes and once +#for synapses on the map. @synapses get filled with all synapses on the map +#and metacodes is filled with all the metacodes that are being used on the map. + + if @map + @map.topics.each_with_index do |topic, index| + if @metacodes.index(topic.metacode) == nil + @metacodes.push(topic.metacode) + end + end + @map.synapses.each_with_index do |synapse, index| + if @synapses.index{|s| s.desc == synapse.desc} == nil + @synapses.push(synapse) + end + end + @map.mappings.each_with_index do |mapping, index| + if @mappers.index(mapping.user) == nil + @mappers.push(mapping.user) + end + end + + @metacodes.sort! {|x,y| x.name <=> y.name } + @synapses.sort! {|x,y| x.desc <=> y.desc } + @mappers.sort! {|x,y| x.name <=> y.name } + + @metacodes.each_with_index do |metacode, index| + @metacodelist += '
  • ' + @metacodelist += '' + metacode.name + '' + @metacodelist += '

    ' + metacode.name.downcase + '

  • ' + end + @synapses.each_with_index do |synapse, index| + @synapselist += '
  • ' + @synapselist += 'synapse icon

    ' + synapse.desc + @synapselist += '

  • ' + end + @mappers.each_with_index do |mapper, index| + @mapperlist += '
  • ' + @mapperlist += '' + mapper.name + '' + @mapperlist += '

    ' + mapper.name + '

  • ' + end + end +%> +
    +

    FILTER BY

    +
    +

    MAPPERS

    + NONE + ALL +
    +
      + <%= @mapperlist.html_safe %> +
    +
    +
    + +
    +

    METACODES

    + NONE + ALL +
    +
      + <%= @metacodelist.html_safe %> +
    +
    +
    + +
    +

    SYNAPSES

    + NONE + ALL +
    +
      + <%= @synapselist.html_safe %> +
    +
    +
    + +
    + diff --git a/app/views/shared/_forkmap.html.erb b/app/views/shared/_forkmap.html.erb new file mode 100644 index 00000000..4f45a647 --- /dev/null +++ b/app/views/shared/_forkmap.html.erb @@ -0,0 +1,62 @@ +<%# + # @file + # Partial view, renders a form that creates a new map. + #%> +
    +<%= form_for Map.new, url: maps_url, remote: true, html: { class: "new_map", id: "fork_map" } do |form|%> + +

    Save To New Map

    + +
    + + <%= form.text_field :name %> +
    +
    + +
    + + <%= form.text_area :desc, class: "description", :rows => 5, :cols => 43 %> +
    +
    + +
    + +

    *new topics and synapses take on the same permission as the map they are created on

    +
    +
    +
    +
    + Collaborate with other mappers on editing this map. Those without accounts can view this map. +
    +
    +

    COMMONS

    +
    +
    +
    +
    + Anyone, with or without an account, can view this map but not edit anything. +
    +
    +

    PUBLIC

    +
    +
    +
    +
    + Only you can view or edit this map. +
    +
    +

    PRIVATE

    +
    +
    +
    +

    Collaborate with other mappers on editing this map. Those without accounts can view this map.

    +
    +
    + +
    + + +
    +
    +<% end %> +
    diff --git a/app/views/shared/_metacodeoptions.html.erb b/app/views/shared/_metacodeoptions.html.erb new file mode 100644 index 00000000..0701be4d --- /dev/null +++ b/app/views/shared/_metacodeoptions.html.erb @@ -0,0 +1,37 @@ +<%# + # @file + # this code generates the list of icons that will drop down in the metacode select list on the topic card + #%> + +
    +
      + <% MetacodeSet.order("name").all.each do |set| %> +
    • + <%= set.name %> +
      +
        + <% set.metacodes.sort { |a, b| a.name <=> b.name }.each do |m| %> +
      • + <%= m.name %> + <%= m.name %> +
        +
      • + <% end %> +
      +
    • + <% end %> +
    • + All +
      +
        + <% Metacode.order("name").all.each do |m| %> +
      • + <%= m.name %> + <%= m.name %> +
        +
      • + <% end %> +
      +
    • +
    +
    \ No newline at end of file diff --git a/app/views/layouts/_switchmetacodes.html.erb b/app/views/shared/_switchmetacodes.html.erb similarity index 80% rename from app/views/layouts/_switchmetacodes.html.erb rename to app/views/shared/_switchmetacodes.html.erb index fcddc7f7..238a83a3 100644 --- a/app/views/layouts/_switchmetacodes.html.erb +++ b/app/views/shared/_switchmetacodes.html.erb @@ -13,18 +13,19 @@ index = allMetacodeSets.index(set) end %>

    Switch Metacode Set

    + +

    Use metacode sets to enter different modes of mapping.

    <% allMetacodeSets.each_with_index do |m, localindex| %>
    -

    <%= m.name %>

    <% @list = '' %> <% m.metacodes.sort{|x,y| x.name <=> y.name }.each_with_index do |m, index| %> <% @list += '
  • ' + m.name + '

    ' + m.name.downcase + '

  • ' %> @@ -36,7 +37,9 @@
- +
<% end %>
@@ -57,13 +60,15 @@
- +
\ No newline at end of file diff --git a/app/views/synapses/_new.html.erb b/app/views/synapses/_new.html.erb index 50ecc35c..e1e7d176 100644 --- a/app/views/synapses/_new.html.erb +++ b/app/views/synapses/_new.html.erb @@ -6,8 +6,5 @@
<%= form_for Synapse.new, url: synapses_url, remote: true do |form| %> <%= form.text_field :desc, :placeholder => "describe the connection..." %> - <%= form.hidden_field :topic1id, :value => 0 %> - <%= form.hidden_field :topic2id, :value => 0 %> - <%= form.hidden_field :grabSynapse, :value => "null" %> <% end %>
diff --git a/app/views/synapses/create.js.erb b/app/views/synapses/create.js.erb deleted file mode 100644 index d2c8dcf8..00000000 --- a/app/views/synapses/create.js.erb +++ /dev/null @@ -1,55 +0,0 @@ -/* - * @file - * Javascript called when you create a new synapse. - */ -$('#new_synapse').fadeOut('fast'); -$('#synapse_desc').typeahead('setQuery',''); -$('#synapse_topic1id').attr('value','0'); -$('#synapse_topic2id').attr('value','0'); -$('#synapse_grabSynapse').attr('value','null'); -// reset the draw synapse positions to false -MetamapsModel.synapseStartCoord = false; -MetamapsModel.synapseEndCoord = false; - -var temp1, temp2, temp; - -if ( Mconsole != null) { - temp1 = Mconsole.graph.getNode(<%= @synapse.topic1.id %>); - temp2 = Mconsole.graph.getNode(<%= @synapse.topic2.id %>); - temp2.setData('dim', 25, 'current'); - Mconsole.graph.addAdjacence(temp1, temp2, {}); - temp = Mconsole.graph.getAdjacence(temp1.id, temp2.id); - temp.setDataset('start', { - lineWidth: 0.4, - alpha: 0.1 - }); - temp.setDataset('end', { - lineWidth: 2, - alpha: 1 - }); - var d = new Array(<%= @synapse.node1_id.to_s() %>, <%= @synapse.node2_id.to_s() %>); - temp.setDataset('current', { - desc: '<%= @synapse.desc %>', - showDesc: true, //will be changed by selectEdge - category: '<%= @synapse.category %>', - id: '<%= @synapse.id %>', - userid: <%= @synapse.user.id %>, - username: '<%= @synapse.user.name %>', - permission: '<%= @synapse.permission %>' - }); - temp.data.$direction = d; - Mconsole.fx.animate({ - modes: ['edge-property:lineWidth:alpha'], - duration: 100, - onComplete: function() { - setTimeout(function (){ - temp.setData('showDesc', false); - Mconsole.plot(); - }, 3000); - } - }); -} -else { - json = <%= @synapse.selfplusnodes_as_json.html_safe %> - initialize("chaotic"); -} diff --git a/app/views/synapses/destroy.js.erb b/app/views/synapses/destroy.js.erb deleted file mode 100644 index c9d0a6b9..00000000 --- a/app/views/synapses/destroy.js.erb +++ /dev/null @@ -1,4 +0,0 @@ -/* - * @file - * Javascript called when you destroy a node - */ diff --git a/app/views/synapses/removefrommap.js.erb b/app/views/synapses/removefrommap.js.erb deleted file mode 100644 index 61bfd185..00000000 --- a/app/views/synapses/removefrommap.js.erb +++ /dev/null @@ -1,5 +0,0 @@ -/* - * @file - * Javascript executed when a synapse is removed from a map - * TODO: Is this file even used? - */ diff --git a/app/views/synapses/update.js.erb b/app/views/synapses/update.js.erb deleted file mode 100644 index b8f9dd59..00000000 --- a/app/views/synapses/update.js.erb +++ /dev/null @@ -1,4 +0,0 @@ -/* - * @file - * Javascript called when you update a synapse - */ diff --git a/app/views/topics/_new.html.erb b/app/views/topics/_new.html.erb index e3421ec3..7aa13eb3 100644 --- a/app/views/topics/_new.html.erb +++ b/app/views/topics/_new.html.erb @@ -24,11 +24,6 @@ <% end %> <%= form.text_field :name, :maxlength => 140, :placeholder => "title..." %> - <%= form.hidden_field :metacode, :value => "Action" %> - <%= form.hidden_field :x, :value => 0 %> - <%= form.hidden_field :y, :value => 0 %> - <%= form.hidden_field :grabTopic, :value => "null" %> - <%= form.hidden_field :addSynapse, :value => false %>
<% end %> diff --git a/app/views/topics/create.js.erb b/app/views/topics/create.js.erb deleted file mode 100644 index 77defa96..00000000 --- a/app/views/topics/create.js.erb +++ /dev/null @@ -1,115 +0,0 @@ -/* - * @file - * This javascript is returned and executed when you create a new node. - */ -$('#new_topic').fadeOut('fast'); -$('#topic_name').typeahead('setQuery',''); -$('#topic_grabTopic').attr('value','null'); -$('#topic_addSynapse').attr('value','false'); - -var newnode = <%= @topic.self_as_json.html_safe %>; -var x = <%= @position['x'] %>; -var y = <%= @position['y'] %>; - - -if (!$.isEmptyObject(Mconsole.graph.nodes)) { - Mconsole.graph.addNode(newnode); - - // set the animation for everything back to normal - Mconsole.graph.eachNode( function (n) { - n.setData('dim', 25, 'start'); - n.setData('dim', 25, 'end'); - }); - var temp = Mconsole.graph.getNode('<%= @topic.id %>'); - temp.setData('dim', 1, 'start'); - temp.setData('dim', 40, 'end'); - temp.setData('whiteCircle', false); - temp.setData('greenCircle', false); - - if (gType == "centered") { - var tempPos = new $jit.Complex(x, y); - tempPos = tempPos.toPolar(); - temp.setPos(tempPos, 'current'); - temp.setPos(tempPos, 'start'); - temp.setPos(tempPos, 'end'); - temp._depth = tempNode._depth + 1; - } - else if (gType == "arranged" || gType == "chaotic") { - temp.setData('xloc',0); - temp.setData('yloc',0); - <% if not @mapping.nil? %> - temp.setData('mappingid', <%= @mapping.id %>); - <% elsif @mapping.nil? %> - temp.setData('mappingid', null); - <% end %> - temp.setPos(new $jit.Complex(x, y), 'current'); - temp.setPos(new $jit.Complex(x, y), 'start'); - temp.setPos(new $jit.Complex(x, y), 'end'); - } - - if ( '<%= @synapse %>' == "true" ) { - $('#synapse_topic1id').val(tempNode.id); - $('#synapse_topic2id').val(temp.id); - $('#synapse_desc').val(""); - $('#new_synapse').fadeIn('fast'); - $('#synapse_desc').focus(); - Mconsole.fx.animate({ - modes: ['node-property:dim'], - duration: 500, - onComplete: function() { - setTimeout(function (){ - temp.setData('dim', 25, 'current'); - Mconsole.plot(); - }, 3000); - Mconsole.fx.plotNode(tempNode, Mconsole.canvas); - Mconsole.fx.plotNode(temp, Mconsole.canvas); - tempNode = null; - tempNode2 = null; - tempInit = false; - } - }); - } else if ( '<%= @synapse %>' == "false" ) { - Mconsole.fx.plotNode(temp, Mconsole.canvas); - Mconsole.fx.animate({ - modes: ['node-property:dim'], - duration: 500, - onComplete: function() { - setTimeout(function (){ - temp.setData('dim', 25, 'current'); - Mconsole.plot(); - }, 3000); - } - }); - - } - -} else { - json = newnode; - Mconsole.loadJSON(json); - var temp = Mconsole.graph.getNode('<%= @topic.id %>'); - temp.setData('dim', 1, 'start'); - temp.setData('dim', 25, 'end'); - temp.setData('whiteCircle', false); - temp.setData('greenCircle', false); - if (gType == "arranged" || gType == "chaotic") { - <% if not @mapping.nil? %> - temp.setData('mappingid', <%= @mapping.id %>); - <% elsif @mapping.nil? %> - temp.setData('mappingid', null); - <% end %> - } - temp.setPos(new $jit.Complex(x, y), 'current'); - temp.setPos(new $jit.Complex(x, y), 'start'); - temp.setPos(new $jit.Complex(x, y), 'end'); - Mconsole.fx.plotNode(temp, Mconsole.canvas); - Mconsole.fx.animate({ - modes: ['node-property:dim'], - duration: 500, - onComplete: function() { - setTimeout(function (){ - temp.setData('dim', 25, 'current'); - Mconsole.plot(); - }, 3000); - } - }); -} diff --git a/app/views/topics/destroy.js.erb b/app/views/topics/destroy.js.erb deleted file mode 100644 index 5c133d12..00000000 --- a/app/views/topics/destroy.js.erb +++ /dev/null @@ -1,33 +0,0 @@ -/* - * @file - * The javascript returned when destroy is called in the topic controller - * This happens when a DELETE is sent to /topics/:id - */ - -if (Mconsole != null) { - - var node = Mconsole.graph.getNode(<%= @topic.id %>); - - if (node.id == Mconsole.root) { - Mconsole.graph.eachNode(function (n) { - if (n.id != node.id) Mconsole.root = n.id; - }); - } - - node.setData('alpha', 0, 'end'); - node.eachAdjacency(function(adj) { - adj.setData('alpha', 0, 'end'); - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 1000 - }); - Mconsole.graph.removeNode(<%= @topic.id %>); - Mconsole.labels.disposeLabel(<%= @topic.id %>); - delete Mconsole.labels.labels['<%= @topic.id %>'] - -} -else { - $('#<%= dom_id(@topic) %>').fadeOut('slow'); -} diff --git a/app/views/topics/removefrommap.js.erb b/app/views/topics/removefrommap.js.erb deleted file mode 100644 index a38fbf9e..00000000 --- a/app/views/topics/removefrommap.js.erb +++ /dev/null @@ -1,27 +0,0 @@ -/* - * @file - * This code removes a mapping from a topic on to a map, which removes the - * topic from that map. - * TODO: is this code still used? - * TODO: What URL accesses this code? - */ - - -if (Mconsole != null) { - var node = Mconsole.graph.getNode(<%= @mapping.topic_id %>); - if (node.id == Mconsole.root) { - Mconsole.graph.eachNode(function (n) { - if (n.id != node.id) Mconsole.root = n.id; - }); - } - node.setData('alpha', 0, 'end'); - node.eachAdjacency(function(adj) { - adj.setData('alpha', 0, 'end'); - }); - Mconsole.fx.animate({ - modes: ['node-property:alpha', - 'edge-property:alpha'], - duration: 1000 - }); - Mconsole.graph.removeNode(<%= @mapping.topic_id %>); -} diff --git a/app/views/topics/show.html.erb b/app/views/topics/show.html.erb index 703af0a5..efe18fcf 100644 --- a/app/views/topics/show.html.erb +++ b/app/views/topics/show.html.erb @@ -1,62 +1,25 @@ <%# - # @file - # This shows a topic view. It is used. - # The first commented out section used to be a card at the top showing all - # info. Now we're moving towards most screens looking the same. The - # consequence of accessing data from this view is that you can't remove - # the topic that corresponds to the page you're on. Originally, accessing this - # page showed the topic with its neighbours arrayed around. Now it shows the - # same, but there's no cues to say which topic's page you're on. So when the - # map recenters on a new topic, it's like you're on that topic's page. - # Nice, but the URL and being unable to remove the root node still hamper that - # experience. - # URL: /topics/ - # - #%> +# @file +# This shows a topic view. It is used. +# The first commented out section used to be a card at the top showing all +# info. Now we're moving towards most screens looking the same. The +# consequence of accessing data from this view is that you can't remove +# the topic that corresponds to the page you're on. Originally, accessing this +# page showed the topic with its neighbours arrayed around. Now it shows the +# same, but there's no cues to say which topic's page you're on. So when the +# map recenters on a new topic, it's like you're on that topic's page. +# Nice, but the URL and being unable to remove the root node still hamper that +# experience. +# URL: /topics/ +# +#%> <% content_for :title, @topic.name + " | Metamaps" %> - -<% if authenticated? %> -
-
-
Save As New Map
-
-
-
-<% end %> -
-
-
-

Filter By Metacode

allnone -
- <%= render :partial => 'main/filterbymetacode' %> -
-
- -
-
- - <%= @topic.name %> -
-
- -
-
-
-
-
-
-
- -<% if authenticated? %> - <%= render :partial => 'topics/new' %> - <%= render :partial => 'synapses/new' %> - <%= render :partial => 'main/metacodeoptions' %> -<% end %> - \ No newline at end of file diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index 732b0f03..738d5c62 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -4,13 +4,17 @@ # User edit form #%> -<% content_for :title, @user.name + "'s Settings | Metamaps" %> -

Your Settings

+<% content_for :title, @user.name + "'s Settings | Metamaps" %> +
<%= formula_form_for @user, url: user_url do |form| %>

Edit Account

+ + <% if @user.image %><%= image_tag @user.image.url(:round), :size => "48x48" %><% end %> + <%= form.file_field :image %> <%= form.input :name, label: "Name", class: "name" %> <%= form.input :email, label: "Email", class: "email" %> <%= form.input :password, label: "Password", class: "password", :autocomplete => :off %> <%= form.submit "Update", class: "update" %> <% end %> +
diff --git a/app/views/users/passwords/edit.html.erb b/app/views/users/passwords/edit.html.erb index a62d33f4..2cec4812 100644 --- a/app/views/users/passwords/edit.html.erb +++ b/app/views/users/passwords/edit.html.erb @@ -1,7 +1,6 @@ <% content_for :title, "Change Password | Metamaps" %> -

Change Password

- +
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, :class => "forgotPassword centerGreyForm" }) do |f| %> <%= devise_error_messages! %> <%= f.hidden_field :reset_password_token %> @@ -17,5 +16,5 @@
<%= f.submit "Change my password" %>
<% end %> - +
diff --git a/app/views/users/passwords/new.html.erb b/app/views/users/passwords/new.html.erb index 2fa7b099..88dddb4a 100644 --- a/app/views/users/passwords/new.html.erb +++ b/app/views/users/passwords/new.html.erb @@ -1,17 +1,17 @@ <% content_for :title, "Password Reset | Metamaps" %> -

Password Reset

- +
<%= form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, :class => "forgotPassword centerGreyForm" }) do |f| %> <%= devise_error_messages! %> -

Forgot your password?

+

FORGOT PASSWORD?

-
<%= f.label :email %> +
<%= f.label :email, "Enter Your Email:" %> <%= f.email_field :email, :autofocus => true %>
-
<%= f.submit "Send me reset password instructions" %>
+
<%= f.submit "Send Reset Password Instructions" %>
<% end %> +
diff --git a/app/views/users/registrations/new.html.erb b/app/views/users/registrations/new.html.erb index ec61da36..e7c08256 100644 --- a/app/views/users/registrations/new.html.erb +++ b/app/views/users/registrations/new.html.erb @@ -1,7 +1,6 @@ <% content_for :title, "Sign Up | Metamaps" %> -

Sign Up

- +
<%= form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :post, :class => "new_user centerGreyForm" }) do |f| %> <%= devise_error_messages! %> @@ -24,7 +23,7 @@
<%= f.submit "Sign up" %>
-

Don't have an access code?
Request an Invite
+

Don't have an access code?
Request an Invite
<% end %> - +
diff --git a/app/views/users/sessions/new.html.erb b/app/views/users/sessions/new.html.erb index ef9866f5..6f55203b 100644 --- a/app/views/users/sessions/new.html.erb +++ b/app/views/users/sessions/new.html.erb @@ -1,7 +1,6 @@ <% content_for :title, "Sign In | Metamaps" %> -

Sign In

- +
<%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :method => :post, :class => "new_user centerGreyForm" }) do |f| %>

Sign in

@@ -19,10 +18,11 @@
<%- if devise_mapping.recoverable? && controller_name != 'passwords' %> - <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+ <%= link_to "Forgot your password?", new_password_path(resource_name), + :data => { :bypass => 'true'} %>
<% end -%>
-
Don't have an account?
Request an Invite
+
Don't have an account?
Request an Invite
<% end %> - +
diff --git a/codeguide.txt b/codeguide.txt new file mode 100644 index 00000000..d10d088e --- /dev/null +++ b/codeguide.txt @@ -0,0 +1,71 @@ +FILE /app/views/layouts/application.html.erb + + ... + <%= javascript_include_tag "application" %> + <% if (controller_name == "maps" || controller_name == "topics") && action_name == "show" %> + <%= javascript_include_tag "compileMapPages" %> + <% end %> + ... + + +WHAT DOES IT MEAN? + + +____________________________________________________________________ + +FILE /app/assets/javascripts/application.js +... +//= require jquery +//= require jquery-ui +//= require jquery_ujs +//= require ./orderedLibraries/underscore +//= require ./orderedLibraries/backbone +//= require_directory ./librariesForAllPages +//= require ./metamaps/Metamaps.GlobalUI +//= require ./metamaps/Metamaps.Backbone + +WHAT DOES IT MEAN? + + +____________________________________________________________________ + +FILE /app/assets/javascripts/compileMapPages.js +... +//= require ./librariesForMapPages/cloudcarousel +//= require ./librariesForMapPages/socket.io +//= require ./metamaps/JIT +//= require ./metamaps/Metamaps +//= require ./metamaps/Metamaps.JIT + +WHAT DOES IT MEAN? + + + +____________________________________________________________________ + +FILE /app/assets/javascripts/metamaps/Metamaps.GlobalUI.js + +var Metamaps = {}; +... +$(document).ready(function () { + for (var prop in Metamaps) { + + // this runs the init function within each sub-object on the Metamaps one + if (Metamaps.hasOwnProperty(prop) && + Metamaps[prop].hasOwnProperty('init') && + typeof (Metamaps[prop].init) == 'function' + ) { + Metamaps[prop].init(); + } + } +}); +Metamaps.GlobalUI = { +... +}; + +WHAT DOES IT MEAN? + + + +____________________________________________________________________ + diff --git a/config.ru b/config.ru index 8d2cc245..e83757ab 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,4 @@ # This file is used by Rack-based servers to start the application. require ::File.expand_path('../config/environment', __FILE__) -run ISSAD::Application +run Metamaps::Application diff --git a/config/application.rb b/config/application.rb index dc87d823..d9f5f0f1 100644 --- a/config/application.rb +++ b/config/application.rb @@ -9,7 +9,7 @@ if defined?(Bundler) # Bundler.require(:default, :assets, Rails.env) end -module ISSAD +module Metamaps class Application < Rails::Application # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers @@ -53,7 +53,7 @@ module ISSAD # Enable the asset pipeline config.assets.enabled = true config.assets.initialize_on_precompile = false - + # Version of your assets, change this if you want to expire all your assets config.assets.version = '2.0' end diff --git a/config/environment.rb b/config/environment.rb index d73e6cb7..6e9ad9e4 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -2,4 +2,4 @@ require File.expand_path('../application', __FILE__) # Initialize the rails application -ISSAD::Application.initialize! +Metamaps::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index 7f1b0375..50a7f79f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,4 @@ -ISSAD::Application.configure do +Metamaps::Application.configure do # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on @@ -13,7 +13,16 @@ ISSAD::Application.configure do config.consider_all_requests_local = true config.action_controller.perform_caching = false - + # S3 file storage + config.paperclip_defaults = { + :storage => :s3, + :s3_credentials => { + :bucket => ENV['S3_BUCKET_NAME'], + :access_key_id => ENV['AWS_ACCESS_KEY_ID'], + :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'] + } + } + config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { address: 'mail.metamaps.cc', diff --git a/config/environments/production.rb b/config/environments/production.rb index 8b1bf0f9..0707c5e7 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,4 +1,4 @@ -ISSAD::Application.configure do +Metamaps::Application.configure do # Settings specified here will take precedence over those in config/application.rb # Code is not reloaded between requests @@ -13,6 +13,17 @@ ISSAD::Application.configure do # Compress JavaScripts and CSS config.assets.compress = true + + + # S3 file storage + config.paperclip_defaults = { + :storage => :s3, + :s3_credentials => { + :bucket => ENV['S3_BUCKET_NAME'], + :access_key_id => ENV['AWS_ACCESS_KEY_ID'], + :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY'] + } + } config.action_mailer.delivery_method = :smtp config.action_mailer.smtp_settings = { @@ -59,7 +70,7 @@ ISSAD::Application.configure do # config.action_controller.asset_host = "http://assets.example.com" # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added) - # config.assets.precompile += %w( search.js ) + #config.assets.precompile += %w( ) # Disable delivery errors, bad email addresses will be ignored # config.action_mailer.raise_delivery_errors = false diff --git a/config/environments/test.rb b/config/environments/test.rb index 5f3706b8..8a7b408c 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,4 +1,4 @@ -ISSAD::Application.configure do +Metamaps::Application.configure do # Settings specified here will take precedence over those in config/application.rb # The test environment is used exclusively to run your application's diff --git a/config/initializers/paperclip.rb b/config/initializers/paperclip.rb new file mode 100644 index 00000000..1447988b --- /dev/null +++ b/config/initializers/paperclip.rb @@ -0,0 +1,2 @@ +Paperclip::Attachment.default_options[:url] = ':s3_domain_url' +Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:filename' \ No newline at end of file diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 736a0d6c..b9f46222 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -4,4 +4,4 @@ # If you change this key, all old signed cookies will become invalid! # Make sure the secret is at least 30 characters and all random, # no regular words or you'll be exposed to dictionary attacks. -ISSAD::Application.config.secret_token = '267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c8005f85ee99d6d01b1ab6394cdee9ca7f8c9213a0cf91d3d8d3350f096123e2caccbcc0924f' +Metamaps::Application.config.secret_token = '267c8a84f63963282f45bc3010eaddf027abfab58fc759d6e239c8005f85ee99d6d01b1ab6394cdee9ca7f8c9213a0cf91d3d8d3350f096123e2caccbcc0924f' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index a6f08f8e..757d66cc 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,8 +1,8 @@ # Be sure to restart your server when you modify this file. -ISSAD::Application.config.session_store :cookie_store, key: '_ISSAD_session' +Metamaps::Application.config.session_store :cookie_store, key: '_Metamaps_session' # Use the database for sessions instead of the cookie-based default, # which shouldn't be used to store highly confidential information # (create the session table with "rails generate session_migration") -# ISSAD::Application.config.session_store :active_record_store +# Metamaps::Application.config.session_store :active_record_store diff --git a/config/routes.rb b/config/routes.rb index 803dea6d..ef03d2e8 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,51 +1,40 @@ -ISSAD::Application.routes.draw do +Metamaps::Application.routes.draw do root to: 'main#home', via: :get - get '/join', to: redirect('/users/sign_up') + devise_scope :user do + get "join" => "devise/registrations#new" + end match 'request', to: 'main#requestinvite', via: :get, as: :request - match 'paq', to: 'main#paq', via: :get, as: :paq - match '/search/topics', to: 'main#searchtopics', via: :get, as: :searchtopics - match '/search/maps', to: 'main#searchmaps', via: :get, as: :searchmaps - match '/search/mappers', to: 'main#searchmappers', via: :get, as: :searchmappers - match '/search/synapses', to: 'main#searchsynapses', via: :get, as: :searchsynapses + match 'search/topics', to: 'main#searchtopics', via: :get, as: :searchtopics + match 'search/maps', to: 'main#searchmaps', via: :get, as: :searchmaps + match 'search/mappers', to: 'main#searchmappers', via: :get, as: :searchmappers + match 'search/synapses', to: 'main#searchsynapses', via: :get, as: :searchsynapses - match 'maps/:id/savelayout', to: 'maps#savelayout', via: :put, as: :savelayout - match 'topics/:map_id/:topic_id/removefrommap', to: 'topics#removefrommap', via: :post, as: :removefrommap - match 'synapses/:map_id/:synapse_id/removefrommap', to: 'synapses#removefrommap', via: :post, as: :removefrommap - - resources :in_metacode_sets + resources :mappings, except: [:index, :new, :edit] resources :metacode_sets, :except => [:show] resources :metacodes, :except => [:show, :destroy] + resources :synapses, except: [:index, :new, :edit] resources :topics, except: [:index, :new, :edit] do get :autocomplete_topic, :on => :collection end - match 'topics/:id/:format', to: 'topics#json', via: :get, as: :json + match 'topics/:id/network', to: 'topics#network', via: :get, as: :network - resources :synapses, except: [:index, :new, :edit, :show] - match 'synapses/:id/:format', to: 'synapses#json', via: :get, as: :json - - match 'maps/active', to: 'maps#index', via: :get, as: :activemaps - match 'maps/featured', to: 'maps#index', via: :get, as: :featuredmaps - match 'maps/new', to: 'maps#index', via: :get, as: :newmaps + match 'explore/active', to: 'maps#index', via: :get, as: :activemaps + match 'explore/featured', to: 'maps#index', via: :get, as: :featuredmaps + match 'explore/mine', to: 'maps#index', via: :get, as: :mymaps match 'maps/mappers/:id', to: 'maps#index', via: :get, as: :usermaps match 'maps/topics/:id', to: 'maps#index', via: :get, as: :topicmaps - - resources :maps, except: [:new, :edit] match 'maps/:id/embed', to: 'maps#embed', via: :get, as: :embed - match 'maps/:id/:format', to: 'maps#json', via: :get, as: :json + match 'maps/:id/contains', to: 'maps#contains', via: :get, as: :contains devise_for :users, :controllers => { :registrations => "registrations" }, :path_names => { :sign_in => 'login', :sign_out => 'logout' } devise_scope :user do get "sign_out", :to => "devise/sessions#destroy" end match 'user/updatemetacodes', to: 'users#updatemetacodes', via: :post, as: :updatemetacodes - - resources :users, except: [:show, :index] - - resources :mappings - + resources :users, except: [:index, :destroy] end diff --git a/db/migrate/20140625212637_add_image_and_audio_to_topics.rb b/db/migrate/20140625212637_add_image_and_audio_to_topics.rb new file mode 100644 index 00000000..46bead64 --- /dev/null +++ b/db/migrate/20140625212637_add_image_and_audio_to_topics.rb @@ -0,0 +1,11 @@ +class AddImageAndAudioToTopics < ActiveRecord::Migration + def self.up + add_attachment :topics, :image + add_attachment :topics, :audio + end + + def self.down + remove_attachment :topics, :image + remove_attachment :topics, :audio + end +end diff --git a/db/migrate/20140707161810_add_image_to_users.rb b/db/migrate/20140707161810_add_image_to_users.rb new file mode 100644 index 00000000..0a479fda --- /dev/null +++ b/db/migrate/20140707161810_add_image_to_users.rb @@ -0,0 +1,9 @@ +class AddImageToUsers < ActiveRecord::Migration + def self.up + add_attachment :users, :image + end + + def self.down + remove_attachment :users, :image + end +end diff --git a/db/migrate/20140815162253_add_screenshot_to_maps.rb b/db/migrate/20140815162253_add_screenshot_to_maps.rb new file mode 100644 index 00000000..c42cca51 --- /dev/null +++ b/db/migrate/20140815162253_add_screenshot_to_maps.rb @@ -0,0 +1,9 @@ +class AddScreenshotToMaps < ActiveRecord::Migration + def self.up + add_attachment :maps, :screenshot + end + + def self.down + remove_attachment :maps, :screenshot + end +end diff --git a/db/schema.rb b/db/schema.rb index 0a8292d7..4c22e7e5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,117 +1,133 @@ -# encoding: UTF-8 -# This file is auto-generated from the current state of the database. Instead -# of editing this file, please use the migrations feature of Active Record to -# incrementally modify your database, and then regenerate this schema definition. -# -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). -# -# It's strongly recommended to check this file into your version control system. - -ActiveRecord::Schema.define(:version => 20140517115841) do - - create_table "in_metacode_sets", :force => true do |t| - t.integer "metacode_id" - t.integer "metacode_set_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "in_metacode_sets", ["metacode_id"], :name => "index_in_metacode_sets_on_metacode_id" - add_index "in_metacode_sets", ["metacode_set_id"], :name => "index_in_metacode_sets_on_metacode_set_id" - - create_table "mappings", :force => true do |t| - t.text "category" - t.integer "xloc" - t.integer "yloc" - t.integer "topic_id" - t.integer "synapse_id" - t.integer "map_id" - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "maps", :force => true do |t| - t.text "name" - t.boolean "arranged" - t.text "desc" - t.text "permission" - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.boolean "featured" - end - - create_table "metacode_sets", :force => true do |t| - t.string "name" - t.text "desc" - t.integer "user_id" - t.boolean "mapperContributed" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - add_index "metacode_sets", ["user_id"], :name => "index_metacode_sets_on_user_id" - - create_table "metacodes", :force => true do |t| - t.text "name" - t.string "icon" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "synapses", :force => true do |t| - t.text "desc" - t.text "category" - t.text "weight" - t.text "permission" - t.integer "node1_id" - t.integer "node2_id" - t.integer "user_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "topics", :force => true do |t| - t.text "name" - t.text "desc" - t.text "link" - t.text "permission" - t.integer "user_id" - t.integer "metacode_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - end - - create_table "users", :force => true do |t| - t.string "name" - t.string "email" - t.text "settings" - t.string "code", :limit => 8 - t.string "joinedwithcode", :limit => 8 - t.string "crypted_password" - t.string "password_salt" - t.string "persistence_token" - t.string "perishable_token" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false - t.string "encrypted_password", :limit => 128, :default => "" - t.string "remember_token" - t.datetime "remember_created_at" - t.string "reset_password_token" - t.datetime "last_sign_in_at" - t.string "last_sign_in_ip" - t.integer "sign_in_count", :default => 0 - t.datetime "current_sign_in_at" - t.string "current_sign_in_ip" - t.datetime "reset_password_sent_at" - t.boolean "admin" - end - - add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true - -end +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20140815162253) do + + create_table "in_metacode_sets", :force => true do |t| + t.integer "metacode_id" + t.integer "metacode_set_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "in_metacode_sets", ["metacode_id"], :name => "index_in_metacode_sets_on_metacode_id" + add_index "in_metacode_sets", ["metacode_set_id"], :name => "index_in_metacode_sets_on_metacode_set_id" + + create_table "mappings", :force => true do |t| + t.text "category" + t.integer "xloc" + t.integer "yloc" + t.integer "topic_id" + t.integer "synapse_id" + t.integer "map_id" + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "maps", :force => true do |t| + t.text "name" + t.boolean "arranged" + t.text "desc" + t.text "permission" + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.boolean "featured" + t.string "screenshot_file_name" + t.string "screenshot_content_type" + t.integer "screenshot_file_size" + t.datetime "screenshot_updated_at" + end + + create_table "metacode_sets", :force => true do |t| + t.string "name" + t.text "desc" + t.integer "user_id" + t.boolean "mapperContributed" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "metacode_sets", ["user_id"], :name => "index_metacode_sets_on_user_id" + + create_table "metacodes", :force => true do |t| + t.text "name" + t.string "icon" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "synapses", :force => true do |t| + t.text "desc" + t.text "category" + t.text "weight" + t.text "permission" + t.integer "node1_id" + t.integer "node2_id" + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "topics", :force => true do |t| + t.text "name" + t.text "desc" + t.text "link" + t.text "permission" + t.integer "user_id" + t.integer "metacode_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "image_file_name" + t.string "image_content_type" + t.integer "image_file_size" + t.datetime "image_updated_at" + t.string "audio_file_name" + t.string "audio_content_type" + t.integer "audio_file_size" + t.datetime "audio_updated_at" + end + + create_table "users", :force => true do |t| + t.string "name" + t.string "email" + t.text "settings" + t.string "code", :limit => 8 + t.string "joinedwithcode", :limit => 8 + t.string "crypted_password" + t.string "password_salt" + t.string "persistence_token" + t.string "perishable_token" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.string "encrypted_password", :limit => 128, :default => "" + t.string "remember_token" + t.datetime "remember_created_at" + t.string "reset_password_token" + t.datetime "last_sign_in_at" + t.string "last_sign_in_ip" + t.integer "sign_in_count", :default => 0 + t.datetime "current_sign_in_at" + t.string "current_sign_in_ip" + t.datetime "reset_password_sent_at" + t.boolean "admin" + t.string "image_file_name" + t.string "image_content_type" + t.integer "image_file_size" + t.datetime "image_updated_at" + end + + add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true + +end diff --git a/phantomjsSetup.txt b/phantomjsSetup.txt new file mode 100644 index 00000000..f8916c30 --- /dev/null +++ b/phantomjsSetup.txt @@ -0,0 +1,21 @@ + +// 64 bit ubuntu +cd /usr/local/share +sudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.7-linux-x86_64.tar.bz2 +sudo tar xjf phantomjs-1.9.7-linux-x86_64.tar.bz2 +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/share/phantomjs +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/local/bin/phantomjs +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-x86_64/bin/phantomjs /usr/bin/phantomjs + + +// 32 bit ubuntu +cd /usr/local/share +sudo wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-1.9.7-linux-i686.tar.bz2 +sudo tar xjf phantomjs-1.9.7-linux-i686.tar.bz2 +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-i686/bin/phantomjs /usr/local/share/phantomjs +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-i686/bin/phantomjs /usr/local/bin/phantomjs +sudo ln -s /usr/local/share/phantomjs-1.9.7-linux-i686/bin/phantomjs /usr/bin/phantomjs + +// on either running +phantomjs -v +// will confirm it's installed \ No newline at end of file diff --git a/public/famous/main.js b/public/famous/main.js new file mode 100644 index 00000000..67265c9f --- /dev/null +++ b/public/famous/main.js @@ -0,0 +1,324 @@ +define(function(require, exports, module) { + // import dependencies + var Engine = require('famous/core/Engine'); + var Modifier = require('famous/core/Modifier'); + var Transform = require('famous/core/Transform'); + var Surface = require('famous/core/Surface'); + var Timer = require('famous/utilities/Timer'); + var Scrollview = require('famous/views/Scrollview'); + var ContainerSurface = require('famous/surfaces/ContainerSurface'); + var RenderNode = require('famous/core/RenderNode'); + + var templates = require('templates'); + + // create the main context + var famous = document.getElementById('famousOverlay'); + + Metamaps.Famous = {}; + var f = Metamaps.Famous; + + f.mainContext = Engine.createContext(famous); + f.Surface = Surface; + f.Modifier = Modifier; + f.Transform = Transform; + + + // INFOVIS + f.viz = {}; + f.viz.surf = new Surface({ + size: [undefined, undefined], + classes: [], + properties: { + display: 'none' + } + }); + var prepare = function () { + f.viz.show(); + Metamaps.JIT.prepareVizData(); + f.viz.surf.removeListener('deploy',prepare); + }; + if (Metamaps.currentSection === "map" || Metamaps.currentSection === "topic") { + f.viz.surf.on('deploy', prepare); + } + f.viz.mod = new Modifier({ + origin: [0.5, 0.5], + opacity: 0 + }); + f.viz.show = function () { + f.viz.surf.setProperties({ "display":"block" }); + f.viz.mod.setOpacity( + 1, + { duration: 300 } + ); + }; + f.viz.hide = function () { + f.viz.mod.setOpacity( + 0, + { duration: 300 }, + function() { + f.viz.surf.setProperties({"display": "none"}); + } + ); + }; + f.mainContext.add(f.viz.mod).add(f.viz.surf); + + + // CONTENT / OTHER PAGES + f.yield = {}; + f.yield.surf = new Surface({ + size: [undefined, undefined], + classes: ['famousYield'], + properties: { + display: 'none' + } + }); + var loadYield = function () { + f.loadYield(); + f.yield.surf.removeListener('deploy',loadYield); + }; + if (!(Metamaps.currentSection === "map" || + Metamaps.currentSection === "topic" || + Metamaps.currentSection === "explore" || + (Metamaps.currentSection === "" && Metamaps.Active.Mapper) )) { + f.yield.surf.on('deploy', loadYield); + } + f.yield.mod = new Modifier({ + origin: [0.5, 0.5], + opacity: 0 + }); + f.yield.show = function () { + f.yield.surf.setProperties({ "display":"block" }); + f.yield.mod.setOpacity( + 1, + { duration: 300 } + ); + }; + f.yield.hide = function () { + f.yield.mod.setOpacity( + 0, + { duration: 300 }, + function() { + f.yield.surf.setProperties({"display": "none"}); + } + ); + }; + f.mainContext.add(f.yield.mod).add(f.yield.surf); + + f.loadYield = function () { + Metamaps.Loading.hide(); + + var y = document.getElementById('yield'); + var yield = y ? y.innerHTML : false; + if (yield) { + f.yield.surf.setContent(yield); + f.yield.surf.deploy(f.yield.surf._currTarget); + f.yield.show(); + + y.parentNode.removeChild(y); + } + }; + + + // CONTENT / OTHER PAGES + f.maps = {}; + f.maps.surf = new Surface({ + size: [undefined, true], // this will get set to a specific height later in order to work + classes: ['mapsWrapper'], + }); + var mapsContainer = new ContainerSurface({ + size: [undefined, undefined], + properties: { + overflow: 'hidden', + } + }); + var loadMaps = function () { + f.loadMaps(); + f.maps.surf.removeListener('deploy',loadMaps); + }; + if (Metamaps.currentSection === "explore" || + (Metamaps.currentSection === "" && Metamaps.Active.Mapper)) { + f.maps.surf.on('deploy', loadMaps); + } + f.maps.mod = new Modifier({ + origin: [0.5, 0], + opacity: 0, + transform: Transform.translate(window.innerWidth,94,0) + }); + f.maps.mod.sizeFrom(function(){ + return [window.innerWidth, window.innerHeight - 94]; + }); + f.maps.show = function () { + // set into the correct position and then fade in + f.maps.mod.setTransform(Transform.translate(0, 94, 0)); + f.maps.mod.setOpacity( + 1, + { duration: 300 } + ); + }; + f.maps.hide = function () { + // fade out and then position it offscreen + f.maps.mod.setOpacity( + 0, + { duration: 300 }, + function() { + f.maps.mod.setTransform(Transform.translate(window.innerWidth, 94, 0)); + } + ); + }; + var mapsScroll = new Scrollview(); + mapsScroll._scroller.on('edgeHit', function(data){ + if (data.position > 0 && + Metamaps.Views && + Metamaps.Views.exploreMaps && + Metamaps.Views.exploreMaps.collection && + Metamaps.Views.exploreMaps.collection.page != "loadedAll") { + Metamaps.Views.exploreMaps.collection.getMaps(); + } + }); + f.maps.resetScroll = function() { + // set the scrollView back to the top + mapsScroll._physicsEngine.detachAll(); + mapsScroll.setVelocity(0); + mapsScroll.setPosition(0); + }; + mapsScroll.sequenceFrom([f.maps.surf]); + f.maps.surf.pipe(mapsScroll); + mapsContainer.add(mapsScroll); + var mapsNode = new RenderNode(f.maps.mod); + mapsNode.add(mapsContainer); + f.mainContext.add(mapsNode); + + f.loadMaps = function () { + if (Metamaps.currentSection === "explore") { + var capitalize = Metamaps.currentPage.charAt(0).toUpperCase() + Metamaps.currentPage.slice(1); + + Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps[capitalize] ); + Metamaps.Views.exploreMaps.render(); + f.maps.show(); + f.explore.set(Metamaps.currentPage); + f.explore.show(); + } + else if (Metamaps.currentSection === "") { + Metamaps.Loading.hide(); + if (Metamaps.Active.Mapper) { + + Metamaps.Views.exploreMaps.setCollection( Metamaps.Maps.Mine ); + Metamaps.Views.exploreMaps.render(); + f.maps.show(); + f.explore.set('mine'); + f.explore.show(); + } + else f.explore.set('featured'); + } + }; + + + // EXPLORE MAPS BAR + f.explore = {}; + f.explore.surf = new Surface({ + size: [true, 42], + content: templates.mineContent, + classes: ['exploreMapsCenter'] + }); + f.explore.surfBg = new Surface({ + size: [undefined, 94], + content: '
', + classes: ['exploreMapsBar', 'exploreElement'] + }); + f.explore.mod = new Modifier({ + size: [undefined, 94], + origin: [0.5, 0], + transform: Transform.translate(0, -94, 0) + }); + f.explore.show = function () { + f.explore.mod.setTransform( + Transform.translate(0, 0, 0), + { duration: 300, curve: 'easeOut' } + ); + }; + f.explore.hide = function () { + f.explore.mod.setTransform( + Transform.translate(0, -94, 0), + { duration: 300, curve: 'easeIn' } + ); + }; + f.explore.set = function (section) { + var loggedIn = Metamaps.Active.Mapper ? 'Auth' : ''; + f.explore.surf.setContent(templates[section + loggedIn + 'Content']); + }; + var exploreMod = f.mainContext.add(f.explore.mod); + exploreMod.add(new Modifier({ + size: [undefined, 42], + origin: [0.5, 1] + })).add(new Modifier({ + origin: [0.5, 1] + })).add(f.explore.surf); + exploreMod.add(f.explore.surfBg); + + + // LOGO + f.logo = {}; + f.logo.surf = new Surface({ + size: [258, 56], + content: templates.logoContent, + classes: ['footer'] + }); + + f.logo.mod = new Modifier({ + origin: [0.5, 1], + transform: Transform.translate(0, 56, 0) + }); + f.logo.show = function () { + f.logo.mod.setTransform( + Transform.translate(0, 0, 0), + { duration: 300, curve: 'easeOut' } + ); + }; + f.logo.hide = function () { + f.logo.mod.setTransform( + Transform.translate(0, 56, 0), + { duration: 300, curve: 'easeIn' } + ); + }; + f.mainContext.add(f.logo.mod).add(f.logo.surf); + + + // TOAST + f.toast = {}; + f.toast.surf = new Surface({ + size: [true, 42], + content: '', + classes: ['toast'] + }); + initialToast = function () { + var message = document.getElementById('toast') ? document.getElementById('toast').innerHTML : false; + if (message) { + Metamaps.GlobalUI.notifyUser(message); + f.toast.surf.deploy(f.toast.surf._currTarget); + } + }; + f.toast.surf.on('deploy', initialToast); + f.toast.mod = new Modifier({ + origin: [0, 1], + opacity: 0, + transform: Transform.translate(24, -24, 0) + }); + f.toast.show = function () { + f.toast.mod.setOpacity( + 1, + { duration: 300 } + ); + }; + f.toast.hide = function () { + f.toast.mod.setOpacity( + 0, + { duration: 300 } + ); + }; + f.mainContext.add(f.toast.mod).add(f.toast.surf); + + // an object for the realtime mapper compasses surfaces + f.compasses = {}; + + f.logo.show(); +}); \ No newline at end of file diff --git a/public/famous/templates.js b/public/famous/templates.js new file mode 100644 index 00000000..68188abe --- /dev/null +++ b/public/famous/templates.js @@ -0,0 +1,34 @@ +define(function(require, exports, module) { + +var t = {}; + +t.logoContent = ''; +t.logoContent += ''; + +/* logged out explore maps bars */ + t.activeContent = '
Recently Active Maps
'; + t.activeContent += '
Featured Maps
'; + + t.featuredContent = '
Recently Active Maps
'; + t.featuredContent += '
Featured Maps
'; + +/* logged in explore maps bars */ + t.mineAuthContent = '
My Maps
'; + t.mineAuthContent += '
Recently Active
'; + t.mineAuthContent += '
Featured
'; + + t.activeAuthContent = '
My Maps
'; + t.activeAuthContent += '
Recently Active
'; + t.activeAuthContent += '
Featured
'; + + t.featuredAuthContent = '
My Maps
'; + t.featuredAuthContent += '
Recently Active
'; + t.featuredAuthContent += '
Featured
'; + + module.exports = t; +}); diff --git a/realtime/realtime-server.js b/realtime/realtime-server.js index 06aae339..fe6524cc 100644 --- a/realtime/realtime-server.js +++ b/realtime/realtime-server.js @@ -20,32 +20,33 @@ app.configure(function() { //redis = require('redis').createClient(rtg.port, rtg.hostname, {no_ready_check: true}); var io = require('socket.io').listen(5001); -var redis = require('redis').createClient(); +//var redis = require('redis').createClient(); //redis.auth(rtg.auth.split(":")[1], function() { // start(); //}); function start() { - redis.subscribe('maps'); + //redis.subscribe('maps'); io.on('connection', function (socket) { // this will ping everyone on a map with updates to the map - redis.on('message', function (channel, message) { + /*redis.on('message', function (channel, message) { console.log(message); var m = JSON.parse(message); var room = 'maps-' + m.mapid; socket.emit(room, m); - }); + });*/ // this will ping a new person with awareness of who's already on the map socket.on('updateNewMapperList', function (data) { var existingUser = { userid: data.userid, username: data.username, - userrealtime: data.userrealtime + userrealtime: data.userrealtime, + userimage: data.userimage }; socket.broadcast.emit(data.userToNotify + '-' + data.mapid + '-UpdateMapperList', existingUser); }); @@ -58,7 +59,8 @@ function start() { var newUser = { userid: data.userid, - username: data.username + username: data.username, + userimage: data.userimage }; socket.broadcast.emit('maps-' + data.mapid + '-newmapper', newUser); @@ -102,6 +104,15 @@ function start() { socket.broadcast.emit('maps-' + data.mapid + '-lostrealtime', newUser); }); + socket.on('updateMapperCoords', function (data) { + var peer = { + userid: data.userid, + usercoords: data.usercoords + }; + + socket.broadcast.emit('maps-' + data.mapid + '-updatePeerCoords', peer); + }); + }); } diff --git a/vendor/assets/javascripts/.gitkeep b/vendor/assets/javascripts/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/assets/stylesheets/.gitkeep b/vendor/assets/stylesheets/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep deleted file mode 100644 index e69de29b..00000000