initial commit
|
@ -0,0 +1,12 @@
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
path = '/var/www/staging/app'
|
||||||
|
if path not in sys.path:
|
||||||
|
sys.path.insert(0, '/var/www/staging/app')
|
||||||
|
sys.path.insert(0, '/var/www/staging/app/ffdemo')
|
||||||
|
|
||||||
|
os.environ['DJANGO_SETTINGS_MODULE'] = 'ffdemo.settings'
|
||||||
|
|
||||||
|
import django.core.handlers.wsgi
|
||||||
|
application = django.core.handlers.wsgi.WSGIHandler()
|
|
@ -0,0 +1,8 @@
|
||||||
|
#/bin/bash
|
||||||
|
virtualenv --distribute --no-site-packages ./ffenv
|
||||||
|
source ./ffenv/bin/activate
|
||||||
|
pip install django==1.2.3
|
||||||
|
pip install south==0.7.2
|
||||||
|
pip install PIL
|
||||||
|
pip install pyyaml
|
||||||
|
easy_install http://pypi.python.org/packages/source/M/MySQL-python/MySQL-python-1.2.3.tar.gz
|
|
@ -0,0 +1,379 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-03-21 23:03-0700\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1)\n"
|
||||||
|
|
||||||
|
#: settings.py:69
|
||||||
|
msgid "German"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:70
|
||||||
|
msgid "English"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:71
|
||||||
|
msgid "French"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:72
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:8
|
||||||
|
msgid "About Mozilla"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:9
|
||||||
|
msgid "GML"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:10 templates_orig/evan-roth.html:8
|
||||||
|
msgid "Evan Roth"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:11
|
||||||
|
msgid "Code Repository"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/code.html:8
|
||||||
|
msgid "Behind the Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/community.html:9
|
||||||
|
msgid "Community"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:9
|
||||||
|
msgid ""
|
||||||
|
"Evan Roth is an artist and researcher based in Paris whose work explores the "
|
||||||
|
"intersection of free culture and popular culture. His notable projects "
|
||||||
|
"include <a href=\"http://graffitiresearchlab.com/projects/laser-tag/\">L.A.S."
|
||||||
|
"E.R. Tag</a> and <a href=\"http://graffitiresearchlab.com/projects/led-"
|
||||||
|
"throwies/\">LED Throwies</a> (Graffiti Research Lab), <a href=\"http://"
|
||||||
|
"whiteglovetracking.com/\">White Glove Tracking</a>, <a href=\"http://www."
|
||||||
|
"eyewriter.org/\">EyeWriter</a>, <a href=\"http://graffitianalysis.com/"
|
||||||
|
"\">Graffiti Analysis</a> and a collaboration with <a href=\"http://www."
|
||||||
|
"youtube.com/watch?v=QftcJtvLr8g\">Jay-Z</a> on the first open source rap "
|
||||||
|
"video. Roth's work is in the permanent collection of the MoMA (NYC) and has "
|
||||||
|
"been exhibited widely in the Americas, Europe and Asia, including the "
|
||||||
|
"Pompidou (Paris), the Kunsthalle (Vienna), the Tate (London), the Fondation "
|
||||||
|
"Cartier (Paris) and the front page of Youtube. Roth has received numerous "
|
||||||
|
"awards for his work, including the <a href=\"http://new.aec.at/repair/en/"
|
||||||
|
"program/prix-ars-electronica/\">Golden Nica</a> from Prix Ars Electronica, "
|
||||||
|
"Rhizome/The New Museum commissions (<a href=\"http://rhizome.org/"
|
||||||
|
"commissions/2007/\">2007</a>, <a href=\"http://rhizome.org/commissions/2009/"
|
||||||
|
"\">2009</a>), the <a href=\"http://2010.futureeverything.org/abouttheawards/"
|
||||||
|
"eyewriter2\">Future Everything Award</a> and Brit Insurance Designs of the "
|
||||||
|
"Year (<a href=\"http://www.designsoftheyear.com/2010/02/05/evan-roth-"
|
||||||
|
"graffiti-taxonomy-paris-france/\">1</a>, <a href=\"http://www."
|
||||||
|
"designsoftheyear.com/2010/02/10/members-of-free-art-and-technology-graffiti-"
|
||||||
|
"research-lab-openframeworks-the-ebeling-group-and-tony-quan-the-eyewriter-"
|
||||||
|
"usa/\">2</a>)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:10
|
||||||
|
msgid ""
|
||||||
|
"Roth is co-founder of the <a href=\"http://www.graffitiresearchlab.com/"
|
||||||
|
"\">Graffiti Research Lab</a> and the <a href=\"http://fffff.at/\">Free Art "
|
||||||
|
"& Technology Lab (F.A.T. Lab)</a>, a web based, open source research and "
|
||||||
|
"development lab. In addition, at the Parsons School of Design, he has "
|
||||||
|
"developed and continues to teach courses on viral media for artists, where "
|
||||||
|
"grades depend on Internet attention metrics, and urban hacking, a course a "
|
||||||
|
"New York City councilman has declared \"an invitation to break the law.\" "
|
||||||
|
"Roth and his work have been featured in multiple outlets, including <a href="
|
||||||
|
"\"http://www.npr.org/templates/story/story.php?storyId=124980282\">NPR</a>, "
|
||||||
|
"the New York Times (<a href=\"http://www.nytimes.com/2006/06/25/arts/"
|
||||||
|
"design/25daya.html?_r=1\">1</a>, <a href=\"http://www.nytimes.com/2007/08/12/"
|
||||||
|
"nyregion/thecity/12graf.html\">2</a>, <a href=\"http://www.nytimes.com/ref/"
|
||||||
|
"weekinreview/buzzwords2008.html\">3</a>), <a href=\"http://www.liberation.fr/"
|
||||||
|
"recherche/?q=%22evan+roth%22\">Liberation</a>, Time magazine (<a href="
|
||||||
|
"\"http://www.time.com/time/magazine/article/0,9171,1691618,00.html\">1</a>, "
|
||||||
|
"<a href=\"http://www.time.com/time/arts/article/0,8599,1730645,00.html\">2</"
|
||||||
|
"a>, <a href=\"http://www.time.com/time/"
|
||||||
|
"photogallery/0,29307,1911799_1912685,00.html\">3</a>), <a href=\"http://"
|
||||||
|
"edition.cnn.com/2010/TECH/web/09/10/gif.images/index.html\">CNN</a>, <a href="
|
||||||
|
"\"http://browse.guardian.co.uk/search?search=%22evan+roth%22&sitesearch-"
|
||||||
|
"radio=guardian&go-guardian=Search\">the Guardian</a>, <a href=\"http://"
|
||||||
|
"abcnews.go.com/Technology/popup?id=2425229\">ABC News</a>, and <a href="
|
||||||
|
"\"http://www.esquire.com/features/best-brightest-2007/"
|
||||||
|
"graffiti1207\">Esquire</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:8
|
||||||
|
msgid "Graffiti Markup Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:9
|
||||||
|
msgid ""
|
||||||
|
"Graffiti Markup Language (.gml) is a universal, XML-based, open file format "
|
||||||
|
"designed to store graffiti motion data (x coordinates, y coordinates and "
|
||||||
|
"time). GML is intended to be a simple bridge between ink and code, promoting "
|
||||||
|
"collaborations between graffiti writers and hackers. GML is today’s new "
|
||||||
|
"digital standard for tomorrow’s vandals."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/home.html:20
|
||||||
|
msgid ""
|
||||||
|
"Oops! Your browser doesn’t support the features used on this site.\n"
|
||||||
|
"\t\t\tPlease download a more modern browser like <a href=\"http://www."
|
||||||
|
"mozilla.com/products/download.html\">Firefox 4</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:1
|
||||||
|
msgid "The Internet is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:2
|
||||||
|
msgid ""
|
||||||
|
"<em>Leave your mark to keep it open and free.</em> Nulla a purus sem, sit "
|
||||||
|
"amet gravida massa. In eget risus ut urna auctor mattis vel eget metus. "
|
||||||
|
"Morbi blandit lobortis imperdiet. Nam vulputate felis vel lectus congue "
|
||||||
|
"fringilla. Nam tristique erat a massa convallis luctus. Sed fermentum "
|
||||||
|
"vestibulum sollicitudin."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:3 templates_orig/sammy/makemark.html:7
|
||||||
|
msgid "Click anywhere in the whitespace to begin your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:4 templates_orig/sammy/makemark.html:9
|
||||||
|
msgid "browse Marks"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:6 templates_orig/sammy/moderate.html:6
|
||||||
|
msgid "Replay this mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:7
|
||||||
|
msgid "Flag as inappropriate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:8 templates_orig/sammy/moderate.html:7
|
||||||
|
msgid "Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:11
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:12
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:14
|
||||||
|
msgid "URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:20
|
||||||
|
msgid "Mark Browsing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:22
|
||||||
|
msgid "zoom in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:23
|
||||||
|
msgid "zoom out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:24
|
||||||
|
msgid "right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:25
|
||||||
|
msgid "left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:28
|
||||||
|
msgid "location:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:30
|
||||||
|
msgid "All countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:34
|
||||||
|
msgid "view yours"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:35
|
||||||
|
msgid "view first"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:36
|
||||||
|
msgid "view last"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:40
|
||||||
|
msgid "Mark Stats"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:42
|
||||||
|
msgid "<span id=\"stats-number-of-marks\"></span> Marks for an open Web"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:43
|
||||||
|
msgid "On <span id=\"stats-number-of-countries\"></span> different countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:44
|
||||||
|
msgid "Over <span id=\"stats-number-of-days\"></span> days"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:48 templates_orig/sammy/moderate.html:13
|
||||||
|
msgid "view source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:52 templates_orig/sammy/moderate.html:17
|
||||||
|
msgid "jan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:53 templates_orig/sammy/moderate.html:18
|
||||||
|
msgid "feb"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:54 templates_orig/sammy/moderate.html:19
|
||||||
|
msgid "mar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:55 templates_orig/sammy/moderate.html:20
|
||||||
|
msgid "apr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:56 templates_orig/sammy/moderate.html:21
|
||||||
|
msgid "may"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:57 templates_orig/sammy/moderate.html:22
|
||||||
|
msgid "jun"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:58 templates_orig/sammy/moderate.html:23
|
||||||
|
msgid "jul"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:59 templates_orig/sammy/moderate.html:24
|
||||||
|
msgid "aug"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:60 templates_orig/sammy/moderate.html:25
|
||||||
|
msgid "sep"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:61 templates_orig/sammy/moderate.html:26
|
||||||
|
msgid "oct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:62 templates_orig/sammy/moderate.html:27
|
||||||
|
msgid "nov"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:63 templates_orig/sammy/moderate.html:28
|
||||||
|
msgid "dec"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:65
|
||||||
|
msgid ""
|
||||||
|
"Mozilla Firefox Mark Up. The internet is your creation. Show your support to "
|
||||||
|
"keep it open and free. Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:66
|
||||||
|
msgid ""
|
||||||
|
"The internet is your creation. Show your support to keep it open and free. "
|
||||||
|
"Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:3
|
||||||
|
msgid "The Web is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid "You are the ones using the Web every day."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid ""
|
||||||
|
"You are the writers, the coders, the artists. Each comment, upload, and "
|
||||||
|
"contribution you make adds up to something bigger. The Web is created by "
|
||||||
|
"everyone, and we believe it should remain free and accessible to everyone, "
|
||||||
|
"with all people controlling their own online journeys."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:5
|
||||||
|
msgid ""
|
||||||
|
"This is an open invitation to join the celebration of a Web that belongs to "
|
||||||
|
"all of us. Make your mark and show your support for the world’s greatest "
|
||||||
|
"public resource."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:8
|
||||||
|
msgid "Make Your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:11
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:12
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:13
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:14
|
||||||
|
msgid "Location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:16
|
||||||
|
msgid "Information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:20
|
||||||
|
msgid "Select your country"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:22
|
||||||
|
msgid ""
|
||||||
|
"Location is only used to associate marks with geographic regions.<br />See "
|
||||||
|
"<a href=\"http://www.mozilla.com/en-US/firefox/geolocation/\">http://www."
|
||||||
|
"mozilla.com/en-US/firefox/geolocation/</a> for more information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:28
|
||||||
|
msgid "Click anywhere to begin your mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:34
|
||||||
|
msgid "Submitting Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:35
|
||||||
|
msgid ""
|
||||||
|
"Oops! Something went wrong on our end.<br />Please submit your mark again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:9
|
||||||
|
msgid "Delete Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:10
|
||||||
|
msgid "Approve Mark"
|
||||||
|
msgstr ""
|
|
@ -0,0 +1,379 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-03-21 23:04-0700\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=n>1;\n"
|
||||||
|
|
||||||
|
#: settings.py:69
|
||||||
|
msgid "German"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:70
|
||||||
|
msgid "English"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:71
|
||||||
|
msgid "French"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:72
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:8
|
||||||
|
msgid "About Mozilla"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:9
|
||||||
|
msgid "GML"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:10 templates_orig/evan-roth.html:8
|
||||||
|
msgid "Evan Roth"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:11
|
||||||
|
msgid "Code Repository"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/code.html:8
|
||||||
|
msgid "Behind the Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/community.html:9
|
||||||
|
msgid "Community"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:9
|
||||||
|
msgid ""
|
||||||
|
"Evan Roth is an artist and researcher based in Paris whose work explores the "
|
||||||
|
"intersection of free culture and popular culture. His notable projects "
|
||||||
|
"include <a href=\"http://graffitiresearchlab.com/projects/laser-tag/\">L.A.S."
|
||||||
|
"E.R. Tag</a> and <a href=\"http://graffitiresearchlab.com/projects/led-"
|
||||||
|
"throwies/\">LED Throwies</a> (Graffiti Research Lab), <a href=\"http://"
|
||||||
|
"whiteglovetracking.com/\">White Glove Tracking</a>, <a href=\"http://www."
|
||||||
|
"eyewriter.org/\">EyeWriter</a>, <a href=\"http://graffitianalysis.com/"
|
||||||
|
"\">Graffiti Analysis</a> and a collaboration with <a href=\"http://www."
|
||||||
|
"youtube.com/watch?v=QftcJtvLr8g\">Jay-Z</a> on the first open source rap "
|
||||||
|
"video. Roth's work is in the permanent collection of the MoMA (NYC) and has "
|
||||||
|
"been exhibited widely in the Americas, Europe and Asia, including the "
|
||||||
|
"Pompidou (Paris), the Kunsthalle (Vienna), the Tate (London), the Fondation "
|
||||||
|
"Cartier (Paris) and the front page of Youtube. Roth has received numerous "
|
||||||
|
"awards for his work, including the <a href=\"http://new.aec.at/repair/en/"
|
||||||
|
"program/prix-ars-electronica/\">Golden Nica</a> from Prix Ars Electronica, "
|
||||||
|
"Rhizome/The New Museum commissions (<a href=\"http://rhizome.org/"
|
||||||
|
"commissions/2007/\">2007</a>, <a href=\"http://rhizome.org/commissions/2009/"
|
||||||
|
"\">2009</a>), the <a href=\"http://2010.futureeverything.org/abouttheawards/"
|
||||||
|
"eyewriter2\">Future Everything Award</a> and Brit Insurance Designs of the "
|
||||||
|
"Year (<a href=\"http://www.designsoftheyear.com/2010/02/05/evan-roth-"
|
||||||
|
"graffiti-taxonomy-paris-france/\">1</a>, <a href=\"http://www."
|
||||||
|
"designsoftheyear.com/2010/02/10/members-of-free-art-and-technology-graffiti-"
|
||||||
|
"research-lab-openframeworks-the-ebeling-group-and-tony-quan-the-eyewriter-"
|
||||||
|
"usa/\">2</a>)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:10
|
||||||
|
msgid ""
|
||||||
|
"Roth is co-founder of the <a href=\"http://www.graffitiresearchlab.com/"
|
||||||
|
"\">Graffiti Research Lab</a> and the <a href=\"http://fffff.at/\">Free Art "
|
||||||
|
"& Technology Lab (F.A.T. Lab)</a>, a web based, open source research and "
|
||||||
|
"development lab. In addition, at the Parsons School of Design, he has "
|
||||||
|
"developed and continues to teach courses on viral media for artists, where "
|
||||||
|
"grades depend on Internet attention metrics, and urban hacking, a course a "
|
||||||
|
"New York City councilman has declared \"an invitation to break the law.\" "
|
||||||
|
"Roth and his work have been featured in multiple outlets, including <a href="
|
||||||
|
"\"http://www.npr.org/templates/story/story.php?storyId=124980282\">NPR</a>, "
|
||||||
|
"the New York Times (<a href=\"http://www.nytimes.com/2006/06/25/arts/"
|
||||||
|
"design/25daya.html?_r=1\">1</a>, <a href=\"http://www.nytimes.com/2007/08/12/"
|
||||||
|
"nyregion/thecity/12graf.html\">2</a>, <a href=\"http://www.nytimes.com/ref/"
|
||||||
|
"weekinreview/buzzwords2008.html\">3</a>), <a href=\"http://www.liberation.fr/"
|
||||||
|
"recherche/?q=%22evan+roth%22\">Liberation</a>, Time magazine (<a href="
|
||||||
|
"\"http://www.time.com/time/magazine/article/0,9171,1691618,00.html\">1</a>, "
|
||||||
|
"<a href=\"http://www.time.com/time/arts/article/0,8599,1730645,00.html\">2</"
|
||||||
|
"a>, <a href=\"http://www.time.com/time/"
|
||||||
|
"photogallery/0,29307,1911799_1912685,00.html\">3</a>), <a href=\"http://"
|
||||||
|
"edition.cnn.com/2010/TECH/web/09/10/gif.images/index.html\">CNN</a>, <a href="
|
||||||
|
"\"http://browse.guardian.co.uk/search?search=%22evan+roth%22&sitesearch-"
|
||||||
|
"radio=guardian&go-guardian=Search\">the Guardian</a>, <a href=\"http://"
|
||||||
|
"abcnews.go.com/Technology/popup?id=2425229\">ABC News</a>, and <a href="
|
||||||
|
"\"http://www.esquire.com/features/best-brightest-2007/"
|
||||||
|
"graffiti1207\">Esquire</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:8
|
||||||
|
msgid "Graffiti Markup Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:9
|
||||||
|
msgid ""
|
||||||
|
"Graffiti Markup Language (.gml) is a universal, XML-based, open file format "
|
||||||
|
"designed to store graffiti motion data (x coordinates, y coordinates and "
|
||||||
|
"time). GML is intended to be a simple bridge between ink and code, promoting "
|
||||||
|
"collaborations between graffiti writers and hackers. GML is today’s new "
|
||||||
|
"digital standard for tomorrow’s vandals."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/home.html:20
|
||||||
|
msgid ""
|
||||||
|
"Oops! Your browser doesn’t support the features used on this site.\n"
|
||||||
|
"\t\t\tPlease download a more modern browser like <a href=\"http://www."
|
||||||
|
"mozilla.com/products/download.html\">Firefox 4</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:1
|
||||||
|
msgid "The Internet is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:2
|
||||||
|
msgid ""
|
||||||
|
"<em>Leave your mark to keep it open and free.</em> Nulla a purus sem, sit "
|
||||||
|
"amet gravida massa. In eget risus ut urna auctor mattis vel eget metus. "
|
||||||
|
"Morbi blandit lobortis imperdiet. Nam vulputate felis vel lectus congue "
|
||||||
|
"fringilla. Nam tristique erat a massa convallis luctus. Sed fermentum "
|
||||||
|
"vestibulum sollicitudin."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:3 templates_orig/sammy/makemark.html:7
|
||||||
|
msgid "Click anywhere in the whitespace to begin your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:4 templates_orig/sammy/makemark.html:9
|
||||||
|
msgid "browse Marks"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:6 templates_orig/sammy/moderate.html:6
|
||||||
|
msgid "Replay this mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:7
|
||||||
|
msgid "Flag as inappropriate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:8 templates_orig/sammy/moderate.html:7
|
||||||
|
msgid "Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:11
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:12
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:14
|
||||||
|
msgid "URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:20
|
||||||
|
msgid "Mark Browsing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:22
|
||||||
|
msgid "zoom in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:23
|
||||||
|
msgid "zoom out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:24
|
||||||
|
msgid "right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:25
|
||||||
|
msgid "left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:28
|
||||||
|
msgid "location:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:30
|
||||||
|
msgid "All countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:34
|
||||||
|
msgid "view yours"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:35
|
||||||
|
msgid "view first"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:36
|
||||||
|
msgid "view last"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:40
|
||||||
|
msgid "Mark Stats"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:42
|
||||||
|
msgid "<span id=\"stats-number-of-marks\"></span> Marks for an open Web"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:43
|
||||||
|
msgid "On <span id=\"stats-number-of-countries\"></span> different countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:44
|
||||||
|
msgid "Over <span id=\"stats-number-of-days\"></span> days"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:48 templates_orig/sammy/moderate.html:13
|
||||||
|
msgid "view source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:52 templates_orig/sammy/moderate.html:17
|
||||||
|
msgid "jan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:53 templates_orig/sammy/moderate.html:18
|
||||||
|
msgid "feb"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:54 templates_orig/sammy/moderate.html:19
|
||||||
|
msgid "mar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:55 templates_orig/sammy/moderate.html:20
|
||||||
|
msgid "apr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:56 templates_orig/sammy/moderate.html:21
|
||||||
|
msgid "may"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:57 templates_orig/sammy/moderate.html:22
|
||||||
|
msgid "jun"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:58 templates_orig/sammy/moderate.html:23
|
||||||
|
msgid "jul"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:59 templates_orig/sammy/moderate.html:24
|
||||||
|
msgid "aug"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:60 templates_orig/sammy/moderate.html:25
|
||||||
|
msgid "sep"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:61 templates_orig/sammy/moderate.html:26
|
||||||
|
msgid "oct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:62 templates_orig/sammy/moderate.html:27
|
||||||
|
msgid "nov"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:63 templates_orig/sammy/moderate.html:28
|
||||||
|
msgid "dec"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:65
|
||||||
|
msgid ""
|
||||||
|
"Mozilla Firefox Mark Up. The internet is your creation. Show your support to "
|
||||||
|
"keep it open and free. Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:66
|
||||||
|
msgid ""
|
||||||
|
"The internet is your creation. Show your support to keep it open and free. "
|
||||||
|
"Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:3
|
||||||
|
msgid "The Web is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid "You are the ones using the Web every day."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid ""
|
||||||
|
"You are the writers, the coders, the artists. Each comment, upload, and "
|
||||||
|
"contribution you make adds up to something bigger. The Web is created by "
|
||||||
|
"everyone, and we believe it should remain free and accessible to everyone, "
|
||||||
|
"with all people controlling their own online journeys."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:5
|
||||||
|
msgid ""
|
||||||
|
"This is an open invitation to join the celebration of a Web that belongs to "
|
||||||
|
"all of us. Make your mark and show your support for the world’s greatest "
|
||||||
|
"public resource."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:8
|
||||||
|
msgid "Make Your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:11
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:12
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:13
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:14
|
||||||
|
msgid "Location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:16
|
||||||
|
msgid "Information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:20
|
||||||
|
msgid "Select your country"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:22
|
||||||
|
msgid ""
|
||||||
|
"Location is only used to associate marks with geographic regions.<br />See "
|
||||||
|
"<a href=\"http://www.mozilla.com/en-US/firefox/geolocation/\">http://www."
|
||||||
|
"mozilla.com/en-US/firefox/geolocation/</a> for more information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:28
|
||||||
|
msgid "Click anywhere to begin your mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:34
|
||||||
|
msgid "Submitting Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:35
|
||||||
|
msgid ""
|
||||||
|
"Oops! Something went wrong on our end.<br />Please submit your mark again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:9
|
||||||
|
msgid "Delete Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:10
|
||||||
|
msgid "Approve Mark"
|
||||||
|
msgstr ""
|
|
@ -0,0 +1,379 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-03-21 23:04-0700\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
|
|
||||||
|
#: settings.py:69
|
||||||
|
msgid "German"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:70
|
||||||
|
msgid "English"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:71
|
||||||
|
msgid "French"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:72
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:8
|
||||||
|
msgid "About Mozilla"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:9
|
||||||
|
msgid "GML"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:10 templates_orig/evan-roth.html:8
|
||||||
|
msgid "Evan Roth"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:11
|
||||||
|
msgid "Code Repository"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/code.html:8
|
||||||
|
msgid "Behind the Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/community.html:9
|
||||||
|
msgid "Community"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:9
|
||||||
|
msgid ""
|
||||||
|
"Evan Roth is an artist and researcher based in Paris whose work explores the "
|
||||||
|
"intersection of free culture and popular culture. His notable projects "
|
||||||
|
"include <a href=\"http://graffitiresearchlab.com/projects/laser-tag/\">L.A.S."
|
||||||
|
"E.R. Tag</a> and <a href=\"http://graffitiresearchlab.com/projects/led-"
|
||||||
|
"throwies/\">LED Throwies</a> (Graffiti Research Lab), <a href=\"http://"
|
||||||
|
"whiteglovetracking.com/\">White Glove Tracking</a>, <a href=\"http://www."
|
||||||
|
"eyewriter.org/\">EyeWriter</a>, <a href=\"http://graffitianalysis.com/"
|
||||||
|
"\">Graffiti Analysis</a> and a collaboration with <a href=\"http://www."
|
||||||
|
"youtube.com/watch?v=QftcJtvLr8g\">Jay-Z</a> on the first open source rap "
|
||||||
|
"video. Roth's work is in the permanent collection of the MoMA (NYC) and has "
|
||||||
|
"been exhibited widely in the Americas, Europe and Asia, including the "
|
||||||
|
"Pompidou (Paris), the Kunsthalle (Vienna), the Tate (London), the Fondation "
|
||||||
|
"Cartier (Paris) and the front page of Youtube. Roth has received numerous "
|
||||||
|
"awards for his work, including the <a href=\"http://new.aec.at/repair/en/"
|
||||||
|
"program/prix-ars-electronica/\">Golden Nica</a> from Prix Ars Electronica, "
|
||||||
|
"Rhizome/The New Museum commissions (<a href=\"http://rhizome.org/"
|
||||||
|
"commissions/2007/\">2007</a>, <a href=\"http://rhizome.org/commissions/2009/"
|
||||||
|
"\">2009</a>), the <a href=\"http://2010.futureeverything.org/abouttheawards/"
|
||||||
|
"eyewriter2\">Future Everything Award</a> and Brit Insurance Designs of the "
|
||||||
|
"Year (<a href=\"http://www.designsoftheyear.com/2010/02/05/evan-roth-"
|
||||||
|
"graffiti-taxonomy-paris-france/\">1</a>, <a href=\"http://www."
|
||||||
|
"designsoftheyear.com/2010/02/10/members-of-free-art-and-technology-graffiti-"
|
||||||
|
"research-lab-openframeworks-the-ebeling-group-and-tony-quan-the-eyewriter-"
|
||||||
|
"usa/\">2</a>)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:10
|
||||||
|
msgid ""
|
||||||
|
"Roth is co-founder of the <a href=\"http://www.graffitiresearchlab.com/"
|
||||||
|
"\">Graffiti Research Lab</a> and the <a href=\"http://fffff.at/\">Free Art "
|
||||||
|
"& Technology Lab (F.A.T. Lab)</a>, a web based, open source research and "
|
||||||
|
"development lab. In addition, at the Parsons School of Design, he has "
|
||||||
|
"developed and continues to teach courses on viral media for artists, where "
|
||||||
|
"grades depend on Internet attention metrics, and urban hacking, a course a "
|
||||||
|
"New York City councilman has declared \"an invitation to break the law.\" "
|
||||||
|
"Roth and his work have been featured in multiple outlets, including <a href="
|
||||||
|
"\"http://www.npr.org/templates/story/story.php?storyId=124980282\">NPR</a>, "
|
||||||
|
"the New York Times (<a href=\"http://www.nytimes.com/2006/06/25/arts/"
|
||||||
|
"design/25daya.html?_r=1\">1</a>, <a href=\"http://www.nytimes.com/2007/08/12/"
|
||||||
|
"nyregion/thecity/12graf.html\">2</a>, <a href=\"http://www.nytimes.com/ref/"
|
||||||
|
"weekinreview/buzzwords2008.html\">3</a>), <a href=\"http://www.liberation.fr/"
|
||||||
|
"recherche/?q=%22evan+roth%22\">Liberation</a>, Time magazine (<a href="
|
||||||
|
"\"http://www.time.com/time/magazine/article/0,9171,1691618,00.html\">1</a>, "
|
||||||
|
"<a href=\"http://www.time.com/time/arts/article/0,8599,1730645,00.html\">2</"
|
||||||
|
"a>, <a href=\"http://www.time.com/time/"
|
||||||
|
"photogallery/0,29307,1911799_1912685,00.html\">3</a>), <a href=\"http://"
|
||||||
|
"edition.cnn.com/2010/TECH/web/09/10/gif.images/index.html\">CNN</a>, <a href="
|
||||||
|
"\"http://browse.guardian.co.uk/search?search=%22evan+roth%22&sitesearch-"
|
||||||
|
"radio=guardian&go-guardian=Search\">the Guardian</a>, <a href=\"http://"
|
||||||
|
"abcnews.go.com/Technology/popup?id=2425229\">ABC News</a>, and <a href="
|
||||||
|
"\"http://www.esquire.com/features/best-brightest-2007/"
|
||||||
|
"graffiti1207\">Esquire</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:8
|
||||||
|
msgid "Graffiti Markup Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:9
|
||||||
|
msgid ""
|
||||||
|
"Graffiti Markup Language (.gml) is a universal, XML-based, open file format "
|
||||||
|
"designed to store graffiti motion data (x coordinates, y coordinates and "
|
||||||
|
"time). GML is intended to be a simple bridge between ink and code, promoting "
|
||||||
|
"collaborations between graffiti writers and hackers. GML is today’s new "
|
||||||
|
"digital standard for tomorrow’s vandals."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/home.html:20
|
||||||
|
msgid ""
|
||||||
|
"Oops! Your browser doesn’t support the features used on this site.\n"
|
||||||
|
"\t\t\tPlease download a more modern browser like <a href=\"http://www."
|
||||||
|
"mozilla.com/products/download.html\">Firefox 4</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:1
|
||||||
|
msgid "The Internet is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:2
|
||||||
|
msgid ""
|
||||||
|
"<em>Leave your mark to keep it open and free.</em> Nulla a purus sem, sit "
|
||||||
|
"amet gravida massa. In eget risus ut urna auctor mattis vel eget metus. "
|
||||||
|
"Morbi blandit lobortis imperdiet. Nam vulputate felis vel lectus congue "
|
||||||
|
"fringilla. Nam tristique erat a massa convallis luctus. Sed fermentum "
|
||||||
|
"vestibulum sollicitudin."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:3 templates_orig/sammy/makemark.html:7
|
||||||
|
msgid "Click anywhere in the whitespace to begin your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:4 templates_orig/sammy/makemark.html:9
|
||||||
|
msgid "browse Marks"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:6 templates_orig/sammy/moderate.html:6
|
||||||
|
msgid "Replay this mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:7
|
||||||
|
msgid "Flag as inappropriate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:8 templates_orig/sammy/moderate.html:7
|
||||||
|
msgid "Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:11
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:12
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:14
|
||||||
|
msgid "URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:20
|
||||||
|
msgid "Mark Browsing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:22
|
||||||
|
msgid "zoom in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:23
|
||||||
|
msgid "zoom out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:24
|
||||||
|
msgid "right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:25
|
||||||
|
msgid "left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:28
|
||||||
|
msgid "location:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:30
|
||||||
|
msgid "All countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:34
|
||||||
|
msgid "view yours"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:35
|
||||||
|
msgid "view first"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:36
|
||||||
|
msgid "view last"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:40
|
||||||
|
msgid "Mark Stats"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:42
|
||||||
|
msgid "<span id=\"stats-number-of-marks\"></span> Marks for an open Web"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:43
|
||||||
|
msgid "On <span id=\"stats-number-of-countries\"></span> different countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:44
|
||||||
|
msgid "Over <span id=\"stats-number-of-days\"></span> days"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:48 templates_orig/sammy/moderate.html:13
|
||||||
|
msgid "view source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:52 templates_orig/sammy/moderate.html:17
|
||||||
|
msgid "jan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:53 templates_orig/sammy/moderate.html:18
|
||||||
|
msgid "feb"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:54 templates_orig/sammy/moderate.html:19
|
||||||
|
msgid "mar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:55 templates_orig/sammy/moderate.html:20
|
||||||
|
msgid "apr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:56 templates_orig/sammy/moderate.html:21
|
||||||
|
msgid "may"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:57 templates_orig/sammy/moderate.html:22
|
||||||
|
msgid "jun"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:58 templates_orig/sammy/moderate.html:23
|
||||||
|
msgid "jul"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:59 templates_orig/sammy/moderate.html:24
|
||||||
|
msgid "aug"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:60 templates_orig/sammy/moderate.html:25
|
||||||
|
msgid "sep"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:61 templates_orig/sammy/moderate.html:26
|
||||||
|
msgid "oct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:62 templates_orig/sammy/moderate.html:27
|
||||||
|
msgid "nov"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:63 templates_orig/sammy/moderate.html:28
|
||||||
|
msgid "dec"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:65
|
||||||
|
msgid ""
|
||||||
|
"Mozilla Firefox Mark Up. The internet is your creation. Show your support to "
|
||||||
|
"keep it open and free. Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:66
|
||||||
|
msgid ""
|
||||||
|
"The internet is your creation. Show your support to keep it open and free. "
|
||||||
|
"Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:3
|
||||||
|
msgid "The Web is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid "You are the ones using the Web every day."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid ""
|
||||||
|
"You are the writers, the coders, the artists. Each comment, upload, and "
|
||||||
|
"contribution you make adds up to something bigger. The Web is created by "
|
||||||
|
"everyone, and we believe it should remain free and accessible to everyone, "
|
||||||
|
"with all people controlling their own online journeys."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:5
|
||||||
|
msgid ""
|
||||||
|
"This is an open invitation to join the celebration of a Web that belongs to "
|
||||||
|
"all of us. Make your mark and show your support for the world’s greatest "
|
||||||
|
"public resource."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:8
|
||||||
|
msgid "Make Your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:11
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:12
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:13
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:14
|
||||||
|
msgid "Location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:16
|
||||||
|
msgid "Information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:20
|
||||||
|
msgid "Select your country"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:22
|
||||||
|
msgid ""
|
||||||
|
"Location is only used to associate marks with geographic regions.<br />See "
|
||||||
|
"<a href=\"http://www.mozilla.com/en-US/firefox/geolocation/\">http://www."
|
||||||
|
"mozilla.com/en-US/firefox/geolocation/</a> for more information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:28
|
||||||
|
msgid "Click anywhere to begin your mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:34
|
||||||
|
msgid "Submitting Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:35
|
||||||
|
msgid ""
|
||||||
|
"Oops! Something went wrong on our end.<br />Please submit your mark again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:9
|
||||||
|
msgid "Delete Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:10
|
||||||
|
msgid "Approve Mark"
|
||||||
|
msgstr ""
|
|
@ -0,0 +1,379 @@
|
||||||
|
# SOME DESCRIPTIVE TITLE.
|
||||||
|
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||||
|
# This file is distributed under the same license as the PACKAGE package.
|
||||||
|
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
|
||||||
|
#
|
||||||
|
#, fuzzy
|
||||||
|
msgid ""
|
||||||
|
msgstr ""
|
||||||
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
|
"Report-Msgid-Bugs-To: \n"
|
||||||
|
"POT-Creation-Date: 2011-03-21 23:04-0700\n"
|
||||||
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
"Language: \n"
|
||||||
|
"MIME-Version: 1.0\n"
|
||||||
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||||
|
|
||||||
|
#: settings.py:69
|
||||||
|
msgid "German"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:70
|
||||||
|
msgid "English"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:71
|
||||||
|
msgid "French"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: settings.py:72
|
||||||
|
msgid "Russian"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:8
|
||||||
|
msgid "About Mozilla"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:9
|
||||||
|
msgid "GML"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:10 templates_orig/evan-roth.html:8
|
||||||
|
msgid "Evan Roth"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/about.html:11
|
||||||
|
msgid "Code Repository"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/code.html:8
|
||||||
|
msgid "Behind the Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/community.html:9
|
||||||
|
msgid "Community"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:9
|
||||||
|
msgid ""
|
||||||
|
"Evan Roth is an artist and researcher based in Paris whose work explores the "
|
||||||
|
"intersection of free culture and popular culture. His notable projects "
|
||||||
|
"include <a href=\"http://graffitiresearchlab.com/projects/laser-tag/\">L.A.S."
|
||||||
|
"E.R. Tag</a> and <a href=\"http://graffitiresearchlab.com/projects/led-"
|
||||||
|
"throwies/\">LED Throwies</a> (Graffiti Research Lab), <a href=\"http://"
|
||||||
|
"whiteglovetracking.com/\">White Glove Tracking</a>, <a href=\"http://www."
|
||||||
|
"eyewriter.org/\">EyeWriter</a>, <a href=\"http://graffitianalysis.com/"
|
||||||
|
"\">Graffiti Analysis</a> and a collaboration with <a href=\"http://www."
|
||||||
|
"youtube.com/watch?v=QftcJtvLr8g\">Jay-Z</a> on the first open source rap "
|
||||||
|
"video. Roth's work is in the permanent collection of the MoMA (NYC) and has "
|
||||||
|
"been exhibited widely in the Americas, Europe and Asia, including the "
|
||||||
|
"Pompidou (Paris), the Kunsthalle (Vienna), the Tate (London), the Fondation "
|
||||||
|
"Cartier (Paris) and the front page of Youtube. Roth has received numerous "
|
||||||
|
"awards for his work, including the <a href=\"http://new.aec.at/repair/en/"
|
||||||
|
"program/prix-ars-electronica/\">Golden Nica</a> from Prix Ars Electronica, "
|
||||||
|
"Rhizome/The New Museum commissions (<a href=\"http://rhizome.org/"
|
||||||
|
"commissions/2007/\">2007</a>, <a href=\"http://rhizome.org/commissions/2009/"
|
||||||
|
"\">2009</a>), the <a href=\"http://2010.futureeverything.org/abouttheawards/"
|
||||||
|
"eyewriter2\">Future Everything Award</a> and Brit Insurance Designs of the "
|
||||||
|
"Year (<a href=\"http://www.designsoftheyear.com/2010/02/05/evan-roth-"
|
||||||
|
"graffiti-taxonomy-paris-france/\">1</a>, <a href=\"http://www."
|
||||||
|
"designsoftheyear.com/2010/02/10/members-of-free-art-and-technology-graffiti-"
|
||||||
|
"research-lab-openframeworks-the-ebeling-group-and-tony-quan-the-eyewriter-"
|
||||||
|
"usa/\">2</a>)."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/evan-roth.html:10
|
||||||
|
msgid ""
|
||||||
|
"Roth is co-founder of the <a href=\"http://www.graffitiresearchlab.com/"
|
||||||
|
"\">Graffiti Research Lab</a> and the <a href=\"http://fffff.at/\">Free Art "
|
||||||
|
"& Technology Lab (F.A.T. Lab)</a>, a web based, open source research and "
|
||||||
|
"development lab. In addition, at the Parsons School of Design, he has "
|
||||||
|
"developed and continues to teach courses on viral media for artists, where "
|
||||||
|
"grades depend on Internet attention metrics, and urban hacking, a course a "
|
||||||
|
"New York City councilman has declared \"an invitation to break the law.\" "
|
||||||
|
"Roth and his work have been featured in multiple outlets, including <a href="
|
||||||
|
"\"http://www.npr.org/templates/story/story.php?storyId=124980282\">NPR</a>, "
|
||||||
|
"the New York Times (<a href=\"http://www.nytimes.com/2006/06/25/arts/"
|
||||||
|
"design/25daya.html?_r=1\">1</a>, <a href=\"http://www.nytimes.com/2007/08/12/"
|
||||||
|
"nyregion/thecity/12graf.html\">2</a>, <a href=\"http://www.nytimes.com/ref/"
|
||||||
|
"weekinreview/buzzwords2008.html\">3</a>), <a href=\"http://www.liberation.fr/"
|
||||||
|
"recherche/?q=%22evan+roth%22\">Liberation</a>, Time magazine (<a href="
|
||||||
|
"\"http://www.time.com/time/magazine/article/0,9171,1691618,00.html\">1</a>, "
|
||||||
|
"<a href=\"http://www.time.com/time/arts/article/0,8599,1730645,00.html\">2</"
|
||||||
|
"a>, <a href=\"http://www.time.com/time/"
|
||||||
|
"photogallery/0,29307,1911799_1912685,00.html\">3</a>), <a href=\"http://"
|
||||||
|
"edition.cnn.com/2010/TECH/web/09/10/gif.images/index.html\">CNN</a>, <a href="
|
||||||
|
"\"http://browse.guardian.co.uk/search?search=%22evan+roth%22&sitesearch-"
|
||||||
|
"radio=guardian&go-guardian=Search\">the Guardian</a>, <a href=\"http://"
|
||||||
|
"abcnews.go.com/Technology/popup?id=2425229\">ABC News</a>, and <a href="
|
||||||
|
"\"http://www.esquire.com/features/best-brightest-2007/"
|
||||||
|
"graffiti1207\">Esquire</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:8
|
||||||
|
msgid "Graffiti Markup Language"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/gml.html:9
|
||||||
|
msgid ""
|
||||||
|
"Graffiti Markup Language (.gml) is a universal, XML-based, open file format "
|
||||||
|
"designed to store graffiti motion data (x coordinates, y coordinates and "
|
||||||
|
"time). GML is intended to be a simple bridge between ink and code, promoting "
|
||||||
|
"collaborations between graffiti writers and hackers. GML is today’s new "
|
||||||
|
"digital standard for tomorrow’s vandals."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/home.html:20
|
||||||
|
msgid ""
|
||||||
|
"Oops! Your browser doesn’t support the features used on this site.\n"
|
||||||
|
"\t\t\tPlease download a more modern browser like <a href=\"http://www."
|
||||||
|
"mozilla.com/products/download.html\">Firefox 4</a>."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:1
|
||||||
|
msgid "The Internet is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:2
|
||||||
|
msgid ""
|
||||||
|
"<em>Leave your mark to keep it open and free.</em> Nulla a purus sem, sit "
|
||||||
|
"amet gravida massa. In eget risus ut urna auctor mattis vel eget metus. "
|
||||||
|
"Morbi blandit lobortis imperdiet. Nam vulputate felis vel lectus congue "
|
||||||
|
"fringilla. Nam tristique erat a massa convallis luctus. Sed fermentum "
|
||||||
|
"vestibulum sollicitudin."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:3 templates_orig/sammy/makemark.html:7
|
||||||
|
msgid "Click anywhere in the whitespace to begin your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/home.html:4 templates_orig/sammy/makemark.html:9
|
||||||
|
msgid "browse Marks"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:6 templates_orig/sammy/moderate.html:6
|
||||||
|
msgid "Replay this mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:7
|
||||||
|
msgid "Flag as inappropriate"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:8 templates_orig/sammy/moderate.html:7
|
||||||
|
msgid "Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:11
|
||||||
|
msgid "Share on Facebook"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:12
|
||||||
|
msgid "Share on Twitter"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:14
|
||||||
|
msgid "URL"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:20
|
||||||
|
msgid "Mark Browsing"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:22
|
||||||
|
msgid "zoom in"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:23
|
||||||
|
msgid "zoom out"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:24
|
||||||
|
msgid "right"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:25
|
||||||
|
msgid "left"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:28
|
||||||
|
msgid "location:"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:30
|
||||||
|
msgid "All countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:34
|
||||||
|
msgid "view yours"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:35
|
||||||
|
msgid "view first"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:36
|
||||||
|
msgid "view last"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:40
|
||||||
|
msgid "Mark Stats"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:42
|
||||||
|
msgid "<span id=\"stats-number-of-marks\"></span> Marks for an open Web"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:43
|
||||||
|
msgid "On <span id=\"stats-number-of-countries\"></span> different countries"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:44
|
||||||
|
msgid "Over <span id=\"stats-number-of-days\"></span> days"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:48 templates_orig/sammy/moderate.html:13
|
||||||
|
msgid "view source"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:52 templates_orig/sammy/moderate.html:17
|
||||||
|
msgid "jan"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:53 templates_orig/sammy/moderate.html:18
|
||||||
|
msgid "feb"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:54 templates_orig/sammy/moderate.html:19
|
||||||
|
msgid "mar"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:55 templates_orig/sammy/moderate.html:20
|
||||||
|
msgid "apr"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:56 templates_orig/sammy/moderate.html:21
|
||||||
|
msgid "may"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:57 templates_orig/sammy/moderate.html:22
|
||||||
|
msgid "jun"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:58 templates_orig/sammy/moderate.html:23
|
||||||
|
msgid "jul"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:59 templates_orig/sammy/moderate.html:24
|
||||||
|
msgid "aug"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:60 templates_orig/sammy/moderate.html:25
|
||||||
|
msgid "sep"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:61 templates_orig/sammy/moderate.html:26
|
||||||
|
msgid "oct"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:62 templates_orig/sammy/moderate.html:27
|
||||||
|
msgid "nov"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:63 templates_orig/sammy/moderate.html:28
|
||||||
|
msgid "dec"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:65
|
||||||
|
msgid ""
|
||||||
|
"Mozilla Firefox Mark Up. The internet is your creation. Show your support to "
|
||||||
|
"keep it open and free. Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/linear.html:66
|
||||||
|
msgid ""
|
||||||
|
"The internet is your creation. Show your support to keep it open and free. "
|
||||||
|
"Make your mark."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:3
|
||||||
|
msgid "The Web is your creation"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid "You are the ones using the Web every day."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:4
|
||||||
|
msgid ""
|
||||||
|
"You are the writers, the coders, the artists. Each comment, upload, and "
|
||||||
|
"contribution you make adds up to something bigger. The Web is created by "
|
||||||
|
"everyone, and we believe it should remain free and accessible to everyone, "
|
||||||
|
"with all people controlling their own online journeys."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:5
|
||||||
|
msgid ""
|
||||||
|
"This is an open invitation to join the celebration of a Web that belongs to "
|
||||||
|
"all of us. Make your mark and show your support for the world’s greatest "
|
||||||
|
"public resource."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:8
|
||||||
|
msgid "Make Your Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:11
|
||||||
|
msgid "Submit"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:12
|
||||||
|
msgid "Reset"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:13
|
||||||
|
msgid "Cancel"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:14
|
||||||
|
msgid "Location"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:16
|
||||||
|
msgid "Information"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:20
|
||||||
|
msgid "Select your country"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:22
|
||||||
|
msgid ""
|
||||||
|
"Location is only used to associate marks with geographic regions.<br />See "
|
||||||
|
"<a href=\"http://www.mozilla.com/en-US/firefox/geolocation/\">http://www."
|
||||||
|
"mozilla.com/en-US/firefox/geolocation/</a> for more information."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:28
|
||||||
|
msgid "Click anywhere to begin your mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:34
|
||||||
|
msgid "Submitting Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/makemark.html:35
|
||||||
|
msgid ""
|
||||||
|
"Oops! Something went wrong on our end.<br />Please submit your mark again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:9
|
||||||
|
msgid "Delete Mark"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: templates_orig/sammy/moderate.html:10
|
||||||
|
msgid "Approve Mark"
|
||||||
|
msgstr ""
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
from django.core.management import execute_manager
|
||||||
|
try:
|
||||||
|
import settings # Assumed to be in the same directory.
|
||||||
|
except ImportError:
|
||||||
|
import sys
|
||||||
|
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
execute_manager(settings)
|
|
@ -0,0 +1,82 @@
|
||||||
|
from ffdemo.markup.models import Mark
|
||||||
|
from ffdemo.markup.models import Invitation
|
||||||
|
from ffdemo.utils import short_url
|
||||||
|
from datetime import datetime
|
||||||
|
import re
|
||||||
|
|
||||||
|
def get_invite_from_code(c):
|
||||||
|
invite = None
|
||||||
|
try:
|
||||||
|
invite = Invitation.objects.get(invite_code=c)
|
||||||
|
except Invitation.DoesNotExist:
|
||||||
|
return None
|
||||||
|
return invite
|
||||||
|
def get_translated_marks():
|
||||||
|
return
|
||||||
|
|
||||||
|
# convenience method to unpack marks for request return
|
||||||
|
def decode_mark_objects(data):
|
||||||
|
if data:
|
||||||
|
all_marks = []
|
||||||
|
for m in data:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'date_drawn': m.date_drawn.strftime("%a, %d %b %Y %I:%M:%S"), 'reference': m.reference, 'id': m.id, 'points_obj_simplified': decoded_points_obj, 'country_code': m.country_code, 'contributor': m.contributor, 'is_approved': m.is_approved})
|
||||||
|
return all_marks
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
return
|
||||||
|
|
||||||
|
def save_new_mark_with_data(data):
|
||||||
|
# Remove whitespace from raw full points obj
|
||||||
|
stripped_points_obj_full = re.sub(r'\s', '', data['points_obj'])
|
||||||
|
# remove whitespace where not in extra_info (the contributor quote)
|
||||||
|
j = re.compile('^.*\"extra\_info"\:\"')
|
||||||
|
k = re.compile('\"extra\_info"\:\".*\"\,*.*$')
|
||||||
|
sec1 = j.search(data['points_obj_simplified'])
|
||||||
|
sec2 = k.search(data['points_obj_simplified'])
|
||||||
|
if sec1 and sec2:
|
||||||
|
stripped_sec1 = re.sub(r'\s','',sec1.group())
|
||||||
|
stripped_sec2 = re.sub('"extra_info":"','',sec2.group())
|
||||||
|
stripped_points_obj_simplified = stripped_sec1 + stripped_sec2
|
||||||
|
else:
|
||||||
|
stripped_points_obj_simplified = re.sub(r'\s','',data['points_obj_simplified'])
|
||||||
|
# stripped_points_obj_simplified = re.sub(r'\s', '', data['points_obj_simplified'])
|
||||||
|
# Encode both
|
||||||
|
encoded_points_obj_full = stripped_points_obj_full.encode('base64', 'strict')
|
||||||
|
encoded_points_obj_simplified = stripped_points_obj_simplified.encode('base64', 'strict')
|
||||||
|
# New mark
|
||||||
|
new_mark = Mark.objects.create()
|
||||||
|
new_mark.points_obj = encoded_points_obj_full
|
||||||
|
new_mark.points_obj_simplified = encoded_points_obj_simplified
|
||||||
|
new_mark.reference = short_url.encode_url(new_mark.id)
|
||||||
|
if 'country_code' in data:
|
||||||
|
new_mark.country_code = data['country_code']
|
||||||
|
invite = None
|
||||||
|
if 'invite' in data:
|
||||||
|
invite = get_invite_from_code(data['invite'])
|
||||||
|
if invite and 'contributor_locale' in data and len(data['contributor_locale'])>0:
|
||||||
|
new_mark.contributor_locale = data['contributor_locale']
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
if invite and 'contributor' in data and len(data['contributor'])>0:
|
||||||
|
new_mark.contributor = data['contributor']
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
new_mark.save()
|
||||||
|
if invite:
|
||||||
|
invite.used_at = datetime.now()
|
||||||
|
invite.save()
|
||||||
|
# Catch errors
|
||||||
|
return new_mark.reference
|
||||||
|
|
||||||
|
def decode_points_obj(obj):
|
||||||
|
returned_str = str(obj)
|
||||||
|
decoded_data = returned_str.decode('base64', 'strict')
|
||||||
|
return decoded_data
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
from django.forms import ModelForm
|
||||||
|
from ffdemo.markup.models import Mark
|
||||||
|
|
||||||
|
class MarkForm(ModelForm):
|
||||||
|
class Meta:
|
||||||
|
model = Mark
|
||||||
|
fields = ('points_obj', 'country_code')
|
|
@ -0,0 +1,25 @@
|
||||||
|
import os, sys
|
||||||
|
from django.db import models
|
||||||
|
from django.core.management.base import BaseCommand, CommandError
|
||||||
|
from django.conf import settings
|
||||||
|
from ffdemo.markup.models import Invitation
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
args = '<num_invites invite_type>'
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
if len(args) < 2:
|
||||||
|
raise CommandError('Requires number of invites to generate and type of invite')
|
||||||
|
num_invites = int(args[0])
|
||||||
|
invite_type = args[1]
|
||||||
|
valid_values = []
|
||||||
|
for choice_id, choice_label in settings.CONTRIBUTOR_TYPE_CHOICES:
|
||||||
|
valid_values += choice_id
|
||||||
|
if invite_type not in valid_values:
|
||||||
|
raise CommandError('Invite type must be in ', valid_values)
|
||||||
|
else:
|
||||||
|
print "generating ", num_invites, " ", invite_type, "invites"
|
||||||
|
for i in range(num_invites):
|
||||||
|
invite = Invitation(contributor_type=invite_type)
|
||||||
|
invite.save()
|
||||||
|
print "finished generating invites"
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
import datetime
|
||||||
|
from south.db import db
|
||||||
|
from south.v2 import SchemaMigration
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
class Migration(SchemaMigration):
|
||||||
|
|
||||||
|
def forwards(self, orm):
|
||||||
|
|
||||||
|
# Adding model 'Mark'
|
||||||
|
db.create_table('markup_mark', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('date_drawn', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
|
||||||
|
('reference', self.gf('django.db.models.fields.CharField')(max_length=50, blank=True, unique=True)),
|
||||||
|
('points_obj', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||||
|
('points_obj_simplified', self.gf('django.db.models.fields.TextField')(blank=True)),
|
||||||
|
('country_code', self.gf('django.db.models.fields.CharField')(max_length=2, blank=True)),
|
||||||
|
('contributor_locale', self.gf('django.db.models.fields.CharField')(max_length=5, null=True, blank=True)),
|
||||||
|
('contributor', self.gf('django.db.models.fields.CharField')(max_length=75, null=True, blank=True)),
|
||||||
|
('flaggings', self.gf('django.db.models.fields.IntegerField')(default=0)),
|
||||||
|
('is_approved', self.gf('django.db.models.fields.BooleanField')(default=False))
|
||||||
|
))
|
||||||
|
db.send_create_signal('markup', ['Mark'])
|
||||||
|
|
||||||
|
# Adding model 'Invitation'
|
||||||
|
db.create_table('markup_invitation', (
|
||||||
|
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
|
||||||
|
('invite_code', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=50, blank=True)),
|
||||||
|
('contributor_type', self.gf('django.db.models.fields.CharField')(max_length=1)),
|
||||||
|
('used_at', self.gf('django.db.models.fields.DateTimeField')(blank=True))
|
||||||
|
))
|
||||||
|
db.send_create_signal('markup', ['Invitation'])
|
||||||
|
|
||||||
|
def backwards(self, orm):
|
||||||
|
|
||||||
|
# Deleting model 'Mark'
|
||||||
|
db.delete_table('markup_mark')
|
||||||
|
# Deleting model 'Invitation'
|
||||||
|
db.delete_table('markup_invitation')
|
||||||
|
|
||||||
|
models = {
|
||||||
|
'markup.invitation': {
|
||||||
|
'Meta': {'object_name': 'Invitation'},
|
||||||
|
'contributor_type': ('django.db.models.fields.CharField', [], {'max_length': '1'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'invite_code': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}),
|
||||||
|
'used_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
|
||||||
|
},
|
||||||
|
'markup.mark': {
|
||||||
|
'Meta': {'object_name': 'Mark'},
|
||||||
|
'contributor': ('django.db.models.fields.CharField', [], {'max_length': '75', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'contributor_locale': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}),
|
||||||
|
'country_code': ('django.db.models.fields.CharField', [], {'max_length': '2', 'blank': 'True'}),
|
||||||
|
'date_drawn': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
|
||||||
|
'flaggings': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
|
||||||
|
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
|
||||||
|
'is_approved': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
|
||||||
|
'points_obj': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'points_obj_simplified': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
|
||||||
|
'reference': ('django.db.models.fields.CharField', [], {'max_length': '50', 'blank': 'True'})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
complete_apps = ['markup']
|
|
@ -0,0 +1,34 @@
|
||||||
|
from django.db import models
|
||||||
|
from django.template.defaultfilters import slugify
|
||||||
|
import hashlib
|
||||||
|
import uuid
|
||||||
|
from datetime import datetime
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
class Mark(models.Model):
|
||||||
|
date_drawn = models.DateTimeField(auto_now_add=True)
|
||||||
|
reference = models.CharField(max_length=50, blank=True, unique=True)
|
||||||
|
points_obj = models.TextField(blank=True)
|
||||||
|
points_obj_simplified = models.TextField(blank=True)
|
||||||
|
country_code = models.CharField(max_length=2, blank=True)
|
||||||
|
flaggings = models.IntegerField(default=0)
|
||||||
|
is_approved = models.BooleanField(default=False)
|
||||||
|
# contributor attrs
|
||||||
|
contributor_locale = models.CharField(max_length=5, blank=True, null=True)
|
||||||
|
contributor = models.CharField(max_length=75, blank=True, null=True)
|
||||||
|
def __unicode__(self):
|
||||||
|
return unicode(self.date_drawn)
|
||||||
|
|
||||||
|
|
||||||
|
class Invitation(models.Model):
|
||||||
|
invite_code = models.SlugField(max_length=50)
|
||||||
|
contributor_type = models.CharField(max_length=1, choices=settings.CONTRIBUTOR_TYPE_CHOICES)
|
||||||
|
used_at = models.DateTimeField(blank=True, null=True)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
myuuid = uuid.uuid1().hex
|
||||||
|
self.invite_code = slugify( hashlib.md5(myuuid + datetime.now().strftime("%Y%m%d%H%m%s") ).hexdigest()[:12] )
|
||||||
|
super( Invitation, self ).save()
|
||||||
|
|
||||||
|
def __unicode__(self):
|
||||||
|
return self.invite_code
|
|
@ -0,0 +1,459 @@
|
||||||
|
from django.http import HttpResponse
|
||||||
|
from ffdemo.markup.models import Mark
|
||||||
|
from ffdemo.markup import common
|
||||||
|
from django.utils import simplejson
|
||||||
|
from django.core import serializers
|
||||||
|
import datetime
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
def get_translated_marks(request):
|
||||||
|
marks_to_be_dumped = None
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(contributor_locale__isnull=True).order_by('id')
|
||||||
|
if marks_to_be_dumped:
|
||||||
|
all_marks = []
|
||||||
|
for m in marks_to_be_dumped:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = common.decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'date_drawn': m.date_drawn.strftime("%a, %d %b %Y %I:%M:%S"), 'reference': m.reference, 'id': m.id, 'points_obj_simplified': decoded_points_obj, 'country_code': m.country_code, 'is_approved': m.is_approved, 'contributor_locale': m.contributor_locale})
|
||||||
|
response['success'] = True
|
||||||
|
response['marks'] = all_marks
|
||||||
|
else:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be parsed"
|
||||||
|
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response,'application/javascript')
|
||||||
|
|
||||||
|
def flag_mark(request):
|
||||||
|
response = {'success': False}
|
||||||
|
if 'reference' in request.POST and len(request.POST['reference']) > 0:
|
||||||
|
try:
|
||||||
|
mark = Mark.objects.get(reference=request.POST['reference'])
|
||||||
|
if mark.is_approved:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
mark.flaggings += 1
|
||||||
|
mark.save()
|
||||||
|
response['success'] = True
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
response['error'] = "Mark does not exist"
|
||||||
|
except Mark.MultipleObjectsReturned:
|
||||||
|
# should never [ever] happen, purely CYA
|
||||||
|
response['error'] = "Multiple marks returned"
|
||||||
|
else:
|
||||||
|
response['error'] = "No mark specified"
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
def init_viz_data(request):
|
||||||
|
# grab the last mark
|
||||||
|
# grab the first mark
|
||||||
|
response = {}
|
||||||
|
response['country_total_marks'] = ''
|
||||||
|
response['country_first_mark'] = ''
|
||||||
|
response['country_last_mark'] = ''
|
||||||
|
response['country_first_mark_at'] = ''
|
||||||
|
# for contributed marks
|
||||||
|
response['contributor_marks'] = []
|
||||||
|
contributor_marks = common.decode_mark_objects(Mark.objects.exclude(contributor__isnull=True).order_by('id'))
|
||||||
|
response['contributor_marks'] = contributor_marks
|
||||||
|
all_marks = Mark.objects.exclude(flaggings__gte=1).order_by('id')
|
||||||
|
if 'country_code' in request.GET and len(request.GET['country_code']) > 0:
|
||||||
|
country_marks = Mark.objects.exclude(flaggings__gte=1).filter(country_code=request.GET['country_code']).order_by('id')
|
||||||
|
if len(country_marks) > 0:
|
||||||
|
response['country_total_marks'] = country_marks.count()
|
||||||
|
response['country_first_mark'] = country_marks[0].reference
|
||||||
|
response['country_last_mark'] = country_marks[response['country_total_marks']-1].reference
|
||||||
|
response['country_first_mark_at'] = country_marks[0].date_drawn.strftime("%a, %d %b %Y %I:%M:%S")
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
response['total_marks'] = all_marks.count()
|
||||||
|
response['last_mark'] = all_marks[response['total_marks']-1].reference
|
||||||
|
response['first_mark'] = all_marks[0].reference
|
||||||
|
response['first_mark_at'] = all_marks[0].date_drawn.strftime("%a, %d %b %Y %I:%M:%S")
|
||||||
|
response['total_countries'] = Mark.objects.values('country_code').distinct().count()
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
def save_mark(request):
|
||||||
|
# Default response
|
||||||
|
response = {'success': False}
|
||||||
|
# Check for mandatory POST data
|
||||||
|
if 'points_obj' in request.POST and 'points_obj_simplified' in request.POST:
|
||||||
|
# Cosntruct mark data
|
||||||
|
mark_data = { 'points_obj': request.POST['points_obj'], 'points_obj_simplified': request.POST['points_obj_simplified'] }
|
||||||
|
if 'country_code' in request.POST:
|
||||||
|
mark_data['country_code'] = request.POST['country_code']
|
||||||
|
if 'invite' in request.POST:
|
||||||
|
mark_data['invite'] = request.POST['invite']
|
||||||
|
if 'contributor_locale' in request.POST:
|
||||||
|
mark_data['contributor_locale'] = request.POST['contributor_locale']
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
if 'contributor' in request.POST:
|
||||||
|
mark_data['contributor'] = request.POST['contributor']
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Save new mark, handled by common.py
|
||||||
|
new_mark_reference = common.save_new_mark_with_data(mark_data)
|
||||||
|
# Successful response, returning new mark reference
|
||||||
|
response['success'] = True
|
||||||
|
response['mark_reference'] = new_mark_reference
|
||||||
|
else:
|
||||||
|
# Error response
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = 'missing data in POST request'
|
||||||
|
# Return response as json
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
def delete_mark(request):
|
||||||
|
# Completely remove the mark
|
||||||
|
response = {'success': False}
|
||||||
|
if 'reference' in request.POST and len(request.POST['reference']) > 0:
|
||||||
|
try:
|
||||||
|
m = Mark.objects.get(reference=request.POST['reference'])
|
||||||
|
m.delete()
|
||||||
|
response['success'] = True
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
response['error'] = 'Mark does not exist'
|
||||||
|
else:
|
||||||
|
response['error'] = "No mark specified"
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def approve_mark(request):
|
||||||
|
# Approve the mark // CHECK
|
||||||
|
response = {'success': False}
|
||||||
|
if 'reference' in request.POST and len(request.POST['reference']) > 0:
|
||||||
|
try:
|
||||||
|
m = Mark.objects.get(reference=request.POST['reference'])
|
||||||
|
should_approve = False
|
||||||
|
if request.POST['should_approve'] == "true":
|
||||||
|
should_approve = True
|
||||||
|
m.is_approved = should_approve
|
||||||
|
m.save()
|
||||||
|
response['success'] = True
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
response['error'] = 'Mark does not exist'
|
||||||
|
else:
|
||||||
|
response['error'] = "No mark specified"
|
||||||
|
json_response = simplejson.dumps(response)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
def get_mark(request):
|
||||||
|
# Get mark by ID
|
||||||
|
mark = None
|
||||||
|
try:
|
||||||
|
mark = Mark.objects.get(reference=request.GET['mark_id'])
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
pass
|
||||||
|
except Mark.MultipleObjectsReturned:
|
||||||
|
pass
|
||||||
|
previous_marks = ""
|
||||||
|
next_marks = ""
|
||||||
|
# Decode simplified points data
|
||||||
|
decoded_points_obj = common.decode_points_obj(mark.points_obj_simplified)
|
||||||
|
# Return raw
|
||||||
|
return HttpResponse(decoded_points_obj, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
def marks_by_offset(request):
|
||||||
|
# Parameters:
|
||||||
|
# offset: Integer -
|
||||||
|
# max: Integer - (defaults 15)
|
||||||
|
# country_code: String - filter by country-code
|
||||||
|
#
|
||||||
|
# returns json object including relevant marks with their attributes: id, reference string, points_obj, points_obj_simplified
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
|
||||||
|
marks_to_be_dumped = None
|
||||||
|
did_fail_get_marks = False
|
||||||
|
|
||||||
|
# We've got an offset to play with
|
||||||
|
if 'offset' in request.GET:
|
||||||
|
# An offset requires a max value to be returned from this offset
|
||||||
|
if 'max' in request.GET:
|
||||||
|
offset = request.GET['offset']
|
||||||
|
max = request.GET['max']
|
||||||
|
# We can also filter by country code if need be
|
||||||
|
if 'country_code' in request.GET:
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude.exclude(contributor_locale__isnull=False).filter(country_code=request.GET['country_code'])[offset:max]
|
||||||
|
else:
|
||||||
|
marks_to_be_dumped = Mark.objects.all()[offset:max]
|
||||||
|
else:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "Querying by offset also requires a 'max' POST var"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
else:
|
||||||
|
# No special query parameters, query for all marks
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(contributor_locale__isnull=False)
|
||||||
|
# Check that we've got marks to dump
|
||||||
|
if not did_fail_get_marks:
|
||||||
|
if marks_to_be_dumped:
|
||||||
|
# Dump out
|
||||||
|
all_marks = []
|
||||||
|
for m in marks_to_be_dumped:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = common.decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'date_drawn': m.date_drawn.strftime("%a, %d %b %Y %I:%M:%S"), 'reference': m.reference, 'points_obj_simplified': decoded_points_obj, 'contributor': m.contributor, 'country_code': m.country_code})
|
||||||
|
response['success'] = True
|
||||||
|
response['marks'] = all_marks
|
||||||
|
else:
|
||||||
|
# No marks to dump
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be parsed"
|
||||||
|
# Dump and return
|
||||||
|
json_response = simplejson.dumps(response, default=dthandler)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def marks_by_locale(request):
|
||||||
|
# Parameters:
|
||||||
|
# country_code: String - filter by country-code
|
||||||
|
# max: Integer - (defaults 15)
|
||||||
|
#
|
||||||
|
# returns json object including relevant marks with their attributes: id, reference string, points_obj, points_obj_simplified
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
|
||||||
|
max_returned = 15
|
||||||
|
|
||||||
|
marks_to_be_dumped = None
|
||||||
|
did_fail_get_marks = False
|
||||||
|
|
||||||
|
|
||||||
|
def marks_by_reference(request):
|
||||||
|
# Parameters:
|
||||||
|
# reference_mark: String - slug of reference mark
|
||||||
|
# include_back: Integer - number of returned marks before the reference mark (defaults to 0)
|
||||||
|
# include_forward: Integer - number of returned marks after the reference mark (defaults to 15)
|
||||||
|
# include_mark: Boolean - include the reference mark (defaults true)
|
||||||
|
# country_code: String - filter by country-code
|
||||||
|
# returns json object including relevant marks with their attributes: id, reference string, points_obj, points_obj_simplified
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
reference_mark = None
|
||||||
|
include_back = 0
|
||||||
|
include_forward = 15
|
||||||
|
include_mark = True
|
||||||
|
country_code = None
|
||||||
|
marks_to_be_dumped = None
|
||||||
|
did_fail_get_marks = False
|
||||||
|
m_offset = None
|
||||||
|
# default limit returns 19 marks
|
||||||
|
m_limit = include_back + 1 + include_forward
|
||||||
|
all_marks = None
|
||||||
|
offset_index = 0
|
||||||
|
total_marks = 0
|
||||||
|
|
||||||
|
if 'reference' in request.GET:
|
||||||
|
reference_mark = request.GET['reference']
|
||||||
|
try:
|
||||||
|
m_offset = Mark.objects.get(reference=reference_mark)
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "Reference mark doesn't exist"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
except Mark.MultipleObjectsReturned:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "Multiple marks found for reference"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
if 'include_mark' in request.GET:
|
||||||
|
if int(request.GET['include_mark']) == 0:
|
||||||
|
include_mark = False
|
||||||
|
|
||||||
|
|
||||||
|
if 'include_forward' in request.GET:
|
||||||
|
include_forward = int(request.GET['include_forward'])
|
||||||
|
if 'include_back' in request.GET:
|
||||||
|
include_back = int(request.GET['include_back'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if 'country_code' in request.GET:
|
||||||
|
kountry_code = request.GET['country_code']
|
||||||
|
all_marks = Mark.objects.exclude(flaggings__gte=1).filter(country_code=kountry_code,contributor_locale__isnull=True).order_by('id')
|
||||||
|
total_marks = all_marks.count()
|
||||||
|
for i, item in enumerate(all_marks):
|
||||||
|
if item.reference == reference_mark:
|
||||||
|
offset_index = i
|
||||||
|
break
|
||||||
|
relative_include_back = offset_index - include_back
|
||||||
|
if relative_include_back < 0: relative_include_back = 0
|
||||||
|
unflagged_marks = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True)
|
||||||
|
if len(unflagged_marks) > 0:
|
||||||
|
marks_to_be_dumped = unflagged_marks.exclude(flaggings__gte=1,contributor_locale__isnull=False).filter(country_code=kountry_code,contributor_locale__isnull=True).order_by('id')[relative_include_back:offset_index+include_forward]
|
||||||
|
else:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be dumped"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
else:
|
||||||
|
all_marks = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True).order_by('id')
|
||||||
|
total_marks = all_marks.count()
|
||||||
|
for i, item in enumerate(all_marks):
|
||||||
|
if item.reference == reference_mark:
|
||||||
|
offset_index = i
|
||||||
|
break
|
||||||
|
relative_include_back = offset_index - include_back
|
||||||
|
if relative_include_back < 0: relative_include_back = 0
|
||||||
|
try:
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True).order_by('id')[relative_include_back:offset_index+include_forward]
|
||||||
|
except Mark.DoesNotExist:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be dumped"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
|
||||||
|
else:
|
||||||
|
# required param
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "Querying by reference requires a reference string"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
|
||||||
|
# Check that we've got marks to dump
|
||||||
|
if not did_fail_get_marks:
|
||||||
|
if marks_to_be_dumped:
|
||||||
|
# Dump out
|
||||||
|
all_marks = []
|
||||||
|
|
||||||
|
for m in marks_to_be_dumped:
|
||||||
|
is_reference_mark = False
|
||||||
|
if m.reference == reference_mark:
|
||||||
|
is_reference_mark = True
|
||||||
|
if include_mark == False and is_reference_mark:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = common.decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'is_reference_mark': is_reference_mark,'date_drawn': m.date_drawn.strftime("%a, %d %b %Y %I:%M:%S"), 'reference': m.reference, 'id': m.id, 'points_obj_simplified': decoded_points_obj, 'contributor': m.contributor, 'country_code': m.country_code})
|
||||||
|
response['success'] = True
|
||||||
|
response['marks'] = all_marks
|
||||||
|
else:
|
||||||
|
# No marks to dump
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be parsed"
|
||||||
|
|
||||||
|
# Dump and return
|
||||||
|
json_response = simplejson.dumps(response, default=dthandler)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
def all_marks(request):
|
||||||
|
# Get all marks, all data per mark excluding full points object
|
||||||
|
# This method can be queried via POST depending what the frontend requires
|
||||||
|
# Handler for dumping datetime field as JSON
|
||||||
|
#
|
||||||
|
# offset: Integer -
|
||||||
|
# max: Integer - (defaults 15)
|
||||||
|
# country_code: String - filter by country-code
|
||||||
|
#
|
||||||
|
# returns json object including relevant marks with their attributes: id, reference string, points_obj, points_obj_simplified
|
||||||
|
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
|
||||||
|
include_back = 3
|
||||||
|
include_forward = 15
|
||||||
|
include_mark = True
|
||||||
|
max_returned = 15
|
||||||
|
|
||||||
|
marks_to_be_dumped = None
|
||||||
|
did_fail_get_marks = False
|
||||||
|
|
||||||
|
# We've got an offset to play with
|
||||||
|
if 'offset' in request.GET:
|
||||||
|
# An offset requires a max value to be returned from this offset
|
||||||
|
if 'max' in request.GET:
|
||||||
|
offset = request.GET['offset']
|
||||||
|
max = request.GET['max']
|
||||||
|
# We can also filter by country code if need be
|
||||||
|
if 'country_code' in request.GET:
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True).order_by('id').filter(country_code=request.GET['country_code'])[offset:max]
|
||||||
|
else:
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True).order_by('id')[offset:max]
|
||||||
|
else:
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "Querying by offset also requires a 'max' POST var"
|
||||||
|
did_fail_get_marks = True
|
||||||
|
else:
|
||||||
|
# We can also filter by country code here as well if need be
|
||||||
|
if 'country_code' in request.GET:
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True,country_code=request.GET['country_code'])
|
||||||
|
else:
|
||||||
|
# No special query parameters, query for all marks
|
||||||
|
marks_to_be_dumped = Mark.objects.exclude(flaggings__gte=1).filter(contributor_locale__isnull=True)
|
||||||
|
# Check that we've got marks to dump
|
||||||
|
if not did_fail_get_marks:
|
||||||
|
if marks_to_be_dumped:
|
||||||
|
# Dump out
|
||||||
|
all_marks = []
|
||||||
|
for m in marks_to_be_dumped:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = common.decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'date_drawn': m.date_drawn.strftime("%a, %d %b %Y %I:%M:%S"), 'reference': m.reference, 'id': m.id, 'points_obj_simplified': decoded_points_obj, 'contributor': m.contributor, 'country_code': m.country_code, 'flaggings': m.flaggings})
|
||||||
|
response['success'] = True
|
||||||
|
response['marks'] = all_marks
|
||||||
|
else:
|
||||||
|
# No marks to dump
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be parsed"
|
||||||
|
# Dump and return
|
||||||
|
json_response = simplejson.dumps(response, default=dthandler)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
|
||||||
|
def marks_by_flagged(request):
|
||||||
|
dthandler = lambda obj: obj.isoformat() if isinstance(obj, datetime.datetime) else None
|
||||||
|
response = {'success': False}
|
||||||
|
|
||||||
|
include_back = 3
|
||||||
|
include_forward = 15
|
||||||
|
include_mark = True
|
||||||
|
max_returned = 15
|
||||||
|
|
||||||
|
marks_to_be_dumped = Mark.objects.filter(flaggings__gte=1).order_by('id') # CHECK offset?
|
||||||
|
|
||||||
|
# Check that we've got marks to dump
|
||||||
|
if marks_to_be_dumped:
|
||||||
|
# Dump out
|
||||||
|
all_marks = []
|
||||||
|
for m in marks_to_be_dumped:
|
||||||
|
# We need to decode the points obj simplified
|
||||||
|
decoded_points_obj = common.decode_points_obj(m.points_obj_simplified)
|
||||||
|
# Append to all marks
|
||||||
|
all_marks.append({'date_drawn': m.date_drawn, 'reference': m.reference, 'id': m.id, 'points_obj_simplified': decoded_points_obj, 'contributor': m.contributor, 'country_code': m.country_code, 'is_approved': m.is_approved})
|
||||||
|
response['success'] = True
|
||||||
|
response['marks'] = all_marks
|
||||||
|
else:
|
||||||
|
# No marks to dump
|
||||||
|
response['success'] = False
|
||||||
|
response['error'] = "No marks to be parsed"
|
||||||
|
# Dump and return
|
||||||
|
json_response = simplejson.dumps(response, default=dthandler)
|
||||||
|
return HttpResponse(json_response, 'application/javascript')
|
||||||
|
|
||||||
|
def update_language(request):
|
||||||
|
response = {}
|
||||||
|
if 'language_code' in request.GET:
|
||||||
|
set_language(request)
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
return response
|
|
@ -0,0 +1,8 @@
|
||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.filter(name='normalize_point')
|
||||||
|
def normalize_point(value,arg):
|
||||||
|
ret_val = float(value)/arg
|
||||||
|
return str(round(ret_val, 2)).replace(',','.')
|
|
@ -0,0 +1,106 @@
|
||||||
|
import json
|
||||||
|
import string
|
||||||
|
from django.http import Http404, HttpResponse, HttpResponseRedirect
|
||||||
|
from django.utils.encoding import force_unicode
|
||||||
|
from django.utils import translation
|
||||||
|
from django.utils.translation import ugettext_lazy as _lazy
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
from django.utils import simplejson
|
||||||
|
from django.conf import settings
|
||||||
|
from django.contrib.sites.models import Site
|
||||||
|
from django.template.loader import get_template
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
|
from django.contrib.auth import authenticate, login, logout
|
||||||
|
from django.core.context_processors import csrf
|
||||||
|
from ffdemo.utils.render import render_response
|
||||||
|
from ffdemo.markup.models import Mark
|
||||||
|
from ffdemo.markup.forms import MarkForm
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
|
from ffdemo.markup import common
|
||||||
|
|
||||||
|
|
||||||
|
def home(request):
|
||||||
|
mr = settings.MEDIA_ROOT
|
||||||
|
return render_response(request, 'home.html', {'mr':mr})
|
||||||
|
|
||||||
|
def about(request):
|
||||||
|
return render_response(request, 'about.html')
|
||||||
|
|
||||||
|
def about_gml(request):
|
||||||
|
return render_response(request, 'gml.html')
|
||||||
|
|
||||||
|
def credits(request):
|
||||||
|
return render_response(request, 'credits.html')
|
||||||
|
|
||||||
|
def code(request):
|
||||||
|
return render_response(request, 'code.html')
|
||||||
|
def mozilla(request):
|
||||||
|
return render_response(request, 'mozilla.html')
|
||||||
|
|
||||||
|
def evan(request):
|
||||||
|
return render_response(request, 'evan-roth.html')
|
||||||
|
|
||||||
|
def gml(request):
|
||||||
|
mark = Mark.objects.all()[10]
|
||||||
|
obj_decoded = simplejson.loads(common.decode_points_obj(mark.points_obj_simplified))
|
||||||
|
context = { 'mark': mark, 'obj_decoded': obj_decoded }
|
||||||
|
return render_response(request, 'gml.xml', context, mimetype='application/xml')
|
||||||
|
|
||||||
|
def manifesto(request):
|
||||||
|
return render_response(request, 'manifesto.html')
|
||||||
|
|
||||||
|
def mark(request, mark_reference):
|
||||||
|
mark = get_object_or_404(Mark, reference=mark_reference)
|
||||||
|
return render_response(request, 'mark.html', {'mark': mark})
|
||||||
|
|
||||||
|
def makemark(request):
|
||||||
|
if request.method == "POST":
|
||||||
|
mark_form = MarkForm(request.POST)
|
||||||
|
if mark_form.is_valid():
|
||||||
|
mark_data = { 'points_obj': mark_form.cleaned_data['points_obj'], 'country_code': mark_form.cleaned_data['country_code'] }
|
||||||
|
common.save_new_mark_with_data(mark_data)
|
||||||
|
else:
|
||||||
|
mark_form = MarkForm()
|
||||||
|
return render_response(request, 'makemark.html', {'form': mark_form})
|
||||||
|
|
||||||
|
def community(request):
|
||||||
|
if 'offset' in request.GET:
|
||||||
|
offset = int(request.GET['offset'])
|
||||||
|
per_page = int(request.GET['per_page'])
|
||||||
|
top_limit = offset + per_page;
|
||||||
|
all_marks = Mark.objects.exclude(flaggings__gte=1)[offset:top_limit]
|
||||||
|
else:
|
||||||
|
all_marks = Mark.objects.exclude(flaggings__gte=1)
|
||||||
|
return render_response(request, 'community.html', {'all_marks': all_marks})
|
||||||
|
|
||||||
|
def newsletter(request):
|
||||||
|
return render_response(request, 'newsletter.html', {})
|
||||||
|
|
||||||
|
def home_sammy(request):
|
||||||
|
mr = settings.MEDIA_ROOT
|
||||||
|
return render_response(request,'sammy/home.html',{'mr':mr})
|
||||||
|
|
||||||
|
def linear_sammy(request):
|
||||||
|
return render_response(request, 'sammy/linear.html')
|
||||||
|
|
||||||
|
def mark_sammy(request):
|
||||||
|
mark = get_object_or_404(Mark, reference=mark_reference)
|
||||||
|
return render_response(request, 'sammy/mark.html', {'mark':mark})
|
||||||
|
|
||||||
|
def makemark_sammy(request):
|
||||||
|
mark_form = MarkForm()
|
||||||
|
return render_response(request, 'sammy/makemark.html', {'form': mark_form})
|
||||||
|
|
||||||
|
|
||||||
|
### MODERATION VIEWS
|
||||||
|
def account_locked(request):
|
||||||
|
return render_response(request, 'registration/locked.html')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def moderate_sammy(request):
|
||||||
|
if not request.user.is_authenticated():
|
||||||
|
return HttpResponseRedirect('/accounts/login/')
|
||||||
|
else:
|
||||||
|
return render_response(request, 'sammy/moderate.html')
|
|
@ -0,0 +1,22 @@
|
||||||
|
from django.db import connection
|
||||||
|
from django.conf import settings
|
||||||
|
from django.utils.encoding import *
|
||||||
|
from urlparse import urlparse
|
||||||
|
|
||||||
|
class SQLLogMiddleware:
|
||||||
|
def process_response(self, request, response):
|
||||||
|
if settings.DEV and connection.queries:
|
||||||
|
time = sum([float(q['time']) for q in connection.queries])
|
||||||
|
|
||||||
|
#print u"%d queries in %s seconds:\n" % (len(connection.queries), time)
|
||||||
|
# for sql in connection.queries:
|
||||||
|
# print u"%s : %s\n" % (sql['time'], force_unicode(sql['sql']))
|
||||||
|
return response
|
||||||
|
|
||||||
|
class DetectReferrer:
|
||||||
|
def process_request(self, request):
|
||||||
|
if not request.session.get('HTTP_REFERER', False):
|
||||||
|
if(request.META.get('HTTP_REFERER')):
|
||||||
|
ref = urlparse(request.META.get('HTTP_REFERER'))
|
||||||
|
request.session['HTTP_REFERER'] = ref.hostname
|
||||||
|
# print u"Referred by: %s" % request.session['HTTP_REFERER']
|
|
@ -0,0 +1,183 @@
|
||||||
|
import settings_local
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Django settings for ff4 project.
|
||||||
|
|
||||||
|
DEBUG = settings_local.DEBUG
|
||||||
|
DEV = settings_local.DEV
|
||||||
|
TEMPLATE_DEBUG = DEBUG
|
||||||
|
|
||||||
|
PROJECT_PATH = os.path.realpath(os.path.dirname(__file__))
|
||||||
|
PROJECT_DOMAIN = ''
|
||||||
|
PROJECT_DIR = os.path.realpath(os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# UNCOMMENT TO ENABLE SECURE SESSIONS
|
||||||
|
#SESSION_COOKIE_SECURE = True
|
||||||
|
#SESSION_COOKIE_HTTPONLY = True
|
||||||
|
|
||||||
|
|
||||||
|
ADMINS = (
|
||||||
|
# ('Your Name', 'your_email@domain.com'),
|
||||||
|
)
|
||||||
|
|
||||||
|
MANAGERS = ADMINS
|
||||||
|
|
||||||
|
DATABASES = {
|
||||||
|
'default': {
|
||||||
|
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
|
||||||
|
'NAME': settings_local.DB_NAME, # Or path to database file if using sqlite3.
|
||||||
|
'USER': settings_local.DB_USER, # Not used with sqlite3.
|
||||||
|
'PASSWORD': settings_local.DB_PASSWORD, # Not used with sqlite3.
|
||||||
|
'HOST': settings_local.DB_HOST, # Set to empty string for localhost. Not used with sqlite3.
|
||||||
|
'PORT': settings_local.DB_PORT, # Set to empty string for default. Not used with sqlite3.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local time zone for this installation. Choices can be found here:
|
||||||
|
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
|
||||||
|
# although not all choices may be available on all operating systems.
|
||||||
|
# On Unix systems, a value of None will cause Django to use the same
|
||||||
|
# timezone as the operating system.
|
||||||
|
# If running in a Windows environment this must be set to the same as your
|
||||||
|
# system time zone.
|
||||||
|
TIME_ZONE = 'America/New_York'
|
||||||
|
|
||||||
|
# Language code for this installation. All choices can be found here:
|
||||||
|
# http://www.i18nguy.com/unicode/language-identifiers.html
|
||||||
|
LANGUAGE_CODE = 'en-US'
|
||||||
|
|
||||||
|
SITE_ID = 1
|
||||||
|
|
||||||
|
# If you set this to False, Django will make some optimizations so as not
|
||||||
|
# to load the internationalization machinery.
|
||||||
|
USE_I18N = True
|
||||||
|
|
||||||
|
# If you set this to False, Django will not format dates, numbers and
|
||||||
|
# calendars according to the current locale
|
||||||
|
USE_L10N = True
|
||||||
|
|
||||||
|
# Accepted locales
|
||||||
|
#INPUT_LANGUAGES = ('ar', 'bg', 'ca', 'cs', 'da', 'de', 'el', 'en-US', 'es',
|
||||||
|
# 'fr', 'fy-NL', 'gl', 'he', 'hu', 'id', 'it', 'ko', 'nb-NO',
|
||||||
|
# 'nl', 'pl', 'pt-PT', 'ro', 'ru', 'sk', 'sq', 'uk', 'vi',
|
||||||
|
# 'zh-CN', 'zh-TW')
|
||||||
|
|
||||||
|
gettext = lambda s: s
|
||||||
|
LANGUAGES = (
|
||||||
|
('de', gettext('German')),
|
||||||
|
('en', gettext('English')),
|
||||||
|
('fr', gettext('French')),
|
||||||
|
('ru', gettext('Russian')),
|
||||||
|
)
|
||||||
|
# default to accept-language header, per localeurl's settings
|
||||||
|
LOCALEURL_USE_ACCEPT_LANGUAGE = True
|
||||||
|
|
||||||
|
# don't url-localize requests
|
||||||
|
import re
|
||||||
|
LOCALE_INDEPENDENT_PATHS = (
|
||||||
|
re.compile('requests/'),
|
||||||
|
re.compile('/accounts/login/$'),
|
||||||
|
re.compile('/accounts/logout/$'),
|
||||||
|
re.compile('/i18n/'),
|
||||||
|
)
|
||||||
|
|
||||||
|
#RTL_LANGUAGES = ('ar', 'he',) # ('fa', 'fa-IR')
|
||||||
|
# Fallbacks for locales that are not recognized by Babel. Bug 596981.
|
||||||
|
BABEL_FALLBACK = {'fy-nl': 'nl'}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Absolute path to the directory that holds media.
|
||||||
|
# Example: "/home/media/media.lawrence.com/"
|
||||||
|
MEDIA_ROOT = PROJECT_PATH+'/static/'
|
||||||
|
|
||||||
|
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||||
|
# trailing slash if there is a path component (optional in other cases).
|
||||||
|
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||||
|
MEDIA_URL = '/media/'
|
||||||
|
|
||||||
|
# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
|
||||||
|
# trailing slash.
|
||||||
|
# Examples: "http://foo.com/media/", "/media/".
|
||||||
|
ADMIN_MEDIA_PREFIX = '/media/admin/'
|
||||||
|
|
||||||
|
# Make this unique, and don't share it with anybody.
|
||||||
|
SECRET_KEY = 'priU+iaciut#uV&aphlADo#zlep?i!rlethiu-wOuslapr2eSp'
|
||||||
|
|
||||||
|
# List of callables that know how to import templates from various sources.
|
||||||
|
TEMPLATE_LOADERS = (
|
||||||
|
'django.template.loaders.filesystem.Loader',
|
||||||
|
'django.template.loaders.app_directories.Loader',
|
||||||
|
# 'django.template.loaders.eggs.Loader',
|
||||||
|
)
|
||||||
|
|
||||||
|
MIDDLEWARE_CLASSES = (
|
||||||
|
'localeurl.middleware.LocaleURLMiddleware',
|
||||||
|
'django.middleware.common.CommonMiddleware',
|
||||||
|
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||||
|
'django.middleware.csrf.CsrfViewMiddleware',
|
||||||
|
'axes.middleware.FailedLoginMiddleware',
|
||||||
|
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||||
|
'django.contrib.messages.middleware.MessageMiddleware',
|
||||||
|
#'django.middleware.locale.LocaleMiddleware',
|
||||||
|
'ffdemo.middleware.SQLLogMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
|
# ADMIN
|
||||||
|
CONTRIBUTOR_TYPE_CHOICES = (
|
||||||
|
('c','contributor'),
|
||||||
|
('t','translator'),
|
||||||
|
)
|
||||||
|
LOGIN_REDIRECT_URL = "/#/moderate"
|
||||||
|
|
||||||
|
# AXES SEC. CONFIG
|
||||||
|
AXES_LOGIN_FAILURE_LIMIT = 5
|
||||||
|
AXES_LOCK_OUT_AT_FAILURE = True
|
||||||
|
AXES_COOLOFF_TIME = 2
|
||||||
|
AXES_LOCKOUT_URL = "/auth/locked/"
|
||||||
|
|
||||||
|
ROOT_URLCONF = 'ffdemo.urls'
|
||||||
|
|
||||||
|
TEMPLATE_DIRS = (
|
||||||
|
PROJECT_PATH+'/templates_orig',
|
||||||
|
PROJECT_PATH+'/templates_orig/sammy',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
TEMPLATE_CONTEXT_PROCESSORS = (
|
||||||
|
'django.core.context_processors.request',
|
||||||
|
'django.core.context_processors.i18n',
|
||||||
|
'django.contrib.auth.context_processors.auth',
|
||||||
|
)
|
||||||
|
|
||||||
|
SERIALIZATION_MODULES = {
|
||||||
|
'yml': "django.core.serializers.pyyaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTALLED_APPS = (
|
||||||
|
'localeurl',
|
||||||
|
'ffdemo.markup',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sessions',
|
||||||
|
'django.contrib.sites',
|
||||||
|
'django.contrib.messages',
|
||||||
|
'south',
|
||||||
|
'axes',
|
||||||
|
)
|
||||||
|
|
||||||
|
FIXTURE_DIRS = (
|
||||||
|
PROJECT_PATH+'/fixtures/',
|
||||||
|
)
|
||||||
|
SOUTH_TESTS_MIGRATE = False
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_HOST = settings_local.EMAIL_HOST
|
||||||
|
EMAIL_PORT = settings_local.EMAIL_PORT
|
||||||
|
EMAIL_HOST_USER = settings_local.EMAIL_HOST_USER
|
||||||
|
EMAIL_HOST_PASSWORD = settings_local.EMAIL_HOST_PASSWORD
|
||||||
|
EMAIL_USE_TLS = settings_local.EMAIL_USE_TLS
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
DEBUG = True
|
||||||
|
DEV = True
|
||||||
|
|
||||||
|
DB_NAME = 'ffdemo_development'
|
||||||
|
DB_USER = 'root'
|
||||||
|
DB_PASSWORD = ''
|
||||||
|
DB_HOST = ''
|
||||||
|
DB_PORT = ''
|
||||||
|
|
||||||
|
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
|
||||||
|
EMAIL_HOST = ''
|
||||||
|
EMAIL_PORT = 587
|
||||||
|
EMAIL_HOST_USER = ''
|
||||||
|
EMAIL_HOST_PASSWORD = ''
|
||||||
|
EMAIL_USE_TLS = True
|
|
@ -0,0 +1,35 @@
|
||||||
|
{
|
||||||
|
"vendor_dir": "assets/js/vendor",
|
||||||
|
"compressed_path": "assets/js/compressed.js",
|
||||||
|
"bundle_dir": "assets/js",
|
||||||
|
"bundles": {
|
||||||
|
"markApp": [
|
||||||
|
"jquery.markApp",
|
||||||
|
"jquery.markApp.linear",
|
||||||
|
"jquery.markApp.capture",
|
||||||
|
"jquery.markApp.intro",
|
||||||
|
"jquery.browserTouchSupport",
|
||||||
|
"jquery.delayedBind",
|
||||||
|
"jquery.collapsibleMod",
|
||||||
|
"jquery.socialShare",
|
||||||
|
"jquery.ui-selectBox",
|
||||||
|
"json2",
|
||||||
|
"canvas_extensions",
|
||||||
|
"mark.layer",
|
||||||
|
"mark.layerManager",
|
||||||
|
"mark.gmlPoint",
|
||||||
|
"mark.simplifyPath",
|
||||||
|
"mark.brushes",
|
||||||
|
"mark.gmlMark",
|
||||||
|
"mark.scene",
|
||||||
|
"mark.renderer",
|
||||||
|
"mark.camera",
|
||||||
|
"mark.base",
|
||||||
|
"tween",
|
||||||
|
"sammy-0.6.3.min",
|
||||||
|
"sammy.hash_push_proxy",
|
||||||
|
"sammy.template"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"compressed_suffix": ".min"
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/* SelectBox styles */
|
||||||
|
.ui-selectBox {
|
||||||
|
position: relative;
|
||||||
|
width: 188px; /* 188px + 35px (padding-right) + 2px (for borders) == 225px wide */
|
||||||
|
border: solid 1px #BBB;
|
||||||
|
text-decoration: none;
|
||||||
|
color: #000;
|
||||||
|
outline: none;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: #F2F2F2;
|
||||||
|
background: -moz-linear-gradient(top, #F8F8F8 1%, #E1E1E1 100%);
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, color-stop(1%, #F8F8F8), color-stop(100%, #E1E1E1));
|
||||||
|
filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#F8F8F8', endColorstr='#E1E1E1', GradientType=0);
|
||||||
|
-moz-box-shadow: 0 1px 0 rgba(255, 255, 255, .75);
|
||||||
|
-webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, .75);
|
||||||
|
box-shadow: 0 1px 0 rgba(255, 255, 255, .75);
|
||||||
|
padding-right: 35px;
|
||||||
|
display: inline-block;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-selectBox-disabled,
|
||||||
|
.ui-selectBox-disabled .ui-selectBox-arrow {
|
||||||
|
color: #888 !important;
|
||||||
|
border-color: #BBB !important;
|
||||||
|
font-style: italic !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-selectBox:hover,
|
||||||
|
.ui-selectBox-focus,
|
||||||
|
.ui-selectBox:hover .ui-selectBox-arrow,
|
||||||
|
.ui-selectBox-focus .ui-selectBox-arrow {
|
||||||
|
border-color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-selectBox-label {
|
||||||
|
width: 100%;
|
||||||
|
padding: .2em .3em;
|
||||||
|
display: inline-block;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ui-selectBox-arrow {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
width: 23px;
|
||||||
|
height: 100%;
|
||||||
|
background: url(jquery.ui-selectBox-arrow.gif) 50% center no-repeat;
|
||||||
|
border-left: solid 1px #BBB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown styles */
|
||||||
|
#ui-selectBox-dropdown {
|
||||||
|
max-height: 200px;
|
||||||
|
border: solid 1px #BBB;
|
||||||
|
background: #FFF;
|
||||||
|
margin-top: -1px;
|
||||||
|
overflow: auto;
|
||||||
|
-moz-box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
|
||||||
|
-webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
|
||||||
|
box-shadow: 0 2px 6px rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown UL,
|
||||||
|
#ui-selectBox-dropdown UL LI {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown UL LI {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: .2em .6em .2em 20px;
|
||||||
|
display: block;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown .ui-selectBox-optgroup {
|
||||||
|
background: #F2F2F2;
|
||||||
|
color: #888;
|
||||||
|
padding-left: .6em;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown.ui-selectBox-hasOptgroups .ui-selectBox-option {
|
||||||
|
padding-left: 20px;
|
||||||
|
background-position: 14px center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown .ui-selectBox-option.ui-selectBox-initial {
|
||||||
|
background-image: url(jquery.ui-selectBox-tick.gif);
|
||||||
|
background-position: 4px center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown .ui-selectBox-current {
|
||||||
|
background-color: #C8DEF4;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ui-selectBox-dropdown .ui-selectBox-disabled {
|
||||||
|
color: #888;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The following can be removed if you already have a jQuery UI theme loaded */
|
||||||
|
.ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
||||||
|
.ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||||
|
.ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||||
|
.ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||||
|
.ui-corner-top { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||||
|
.ui-corner-bottom { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||||
|
.ui-corner-right { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; border-top-right-radius: 4px; -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||||
|
.ui-corner-left { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; border-top-left-radius: 4px; -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||||
|
.ui-corner-all { -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; }
|
После Ширина: | Высота: | Размер: 192 B |
После Ширина: | Высота: | Размер: 372 B |
После Ширина: | Высота: | Размер: 6.8 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 145 B |
После Ширина: | Высота: | Размер: 989 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 1023 B |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 2.2 KiB |
После Ширина: | Высота: | Размер: 23 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 3.1 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 106 B |
После Ширина: | Высота: | Размер: 970 B |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 1.0 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 2.0 KiB |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 2.0 KiB |
После Ширина: | Высота: | Размер: 1.6 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 3.0 KiB |
После Ширина: | Высота: | Размер: 12 KiB |
После Ширина: | Высота: | Размер: 3.3 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 197 B |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 1.3 KiB |
После Ширина: | Высота: | Размер: 1.5 KiB |
После Ширина: | Высота: | Размер: 2.5 KiB |
После Ширина: | Высота: | Размер: 1.1 KiB |
После Ширина: | Высота: | Размер: 993 B |
После Ширина: | Высота: | Размер: 1010 B |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 2.8 KiB |
После Ширина: | Высота: | Размер: 2.1 KiB |
После Ширина: | Высота: | Размер: 1.2 KiB |
После Ширина: | Высота: | Размер: 1.4 KiB |
|
@ -0,0 +1,159 @@
|
||||||
|
( function( $ ) {
|
||||||
|
var app = $.sammy( '#sammy', function() {
|
||||||
|
// ROUTES
|
||||||
|
this.get( '#/', function( context ) {
|
||||||
|
// making our mark
|
||||||
|
// load the template
|
||||||
|
this.partial( 'makemark_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
// unload the visualization if it's loaded
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'linear' );
|
||||||
|
// init the intro
|
||||||
|
// init the capture interface, specifying that we're playing the intro first, and it should be ready to go when it's done
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'capture': { 'state': 'intro' } } );
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'intro': { } } );
|
||||||
|
|
||||||
|
$( '#sammy' ).css( 'zIndex', '' );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// MARK CREATION
|
||||||
|
this.get( '#/mark/new', function( context ) {
|
||||||
|
var modOptions = {
|
||||||
|
'state': 'drawing',
|
||||||
|
'invite_code': context.params['invite'],
|
||||||
|
'contributor_type': context.params['contributor_type']
|
||||||
|
}
|
||||||
|
// if we already have the content loaded, just update the state of the interface
|
||||||
|
if ( $( '#markmaker' ).size() > 0 ) {
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||||
|
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'capture': modOptions } );
|
||||||
|
} else {
|
||||||
|
// template is not yet loaded, so lets start fresh
|
||||||
|
// load the template
|
||||||
|
this.partial( 'makemark_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
// unload the visualization if it's loaded
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'linear' );
|
||||||
|
// init the capture interface, specifying that the intro should not be shown
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'capture': modOptions } );
|
||||||
|
$( '#sammy' ).css( 'zIndex', '' );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// MODERATION PAGE
|
||||||
|
this.get( '#/moderate', function( context ) {
|
||||||
|
this.partial( '/en/moderate_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
// unload all mods
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'all' );
|
||||||
|
// load the linear module
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'is_flagged': true, 'linear_root': 'moderate' } } );
|
||||||
|
} );
|
||||||
|
} );
|
||||||
|
// Moderation via direct reference
|
||||||
|
this.get( '#\/moderate\/(.*)', function( context ) {
|
||||||
|
if ( $( '#linear' ).size() > 0 ) {
|
||||||
|
// already setup, just load the new reference mark into the module
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'is_flagged': true, 'linear_root': 'moderate', 'reference_mark': context.params['splat'][0], 'playback': context.params['playback'] } } );
|
||||||
|
} else {
|
||||||
|
// show all the signatures
|
||||||
|
this.partial( '/en/moderate_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
$( '#sammy' ).css( 'zIndex', '' );
|
||||||
|
$( '#markapp' ).css( { 'zIndex': 100, 'cursor': 'default' } );
|
||||||
|
// unload the capture and intro interface if it's loaded
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||||
|
// load up the visualization
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'is_flagged': true, 'linear_root': 'moderate', 'reference_mark': context.params['splat'][0], 'playback': context.params['playback'] } } );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// visualization
|
||||||
|
// visualization with country filtering
|
||||||
|
this.get( '#/linear/country/:country_code\/(.*)', function( context ) {
|
||||||
|
if ( $( '#linear' ).size() > 0 ) {
|
||||||
|
// already setup, just load the new reference mark into the module
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'country_code': context.params['country_code'], 'reference_mark': context.params['splat'][0] } } );
|
||||||
|
} else {
|
||||||
|
this.partial( 'linear_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
$( '#sammy' ).css( 'zIndex', '' );
|
||||||
|
$( '#markapp' ).css( { 'zIndex': 100, 'cursor': 'default' } );
|
||||||
|
// unload the capture interface if it's loaded
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||||
|
// load up the visualization
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'country_code': context.params['country_code'], 'reference_mark': context.params['splat'][0] } } );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
// visualization without country filtering
|
||||||
|
this.get( '#\/linear\/(.*)', function( context ) {
|
||||||
|
if ( $( '#linear' ).size() > 0 ) {
|
||||||
|
// already setup, just load the new reference mark into the module
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'reference_mark': context.params['splat'][0], 'playback': context.params['playback'] } } );
|
||||||
|
} else {
|
||||||
|
// show all the signatures
|
||||||
|
this.partial( 'linear_sammy.html' )
|
||||||
|
.then( function() {
|
||||||
|
$( '#sammy' ).css( 'zIndex', '' );
|
||||||
|
$( '#markapp' ).css( { 'zIndex': 100, 'cursor': 'default' } );
|
||||||
|
// unload the capture interface if it's loaded
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||||
|
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||||
|
// load up the visualization
|
||||||
|
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'reference_mark': context.params['splat'][0], 'playback': context.params['playback'] } } );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
// event handlers
|
||||||
|
this.bind( 'run', function() {
|
||||||
|
// add an instance of markApp
|
||||||
|
$( '#markapp' )
|
||||||
|
.markApp()
|
||||||
|
// and privide it a way of accessing the sammy app
|
||||||
|
.data( 'markApp-context' )['app'] = app;
|
||||||
|
} );
|
||||||
|
|
||||||
|
// other stuff
|
||||||
|
this.swap = function( content ) {
|
||||||
|
this.$element().fadeOut( 'fast', function() {
|
||||||
|
$( this ).html( content ).fadeIn( 'normal' );
|
||||||
|
$( '#markapp' ).trigger( 'ready' );
|
||||||
|
} );
|
||||||
|
$( '#markapp' ).trigger( 'swap' );
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.use( 'Template' );
|
||||||
|
|
||||||
|
} );
|
||||||
|
|
||||||
|
$( document ).ready( function () {
|
||||||
|
function browserSupportsRequiredFeatures() {
|
||||||
|
// detect canvas support
|
||||||
|
return !!document.createElement('canvas').getContext;
|
||||||
|
}
|
||||||
|
if ( browserSupportsRequiredFeatures ) {
|
||||||
|
// remove the placeholder content
|
||||||
|
$( '#fallback' ).remove();
|
||||||
|
// run the app
|
||||||
|
app.run( '#/' );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try binding click event to locale here
|
||||||
|
$("#current-locale").click(function ()
|
||||||
|
{
|
||||||
|
$(this).parent().find("ul").toggle();
|
||||||
|
$(this).toggleClass("selected");
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
} ); //document ready
|
||||||
|
} )( jQuery );
|
|
@ -0,0 +1,8 @@
|
||||||
|
$(document).ready(function ()
|
||||||
|
{
|
||||||
|
$("#community").hover(function ()
|
||||||
|
{
|
||||||
|
$("#coming-soon-tip").toggle();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
|
@ -0,0 +1,189 @@
|
||||||
|
(function(a){a.markApp={modules:{},instances:[],fn:{}};a.fn.markApp=function(){var d=a(this),b=d.data("markApp-context");if(!b||typeof b=="undefined")b={app:null,$container:d,frameCount:0,width:0,height:0,minWidth:700,minHeight:500,countries:[],mouseX:null,mouseY:null,mouseDown:!1,mouseIn:!1,modules:{},usersMark:null,defaultErrorMsg:a("#default-error-msg").text(),defaultLoadingMsg:a("#default-loading-msg").text(),locale:window.location.pathname.split("/").length>1?window.location.pathname.split("/")[1]:
|
||||||
|
"en",instance:a.markApp.instances.push(d)-1,evt:{resize:function(){var d=a(window).width(),c=a(window).height()-(a("header").height()+a("#callout-boxes").height());if(d<b.minWidth)d=b.minWidth;if(c<b.minHeight)c=b.minHeight;b.$container.parent().width(d);b.$container.parent().height(c);b.width=d;b.height=c;a(".autoResize").height(c).width(d).trigger("resize.markApp",[d,c])},mousemove:function(a){b.mouseX=a.layerX;b.mouseY=a.layerY},mousedown:function(a){"preventDefault"in a&&a.preventDefault();b.mouseDown=
|
||||||
|
!0},mouseup:function(a){"preventDefault"in a&&a.preventDefault();b.mouseDown=!1},mouseover:function(a){"preventDefault"in a&&a.preventDefault();b.mouseIn=!0},mouseout:function(a){"preventDefault"in a&&a.preventDefault();b.mouseX=null;b.mouseY=null;b.mouseIn=!1}},public_fn:{addModule:function(b,d){var c,e={};if(typeof d=="string")c=d;else if(typeof d=="object")for(var k in d){c=k;e=d[k];break}a.markApp.modules[c]&&(b.modules[c]=b.modules[c]||{},"init"in a.markApp.modules[c].fn&&a.markApp.modules[c].fn.init(b,
|
||||||
|
e))},unloadModule:function(b,d){if(d=="all")for(d in b.modules)"deinit"in a.markApp.modules[d].fn&&a.markApp.modules[d].fn.deinit(b),delete b.modules[d];else d in b.modules&&("deinit"in a.markApp.modules[d].fn&&a.markApp.modules[d].fn.deinit(b),delete b.modules[d])}},fn:{trigger:function(d,c,e){typeof c=="undefined"&&(c={type:"custom"});if(d in b.evt&&b.evt[d](c)==!1)return!1;for(var j in b.modules)if(j in a.markApp.modules&&"evt"in a.markApp.modules[j]&&d in a.markApp.modules[j].evt)a.markApp.modules[j].evt[d](b,
|
||||||
|
c,e)},loop:function(){setTimeout(function(){b.fn.loop()},42);b.frameCount++;b.fn.trigger("loop",{},[])},withCountryCodes:function(d){"US"in b.countries?d(b.countries):a.ajax({url:"/media/assets/js/vendor/country_codes.json",dataType:"JSON",success:function(a){b.countries=a;for(var c=0;c<a.length;c++)b.countries[a[c].code]=a[c].name;d(b.countries)},error:function(){}})},showLoader:function(d,c){d=typeof d==="string"?d:b.defaultLoadingMsg;var e=a("<div />").width(b.width).height(b.height).hide().addClass("overlay-wrapper autoResize").addClass(c||
|
||||||
|
"").attr("id","markapp-loader").append(a("<div />").text(d));b.$container.append(e);e.fadeIn("fast")},hideLoader:function(){a("#markapp-loader").fadeOut("fast",function(){a(this).remove()})},showError:function(d){d=typeof d==="string"?d:b.defaultErrorMsg;d=a("<div />").width(b.width).height(b.height).hide().click(function(a){a.preventDefault();b.fn.hideError()}).addClass("overlay-wrapper autoResize").attr("id","markapp-error").append(a("<div />").attr("id","markapp-error-content").append(a("<p />").text(d)));
|
||||||
|
b.$container.append(d);d.fadeIn("fast")},hideError:function(){a("#markapp-error").fadeOut("fast",function(){a(this).remove()})},storeData:function(a,b){if(typeof localStorage!="undefined")try{typeof b==="object"&&(b=JSON.stringify(b)),localStorage.setItem(a,b)}catch(d){}},getData:function(a){if(typeof localStorage!="undefined")return(a=localStorage.getItem(a))?(a[0]=="{"&&(a=JSON.parse(a)),a):!1}}},a(window).delayedBind(300,"resize",function(a){return b.fn.trigger("resize",a)}).bind("keydown keypress keyup",
|
||||||
|
function(a){return b.fn.trigger(a.type,a)}).trigger("resize"),b.$container.bind("mousemove mousedown mouseup mouseover mouseout ready swap",function(a){return b.fn.trigger(a.type,a)}),b.fn.loop();var c=a.makeArray(arguments);if(c.length>0){var e=c.shift();if(e in b.public_fn)b.public_fn[e](b,typeof c[0]=="undefined"?{}:c[0])}return d.data("markApp-context",b)}})(jQuery);
|
||||||
|
(function(a){markApp=a.markApp=a.markApp||{};modules=a.markApp.modules=a.markApp.modules||{};modules.linear={defaults:{reference_mark:null,country_code:null,playback:!1,is_flagged:!1,linear_root:"linear"},config:{marks:{},flaggings:{},orderedMarks:[],leftBuffer:[],rightBuffer:[],bufferSize:20,bufferMinSize:5,scene:null,cameraChange:{},tweens:{},layerManager:null,initialized:!1,requestingMarks:!1,moreLeft:!0,moreRight:!0,hoverMark:null,currentMark:null,playbackTimes:{},eventChange:!1},evt:{ready:function(a){modules.linear.fn.initInterface(a)},
|
||||||
|
resize:function(a){a.modules.linear.eventChange=!0;a.modules.linear.layerManager.resizeAll(a.width,a.height)},keydown:function(a,b){var c=a.modules.linear;switch(b.keyCode){case 38:b.preventDefault();c.cameraChange.aZ=10;break;case 40:b.preventDefault();c.cameraChange.aZ=-10;break;case 39:b.preventDefault();c.cameraChange.aX=10;modules.linear.fn.hideMarkInformation(a);break;case 37:b.preventDefault(),c.cameraChange.aX=-10,modules.linear.fn.hideMarkInformation(a)}},keyup:function(a,b){var c=a.modules.linear;
|
||||||
|
switch(b.keyCode){case 38:case 40:b.preventDefault();c.cameraChange.aZ=0;break;case 39:case 37:b.preventDefault(),c.cameraChange.aX=0}},keypress:function(a,b){switch(b.keyCode){case 38:case 40:case 39:case 37:b.preventDefault()}},mousedown:function(a){var b=a.modules.linear;if(mark=modules.linear.fn.hitTest(a,a.mouseX,a.mouseY))mark==b.currentMark?modules.linear.fn.centerCurrentMark(a,function(){modules.linear.fn.showMarkInformation(a)}):b.country_code?a.app.setLocation("#/"+b.linear_root+"/country/"+
|
||||||
|
b.country_code+"/"+mark.reference):a.app.setLocation("#/"+b.linear_root+"/"+mark.reference)},mousemove:function(d){var b=d.modules.linear;b.eventChange=!0;if(mark=modules.linear.fn.hoverTest(d,d.mouseX,d.mouseY,b.hoverMark)){if(b.hoverMark)b.hoverMark.color=b.hoverMark.contributor_name?"171,73,27":"0,0,0";b.hoverMark=mark;b.hoverMark.reference==b.currentMark.reference&&b.hoverMark.contributor_name&&a("#mark-information").is(":visible")?a("#contributor-quote-box").fadeIn("fast").css({left:d.mouseX-
|
||||||
|
15,top:d.mouseY-a("#contributor-quote-box").height()-15}):b.hoverMark.color="0,139,211"}else if(b.hoverMark)b.hoverMark.color=b.hoverMark.contributor_name?"171,73,27":"0,0,0",b.hoverMark=null,a("#contributor-quote-box:visible").fadeOut("fast")},loop:function(d){var b=d.modules.linear,c=b.layerManager.layers.drawingLayer,e={x:b.scene.camera.position.x,y:b.scene.camera.position.y,z:b.scene.camera.position.z};if("cameraEase"in b.tweens)TWEEN.update();else{b.cameraChange.vZ+=b.cameraChange.aZ;b.cameraChange.vX+=
|
||||||
|
b.cameraChange.aX;b.cameraChange.vX*=0.93;b.cameraChange.vZ*=0.93;b.scene.camera.position.x+=b.cameraChange.vX;b.scene.camera.position.z+=b.cameraChange.vZ;var f=modules.linear.fn.closestMark(d);if(f){var g=b.scene.camera.position.y-(f.position.y+f.bHeight/2);g!=0&&Math.abs(g)>=10&&(b.scene.camera.position.y+=g>0?-10:10)}}if(!b.eventChange&&e.x==b.scene.camera.position.x&&e.y==b.scene.camera.position.y&&e.z==b.scene.camera.position.z)return!1;if(b.hoverMark&&!modules.linear.fn.hoverTest(d,d.mouseX,
|
||||||
|
d.mouseY,b.hoverMark))b.hoverMark.color=b.hoverMark.contributor_name?"171,73,27":"0,0,0",b.hoverMark=null,a("#contributor-quote-box:visible").fadeOut("fast");c.clean();modules.linear.fn.updateScene(d,b.scene.camera.position.x-1E4,b.scene.camera.position.x+1E4);modules.linear.fn.updateBuffers(d,b.scene.camera.position.x-1E4,b.scene.camera.position.x+1E4);Mark.renderer.renderScene(b.scene,{cursor:{x:d.mouseX,y:d.mouseY},width:d.width,height:d.height});b.eventChange=!1;for(f in b.scene.timers)d=(new Date).getTime(),
|
||||||
|
b.scene.timers[f].end<d&&delete b.scene.timers[f],b.eventChange=!0}},fn:{init:function(d,b){var c=d.modules.linear;if("$linear"in d.modules.linear){b.country_code!=c.country_code&&modules.linear.fn.dumpAllMarks(d);a.extend(c,c,b);for(option in modules.linear.defaults)b[option]==null&&(c[option]=modules.linear.defaults[option]);modules.linear.fn.updateInterface(d);modules.linear.fn.initMarks(d)}else a.extend(c,modules.linear.defaults,b),a.extend(c,c,modules.linear.config),c.$linear=a("<div />").addClass("linear-container"),
|
||||||
|
d.$container.append(c.$linear),c.scene=new Mark.scene,c.cameraChange={aX:0,aY:0,aZ:0,vX:0,vY:0,vZ:0},c.layerManager=new Mark.layerManager(c.$linear.get(0)),c.layerManager.addLayer("drawingLayer"),c.scene.canvasContext=c.layerManager.layers.drawingLayer.context,d.fn.trigger("resize"),c.initialized=!0;c.flaggings=d.fn.getData("markFlaggings")||{}},deinit:function(a){var b=a.modules.linear;b.$linear.fadeOut("fast",function(){b.layerManager.removeAll();b.$linear.remove();b.initialized=!1})},initInterface:function(d){var b=
|
||||||
|
d.modules.linear;a("#stats").hide();a("#mark-browsing-zoom-in a, #mark-browsing-zoom-out a, #mark-browsing-next a, #mark-browsing-prev a").click(function(a){a.preventDefault()}).bind("mouseup mouseout",function(b){b.preventDefault();if(a(this).data("mouseDown")){if(a(this).is("#mark-browsing-zoom-in a, #mark-browsing-zoom-out a"))d.modules.linear.cameraChange.aZ=0;else if(a(this).is("#mark-browsing-next a, #mark-browsing-prev a"))d.modules.linear.cameraChange.aX=0;a(this).data("mouseDown",!1)}}).bind("mousedown",
|
||||||
|
function(b){b.preventDefault();a(this).data("mouseDown",!0);if(a(this).is("#mark-browsing-zoom-in a, #mark-browsing-zoom-out a"))d.modules.linear.cameraChange.aZ=a(this).is("#mark-browsing-zoom-in a")?10:-10;else if(a(this).is("#mark-browsing-next a, #mark-browsing-prev a"))d.modules.linear.cameraChange.aX=a(this).is("#mark-browsing-next a")?10:-10,modules.linear.fn.hideMarkInformation(d)});d.fn.withCountryCodes(function(c){for(var e=a("#country-select"),f=0;f<c.length;f++){var g=a("<option />").val(c[f].code).text(c[f].name);
|
||||||
|
e.append(g)}e.change(function(){var c=a(this).val();c.length!=2&&b.country_code?d.app.setLocation("#/"+b.linear_root+"/"):c.length==2&&c!=b.country_code&&d.app.setLocation("#/"+b.linear_root+"/country/"+c+"/");a(this).blur();d.$container.focus()});b.country_code&&e.val(b.country_code)});a("#mark-information").hide();a("#mark-playback").click(function(a){a.preventDefault();modules.linear.fn.replayCurrentMark(d)});a("#mark-flag").click(function(a){a.preventDefault();modules.linear.fn.flagCurrentMark(d)});
|
||||||
|
a("#delete-mark").click(function(a){a.preventDefault();modules.linear.fn.deleteCurrentMark(d)});a("#approve-mark-checkbox").change(function(b){b.preventDefault();b=a(this).is(":checked");modules.linear.fn.approveCurrentMark(d,b)});a("#twitter-share").socialShare({share_url:"http://twitter.com/share",share_params:{text:escape("Mozilla Firefox Mark Up. The internet is your creation. Show your support to keep it open and free. Make your mark.")}});a("#facebook-share").socialShare({share_url:"http://www.facebook.com/sharer.php",
|
||||||
|
share_params:{t:"The internet is your creation. Show your support to keep it open and free. Make your mark."}});modules.linear.fn.updateInterface(d);modules.linear.fn.initMarks(d);a("#sammy #country-select").selectBox({autoWidth:!1});a("#sammy #contributor-select").selectBox({autoWidth:!1})},initMarks:function(a){var b=a.modules.linear;b.reference_mark&&b.reference_mark!=""?b.reference_mark in b.marks?modules.linear.fn.jumpToMark(a,b.reference_mark,b.playback):modules.linear.fn.loadMarks(a,{reference:b.reference_mark,
|
||||||
|
include_forward:20,include_back:20,include_mark:1,success:function(c){c.success&&(modules.linear.fn.setupMarks(a,c.marks),modules.linear.fn.jumpToMark(a,b.reference_mark,b.playback));b.requestingMarks=!1}}):modules.linear.fn.loadMarks(a,{offset:0,max:20,success:function(c){c.success&&(modules.linear.fn.setupMarks(a,c.marks),modules.linear.fn.jumpToMark(a,c.marks[0].reference));b.requestingMarks=!1}})},updateInterface:function(d){var b=d.modules.linear,c=d.fn.getData("userMark");c&&(b.country_code?
|
||||||
|
c.country_code==b.country_code:1)?a("#your-mark-link").attr("href","#/"+b.linear_root+"/"+d.fn.getData("userMark").reference).show():a("#your-mark-link").hide();var e={};b.country_code?(e.country_code=b.country_code,a("#contributor-select").next().hide(),a("#contributor-select-label").hide()):(a("#contributor-select").next().show(),a("#contributor-select-label").show());a("#mark-browsing-options").is(".country-"+(b.country_code?b.country_code:"all"))||a.ajax({url:"/requests/init_viz_data",data:e,
|
||||||
|
dataType:"JSON",success:function(c){a("#mark-browsing-options").removeAttr("class").addClass("country-"+(b.country_code?b.country_code:"all"));a("#stats-number-of-marks").text(c.total_marks);a("#stats-number-of-countries").text(c.total_countries);var g=new Date(c.first_mark_at);g=Math.ceil(((new Date).getTime()-g.getTime())/864E5);a("#stats-number-of-days").text(g);a("#stats").fadeIn("fast");b.country_code?(a("#first-mark-link").attr("href","#/"+b.linear_root+"/country/"+b.country_code+"/"+c.country_first_mark),
|
||||||
|
a("#last-mark-link").attr("href","#/"+b.linear_root+"/country/"+b.country_code+"/"+c.country_last_mark)):(a("#first-mark-link").attr("href","#/"+b.linear_root+"/"+c.first_mark),a("#last-mark-link").attr("href","#/"+b.linear_root+"/"+c.last_mark));a(".collapsible").collapsibleMod({previewSelector:".collapsed-preview"});if(a("#contributor-select option").size()==1){g=a("#contributor-select");if(c.contributor_marks)for(var h=0;h<c.contributor_marks.length;h++){var j=a("<option />").val(c.contributor_marks[h].reference).text(c.contributor_marks[h].contributor);
|
||||||
|
g.append(j)}g.change(function(){var c=a(this).val();c.length!="label"&&d.app.setLocation("#/"+b.linear_root+"/"+c);a(this).blur();d.$container.focus()});b.country_code?(e.country_code=b.country_code,a("#contributor-select").next().hide(),a("#contributor-select-label").hide()):(a("#contributor-select").next().show(),a("#contributor-select-label").show())}}})},dumpAllMarks:function(a){a=a.modules.linear;for(mark in a.marks)delete a.marks[mark];a.scene.objects=[];a.leftBuffer=[];a.rightBuffer=[];a.moreRight=
|
||||||
|
!0;a.moreLeft=!0;a.scene.camera.position.x=0;a.scene.camera.position.y=0;a.scene.camera.position.z=-1E3},loadMarks:function(d,b){var c=d.modules.linear,e=b.success;delete b.success;if(c.country_code)b.country_code=c.country_code;var f=b.reference?"/requests/marks_by_reference":"/requests/all_marks";c.is_flagged&&(f="/requests/marks_by_flagged");b.reference&&!(b.reference in c.marks)?(modules.linear.fn.dumpAllMarks(d),d.fn.showLoader(a("#loading-marks-msg").text(),"overlay-light")):b.reference||d.fn.showLoader(a("#loading-marks-msg").text(),
|
||||||
|
"overlay-light");a.ajax({url:f,data:b,dataType:"JSON"}).success(e).success(function(){d.fn.hideLoader()})},setupMarks:function(a,b){var c=a.modules.linear;if(b.length!=0){for(var e=0;e<b.length;e++)b[e].reference in c.marks&&b.shift(e,1);e=[];for(var f in c.marks)e.push([f,c.marks[f].id]);e.sort(function(a,b){return a[1]-b[1]});var g=e.length==0||e[0][1]<b[0].id?c.rightBuffer:c.leftBuffer,h=g==c.leftBuffer?!0:!1;h&&b.reverse();var j=g.length>0?c.marks[g[h?0:g.length-1]]:c.scene.objects[h?0:c.scene.objects.length-
|
||||||
|
1];for(e=0;e<b.length;e++)if(!(b[e].reference in c.marks)){var k=JSON.parse(b[e].points_obj_simplified);if("strokes"in k&&!(k.strokes.length==0||k.strokes[0].length<2)){f=new Mark.gmlMark(k.strokes,b[e].reference,b[e].country_code,b[e].date_drawn,k.rtl,b[e].id,b[e].is_approved);if(b[e].contributor)f.contributor_name=b[e].contributor,f.extra_info=k.extra_info,f.color="171,73,27";c.marks[f.reference]=f;j&&f.positionRelativeTo(j,h);h?g.unshift(f.reference):g.push(f.reference);j=f}}}},refillBuffer:function(a,
|
||||||
|
b){var c=a.modules.linear;if(!c.requestingMarks){c.requestingMarks=!0;var e=b==c.leftBuffer,f=null;f=b.length>0?c.marks[b[e?0:b.length-1]]:c.scene.objects[e?0:c.scene.objects.length-1];modules.linear.fn.loadMarks(a,{reference:f.reference,include_forward:e?0:20,include_back:e?20:0,include_mark:0,success:function(b){b.success?(modules.linear.fn.setupMarks(a,b.marks),b.marks.length<c.bufferSize&&(c[e?"moreLeft":"moreRight"]=!1)):c[e?"moreLeft":"moreRight"]=!1;c.requestingMarks=!1}})}},updateBuffers:function(a,
|
||||||
|
b,c){var e=a.modules.linear;if(e.scene.objects.length!=0){for(var f=e.scene.objects[0];f&&f.position.x+f.bWidth<b;)e.leftBuffer.push(e.scene.objects.shift().reference),f=e.scene.objects[0];for(f=e.scene.objects[e.scene.objects.length-1];f&&f.position.x>c;)e.rightBuffer.unshift(e.scene.objects.pop().reference),f=e.scene.objects[e.scene.objects-1];e.leftBuffer.length<5&&e.scene.objects.length>0&&e.moreLeft&&!e.requestingMarks?modules.linear.fn.refillBuffer(a,e.leftBuffer):e.rightBuffer.length<5&&e.scene.objects.length>
|
||||||
|
0&&e.moreRight&&!e.requestingMarks&&modules.linear.fn.refillBuffer(a,e.rightBuffer)}},updateScene:function(a,b,c){a=a.modules.linear;if(a.rightBuffer.length>0)for(var e=a.marks[a.rightBuffer[0]];e&&e.position&&e.position.x<c;)a.scene.objects.push(a.marks[a.rightBuffer.shift()]),e=a.rightBuffer[0];if(a.leftBuffer.length>0)for(e=a.marks[a.leftBuffer[a.leftBuffer.length-1]];e&&e.position&&e.position.x+e.bWidth>b;)a.scene.objects.unshift(a.marks[a.leftBuffer.pop()]),e=a.leftBuffer[a.leftBuffer.length-
|
||||||
|
1]},jumpToMark:function(a,b,c){var e=a.modules.linear;e.currentMark=e.marks[b];if(c){var f=(new Date).getTime()*2;e.scene.timers[b]={start:f,end:f+e.currentMark.maxTime,speed:1}}modules.linear.fn.centerCurrentMark(a,function(){c&&modules.linear.fn.replayCurrentMark(a);modules.linear.fn.showMarkInformation(a)})},closestMark:function(a){a=a.modules.linear;for(var b=a.scene.objects[0],c=1;c<a.scene.objects.length;c++){var e=a.scene.objects[c];Math.abs(a.scene.camera.position.x-(e.position.x+e.bWidth/
|
||||||
|
2))<Math.abs(a.scene.camera.position.x-(b.position.x+b.bWidth/2))&&(b=e)}return b},hoverTest:function(a,b,c,e){if(e&&e.renderedBounds&&b>=e.renderedBounds.minX&&b<=e.renderedBounds.maxX&&c>=e.renderedBounds.minY&&c<=e.renderedBounds.maxY)return e;return modules.linear.fn.hitTest(a,b,c)},hitTest:function(a,b,c){a=a.modules.linear;for(var e=0;e<a.scene.objects.length;e++)if(a.scene.objects[e].renderedBounds&&b>=a.scene.objects[e].renderedBounds.minX&&b<=a.scene.objects[e].renderedBounds.maxX&&c>=a.scene.objects[e].renderedBounds.minY&&
|
||||||
|
c<=a.scene.objects[e].renderedBounds.maxY)return a.scene.objects[e];return!1},showMarkInformation:function(d){var b=d.modules.linear;if(!b.currentMark)return!1;var c=b.currentMark;a("#mark-id").text(c.id);var e=new Date(c.time),f=[];f.push(a("#month-abreviations li:eq("+e.getMonth()+")").text()+" "+e.getDate());f.push(e.getHours()+":"+(String(e.getMinutes()).length==1?"0"+e.getMinutes():e.getMinutes()));c.country_code?d.fn.withCountryCodes(function(b){a("#mark-country").text(" / "+b[c.country_code])}):
|
||||||
|
a("#mark-country").text("");c.contributor_name?(a("#mark-contributor-name").text("- "+c.contributor_name),a("#mark-flag").hide(),a("#contributor-quote").text(c.extra_info).html("“"+a("#contributor-quote").text()+"”")):(a("#mark-contributor-name, #contributor-quote").text(""),a("#mark-flag").show());a("#mark-timestamp").text(f.join(" / "));a("#url-share input").val(window.location.href);if(b.linear_root!="moderate")a("#twitter-share").data("socialShare-context").share_params.url=window.location.href,
|
||||||
|
a("#facebook-share").data("socialShare-context").share_params.u=window.location.href;b.linear_root=="moderate"&&a("#approve-mark-checkbox").attr("checked",c.is_approved);b.currentMark.reference in b.flaggings?a("#mark-flag").addClass("disabled"):a("#mark-flag").removeClass("disabled");a("#mark-information").fadeIn("fast")},hideMarkInformation:function(){a("#mark-information").fadeOut("fast")},replayCurrentMark:function(a){a=a.modules.linear;var b=(new Date).getTime();a.eventChange=!0;a.scene.timers[a.currentMark.reference]=
|
||||||
|
{start:b,end:b+a.currentMark.maxTime,speed:1}},flagCurrentMark:function(d){var b=d.modules.linear;b.currentMark.reference in b.flaggings||a.ajax({url:"/requests/flag_mark",data:{reference:b.currentMark.reference},type:"POST",dataType:"JSON",success:function(){a("#mark-flag").addClass("disabled");b.flaggings[b.currentMark.reference]=!0;d.fn.storeData("markFlaggings",b.flaggings)},error:function(){d.fn.showError("Sorry, an error occured.")}})},deleteCurrentMark:function(d){var b=d.modules.linear;a.ajax({url:"/requests/delete_mark",
|
||||||
|
data:{reference:b.currentMark.reference},type:"POST",dataType:"JSON",success:function(){var a=b.currentMark.reference,e=null;delete b.marks[b.currentMark.reference];b.currentMark=null;for(var f=0;f<b.scene.objects.length;f++)if(e||b.scene.objects[f].reference==a){if(!e)e=f,b.scene.objects.splice(f,1),b.currentMark=b.scene.objects[f];f==0?b.scene.objects[f].positionToStart():b.scene.objects[f].positionRelativeTo(b.scene.objects[f-1])}d.app.setLocation("#/"+b.linear_root+"/"+b.currentMark.reference);
|
||||||
|
b.eventChange=!0},error:function(){d.fn.showError("Sorry, an error occured.")}})},approveCurrentMark:function(d,b){var c=d.modules.linear;a.ajax({url:"/requests/approve_mark",data:{reference:c.currentMark.reference,should_approve:b},type:"POST",dataType:"JSON",success:function(a){console.log(a);c.currentMark.is_approved=b},error:function(){d.fn.showError("Sorry, an error occured.")}})},centerCurrentMark:function(a,b){var c=a.modules.linear;if(!c.currentMark)return!1;modules.linear.fn.showMarkInformation(a);
|
||||||
|
c.cameraChange.aX=0;c.cameraChange.vX=0;c.cameraChange.aZ=0;c.cameraChange.vZ=0;var e=Math.abs(c.currentMark.position.x-c.scene.camera.position.x)/2;e=Math.min(8E3,Math.max(1E3,e));var f="cameraEase"in c.tweens?c.tweens.cameraEase:new TWEEN.Tween(c.scene.camera.position);f.to({x:c.currentMark.position.x+c.currentMark.bWidth/2,y:c.currentMark.position.y+c.currentMark.bHeight/2,z:c.currentMark.position.z-1E3},e).onComplete(function(){delete c.tweens.cameraEase;typeof b==="function"&&b(this)}).easing(TWEEN.Easing.Quartic.EaseInOut).start();
|
||||||
|
c.tweens.cameraEase=f}}}})(jQuery);
|
||||||
|
(function(a){a.markApp=a.markApp||{};var d=a.markApp.modules=a.markApp.modules||{};d.capture={defaults:{state:"intro",invite_code:null,locale:null,contributor_type:null},config:{captureLimit:300,layerManager:null,capturedPoints:0,strokes:[],framecount:0,cleanedStrokes:[],lastX:null,lastY:null,captureTime:null,rtl:null,initialized:!1,currentStroke:null,mark:null,timeBetweenStrokes:400,events:[]},evt:{resize:function(a){var c=a.modules.capture;c.layerManager.resizeAll(a.width,a.height);if(c.mark&&c.mark.strokes.length>
|
||||||
|
0)for(var e=0;e<c.mark.strokes.length;e++)d.capture.fn.drawStroke(a,c.mark.strokes[e])},mousemove:function(a){a.mouseDown&&a.modules.capture.state=="drawing"&&d.capture.fn.capturePoint(a)},mousedown:function(b){switch(b.modules.capture.state){case "drawing":a("#location-dialog").is(":visible")&&a("#location-dialog").fadeOut("fast");b.modules.capture.mark||d.capture.fn.startMark(b);b.modules.capture.currentStroke||d.capture.fn.startStroke(b);break;case "intro":b.modules.capture.mark||d.capture.fn.startMark(b),
|
||||||
|
b.modules.capture.currentStroke||d.capture.fn.startStroke(b),d.capture.fn.endIntro(b)}},mouseup:function(a){a.modules.capture.state=="drawing"&&d.capture.fn.endStroke(a)},ready:function(b){var c=b.modules.capture;a("#markmaker").hide().children().hide();a("#markmaker-reset a").addClass("disabled").bind("mousedown",function(a){a.preventDefault();d.capture.fn.reset(b)});a("#markmaker-submit a").addClass("disabled").bind("mousedown",function(a){a.preventDefault();d.capture.fn.submit(b)});b.fn.withCountryCodes(function(b){for(var c=
|
||||||
|
a("#markmaker-country"),d=0;d<b.length;d++){var h=a("<option />").val(b[d].code).text(b[d].name);c.append(h)}});a("#markmaker-location a").bind("mousedown",{context:b},d.capture.fn.locationDialogToggle);a("#markmaker-information").bind("mouseover",{context:b},d.capture.fn.informationDialogToggle).bind("mouseout",{context:b},d.capture.fn.informationDialogToggle);c.state=="drawing"&&d.capture.fn.initDrawing(b);a("#sammy #markmaker-country").selectBox({autoWidth:!1})},loop:function(a){var c=a.modules.capture;
|
||||||
|
if(c.initialized)switch(c.frameCount++,d.capture.fn.commonLoop(a),a.modules.capture.state){case "drawing":d.capture.fn.drawLoop(a)}}},fn:{init:function(b,c){var e=b.modules.capture;if("$capture"in e){if("state"in c)d.capture.fn.reset(b),c.state=="drawing"&&b.mouseDown&&b.fn.trigger("mousedown"),e.state=c.state,d.capture.fn.initDrawing(b)}else a.extend(e,d.capture.defaults),a.extend(e,c),a.extend(e,d.capture.config),e.$capture=a("<div />").addClass("capture-container"),b.$container.css({zIndex:100,
|
||||||
|
cursor:"none"}).append(e.$capture),e.layerManager=new Mark.layerManager(e.$capture.get(0)),e.layerManager.addLayer("drawnLayer"),e.layerManager.addLayer("liveDrawingLayer"),b.fn.trigger("resize"),e.initialized=!0},deinit:function(a){var c=a.modules.capture;c.$capture.fadeOut("fast",function(){c.layerManager.removeAll();c.$capture.remove();c.initialized=!1})},initIntro:function(){},initDrawing:function(b){var c=b.modules.capture;a("#browse-marks").is(":visible")&&(a("#browse-marks, #click-anywhere, #intro-main-copy").fadeOut("fast"),
|
||||||
|
a("#markmaker-legal-line").fadeIn("slow"));a("#markmaker").css("background-position","0 "+(b.height-140)+"px");a("#markmaker").unbind("resize.markApp").bind("resize.markApp",function(){a("#markmaker").css("background-position","0 "+(b.height-140)+"px");a("#location-dialog:visible").size()>0&&a("#location-dialog:visible").css({bottom:a("#markmaker-location").height()+25,left:a("#markmaker-location").offset().left+32})});a("#markmaker").is(":visible")?a("#markmaker-controls").fadeIn("slow",function(){a("#markmaker-information").fadeIn("slow")}):
|
||||||
|
a("#markmaker").width(0).show().animate({width:b.width},"slow",function(){a("#markmaker-controls").fadeIn("slow",function(){a("#markmaker-information").fadeIn("slow")});a("#markmaker-legal-line").fadeIn("slow")});c.invite_code&&c.contributor_type=="t"?(c.captureLimit=1E3,c.$capture.addClass("translator")):c.invite_code&&c.contributor_type=="c"&&(c.$capture.addClass("contributor"),a("#contributor-fields").collapsibleMod().fadeIn("slow"))},endIntro:function(a){a.app.setLocation("#/mark/new")},locationDialogToggle:function(b){b.preventDefault();
|
||||||
|
a("#location-dialog").is(":visible")?a("#location-dialog").fadeOut("fast"):a("#location-dialog").fadeIn("fast").css({bottom:a("#markmaker-location").height()+25,left:a("#markmaker-location").offset().left+32})},informationDialogToggle:function(b){b.preventDefault();b.type=="mouseout"?a("#information-dialog").fadeOut("fast"):a("#information-dialog").fadeIn("fast").css({bottom:a("#markmaker-information").height()+36,left:a("#markmaker-information").offset().left-a("#information-dialog").width()+30})},
|
||||||
|
startMark:function(b){var c=b.modules.capture;c.captureTime=(new Date).getTime();c.rtl=b.mouseX>a(window).width()/2;c.mark=new Mark.gmlMark([],"","",c.captureTime,c.rtl);a("#markmaker-submit a, #markmaker-reset a").removeClass("disabled")},endMark:function(a){a.modules.capture.mark.setupVars()},startStroke:function(a){a=a.modules.capture;a.currentStroke=[];if(a.strokes.length>0)a.captureTime=(new Date).getTime()-(a.strokes[a.strokes.length-1][a.strokes[a.strokes.length-1].length-1].time+a.timeBetweenStrokes)},
|
||||||
|
endStroke:function(a){var c=a.modules.capture;if(c.currentStroke.length>2){c.strokes.push(c.currentStroke);var e=Mark.simplification.simplifyPath(c.currentStroke,1);e=Mark.simplification.weightPath(e,[5,10,20,40]);c.mark.strokes.push(e);c.cleanedStrokes.push(e);d.capture.fn.drawStroke(a,e);c.capturedPoints-=c.currentStroke.length-e.length}c.currentStroke=null},capturePoint:function(a){var c=a.modules.capture;if(c.capturedPoints>c.captureLimit)a.fn.trigger("mouseup"),d.capture.fn.closeShop(a);else{var e=
|
||||||
|
(new Date).getTime();a=new Mark.gmlPoint(a.mouseX,a.mouseY,e-c.captureTime,0);c.currentStroke.length>0?(e=c.currentStroke[c.currentStroke.length-1],a.speed=e.speedToPoint(a),a.setAngleFromPoint(e),a.smoothAgainst(e,0.01)):c.strokes.length>=1&&d.capture.fn.drawGuide(c.layerManager.layers.drawnLayer.context,c.lastX,c.lastY,a.x,a.y);c.currentStroke.push(a);c.lastX=a.x;c.lastY=a.y;c.capturedPoints++}},reset:function(b){b=b.modules.capture;b.layerManager.layers.liveDrawingLayer.clean();b.layerManager.layers.drawnLayer.clean();
|
||||||
|
b.capturedPoints=0;b.rtl=null;b.mouseDown=!1;b.lastX=null;b.lastY=null;b.strokes=[];b.currentStroke=null;b.mark=null;b.captureTime=null;b.state="drawing";a("#markmaker-submit a, #markmaker-reset a").addClass("disabled");a("#markapp").css({cursor:"none"});a("#markmaker-instructions").fadeIn()},closeShop:function(b){var c=b.modules.capture;c.state="preview";d.capture.fn.endMark(b);c.layerManager.layers.liveDrawingLayer.clean();b=c.layerManager.layers.liveDrawingLayer.context;var e=c.lastX,f=c.lastY;
|
||||||
|
b.strokeStyle="rgba(0,0,0,0.2)";b.lineWidth=1;b.beginPath();b.dashedLineTo(e,f,c.rtl?0:c.layerManager.layers.liveDrawingLayer.canvas.width,f,[7,5]);b.closePath();b.stroke();a("#markapp").css({cursor:"default"})},submit:function(b){var c=b.modules.capture;if(c.state!="submitting"){c.state!="preview"&&d.capture.fn.closeShop(b);c.state="submitting";a("#markmaker-submit a").addClass("disabled");var e={};e.rtl=c.rtl;e.strokes=c.strokes;e=JSON.stringify(e);var f=JSON.stringify(c.mark),g=a("#markmaker-country").val()==
|
||||||
|
"label"?"":a("#markmaker-country").val();b.fn.showLoader(a(".translated-strings #submitting-mark").text());e={points_obj:e,points_obj_simplified:f,country_code:g};if(c.invite_code&&c.contributor_type=="t")e.contributor_locale=b.locale,e.invite=c.invite_code;else if(c.invite_code&&c.contributor_type=="c")e.contributor=a("#contributor-name").val(),c.mark.extra_info=a("#contributor-quote").val(),e.points_obj_simplified=JSON.stringify(c.mark),e.invite=c.invite_code;a.ajax({url:"/requests/save_mark",data:e,
|
||||||
|
type:"POST",dataType:"JSON",success:function(a){b.fn.storeData("userMark",{reference:a.mark_reference,country_code:g});b.app.setLocation("#/linear/"+a.mark_reference+"?playback=true");b.fn.hideLoader()},error:function(){b.fn.showError()}});return!1}},drawStroke:function(a,c){var d=a.modules.capture;Mark.thickBrush(d.layerManager.layers.drawnLayer.context,[c]);d.layerManager.layers.drawnLayer.context.fillStyle="rgba(255,255,255,0.3)";d.layerManager.layers.drawnLayer.context.strokeStyle="rgba(255,255,255,0.3)";
|
||||||
|
Mark.circleBrush(d.layerManager.layers.drawnLayer.context,[c])},drawGuide:function(a,c,d,f,g){a.strokeStyle="rgba(0,0,0,0.2)";a.lineWidth=1;a.beginPath();a.dashedLineTo(c,d,f,g,[7,5]);a.closePath();a.stroke()},drawCursor:function(a,c,d,f){a.strokeStyle="#ff5400";a.fillStyle="#000000";a.beginPath();a.moveTo(c,d);a.lineTo(c+1,d-8);a.lineTo(c+20,d-27);a.lineTo(c+23,d-23);a.lineTo(c,d);a.closePath();a.stroke();f*=18.5;f+=4.5;a.beginPath();a.moveTo(c,d);a.lineTo(c+1,d-8);a.lineTo(c+(f-3),d-(f+4));a.lineTo(c+
|
||||||
|
f,d-f);a.lineTo(c,d);a.closePath();a.fill()},commonLoop:function(a){var c=a.modules.capture;c.layerManager.layers.liveDrawingLayer.clean();a.mouseIn&&(c.state=="drawing"||c.state=="intro")&&d.capture.fn.drawCursor(c.layerManager.layers.liveDrawingLayer.context,a.mouseX,a.mouseY,(c.captureLimit-c.capturedPoints)/c.captureLimit)},introLoop:function(){},drawLoop:function(b){var c=b.modules.capture;if(c.currentStroke&&c.currentStroke.length>0)Mark.thickBrush(c.layerManager.layers.liveDrawingLayer.context,
|
||||||
|
[c.currentStroke]),c.layerManager.layers.liveDrawingLayer.context.fillStyle="rgba(255,255,255,0.3)",c.layerManager.layers.liveDrawingLayer.context.strokeStyle="rgba(255,255,255,0.3)",Mark.circleBrush(c.layerManager.layers.liveDrawingLayer.context,[c.currentStroke]);if(b.mouseIn&&!b.mouseDown){var e,f;c.strokes.length==0?(e=b.mouseX>a(window).width()/2?c.layerManager.layers.liveDrawingLayer.canvas.width:0,f=b.mouseY):(e=c.lastX,f=c.lastY);d.capture.fn.drawGuide(c.layerManager.layers.liveDrawingLayer.context,
|
||||||
|
e,f,b.mouseX,b.mouseY)}}}}})(jQuery);
|
||||||
|
(function(a){markApp=a.markApp=a.markApp||{};modules=a.markApp.modules=a.markApp.modules||{};modules.intro={defaults:{reference_mark:null},config:{marks:{},animationMarks:["vVR","myWb"],playbackTimes:{},vizScene:null,textScene:null,layerManager:null,initialized:!1,eventChange:!1,curLocaleMark:null,animationComplete:!1,tweens:{}},evt:{resize:function(a){a.modules.intro.layerManager.resizeAll(a.width,a.height);a.modules.intro.eventChange=!0;a.modules.intro.xAnimationComplete&&modules.intro.fn.drawX(a)},
|
||||||
|
loop:function(a){var b=a.modules.intro;TWEEN.update();b.layerManager.layers.viz.clean();Mark.renderer.renderScene(b.vizScene,{width:a.width,height:a.height});if(b.curLocaleMark||b.xMark){b.layerManager.layers.mainMark.clean();if(b.curLocaleMark){var c=500/b.curLocaleMark.bWidth;Mark.renderer.renderMark(b.layerManager.layers.mainMark.context,b.curLocaleMark,{offset:{x:a.width/2-115,y:a.height-240},scale:{x:c,y:c,thickness:c},color:"255,84,0",timer:b.textScene.timers[b.curLocaleMark.reference]})}b.xMark&&
|
||||||
|
Mark.renderer.renderMark(b.layerManager.layers.mainMark.context,b.xMark,{offset:{x:10,y:-50},scale:{x:(a.width/2-200)/b.xMark.bWidth,y:(a.height+200)/b.xMark.bHeight,thickness:5},color:"0,0,0",timer:b.textScene.timers[b.xMark.reference]})}},ready:function(d){a("#markmaker").hide().children().hide();a.when(modules.intro.fn.initInterface(d),modules.intro.fn.loadMarks(d)).then(function(){modules.intro.fn.runVizPreview(d)}).then(function(){modules.intro.fn.startDomAnimation(d)}).fail(function(){modules.intro.fn.simpleIntro(d)})}},
|
||||||
|
fn:{init:function(d,b){var c=d.modules.intro;if(c.initialized)for(option in console.log("this module isn't really intended to be reloaded"),a.extend(c,c,b),modules.intro.defaults)b[option]==null&&(c[option]=modules.intro.defaults[option]);else a.extend(c,modules.intro.defaults,b),a.extend(c,c,modules.intro.config),c.$intro=a("<div />").addClass("intro-container"),d.$container.append(c.$intro),c.vizScene=new Mark.scene,c.textScene=new Mark.scene,c.layerManager=new Mark.layerManager(c.$intro.get(0)),
|
||||||
|
c.layerManager.addLayer("viz"),c.vizScene.canvasContext=c.layerManager.layers.viz.context,c.layerManager.addLayer("mainMark"),c.textScene.canvasContext=c.layerManager.layers.mainMark.context,c.layerManager.addLayer("X"),d.fn.trigger("resize"),c.initialized=!0},deinit:function(a){var b=a.modules.intro;b.$intro.fadeOut("fast",function(){b.layerManager.removeAll();b.$intro.remove();b.initialized=!1})},initInterface:function(d){a("#markmaker").unbind("resize.markApp").bind("resize.markApp",function(b,
|
||||||
|
c,d){b=c/2+485;d-=140;c=!1;a("#markmaker").css("background-position","0 "+d+"px");a("#markmaker").is(":visible")||(c=!0,a("#markmaker, #browse-marks, #click-anywhere, #intro-main-copy").css({display:"block"}));a("#browse-marks").css({top:d-50,left:b-85});a("#click-anywhere").css({top:d+12,left:b-a("#intro-main-copy").width()});a("#intro-main-copy").css({top:d-a("#intro-main-copy").height()-100,left:b-a("#intro-main-copy").width()});c&&a("#markmaker, #browse-marks, #click-anywhere, #intro-main-copy").css({display:"none"})}).trigger("resize.markApp",
|
||||||
|
[d.width,d.height]).width(0).height(d.height)},loadMarks:function(d){return a.ajax({url:"/requests/get_translated_marks",dataType:"JSON"}).success(function(a){modules.intro.fn.setupMarks(d,a.marks)})},setupMarks:function(d,b){var c=d.modules.intro;if(!(typeof b==="undefined"||b.length==0)){a(c.layerManager.layers.viz.canvas).css("opacity",0);b.sort(function(){return Math.round(Math.random())-0.5});for(var e=null,f=0;f<b.length;f++)try{var g=JSON.parse(b[f].points_obj_simplified),h=new Mark.gmlMark(g.strokes,
|
||||||
|
b[f].reference,b[f].country_code,b[f].date_drawn,g.rtl,b[f].id,b[f].is_approved);if(!c.currentMark)c.currentMark=h;b[f].reference in c.marks||(c.marks[h.reference]=h);e&&h.positionRelativeTo(e,!1);if(b[f].contributor_locale==d.locale||!c.curLocaleMark){var j=(new Date).getTime()*3;c.curLocaleMark=new Mark.gmlMark(g.strokes,b[f].reference,b[f].country_code,b[f].date_drawn,g.rtl,b[f].id,b[f].is_approved);c.textScene.timers[c.curLocaleMark.reference]={start:j,end:j+c.curLocaleMark.maxTime,speed:2}}c.vizScene.objects.push(h);
|
||||||
|
e=h}catch(k){console.warn("Mark failed import",b[f].reference)}}},runVizPreview:function(d){var b=d.modules.intro;if(!(b.vizScene.objects.length<3)){b.vizScene.camera.position.x=-2E3;b.vizScene.camera.position.z=-3E3;d=b.vizScene.objects[b.vizScene.objects.length-2];var c=new TWEEN.Tween(b.vizScene.camera.position);c.to({x:d.position.x+d.bWidth/2,y:d.position.y+d.bHeight/2,z:d.position.z-2E3},6E3).onComplete(function(){delete b.tweens.cameraEase}).easing(TWEEN.Easing.Quartic.EaseInOut).start();b.tweens.cameraEase=
|
||||||
|
c;a(b.layerManager.layers.viz.canvas).animate({opacity:"1"},"slow").delay(2E3).animate({opacity:"0.1"},"slow");a("#markmaker").delay(3E3)}},startDomAnimation:function(d){a("#markmaker").width(0).show().animate({width:d.width},"slow",function(){modules.intro.fn.startMarkAnimations(d);a("#intro-main-copy").fadeIn("slow");a("#click-anywhere").delay(200).fadeIn("slow");a("#browse-marks").delay(100).fadeIn("slow")})},startMarkAnimations:function(a){var b=a.modules.intro;modules.intro.fn.drawX(a);b.curLocaleMark&&
|
||||||
|
(a=(new Date).getTime()+2E3,b.textScene.timers[b.curLocaleMark.reference]={start:a,end:a+b.curLocaleMark.maxTime,speed:2})},drawX:function(a){a=a.modules.intro;a.xMark=new Mark.gmlMark({strokes:[[{x:177,y:0,z:0,time:51,speed:0,angle:0,significance:5},{x:129,y:60,z:0,time:255,speed:0.45069390943299864,angle:0.5880026035475675,significance:1},{x:123,y:65,z:0,time:271,speed:0.4931203163041915,angle:0.7853981633974483,significance:1},{x:103,y:89,z:0,time:339,speed:0.45069390943299864,angle:0.5880026035475675,
|
||||||
|
significance:1},{x:56,y:139,z:0,time:503,speed:0.45073896963561083,angle:0.7853981633974483,significance:1},{x:38,y:162,z:0,time:584,speed:0.3572203090978693,angle:0.46364760900080615,significance:1},{x:9,y:192,z:0,time:691,speed:0.3535533905932738,angle:0.7853981633974483,significance:1},{x:0,y:206,z:0,time:727,speed:0.45069390943299864,angle:0.5880026035475675,significance:5}],[{x:11,y:23,z:0,time:1178,speed:0,angle:0,significance:5},{x:30,y:49,z:0,time:1246,speed:0.32424352695503,angle:5.639684198386302,
|
||||||
|
significance:1},{x:55,y:77,z:0,time:1321,speed:0.48790367901871773,angle:5.497787143782138,significance:1},{x:72,y:100,z:0,time:1367,speed:0.5216642390945547,angle:5.695182703632019,significance:1},{x:85,y:113,z:0,time:1408,speed:0.5355917833779965,angle:5.497787143782138,significance:2},{x:154,y:175,z:0,time:1662,speed:0.3311927108182759,angle:5.497787143782138,significance:1},{x:186,y:196,z:0,time:1802,speed:0.2849548128987055,angle:5.497787143782138,significance:5}]],country_code:"",time:1300925747439,
|
||||||
|
rtl:!1,maxTime:1802,reference:"",hoverState:!1,renderedBounds:null,id:null,contributor_name:null,extra_info:null,color:"0,0,0",hoverColor:"0,139,211",x:454,y:199,position:{x:0,y:0,z:0},rotationAngle:{x:0,y:0,z:0},sX:0,sY:0,bWidth:186,bHeight:206}.strokes,"xMark");a.textScene.objects.push(a.xMark);var b=(new Date).getTime();a.textScene.timers[a.xMark.reference]={start:b,end:b+a.xMark.maxTime,speed:1}},simpleIntro:function(d){a("#markmaker").width(0).show().animate({width:d.width},"slow",function(){a("#intro-main-copy").fadeIn("slow");
|
||||||
|
a("#click-anywhere").delay(200).fadeIn("slow");a("#browse-marks").delay(100).fadeIn("slow")})}}}})(jQuery);(function(a){var d={},b=["touchstart","touchmove","touchend","gesturestart","gesturechange","gestureend"],c=document.createElement("div");for(i in b){var e=b[i];e="on"+e;var f=e in c;f||(c.setAttribute(e,"return;"),f=typeof c[e]=="function");d[b[i]]=f}d.touches=d.touchstart&&d.touchend&&d.touchmove;d.gestures=d.gesturestart&&d.gesturechange&&d.gestureend;a.fn.browserTouchSupport=d})(jQuery);
|
||||||
|
(function(a){function d(a){return a.replace(/-/g,"--").replace(/ /g,"-")}a.fn.extend({delayedBind:function(b,c,e,f){var g=d(c);return this.each(function(){var d=this;a(this).data("_delayedBindBound-"+g+"-"+b)||(a(this).data("_delayedBindBound-"+g+"-"+b,!0),a(this).bind(c,function(){var c=a(this).data("_delayedBindTimerID-"+g+"-"+b);typeof c!="undefined"&&clearTimeout(c);c=setTimeout(function(){a(d).trigger("_delayedBind-"+g+"-"+b)},b);a(this).data("_delayedBindTimerID-"+g+"-"+b,c)}));a(this).bind("_delayedBind-"+
|
||||||
|
g+"-"+b,e,f)})},delayedBindCancel:function(b,c){var e=d(c);return this.each(function(){var c=a(this).data("_delayedBindTimerID-"+e+"-"+b);typeof c!="undefined"&&clearTimeout(c)})},delayedBindUnbind:function(b,c,e){var f=d(c);return this.each(function(){a(this).unbind("_delayedBind-"+f+"-"+b,e)})}})})(jQuery);
|
||||||
|
(function(a){a.collapsibleMod={cfg:{collapsedClass:"collapsibleMod-collapsed",expandedClass:"collapsibleMod-expanded",$header:null,previewSelector:"",$content:null,collapsed:!1,stateKey:"",saveState:!0},fn:{init:function(d,b){var c=a(d),e=a.extend({},a.collapsibleMod.cfg,b);e.$container=c;e.$header=c.find("h3:first");e.$content=c.children().not("h3:first").not(e.previewSelector);e.$header.bind("click",function(b){b.preventDefault();a.collapsibleMod.fn.toggle(e)});e.saveState&&e.$container.attr("id")!=
|
||||||
|
""&&typeof localStorage!="undefined"?(e.stateKey="collapsibleMod-state-"+e.$container.attr("id"),a.collapsibleMod.fn.restoreState(e)):e.saveState=!1;e.collapsed?a.collapsibleMod.fn.collapse(e):e.$container.addClass(e.expandedClass);c.data("collapsibleMod-context",e)},collapse:function(d){d.$container.addClass(d.collapsedClass).removeClass(d.expandedClass);d.$content.slideUp("fast");d.collapsed=!0;a.collapsibleMod.fn.saveState(d)},expand:function(d){d.$container.removeClass(d.collapsedClass).addClass(d.expandedClass);
|
||||||
|
d.$content.slideDown("fast");d.collapsed=!1;a.collapsibleMod.fn.saveState(d)},saveState:function(a){if(a.saveState)try{localStorage.removeItem(a.stateKey),localStorage.setItem(a.stateKey,a.collapsed)}catch(b){}},restoreState:function(a){if(a.saveState&&localStorage.getItem(a.stateKey))a.collapsed=localStorage.getItem(a.stateKey)==="true"},toggle:function(d){d.collapsed?a.collapsibleMod.fn.expand(d):a.collapsibleMod.fn.collapse(d)}}};a.fn.collapsibleMod=function(d){return a(this).each(function(){a.collapsibleMod.fn.init(this,
|
||||||
|
d)})}})(jQuery);
|
||||||
|
(function(a){a.socialShare={cfg:{$link:null,share_url:"http://twitter.com/share",share_title:"Share on Twitter",share_params:{},popupWidth:550,popupHeight:450},fn:{init:function(d,b){var c=a(d),e=a.extend({},a.socialShare.cfg,b);e.$link=c;e.$link.bind("click",function(b){b.preventDefault();a.socialShare.fn.share(e)});c.data("socialShare-context",e)},shareURL:function(a){var b=[];for(param in a.share_params)b.push(param+"="+escape(a.share_params[param]));return a.share_url+"?"+b.join("&")},share:function(d){window.open(a.socialShare.fn.shareURL(d),
|
||||||
|
d.share_title,"height="+d.popupHeight+",width="+d.popupWidth)}}};a.fn.socialShare=function(d){return a(this).each(function(){a.socialShare.fn.init(this,d)})}})(jQuery);
|
||||||
|
jQuery&&function(a){a.extend(a.fn,{selectBox:function(d,b){var c=function(b){var c=b.data.select,d=b.data.control;if(a(d).hasClass("ui-selectBox-disabled"))return!1;if(a(d).hasClass("ui-selectBox-focus")&&a("#ui-selectBox-dropdown").size()===1)return e(b,!0),!1;a(".ui-selectBox").not(d).trigger("blur");g(b);b.stopPropagation();a("#ui-selectBox-dropdown").remove();var n=a('<div id="ui-selectBox-dropdown" class="ui-corner-bottom" />'),s=a("<ul />");a(c).children("optgroup").size()===0?a(c).children("option").each(function(){var b=
|
||||||
|
a(this).text()!==""?a(this).text():"\u00a0",c="";a(this).attr("disabled")&&(c+=" ui-selectBox-disabled");a(s).append('<li class="ui-selectBox-option'+c+'">'+q(b)+"</li>")}):(a(n).addClass("ui-selectBox-hasOptgroups"),a(c).children("optgroup").each(function(){a(s).append('<li class="ui-selectBox-optgroup">'+q(a(this).attr("label"))+"</li>");a(this).children("option").each(function(){var b=a(this).text()!==""?a(this).text():"\u00a0",c="";a(this).attr("disabled")&&(c+=" ui-selectBox-disabled");a(s).append('<li class="ui-selectBox-option'+
|
||||||
|
c+'">'+q(b)+"</li>")})}));a(n).append(s);b=a(c)[0].selectedIndex;a(n).find("LI.ui-selectBox-option").eq(b).addClass("ui-selectBox-initial ui-selectBox-current");a(n).find("LI.ui-selectBox-option").hover(function(){a(n).find(".ui-selectBox-current").removeClass("ui-selectBox-current");a(this).addClass("ui-selectBox-current")},function(){a(this).removeClass("ui-selectBox-current")}).click({select:c,control:d},function(a){f(a)}).mouseup({select:c,control:d},function(b){a(b.target).trigger("click")});
|
||||||
|
a("BODY").append(n);c=a(d).offset();b=a(d).outerHeight();var l=a(d).outerWidth(),h=parseInt(a(n).css("borderLeftWidth"))+parseInt(a(n).css("borderRightWidth"));a(n).css({position:"absolute",zIndex:"999999",top:c.top+b,left:c.left,width:l-h}).show();a(d).removeClass("ui-corner-all").addClass("ui-corner-top");p(n);k(!0)},e=function(b,c){var d=b.data.control;a("#ui-selectBox-dropdown").remove();a(d).removeClass("ui-corner-top").addClass("ui-corner-all");c?a(d).focus():h(b)},f=function(b,c){var d=b.data.select,
|
||||||
|
n=b.data.control;c=c?c:b.target;if(a(c).hasClass("ui-selectBox-disabled"))return!1;var f=a(d)[0].selectedIndex;a("#ui-selectBox-dropdown .ui-selectBox-optgroup").remove();var g=a("#ui-selectBox-dropdown").find("LI.ui-selectBox-current").index();if(f!==g)a(d)[0].selectedIndex=g,a(n).find(".ui-selectBox-label").text(a(c).text()),a(d).trigger("change");e(b,!0)},g=function(b){var c=b.data.select;b=b.data.control;if(a(b).hasClass("ui-selectBox-disabled"))return!0;if(a(b).hasClass("ui-selectBox-focus"))return!1;
|
||||||
|
a(".ui-selectBox.ui-selectBox-focus").removeClass("ui-selectBox-focus");a("#ui-selectBox-dropdown").remove();a(b).addClass("ui-selectBox-focus");a(document).bind("mousedown",{select:c,control:b},h);a(document).bind("keydown",{select:c,control:b},j);a(c).trigger("focus");a(b).focus()},h=function(b){var c=b.data.select,d=b.data.control;if(b.target.id==="ui-selectBox-dropdown"||a(b.target).parents("#ui-selectBox-dropdown").size()===1)return a(d).trigger("focus"),!1;a(d).hasClass("ui-selectBox-focus")&&
|
||||||
|
(a(d).removeClass("ui-selectBox-focus"),a(document).unbind("mousedown",h),a(document).unbind("keydown",j),a(c).trigger("blur"),e(b))},j=function(b){var d=b.data.select,m=b.data.control,n=a("#ui-selectBox-dropdown");if(a(m).hasClass("ui-selectBox-disabled"))return!1;switch(b.keyCode){case 9:h(b);break;case 13:if(a(n).size()===0)return!1;d=a(n).find(".ui-selectBox-option");var g=-1;a.each(d,function(b,c){a(c).hasClass("ui-selectBox-current")&&(g=b)});g>=0&&f(b,a(d).eq(g));return!1;case 27:e(b,!0);break;
|
||||||
|
case 38:case 37:case 33:var l=b.keyCode===33?20:1;if(a(n).size()===0){if(b.altKey)return c(b),!1;b=a(d).find("OPTION").size();n=a(d)[0].selectedIndex;for(l=a(d)[0].selectedIndex-l;a(d).find("OPTION").eq(l).attr("disabled")===!0&&l>=0;)l--;l<0&&(l=a(d).find("OPTION:not([disabled]):first").index());a(d)[0].selectedIndex=l;if(a(d)[0].selectedIndex===-1)l=0,a(d)[0].selectedIndex=l;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(m).find(".ui-selectBox-label").text(b);l!==n&&a(d).trigger("change");
|
||||||
|
return!1}d=a(n).find(".ui-selectBox-option");g=-1;a.each(d,function(b,c){a(c).hasClass("ui-selectBox-current")&&(g=b)});g-=l;g<0&&(g=0);a(d).removeClass("ui-selectBox-current");a(d).eq(g).addClass("ui-selectBox-current");k();return!1;case 40:case 39:case 34:l=b.keyCode===34?20:1;if(a(n).size()===0){if(b.altKey)return c(b),!1;b=a(d).find("OPTION").size();n=a(d)[0].selectedIndex;for(l=a(d)[0].selectedIndex+l;a(d).find("OPTION").eq(l).attr("disabled")===!0&&l<=a(d).find("OPTION").size();)l++;l>b-1&&
|
||||||
|
(l=a(d).find("OPTION:not([disabled]):last").index());a(d)[0].selectedIndex=l;if(a(d)[0].selectedIndex===-1)l=a(d).find("OPTION").size()-1,a(d)[0].selectedIndex=l;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(m).find(".ui-selectBox-label").text(b);l!=n&&a(d).trigger("change");return!1}d=a(n).find(".ui-selectBox-option");g=-1;a.each(d,function(b,c){a(c).hasClass("ui-selectBox-current")&&(g=b)});g+=l;g>a(d).size()-1&&(g=a(d).size()-1);a(d).removeClass("ui-selectBox-current");a(d).eq(g).addClass("ui-selectBox-current");
|
||||||
|
k();return!1;case 36:case 35:if(a(n).size()===0){if(b.altKey)return c(b),!1;n=a(d)[0].selectedIndex;l=b.keyCode===36?0:a(d).find("OPTION").size()-1;a(d).find("OPTION").eq(l).attr("disabled")===!0&&(l=b.keyCode===36?a(d).find("OPTION:not([disabled]):first").index():a(d).find("OPTION:not([disabled]):last").index());a(d)[0].selectedIndex=l;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(m).find(".ui-selectBox-label").text(b);l!=n&&a(d).trigger("change");return!1}a(n).find(".ui-selectBox-current").removeClass("ui-selectBox-current");
|
||||||
|
b.keyCode===36?a(n).find(".ui-selectBox-option:first").addClass("ui-selectBox-current"):a(n).find(".ui-selectBox-option:last").addClass("ui-selectBox-current");k();return!1}},k=function(b){var c=a("#ui-selectBox-dropdown");if(a(c).size()===0)return!1;var d=a(c).find(".ui-selectBox-current");if(a(d).size()===0)return!1;var e=parseInt(a(d).offset().top-a(c).position().top),f=parseInt(e+a(d).outerHeight());b?a(c).scrollTop(a(d).offset().top-a(c).offset().top+a(c).scrollTop()-a(c).height()/2):(e<0&&a(c).scrollTop(a(d).offset().top-
|
||||||
|
a(c).offset().top+a(c).scrollTop()),f>a(c).height()&&a(c).scrollTop(a(d).offset().top+a(d).outerHeight()-a(c).offset().top+a(c).scrollTop()-a(c).height()))},p=function(b){a(b).css("MozUserSelect","none").bind("selectstart",function(){return!1}).bind("mousedown",function(){return!1});return!0},q=function(a){return a.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")};switch(d){case "destroy":return a(this).each(function(){var b=a(this),c=a(this).next(".ui-selectBox");
|
||||||
|
a(b)[0].tagName.toLowerCase()==="select"&&(a(c).remove(),a(b).removeData("selectBox-options").show())}),a(this);case "disable":return a(this).each(function(){var b=a(this),c=a(this).next(".ui-selectBox");a(b).attr("disabled",!0);a(c).addClass("ui-selectBox-disabled")}),a(this);case "enable":return a(this).each(function(){var b=a(this),c=a(this).next(".ui-selectBox");a(b).attr("disabled",!1);a(c).removeClass("ui-selectBox-disabled")}),a(this);case "setOptions":if(!b)return a(this);a(this).each(function(){var c=
|
||||||
|
a(this);a(this).next(".ui-selectBox");switch(typeof b){case "string":a(c).html(b);break;case "object":for(var d in a(c).html(""),b)if(b[d]!==null){if(typeof b[d]==="object"){var m=a('<optgroup label="'+d+'" />'),e;for(e in b[d])a(m).append('<option value="'+e+'">'+b[d][e]+"</option>")}else m=a('<option value="'+d+'">'+b[d]+"</option>");a(c).append(m)}}d=a(c).data("selectBox-options");a(c).selectBox("destroy");a(c).selectBox(d)});return a(this);case "value":return a("#ui-selectBox-dropdown").remove(),
|
||||||
|
a(this).each(function(){var c=a(this),d=a(this).next(".ui-selectBox");a(c).val(b);c=a(c).find(":selected").text();c===""&&(c="\u00a0");a(d).removeClass("ui-corner-top").addClass("ui-corner-all").find(".ui-selectBox-label").text(c)}),a(this);default:return a(this).each(function(){d||(d={});var b=a.extend({autoWidth:!0},d),e=a(this);if(a(this).next(".ui-selectBox").size()===0){var m=a('<a href="#" class="ui-selectBox ui-corner-all" tabindex="'+parseInt(a(e).attr("tabindex"))+'" />');a(m).addClass(a(e).attr("class")).attr({style:(a(e).attr("style")+
|
||||||
|
"").replace(/inline/,"inline-block"),title:a(e).attr("title")});a(e).data("selectBox-options",b);if(b.autoWidth){var n="";a(e).find("OPTION").each(function(){a(this).text().length>n.length&&(n=a(this).text())});b=a('<div class="ui-selectBox-dropdown" style="position: absolute; top: -9999em; left: -9999em; width: auto; display: inline-block;" />');var f=a('<li class="ui-selectBox-option">'+q(n)+"</li>");a(b).append(f);a("BODY").append(b);a(m).width(f.outerWidth());a(b).remove()}a(e)[0].tagName.toLowerCase()!==
|
||||||
|
"select"||a(e).attr("multiple")===!0||(a(e).attr("disabled")===!0&&a(m).addClass("ui-selectBox-disabled"),b=a(e).find("OPTION:selected").text(),b===""&&(b="\u00a0"),a(m).append('<span class="ui-selectBox-label">'+q(b)+"</span>"),a(m).append('<span class="ui-selectBox-arrow"></span>'),a(e).hide().after(m),p(m),a(m).bind("click",function(){return!1}).bind("mousedown",{select:e,control:m},c).bind("focus",{select:e,control:m},g).bind("blur",{select:e,control:m},h))}}),a(this)}}})}(jQuery);
|
||||||
|
this.JSON||(JSON={});
|
||||||
|
(function(){function a(a){return a<10?"0"+a:a}function d(a){e.lastIndex=0;return e.test(a)?'"'+a.replace(e,function(a){var b=h[a];return typeof b==="string"?b:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function b(a,c){var e,h,r,m,n=f,s,l=c[a];l&&typeof l==="object"&&typeof l.toJSON==="function"&&(l=l.toJSON(a));typeof j==="function"&&(l=j.call(c,a,l));switch(typeof l){case "string":return d(l);case "number":return isFinite(l)?String(l):"null";case "boolean":case "null":return String(l);case "object":if(!l)return"null";
|
||||||
|
f+=g;s=[];if(Object.prototype.toString.apply(l)==="[object Array]"){m=l.length;for(e=0;e<m;e+=1)s[e]=b(e,l)||"null";r=s.length===0?"[]":f?"[\n"+f+s.join(",\n"+f)+"\n"+n+"]":"["+s.join(",")+"]";f=n;return r}if(j&&typeof j==="object"){m=j.length;for(e=0;e<m;e+=1)h=j[e],typeof h==="string"&&(r=b(h,l))&&s.push(d(h)+(f?": ":":")+r)}else for(h in l)Object.hasOwnProperty.call(l,h)&&(r=b(h,l))&&s.push(d(h)+(f?": ":":")+r);r=s.length===0?"{}":f?"{\n"+f+s.join(",\n"+f)+"\n"+n+"}":"{"+s.join(",")+"}";f=n;return r}}
|
||||||
|
if(typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function(){return this.getUTCFullYear()+"-"+a(this.getUTCMonth()+1)+"-"+a(this.getUTCDate())+"T"+a(this.getUTCHours())+":"+a(this.getUTCMinutes())+":"+a(this.getUTCSeconds())+"Z"},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){return this.valueOf()};var c=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
f,g,h={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},j;if(typeof JSON.stringify!=="function")JSON.stringify=function(a,c,d){var e;g=f="";if(typeof d==="number")for(e=0;e<d;e+=1)g+=" ";else typeof d==="string"&&(g=d);if((j=c)&&typeof c!=="function"&&(typeof c!=="object"||typeof c.length!=="number"))throw Error("JSON.stringify");return b("",{"":a})};if(typeof JSON.parse!=="function")JSON.parse=function(a,b){function d(a,c){var e,f,g=a[c];if(g&&typeof g==="object")for(e in g)Object.hasOwnProperty.call(g,
|
||||||
|
e)&&(f=d(g,e),f!==void 0?g[e]=f:delete g[e]);return b.call(a,c,g)}var e;c.lastIndex=0;c.test(a)&&(a=a.replace(c,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return e=eval("("+a+")"),typeof b==="function"?d({"":e},""):e;throw new SyntaxError("JSON.parse");}})();
|
||||||
|
CanvasRenderingContext2D.prototype.dashedLineTo=function(a,d,b,c,e){var f=function(a,b){return a<=b},g=function(a,b){return a>=b},h=function(a,b){return Math.min(a,b)},j=function(a,b){return Math.max(a,b)},k={thereYet:g,cap:h};g={thereYet:g,cap:h};if(d-c>0)g.thereYet=f,g.cap=j;if(a-b>0)k.thereYet=f,k.cap=j;this.moveTo(a,d);f=a;j=d;h=0;for(var p=!0;!k.thereYet(f,b)||!g.thereYet(j,c);){var q=Math.atan2(c-d,b-a),o=e[h];f=k.cap(b,f+Math.cos(q)*o);j=g.cap(c,j+Math.sin(q)*o);p?this.lineTo(f,j):this.moveTo(f,
|
||||||
|
j);h=(h+1)%e.length;p=!p}};CanvasRenderingContext2D.prototype.dottedArc=function(a,d,b,c,e,f){var g=Math.PI/b/2,h=c;for(c+=g;c<e;)this.beginPath(),this.arc(a,d,b,h,c,f),this.stroke(),h=c+g,c=h+g};
|
||||||
|
var Mark=function(a){a.layer=function(a,b){this.context=this.canvas=null;this.dirtyRectangles=[];this.layerName=b;this.manager=a;this.clean=function(){if(this.dirtyRectangles.length==0)this.context.clearRect(0,0,this.canvas.width,this.canvas.height);else for(var a=0;a<this.dirtyRectangles.length;a++)this.context.clearRect(a.x,a.y,a.w,a.h)};this.setSize=function(a,b){if(this.canvas.width!=a)this.canvas.width=a;if(this.canvas.height!=b)this.canvas.height=b};this.init=function(){this.canvas=document.createElement("canvas");
|
||||||
|
this.context=this.canvas.getContext("2d");this.setSize(this.manager.container.scrollWidth,this.manager.container.scrollHeight);this.manager.layerWrapper.appendChild(this.canvas)};this.remove=function(){this.manager.layerWrapper.removeChild(this.canvas)};this.sendToTop=function(){};this.init()};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.layerManager=function(d){this.container=d;this.layerWrapper=null;this.layers={};this.init=function(){this.layerWrapper=document.createElement("div");this.layerWrapper.className="mark-layerManager";this.container.appendChild(this.layerWrapper)};this.addLayer=function(b){var c=new a.layer(this,b);return this.layers[b]=c};this.removeAll=function(){for(var a in this.layers)this.layers[a].remove(),delete this.layers[a]};this.resizeAll=function(a,c){for(var d in this.layers)this.layers[d].setSize(a,
|
||||||
|
c)};this.init()};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.gmlPoint=function(a,b,c,e,f){this.x=a;this.y=b;this.z=typeof f=="integer"?f:0;this.time=c;this.speed=e;this.angle=0;this.significance=1;this.distanceToPoint=function(a){return Math.sqrt(Math.pow(a.x-this.x,2)+Math.pow(a.y-this.y,2))};this.speedToPoint=function(a){return this.distanceToPoint(a)/(a.time-this.time)};this.smoothAgainst=function(a,b){var c=this.distanceToPoint(a);c*=b;if(Math.abs(this.speed-a.speed)>c)this.speed=this.speed>a.speed?a.speed+c:a.speed-c};this.setAngleFromPoint=
|
||||||
|
function(a){this.angle=Math.atan2(a.y-this.y,a.x-this.x)+Math.PI/2;this.angle%=2*Math.PI;if(this.angle<0)this.angle=2*Math.PI+this.angle};this.clone=function(){return{x:this.x,y:this.y,z:this.z,time:this.time,significance:this.significance,angle:this.angle,speed:this.speed}};this.getTranslatedPoint=function(a,b){var c=this.clone();c.x+=a;c.y+=b;return c}};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.simplification={Line:function(a,b){this.p1=a;this.p2=b;this.distanceToPoint=function(a){var b=(this.p2.y-this.p1.y)/(this.p2.x-this.p1.x),d=[];d.push(Math.abs(a.y-b*a.x-(this.p1.y-b*this.p1.x))/Math.sqrt(Math.pow(b,2)+1));d.push(Math.sqrt(Math.pow(a.x-this.p1.x,2)+Math.pow(a.y-this.p1.y,2)));d.push(Math.sqrt(Math.pow(a.x-this.p2.x,2)+Math.pow(a.y-this.p2.y,2)));return d.sort(function(a,b){return a-b})[0]}},douglasPeucker:function(d,b){var c=[];if(d.length<=2)return[d[0]];for(var e=
|
||||||
|
new a.simplification.Line(d[0],d[d.length-1]),f=0,g=0,h=1;h<=d.length-2;h++){var j=e.distanceToPoint(d[h]);j>f&&(f=j,g=h)}f>=b?(f=d[g],e.distanceToPoint(f,!0),c=c.concat(a.simplification.douglasPeucker(d.slice(0,g+1),b)),c=c.concat(a.simplification.douglasPeucker(d.slice(g,d.length),b))):(f=d[g],e.distanceToPoint(f,!0),c=[d[0]]);return c},simplifyPath:function(d,b){var c=a.simplification.douglasPeucker(d,b);c.push(d[d.length-1]);return c},weightPath:function(d,b){for(var c=b.length+1,e=d;tolerance=
|
||||||
|
b.shift();){e=a.simplification.douglasPeucker(e,tolerance);for(var f=0;f<e.length;f++)e[f].significance++}d[0].significance=c;d[d.length-1].significance=c;return d}};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.dof=1E4;a.thickMarkBrush=function(d,b,c,e,f,g){e=e?e:"0,0,0";var h=Mark.renderer.translatePoint(b[0][0],c),j={minX:h.x,maxX:h.x,minY:h.y,maxY:h.y};if(!f||!g||!(h.x>f*2||h.x<-f||h.y>g*2||h.y<-g||h.z>a.dof||h.z<0)){for(f=0;f<b.length;f++)if(!(typeof b[f]=="undefined"||b[f].length<=1))for(var k=null,p=0;p<b[f].length;p++)if(h=Mark.renderer.translatePoint(b[f][p],c),(!h.z||!(h.z>a.dof||h.z<0))&&!(h.significance&&h.significance*(a.dof/5)<h.z-500))if(k){d.lineWidth=1;if(p==b[f].length-
|
||||||
|
1)var q=0,o=0;else o=9-Math.max(0,Math.pow(h.speed+1,3)),c.mode=="flatScale"&&c.scale.thickness?o*=c.scale.thickness:h.z&&(o*=2/h.z*(g/2)),o<0.1&&(o=0.1),o+=1,q=Math.cos(h.angle)*o,o*=Math.sin(h.angle);d.strokeStyle="rgba("+e+","+(a.dof-h.z)/a.dof+")";d.fillStyle="rgba("+e+","+(a.dof-h.z)/a.dof+")";try{d.beginPath(),d.lineWidth=0.5*((a.dof-h.z)/a.dof),d.moveTo(k.x-prevPX-0.5,k.y-prevPY-0.5),d.lineTo(k.x+prevPX-0.5,k.y+prevPY-0.5),d.lineTo(h.x+q-0.5,h.y+o-0.5),d.lineTo(h.x-q-0.5,h.y-o-0.5),d.lineTo(k.x-
|
||||||
|
prevPX-0.5,k.y-prevPY-0.5),d.fill(),d.stroke()}catch(r){}j.minX=h.x<j.minX?h.x:j.minX;j.minY=h.y<j.minY?h.y:j.minY;j.maxX=h.x>j.maxX?h.x:j.maxX;j.maxY=h.y>j.maxY?h.y:j.maxY;k=h;prevPX=q;prevPY=o}else{if(f!=0&&h.z<1500&&(k=Mark.renderer.translatePoint(b[f-1][b[f-1].length-1],c),k.z&&k.z<a.dof))d.strokeStyle="rgba(0,0,0,0.3)",d.lineWidth=1,d.beginPath(),d.dashedLineTo(k.x,k.y,h.x,h.y,[6,4]),d.closePath(),d.stroke();k=h;prevPY=prevPX=0}return j}};a.connectionBrush=function(d,b,c,e,f,g,h){e={offset:e,
|
||||||
|
w:g,h:h,mode:"pinhole"};b=Mark.renderer.translatePoint(b,e);e.offset=f;c=Mark.renderer.translatePoint(c,e);if(!(b.x>g||b.x<0||b.y>h||b.y<0)||!(c.x>g||c.x<0||c.y>h||c.y<0))if(!b.z||!c.z||!(b.z>a.dof||b.z<0)||!(c.z>a.dof||c.z<0))d.strokeStyle="rgba(0,0,0,"+(a.dof-b.z)/(a.dof*2)+")",f=3*(2/b.z)*(h/2),f<1&&(f=1),d.lineWidth=f,d.beginPath(),d.moveTo(b.x,b.y),d.lineTo(c.x,c.y),d.closePath(),d.stroke()};a.thickBrush=function(a,b,c,e,f){c=c?c:0;e=e?e:0;f=f?f:1;for(var g=0;g<b.length;g++)if(!(typeof b[g]==
|
||||||
|
"undefined"||b[g].length<=1)){if(g>0)a.strokeStyle="rgba(0,0,0,0.1)",a.lineWidth=1,a.beginPath(),a.dashedLineTo(b[g-1][b[g-1].length-1].x+c,b[g-1][b[g-1].length-1].y+e,b[g][0].x+c,b[g][0].y+e,[6,4]),a.closePath(),a.stroke();a.lineWidth=1;a.strokeStyle="#000000";a.fillStyle="#000000";for(var h=0,j=0,k=b[g][0].x,p=b[g][0].y,q=1;q<b[g].length;q++){var o=b[g][q];if(!(o.significance<f)){if(q==b[g].length-1)var r=0,m=0;else m=9-Math.pow(o.speed+1,3),m<0.5&&(m=0.5),m+=1,r=Math.cos(o.angle)*m,m*=Math.sin(o.angle);
|
||||||
|
try{a.beginPath(),a.moveTo(k-h-0.5+c,p-j-0.5+e),a.lineTo(k+h-0.5+c,p+j-0.5+e),a.lineTo(o.x+r-0.5+c,o.y+m-0.5+e),a.lineTo(o.x-r-0.5+c,o.y-m-0.5+e),a.lineTo(k-h-0.5+c,p-j-0.5+e),a.fill(),a.stroke()}catch(n){}h=r;j=m;k=o.x;p=o.y;prevAng=o.angle}}}};a.circleMarkBrush=function(d,b,c){for(var e=3,f=0;f<b.length;f++)if(b[f].length!=0)for(var g=0;g<b[f].length;g++){var h=Mark.renderer.translatePoint(b[f][g],c);if(!(h.z&&h.z>a.dof))e=3*((a.dof-h.z)/a.dof),d.fillStyle="rgba(255,255,255,0.4)",d.strokeStyle=
|
||||||
|
"rgba(255,255,255,0.4)",d.beginPath(),d.arc(h.x,h.y,e,0,Math.PI*2,!0),d.closePath(),d.fill(),d.stroke(),d.lineTo(h.x,h.y)}};a.circleBrush=function(a,b,c,e,f){c=c?c:0;e=e?e:0;f=f?f:1;for(var g=0;g<b.length;g++)if(b[g].length!=0){a.beginPath();for(var h=0;h<b[g].length;h++){var j=b[g][h];j.significance<f||(a.beginPath(),a.arc(j.x+c,j.y+e,3,0,Math.PI*2,!0),a.closePath(),a.fill(),a.stroke(),a.lineTo(j.x+c,j.y+e))}}};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.gmlMark=function(a,b,c,e,f,g,h){this.strokes=a;this.country_code=c;this.time=e;this.rtl=f;this.maxTime=0;this.reference=b;this.hoverState=!1;this.renderedBounds=null;this.id=g?g:null;this.is_approved=h;this.extra_info=this.contributor_name=null;this.color="0,0,0";this.hoverColor="0,139,211";this.y=this.x=0;this.position={x:0,y:0,z:0};this.rotationAngle={x:0,y:0,z:0};this.bHeight=this.bWidth=this.sY=this.sX=0;this.init=function(){this.strokes.length>0&&this.setupVars()};this.setupVars=
|
||||||
|
function(){this.maxTime=this.lastPoint().time;this.getBoundingBox()};this.leftmostStrokeStart=function(){for(var a=this.strokes[0][0],b=1;b<this.strokes.length;b++){var c=this.strokes[b][0];c.x<a.x&&(lastPoint=c)}return a};this.rightmostStrokeEnd=function(){for(var a=this.strokes[0][this.strokes[0].length-1],b=1;b<this.strokes.length;b++){var c=this.strokes[b][this.strokes[b].length-1];c.x>a.x&&(a=c)}return a};this.firstPoint=function(){return this.strokes[0][0]};this.lastPoint=function(){return this.strokes[this.strokes.length-
|
||||||
|
1][this.strokes[this.strokes.length-1].length-1]};this.translatePoint=function(a){var b=a.clone();b.x=this.x+a.x;b.y=this.y+a.y;return b};this.getBoundingBox=function(){var a=this.strokes[0][0],b=a.x,c=a.x,d=a.y;a=a.y;for(var e=0;e<this.strokes.length;e++)for(var f=0;f<this.strokes[e].length;f++){var m=this.strokes[e][f];b=m.x>b?m.x:b;d=m.y>d?m.y:d;c=m.x<c?m.x:c;a=m.y<a?m.y:a}this.bWidth=b-c;this.bHeight=d-a;this.x=c;this.y=a;(c!=0||a!=0)&&this.fitPointsToBounds(c,a)};this.fitPointsToBounds=function(a,
|
||||||
|
b){for(var c=0;c<this.strokes.length;c++)for(var d=0;d<this.strokes[c].length;d++)this.strokes[c][d].x-=a,this.strokes[c][d].y-=b};this.strokesAtTime=function(a){if(a>this.maxTime)return this.strokes;for(var b=[[]],c=[0,0],d=this.strokes[c[0]][c[1]];d.time<a;)b[b.length-1].push(d),c[1]++,this.strokes[c[0]].length==c[1]&&(c[0]++,c[1]=0,b.push([])),d=this.strokes[c[0]][c[1]];return b};this.positionRelativeTo=function(a,b){b&&b?(this.position.x=a.position.x-50-this.bWidth,this.position.y=a.position.y+
|
||||||
|
a.leftmostStrokeStart().y-this.rightmostStrokeEnd().y,this.position.z=a.position.z-this.maxTime/50):(this.position.x=a.position.x+a.bWidth+this.leftmostStrokeStart().x+50,this.position.y=a.position.y+a.rightmostStrokeEnd().y-this.firstPoint().y,this.position.z=a.position.z+a.maxTime/50)};this.positionToStart=function(){this.position.x=0;this.position.y=0;this.position.z=0};this.translatePoint=function(){};this.url=function(){return"http://domain.tld/#/mark/"+this.reference};this.init()};return a}(Mark||
|
||||||
|
{});Mark=function(a){a.scene=function(){this.camera=new Mark.camera;this.objects=[];this.canvasContext=null;this.timers={};this.init=function(){};this.addObject=function(a){this.objects.push(a)};this.removeObject=function(a){this.objects.splice(a,1)};this.update=function(){var d=(new Date).getTime();for(a in this.timers)this.timers[a].end<d&&delete this.timers[a]};this.init()};return a}(Mark||{});
|
||||||
|
Mark=function(a){a.renderer={translatePoint:function(a,b){var c={flatScale:function(a,b){var c="offset"in b&&"x"in b.offset?b.offset.x:0,d="offset"in b&&"y"in b.offset?b.offset.y:0,e="scale"in b&&"y"in b.scale?b.scale.y:1;a.x*="scale"in b&&"x"in b.scale?b.scale.x:1;a.y*=e;a.x+=c;a.y+=d;return a},pinhole:function(a,b){var c="offset"in b&&"y"in b.offset?b.offset.y:0,d="offset"in b&&"z"in b.offset?b.offset.z:0,e="w"in b?b.w:500,p="h"in b?b.h:500;a.x+="offset"in b&&"x"in b.offset?b.offset.x:0;a.y+=c;
|
||||||
|
a.z=a.x>0?Math.pow((a.x- -100)/100,2)+d:Math.pow((a.x- -100)/100/2,2)+d;a.time&&(a.z+=a.time/50);c=2/a.z;a.x=a.x*c*(p/2)+e/2;a.y=a.y*c*(p/2)+p/2;return a}},e={x:a.x,y:a.y,z:a.z,time:a.time,significance:a.significance,angle:a.angle,speed:a.speed};return"mode"in b&&b.mode in c?c[b.mode](e,b):c.pinhole(e,b)},strokesAtTime:function(a,b){for(var c=[[]],e=[0,0],f=a[e[0]][e[1]];f.time<b;){c[c.length-1].push(f);e[1]++;if(a[e[0]].length==e[1]){if(a.length==e[0]+1)break;e[0]++;e[1]=0;c.push([])}f=a[e[0]][e[1]]}return c},
|
||||||
|
renderScene:function(d,b){for(var c=b.width,e=b.height,f=d.objects.length-1;f>=0;f--){var g={x:d.objects[f].position.x-d.camera.position.x,y:d.objects[f].position.y-d.camera.position.y,z:d.objects[f].position.z-d.camera.position.z};colorBase=d.objects[f].color;var h={offset:g,w:b.width,h:b.height,mode:"pinhole"};if(f<d.objects.length-1&&!(d.objects[f].reference in d.timers)){h={x:d.objects[f+1].position.x-d.camera.position.x,y:d.objects[f+1].position.y-d.camera.position.y,z:d.objects[f+1].position.z-
|
||||||
|
d.camera.position.z};var j={x:d.objects[f].position.x-d.camera.position.x,y:d.objects[f].position.y-d.camera.position.y,z:d.objects[f].position.z-d.camera.position.z},k=d.objects[f+1].leftmostStrokeStart(),p=d.objects[f].rightmostStrokeEnd();Mark.connectionBrush(d.canvasContext,k,p,h,j,c,e)}h={offset:g,w:b.width,h:b.height,mode:"pinhole"};if(d.objects[f].reference in d.timers){if((g=a.renderer.strokesAtTime(d.objects[f].strokes,((new Date).getTime()-d.timers[d.objects[f].reference].start)*d.timers[d.objects[f].reference].speed))&&
|
||||||
|
g.length>0&&g[0].length>0)d.objects[f].renderedBounds=Mark.thickMarkBrush(d.canvasContext,g,h,colorBase,b.width,b.height)}else d.objects[f].renderedBounds=Mark.thickMarkBrush(d.canvasContext,d.objects[f].strokes,h,colorBase,b.width,b.height)}},renderMark:function(d,b,c){var e={offset:c.offset,scale:c.scale,mode:"flatScale"};if("timer"in c&&c.timer){var f=a.renderer.strokesAtTime(b.strokes,((new Date).getTime()-c.timer.start)*c.timer.speed);if(f&&f.length>0&&f[0].length>0)b.renderedBounds=Mark.thickMarkBrush(d,
|
||||||
|
f,e,c.color)}else b.renderedBounds=Mark.thickMarkBrush(d,b.strokes,e,c.color)}};return a}(Mark||{});Mark=function(a){a.camera=function(){this.position=new a.vector(0,0,-1E3);this.targetPosition=new a.vector(0,0,0);this.tweenTo=function(){}};return a}(Mark||{});Mark=function(a){a.vector=function(a,b,c){this.x=a||0;this.y=b||0;this.z=c||0};return a}(Mark||{});
|
||||||
|
var TWEEN=TWEEN||function(){var a,d,b,c=[];this.add=function(a){c.push(a)};this.remove=function(b){a=c.indexOf(b);a!==-1&&c.splice(a,1)};this.update=function(){a=0;d=c.length;for(b=(new Date).getTime();a<d;)c[a].update(b)?a++:(c.splice(a,1),d--)};return this}();
|
||||||
|
TWEEN.Tween=function(a){var d={},b={},c={},e=1E3,f=0,g=null,h=TWEEN.Easing.Linear.EaseNone,j=null,k=null,p=null;this.to=function(b,d){d!==null&&(e=d);for(var f in b)a[f]!==null&&(c[f]=b[f]);return this};this.start=function(){TWEEN.add(this);g=(new Date).getTime()+f;for(var e in c)a[e]!==null&&(d[e]=a[e],b[e]=c[e]-a[e]);return this};this.stop=function(){TWEEN.remove(this);return this};this.delay=function(a){f=a;return this};this.easing=function(a){h=a;return this};this.chain=function(a){j=a};this.onUpdate=
|
||||||
|
function(a){k=a;return this};this.onComplete=function(a){p=a;return this};this.update=function(c){var f,r;if(c<g)return!0;c=(c-g)/e;c=c>1?1:c;r=h(c);for(f in b)a[f]=d[f]+b[f]*r;k!==null&&k.call(a,r);if(c==1)return p!==null&&p.call(a),j!==null&&j.start(),!1;return!0}};TWEEN.Easing={Linear:{},Quadratic:{},Cubic:{},Quartic:{},Quintic:{},Sinusoidal:{},Exponential:{},Circular:{},Elastic:{},Back:{},Bounce:{}};TWEEN.Easing.Linear.EaseNone=function(a){return a};
|
||||||
|
TWEEN.Easing.Quadratic.EaseIn=function(a){return a*a};TWEEN.Easing.Quadratic.EaseOut=function(a){return-a*(a-2)};TWEEN.Easing.Quadratic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a;return-0.5*(--a*(a-2)-1)};TWEEN.Easing.Cubic.EaseIn=function(a){return a*a*a};TWEEN.Easing.Cubic.EaseOut=function(a){return--a*a*a+1};TWEEN.Easing.Cubic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a;return 0.5*((a-=2)*a*a+2)};TWEEN.Easing.Quartic.EaseIn=function(a){return a*a*a*a};
|
||||||
|
TWEEN.Easing.Quartic.EaseOut=function(a){return-(--a*a*a*a-1)};TWEEN.Easing.Quartic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a;return-0.5*((a-=2)*a*a*a-2)};TWEEN.Easing.Quintic.EaseIn=function(a){return a*a*a*a*a};TWEEN.Easing.Quintic.EaseOut=function(a){return(a-=1)*a*a*a*a+1};TWEEN.Easing.Quintic.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*a*a*a;return 0.5*((a-=2)*a*a*a*a+2)};TWEEN.Easing.Sinusoidal.EaseIn=function(a){return-Math.cos(a*Math.PI/2)+1};
|
||||||
|
TWEEN.Easing.Sinusoidal.EaseOut=function(a){return Math.sin(a*Math.PI/2)};TWEEN.Easing.Sinusoidal.EaseInOut=function(a){return-0.5*(Math.cos(Math.PI*a)-1)};TWEEN.Easing.Exponential.EaseIn=function(a){return a==0?0:Math.pow(2,10*(a-1))};TWEEN.Easing.Exponential.EaseOut=function(a){return a==1?1:-Math.pow(2,-10*a)+1};TWEEN.Easing.Exponential.EaseInOut=function(a){if(a==0)return 0;if(a==1)return 1;if((a*=2)<1)return 0.5*Math.pow(2,10*(a-1));return 0.5*(-Math.pow(2,-10*(a-1))+2)};
|
||||||
|
TWEEN.Easing.Circular.EaseIn=function(a){return-(Math.sqrt(1-a*a)-1)};TWEEN.Easing.Circular.EaseOut=function(a){return Math.sqrt(1- --a*a)};TWEEN.Easing.Circular.EaseInOut=function(a){if((a/=0.5)<1)return-0.5*(Math.sqrt(1-a*a)-1);return 0.5*(Math.sqrt(1-(a-=2)*a)+1)};TWEEN.Easing.Elastic.EaseIn=function(a){var d,b=0.1,c=0.4;if(a==0)return 0;if(a==1)return 1;c||(c=0.3);!b||b<1?(b=1,d=c/4):d=c/(2*Math.PI)*Math.asin(1/b);return-(b*Math.pow(2,10*(a-=1))*Math.sin((a-d)*2*Math.PI/c))};
|
||||||
|
TWEEN.Easing.Elastic.EaseOut=function(a){var d,b=0.1,c=0.4;if(a==0)return 0;if(a==1)return 1;c||(c=0.3);!b||b<1?(b=1,d=c/4):d=c/(2*Math.PI)*Math.asin(1/b);return b*Math.pow(2,-10*a)*Math.sin((a-d)*2*Math.PI/c)+1};
|
||||||
|
TWEEN.Easing.Elastic.EaseInOut=function(a){var d,b=0.1,c=0.4;if(a==0)return 0;if(a==1)return 1;c||(c=0.3);!b||b<1?(b=1,d=c/4):d=c/(2*Math.PI)*Math.asin(1/b);if((a*=2)<1)return-0.5*b*Math.pow(2,10*(a-=1))*Math.sin((a-d)*2*Math.PI/c);return b*Math.pow(2,-10*(a-=1))*Math.sin((a-d)*2*Math.PI/c)*0.5+1};TWEEN.Easing.Back.EaseIn=function(a){return a*a*(2.70158*a-1.70158)};TWEEN.Easing.Back.EaseOut=function(a){return(a-=1)*a*(2.70158*a+1.70158)+1};
|
||||||
|
TWEEN.Easing.Back.EaseInOut=function(a){if((a*=2)<1)return 0.5*a*a*(3.5949095*a-2.5949095);return 0.5*((a-=2)*a*(3.5949095*a+2.5949095)+2)};TWEEN.Easing.Bounce.EaseIn=function(a){return 1-TWEEN.Easing.Bounce.EaseOut(1-a)};TWEEN.Easing.Bounce.EaseOut=function(a){return(a/=1)<1/2.75?7.5625*a*a:a<2/2.75?7.5625*(a-=1.5/2.75)*a+0.75:a<2.5/2.75?7.5625*(a-=2.25/2.75)*a+0.9375:7.5625*(a-=2.625/2.75)*a+0.984375};
|
||||||
|
TWEEN.Easing.Bounce.EaseInOut=function(a){if(a<0.5)return TWEEN.Easing.Bounce.EaseIn(a*2)*0.5;return TWEEN.Easing.Bounce.EaseOut(a*2-1)*0.5+0.5};
|
||||||
|
(function(a,d){var b,c=/:([\w\d]+)/g,e=/\?([^#]*)$/,f=function(a){return Array.prototype.slice.call(a)},g=function(a){return Object.prototype.toString.call(a)==="[object Function]"},h=function(a){return Object.prototype.toString.call(a)==="[object Array]"},j=function(a){return decodeURIComponent(a.replace(/\+/g," "))},k=encodeURIComponent,p=function(a){return String(a).replace(/&(?!\w+;)/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},q=function(a){return function(b,c){return this.route.apply(this,
|
||||||
|
[a,b,c])}},o={},r=[];b=function(){var c=f(arguments),d,e;b.apps=b.apps||{};if(c.length===0||c[0]&&g(c[0]))return b.apply(b,["body"].concat(c));else if(typeof(e=c.shift())=="string")return d=b.apps[e]||new b.Application,d.element_selector=e,c.length>0&&a.each(c,function(a,b){d.use(b)}),d.element_selector!=e&&delete b.apps[e],b.apps[d.element_selector]=d};b.VERSION="0.6.3";b.addLogger=function(a){r.push(a)};b.log=function(){var c=f(arguments);c.unshift("["+Date()+"]");a.each(r,function(a,d){d.apply(b,
|
||||||
|
c)})};typeof d.console!="undefined"?g(d.console.log.apply)?b.addLogger(function(){d.console.log.apply(d.console,arguments)}):b.addLogger(function(){d.console.log(arguments)}):typeof console!="undefined"&&b.addLogger(function(){console.log.apply(console,arguments)});a.extend(b,{makeArray:f,isFunction:g,isArray:h});b.Object=function(b){return a.extend(this,b||{})};a.extend(b.Object.prototype,{escapeHTML:p,h:p,toHash:function(){var b={};a.each(this,function(a,c){g(c)||(b[a]=c)});return b},toHTML:function(){var b=
|
||||||
|
"";a.each(this,function(a,c){g(c)||(b+="<strong>"+a+"</strong> "+c+"<br />")});return b},keys:function(a){var b=[],c;for(c in this)(!g(this[c])||!a)&&b.push(c);return b},has:function(b){return this[b]&&a.trim(this[b].toString())!=""},join:function(){var a=f(arguments),b=a.shift();return a.join(b)},log:function(){b.log.apply(b,arguments)},toString:function(b){var c=[];a.each(this,function(a,d){(!g(d)||b)&&c.push('"'+a+'": '+d.toString())});return"Sammy.Object: {"+c.join(",")+"}"}});b.HashLocationProxy=
|
||||||
|
function(a,b){this.app=a;this.is_native=!1;this._startPolling(b)};b.HashLocationProxy.prototype={bind:function(){var c=this,e=this.app;a(d).bind("hashchange."+this.app.eventNamespace(),function(a,f){if(c.is_native===!1&&!f)b.log("native hash change exists, using"),c.is_native=!0,d.clearInterval(b.HashLocationProxy._interval);e.trigger("location-changed")});if(!b.HashLocationProxy._bindings)b.HashLocationProxy._bindings=0;b.HashLocationProxy._bindings++},unbind:function(){a(d).unbind("hashchange."+
|
||||||
|
this.app.eventNamespace());b.HashLocationProxy._bindings--;b.HashLocationProxy._bindings<=0&&d.clearInterval(b.HashLocationProxy._interval)},getLocation:function(){var a=d.location.toString().match(/^[^#]*(#.+)$/);return a?a[1]:""},setLocation:function(a){return d.location=a},_startPolling:function(c){var e=this;if(!b.HashLocationProxy._interval){c||(c=10);var f=function(){var c=e.getLocation();(!b.HashLocationProxy._last_location||c!=b.HashLocationProxy._last_location)&&d.setTimeout(function(){a(d).trigger("hashchange",
|
||||||
|
[!0])},13);b.HashLocationProxy._last_location=c};f();b.HashLocationProxy._interval=d.setInterval(f,c)}}};b.Application=function(a){var c=this;this.routes={};this.listeners=new b.Object({});this.arounds=[];this.befores=[];this.namespace=(new Date).getTime()+"-"+parseInt(Math.random()*1E3,10);this.context_prototype=function(){b.EventContext.apply(this,arguments)};this.context_prototype.prototype=new b.EventContext;g(a)&&a.apply(this,[this]);this._location_proxy||this.setLocationProxy(new b.HashLocationProxy(this,
|
||||||
|
this.run_interval_every));this.debug&&this.bindToAllEvents(function(a,b){c.log(c.toString(),a.cleaned_type,b||{})})};b.Application.prototype=a.extend({},b.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error","check-form-submission","redirect","location-changed"],_last_route:null,_location_proxy:null,_running:!1,element_selector:"body",debug:!1,raise_errors:!1,run_interval_every:50,
|
||||||
|
template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(b){return b?a(this.element_selector).find(b):a(this.element_selector)},use:function(){var a=f(arguments),c=a.shift(),d=c||"";try{a.unshift(this),typeof c=="string"&&(d="Sammy."+c,c=b[c]),c.apply(this,a)}catch(e){typeof c==="undefined"?this.error("Plugin Error: called use() but plugin ("+d.toString()+") is not defined",e):g(c)?this.error("Plugin Error",e):this.error("Plugin Error: called use() but '"+
|
||||||
|
d.toString()+"' is not a function",e)}return this},setLocationProxy:function(a){var b=this._location_proxy;this._location_proxy=a;this.isRunning()&&(b&&b.unbind(),this._location_proxy.bind())},route:function(b,d,e){var f=this,h=[],j,k;!e&&g(d)&&(e=d=b,b="any");b=b.toLowerCase();if(d.constructor==String){for(c.lastIndex=0;(k=c.exec(d))!==null;)h.push(k[1]);d=RegExp("^"+d.replace(c,"([^/]+)")+"$")}typeof e=="string"&&(e=f[e]);j=function(a){var b={verb:a,path:d,callback:e,param_names:h};f.routes[a]=
|
||||||
|
f.routes[a]||[];f.routes[a].push(b)};b==="any"?a.each(this.ROUTE_VERBS,function(a,b){j(b)}):j(b);return this},get:q("get"),post:q("post"),put:q("put"),del:q("delete"),any:q("any"),mapRoutes:function(b){var c=this;a.each(b,function(a,b){c.route.apply(c,b)});return this},eventNamespace:function(){return["sammy-app",this.namespace].join("-")},bind:function(a,b,c){var d=this;typeof c=="undefined"&&(c=b);b=function(a,b){var e;b&&b.context?(e=b.context,delete b.context):e=new d.context_prototype(d,"bind",
|
||||||
|
a.type,b,a.target);a.cleaned_type=a.type.replace(d.eventNamespace(),"");c.apply(e,[a,b])};this.listeners[a]||(this.listeners[a]=[]);this.listeners[a].push(b);this.isRunning()&&this._listen(a,b);return this},trigger:function(a,b){this.$element().trigger([a,this.eventNamespace()].join("."),[b]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(a,b){g(a)&&(b=a,a={});this.befores.push([a,b]);return this},after:function(a){return this.bind("event-context-after",
|
||||||
|
a)},around:function(a){this.arounds.push(a);return this},isRunning:function(){return this._running},helpers:function(b){a.extend(this.context_prototype.prototype,b);return this},helper:function(a,b){this.context_prototype.prototype[a]=b;return this},run:function(b){if(this.isRunning())return!1;var c=this;a.each(this.listeners.toHash(),function(b,d){a.each(d,function(a,d){c._listen(b,d)})});this.trigger("run",{start_url:b});this._running=!0;this.last_location=null;this.getLocation()==""&&typeof b!=
|
||||||
|
"undefined"&&this.setLocation(b);this._checkLocation();this._location_proxy.bind();this.bind("location-changed",function(){c._checkLocation()});this.bind("submit",function(b){return c._checkFormSubmission(a(b.target).closest("form"))===!1?b.preventDefault():!1});a(d).bind("beforeunload",function(){c.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning())return!1;var b=this;this.trigger("unload");this._location_proxy.unbind();this.$element().unbind("submit").removeClass(b.eventNamespace());
|
||||||
|
a.each(this.listeners.toHash(),function(c,d){a.each(d,function(a,d){b._unlisten(c,d)})});this._running=!1;return this},bindToAllEvents:function(b){var c=this;a.each(this.APP_EVENTS,function(a,d){c.bind(d,b)});a.each(this.listeners.keys(!0),function(a,d){c.APP_EVENTS.indexOf(d)==-1&&c.bind(d,b)});return this},routablePath:function(a){return a.replace(e,"")},lookupRoute:function(b,c){var d=this,e=!1;this.trigger("lookup-route",{verb:b,path:c});typeof this.routes[b]!="undefined"&&a.each(this.routes[b],
|
||||||
|
function(a,b){if(d.routablePath(c).match(b.path))return e=b,!1});return e},runRoute:function(b,c,d,e){var f=this,g=this.lookupRoute(b,c),h,k,o,p,q,r,t;this.log("runRoute",[b,c].join(" "));this.trigger("run-route",{verb:b,path:c,params:d});typeof d=="undefined"&&(d={});a.extend(d,this._parseQueryString(c));if(g){this.trigger("route-found",{route:g});if((r=g.path.exec(this.routablePath(c)))!==null)r.shift(),a.each(r,function(a,b){if(g.param_names[a])d[g.param_names[a]]=j(b);else{if(!d.splat)d.splat=
|
||||||
|
[];d.splat.push(j(b))}});h=new this.context_prototype(this,b,c,d,e);e=this.arounds.slice(0);o=this.befores.slice(0);q=[h].concat(d.splat);k=function(){for(var a;o.length>0;)if(p=o.shift(),f.contextMatchesOptions(h,p[0])&&(a=p[1].apply(h,[h]),a===!1))return!1;f.last_route=g;h.trigger("event-context-before",{context:h});a=g.callback.apply(h,q);h.trigger("event-context-after",{context:h});return a};a.each(e.reverse(),function(a,b){var c=k;k=function(){return b.apply(h,[c])}});try{t=k()}catch(u){this.error(["500 Error",
|
||||||
|
b,c].join(" "),u)}return t}else return this.notFound(b,c)},contextMatchesOptions:function(a,b,c){if(typeof b==="undefined"||b=={})return!0;typeof c==="undefined"&&(c=!0);if(typeof b==="string"||g(b.test))b={path:b};if(b.only)return this.contextMatchesOptions(a,b.only,!0);else if(b.except)return this.contextMatchesOptions(a,b.except,!1);var d=!0,e=!0;b.path&&(d=g(b.path.test)?b.path.test(a.path):b.path.toString()===a.path);b.verb&&(e=b.verb===a.verb);return c?e&&d:!(e&&d)},getLocation:function(){return this._location_proxy.getLocation()},
|
||||||
|
setLocation:function(a){return this._location_proxy.setLocation(a)},swap:function(a){return this.$element().html(a)},templateCache:function(a,b){return typeof b!="undefined"?o[a]=b:o[a]},clearTemplateCache:function(){return o={}},notFound:function(a,b){var c=this.error(["404 Not Found",a,b].join(" "));return a==="get"?c:!0},error:function(a,b){b||(b=Error());b.message=[a,b.message].join(" ");this.trigger("error",{message:b.message,error:b});if(this.raise_errors)throw b;else this.log(b.message,b)},
|
||||||
|
_checkLocation:function(){var a,b;a=this.getLocation();if(!this.last_location||this.last_location[0]!="get"||this.last_location[1]!=a)this.last_location=["get",a],b=this.runRoute("get",a);return b},_getFormVerb:function(b){b=a(b);var c,d;d=b.find('input[name="_method"]');d.length>0&&(c=d.val());c||(c=b[0].getAttribute("method"));if(!c||c=="")c="get";return a.trim(c.toString().toLowerCase())},_checkFormSubmission:function(b){var c,d,e;this.trigger("check-form-submission",{form:b});c=a(b);d=c.attr("action");
|
||||||
|
e=this._getFormVerb(c);this.log("_checkFormSubmission",c,d,e);e==="get"?(this.setLocation(d+"?"+this._serializeFormParams(c)),b=!1):(c=a.extend({},this._parseFormParams(c)),b=this.runRoute(e,d,c,b.get(0)));return typeof b=="undefined"?!1:b},_serializeFormParams:function(a){var b="";a=a.serializeArray();var c;if(a.length>0){b=this._encodeFormPair(a[0].name,a[0].value);for(c=1;c<a.length;c++)b=b+"&"+this._encodeFormPair(a[c].name,a[c].value)}return b},_encodeFormPair:function(a,b){return k(a)+"="+k(b)},
|
||||||
|
_parseFormParams:function(a){var b={};a=a.serializeArray();var c;for(c=0;c<a.length;c++)b=this._parseParamPair(b,a[c].name,a[c].value);return b},_parseQueryString:function(a){var b={},c,d;if(a=a.match(e)){a=a[1].split("&");for(d=0;d<a.length;d++)c=a[d].split("="),b=this._parseParamPair(b,j(c[0]),j(c[1]))}return b},_parseParamPair:function(a,b,c){a[b]?h(a[b])?a[b].push(c):a[b]=[a[b],c]:a[b]=c;return a},_listen:function(a,b){return this.$element().bind([a,this.eventNamespace()].join("."),b)},_unlisten:function(a,
|
||||||
|
b){return this.$element().unbind([a,this.eventNamespace()].join("."),b)}});b.RenderContext=function(a){this.event_context=a;this.callbacks=[];this.content=this.previous_content=null;this.waiting=this.next_engine=!1};b.RenderContext.prototype=a.extend({},b.Object.prototype,{then:function(a){if(!g(a))if(typeof a==="string"&&a in this.event_context){var b=this.event_context[a];a=function(a){return b.apply(this.event_context,[a])}}else return this;var c=this;this.waiting?this.callbacks.push(a):(this.wait(),
|
||||||
|
d.setTimeout(function(){var b=a.apply(c,[c.content,c.previous_content]);b!==!1&&c.next(b)},13));return this},wait:function(){this.waiting=!0},next:function(a){this.waiting=!1;if(typeof a!=="undefined")this.previous_content=this.content,this.content=a;this.callbacks.length>0&&this.then(this.callbacks.shift())},load:function(b,c,d){var e=this;return this.then(function(){var f,h,j;g(c)?(d=c,c={}):c=a.extend({},c);d&&this.then(d);if(typeof b==="string"){f=(j=b.match(/\.json$/)||c.json)&&c.cache===!0||
|
||||||
|
c.cache!==!1;e.next_engine=e.event_context.engineFor(b);delete c.cache;delete c.json;if(c.engine)e.next_engine=c.engine,delete c.engine;if(f&&(h=this.event_context.app.templateCache(b)))return h;this.wait();a.ajax(a.extend({url:b,data:{},dataType:j?"json":null,type:"get",success:function(a){f&&e.event_context.app.templateCache(b,a);e.next(a)}},c));return!1}else{if(b.nodeType)return b.innerHTML;if(b.selector)return e.next_engine=b.attr("data-engine"),c.clone===!1?b.remove()[0].innerHTML.toString():
|
||||||
|
b[0].innerHTML.toString()}})},render:function(a,b,c){if(g(a)&&!b)return this.then(a);else{if(!b&&this.content)b=this.content;return this.load(a).interpolate(b,a).then(c)}},partial:function(a,b){return this.render(a,b).swap()},send:function(){var a=this,b=f(arguments),c=b.shift();h(b[0])&&(b=b[0]);return this.then(function(){b.push(function(b){a.next(b)});a.wait();c.apply(c,b);return!1})},collect:function(b,c,d){var e=this,f=function(){if(g(b))c=b,b=this.content;var d=[],f=!1;a.each(b,function(a,b){var g=
|
||||||
|
c.apply(e,[a,b]);g.jquery&&g.length==1&&(g=g[0],f=!0);d.push(g);return g});return f?d:d.join("")};return d?f():this.then(f)},renderEach:function(b,c,d,e){h(c)&&(e=d,d=c,c=null);return this.load(b).then(function(f){var g=this;d||(d=h(this.previous_content)?this.previous_content:[]);if(e)a.each(d,function(a,d){var h={},j=this.next_engine||b;c?h[c]=d:h=d;e(d,g.event_context.interpolate(f,h,j))});else return this.collect(d,function(a,d){var e={},g=this.next_engine||b;c?e[c]=d:e=d;return this.event_context.interpolate(f,
|
||||||
|
e,g)},!0)})},interpolate:function(a,b,c){var d=this;return this.then(function(e,f){!a&&f&&(a=f);if(this.next_engine)b=this.next_engine,this.next_engine=!1;var g=d.event_context.interpolate(e,a,b);return c?f+g:g})},swap:function(){return this.then(function(a){this.event_context.swap(a)}).trigger("changed",{})},appendTo:function(b){return this.then(function(c){a(b).append(c)}).trigger("changed",{})},prependTo:function(b){return this.then(function(c){a(b).prepend(c)}).trigger("changed",{})},replace:function(b){return this.then(function(c){a(b).html(c)}).trigger("changed",
|
||||||
|
{})},trigger:function(a,b){return this.then(function(c){typeof b=="undefined"&&(b={content:c});this.event_context.trigger(a,b)})}});b.EventContext=function(a,c,d,e,f){this.app=a;this.verb=c;this.path=d;this.params=new b.Object(e);this.target=f};b.EventContext.prototype=a.extend({},b.Object.prototype,{$element:function(){return this.app.$element(f(arguments).shift())},engineFor:function(a){var b;if(g(a))return a;a=(a||this.app.template_engine).toString();if(b=a.match(/\.([^\.]+)$/))a=b[1];if(a&&g(this[a]))return this[a];
|
||||||
|
if(this.app.template_engine)return this.engineFor(this.app.template_engine);return function(a){return a}},interpolate:function(a,b,c){return this.engineFor(c).apply(this,[a,b])},render:function(a,c,d){return(new b.RenderContext(this)).render(a,c,d)},renderEach:function(a,c,d,e){return(new b.RenderContext(this)).renderEach(a,c,d,e)},load:function(a,c,d){return(new b.RenderContext(this)).load(a,c,d)},partial:function(a,c){return(new b.RenderContext(this)).partial(a,c)},send:function(){var a=new b.RenderContext(this);
|
||||||
|
return a.send.apply(a,arguments)},redirect:function(){var a;a=f(arguments);var b=this.app.getLocation();a.length>1?(a.unshift("/"),a=this.join.apply(this,a)):a=a[0];this.trigger("redirect",{to:a});this.app.last_location=[this.verb,this.path];this.app.setLocation(a);b==a&&this.app.trigger("location-changed")},trigger:function(a,b){typeof b=="undefined"&&(b={});if(!b.context)b.context=this;return this.app.trigger(a,b)},eventNamespace:function(){return this.app.eventNamespace()},swap:function(a){return this.app.swap(a)},
|
||||||
|
notFound:function(){return this.app.notFound(this.verb,this.path)},json:function(b){return a.parseJSON(b)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});a.sammy=d.Sammy=b})(jQuery,window);Sammy.HashPushProxy=function(a,d){this.app=a;this.supportsHistory=!(!window.history||!history.pushState);if(!this.supportsHistory)this._startPolling(d),this.is_native=!1};
|
||||||
|
Sammy.HashPushProxy.prototype={bind:function(){var a=this,d=this.app;if(this.app.supportsHistory)$(window).bind("popstate",function(){a.app.trigger("location-changed")}),$("a").live("click",function(b){location.hostname==this.hostname&&(b.preventDefault(),a.historyAPISupported?a.setLocation($(this).attr("href")):a.setLocation("#"+$(this).attr("href")),a.app.trigger("location-changed"))});else{$(window).bind("hashchange."+this.app.eventNamespace(),function(b,c){if(a.is_native===!1&&!c)Sammy.log("native hash change exists, using"),
|
||||||
|
a.is_native=!0,window.clearInterval(Sammy.HashLocationProxy._interval);d.trigger("location-changed")});if(!Sammy.HashLocationProxy._bindings)Sammy.HashLocationProxy._bindings=0;Sammy.HashLocationProxy._bindings++}},unbind:function(){this.app.supportsHistory?($("a").unbind("click"),$(window).unbind("popstate")):($(window).unbind("hashchange."+this.app.eventNamespace()),Sammy.HashLocationProxy._bindings--,Sammy.HashLocationProxy._bindings<=0&&window.clearInterval(Sammy.HashLocationProxy._interval))},
|
||||||
|
getLocation:function(){if(this.app.supportsHistory)return window.location.pathname;else{var a=window.location.toString().match(/^[^#]*(#.+)$/);return a?a[1]:""}},setLocation:function(a){if(this.app.supportsHistory)history.pushState({path:this.path},"",a);else return window.location=a},_startPolling:function(a){var d=this;if(!Sammy.HashLocationProxy._interval){a||(a=10);var b=function(){var a=d.getLocation();(!Sammy.HashLocationProxy._last_location||a!=Sammy.HashLocationProxy._last_location)&&window.setTimeout(function(){$(window).trigger("hashchange",
|
||||||
|
[!0])},13);Sammy.HashLocationProxy._last_location=a};b();Sammy.HashLocationProxy._interval=window.setInterval(b,a)}}};
|
||||||
|
(function(a){var d={};Sammy=Sammy||{};Sammy.Template=function(b,c){c||(c="template");b.helper(c,function(b,c,g,h){typeof g=="undefined"&&(g=b);typeof h=="undefined"&&typeof g=="object"&&(h=g,g=b);a:{c=a.extend({},this,c);if(d[g])b=d[g];else{if(typeof b=="undefined"){b=!1;break a}h=h&&h.escape_html===!1?'",$1,"':'",h($1),"';b=d[g]=new Function("obj",'var ___$$$___=[],print=function(){___$$$___.push.apply(___$$$___,arguments);};with(obj){___$$$___.push("'+String(b).replace(/[\r\t\n]/g," ").replace(/\"/g,
|
||||||
|
'\\"').split("<%").join("\t").replace(/((^|%>)[^\t]*)/g,"$1\r").replace(/\t=(.*?)%>/g,h).replace(/\t!(.*?)%>/g,'",$1,"').split("\t").join('");').split("%>").join('___$$$___.push("').split("\r").join("")+"\");}return ___$$$___.join('');")}b=typeof c!="undefined"?b(c):b}return b})}})(jQuery);
|
|
@ -0,0 +1,52 @@
|
||||||
|
CanvasRenderingContext2D.prototype.dashedLineTo = function( fromX, fromY, toX, toY, pattern ) {
|
||||||
|
// Our growth rate for our line can be one of the following:
|
||||||
|
// (+,+), (+,-), (-,+), (-,-)
|
||||||
|
// Because of this, our algorithm needs to understand if the x-coord and
|
||||||
|
// y-coord should be getting smaller or larger and properly cap the values
|
||||||
|
// based on (x,y).
|
||||||
|
var lt = function ( a, b ) { return a <= b; };
|
||||||
|
var gt = function ( a, b ) { return a >= b; };
|
||||||
|
var capmin = function ( a, b ) { return Math.min( a, b ); };
|
||||||
|
var capmax = function ( a, b ) { return Math.max( a, b ); };
|
||||||
|
|
||||||
|
// if ( typeof(pattern) != "Array" ) pattern = [pattern];
|
||||||
|
var checkX = { thereYet: gt, cap: capmin };
|
||||||
|
var checkY = { thereYet: gt, cap: capmin };
|
||||||
|
|
||||||
|
if ( fromY - toY > 0 ) {
|
||||||
|
checkY.thereYet = lt;
|
||||||
|
checkY.cap = capmax;
|
||||||
|
}
|
||||||
|
if ( fromX - toX > 0 ) {
|
||||||
|
checkX.thereYet = lt;
|
||||||
|
checkX.cap = capmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.moveTo( fromX, fromY );
|
||||||
|
var offsetX = fromX;
|
||||||
|
var offsetY = fromY;
|
||||||
|
var idx = 0, dash = true;
|
||||||
|
while ( !( checkX.thereYet( offsetX, toX ) && checkY.thereYet( offsetY, toY ) ) ) {
|
||||||
|
var ang = Math.atan2( toY - fromY, toX - fromX );
|
||||||
|
var len = pattern[idx];
|
||||||
|
|
||||||
|
offsetX = checkX.cap( toX, offsetX + (Math.cos( ang ) * len ) );
|
||||||
|
offsetY = checkY.cap( toY, offsetY + (Math.sin( ang ) * len ) );
|
||||||
|
|
||||||
|
if ( dash ) this.lineTo( offsetX, offsetY );
|
||||||
|
else this.moveTo( offsetX, offsetY );
|
||||||
|
|
||||||
|
idx = ( idx + 1 ) % pattern.length;
|
||||||
|
dash = !dash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
CanvasRenderingContext2D.prototype.dottedArc = function( x, y, radius, startAngle, endAngle, anticlockwise ) {
|
||||||
|
var g = Math.PI / radius / 2, sa = startAngle, ea = startAngle + g;
|
||||||
|
while( ea < endAngle ) {
|
||||||
|
this.beginPath();
|
||||||
|
this.arc( x, y, radius, sa, ea, anticlockwise );
|
||||||
|
this.stroke();
|
||||||
|
sa = ea + g;
|
||||||
|
ea = sa + g;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* jQuery touch and gesture detection.
|
||||||
|
*
|
||||||
|
* identifies support for touch and gestures.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
*
|
||||||
|
* if ($fn.browserTouchSupport.touches) {
|
||||||
|
* // Touch specific interactions
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* Support:
|
||||||
|
* bool $.fn.browserTouchSupport.touches // all touches supported
|
||||||
|
* bool $.fn.browserTouchSupport.gestures // all gestures supported
|
||||||
|
* bool $.fn.browserTouchSupport.touchstart
|
||||||
|
* bool $.fn.browserTouchSupport.touchmove
|
||||||
|
* bool $.fn.browserTouchSupport.touchend
|
||||||
|
* bool $.fn.browserTouchSupport.gesturestart
|
||||||
|
* bool $.fn.browserTouchSupport.gesturechange
|
||||||
|
* bool $.fn.browserTouchSupport.gestureend
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Jeffrey Sambells <jeff@tropicalpixels.com>
|
||||||
|
* @license The MIT License
|
||||||
|
*
|
||||||
|
* Copyright (c) 2010 Jeffrey Sambells / TropicalPixels
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
var support = {};
|
||||||
|
|
||||||
|
var events = [
|
||||||
|
'touchstart',
|
||||||
|
'touchmove',
|
||||||
|
'touchend',
|
||||||
|
'gesturestart',
|
||||||
|
'gesturechange',
|
||||||
|
'gestureend'
|
||||||
|
];
|
||||||
|
|
||||||
|
var el = document.createElement('div');
|
||||||
|
|
||||||
|
for( i in events ) {
|
||||||
|
var eventName = events[i];
|
||||||
|
eventName = 'on' + eventName;
|
||||||
|
var isSupported = (eventName in el);
|
||||||
|
if (!isSupported) {
|
||||||
|
el.setAttribute(eventName, 'return;');
|
||||||
|
isSupported = typeof el[eventName] == 'function';
|
||||||
|
}
|
||||||
|
support[events[i]] = isSupported;
|
||||||
|
}
|
||||||
|
|
||||||
|
support.touches =
|
||||||
|
support.touchstart
|
||||||
|
&& support.touchend
|
||||||
|
&& support.touchmove;
|
||||||
|
|
||||||
|
support.gestures =
|
||||||
|
support.gesturestart &&
|
||||||
|
support.gesturechange &&
|
||||||
|
support.gestureend;
|
||||||
|
|
||||||
|
$.fn.browserTouchSupport = support;
|
||||||
|
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
* makes divs with an h3 and a ul collapse. Not very useful for other things.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function($) {
|
||||||
|
|
||||||
|
$.collapsibleMod = {
|
||||||
|
cfg: {
|
||||||
|
'collapsedClass': 'collapsibleMod-collapsed',
|
||||||
|
'expandedClass': 'collapsibleMod-expanded',
|
||||||
|
'$header': null,
|
||||||
|
'previewSelector': '',
|
||||||
|
'$content': null,
|
||||||
|
'collapsed': false,
|
||||||
|
'stateKey': '',
|
||||||
|
'saveState': true // when set to true, and the container ele has an id, we'll attempt to save the state between requests
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
'init': function ( container, options ) {
|
||||||
|
var $this = $( container );
|
||||||
|
var context = $.extend({}, $.collapsibleMod.cfg, options );
|
||||||
|
|
||||||
|
context.$container = $this;
|
||||||
|
context.$header = $this.find( 'h3:first' );
|
||||||
|
context.$content = $this.children().not( 'h3:first' ).not( context.previewSelector );
|
||||||
|
|
||||||
|
context.$header.bind( 'click', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
$.collapsibleMod.fn.toggle( context );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// setup state saving
|
||||||
|
if( context.saveState && context.$container.attr( 'id' ) != "" && typeof localStorage != 'undefined' ) {
|
||||||
|
context.stateKey = 'collapsibleMod-state-' + context.$container.attr( 'id' );
|
||||||
|
$.collapsibleMod.fn.restoreState( context );
|
||||||
|
} else {
|
||||||
|
context.saveState = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( context.collapsed ) {
|
||||||
|
$.collapsibleMod.fn.collapse( context );
|
||||||
|
} else {
|
||||||
|
context.$container
|
||||||
|
.addClass( context.expandedClass );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.data( 'collapsibleMod-context', context );
|
||||||
|
},
|
||||||
|
'collapse': function ( context ) {
|
||||||
|
context.$container
|
||||||
|
.addClass( context.collapsedClass )
|
||||||
|
.removeClass( context.expandedClass );
|
||||||
|
context.$content
|
||||||
|
.slideUp( 'fast' );
|
||||||
|
context.collapsed = true;
|
||||||
|
$.collapsibleMod.fn.saveState( context );
|
||||||
|
},
|
||||||
|
'expand': function ( context ) {
|
||||||
|
context.$container
|
||||||
|
.removeClass( context.collapsedClass )
|
||||||
|
.addClass( context.expandedClass );
|
||||||
|
context.$content
|
||||||
|
.slideDown( 'fast' );
|
||||||
|
context.collapsed = false;
|
||||||
|
$.collapsibleMod.fn.saveState( context );
|
||||||
|
},
|
||||||
|
'saveState': function( context ) {
|
||||||
|
if( context.saveState ) {
|
||||||
|
try {
|
||||||
|
localStorage.removeItem( context.stateKey );
|
||||||
|
localStorage.setItem( context.stateKey, context.collapsed );
|
||||||
|
} catch (e) {
|
||||||
|
if ( e == QUOTA_EXCEEDED_ERR ) { /* data wasn't successfully saved due to quota exceed */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'restoreState': function( context ) {
|
||||||
|
if ( context.saveState && localStorage.getItem( context.stateKey ) ) {
|
||||||
|
context.collapsed = ( localStorage.getItem( context.stateKey ) === 'true' ) ;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'toggle': function ( context ) {
|
||||||
|
context.collapsed ? $.collapsibleMod.fn.expand( context ) : $.collapsibleMod.fn.collapse( context );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.collapsibleMod = function ( options ) {
|
||||||
|
return $( this ).each( function () {
|
||||||
|
$.collapsibleMod.fn.init( this, options );
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,96 @@
|
||||||
|
/**
|
||||||
|
* Cookie plugin
|
||||||
|
*
|
||||||
|
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
|
||||||
|
* Dual licensed under the MIT and GPL licenses:
|
||||||
|
* http://www.opensource.org/licenses/mit-license.php
|
||||||
|
* http://www.gnu.org/licenses/gpl.html
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a cookie with the given name and value and other optional parameters.
|
||||||
|
*
|
||||||
|
* @example $.cookie('the_cookie', 'the_value');
|
||||||
|
* @desc Set the value of a cookie.
|
||||||
|
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
|
||||||
|
* @desc Create a cookie with all available options.
|
||||||
|
* @example $.cookie('the_cookie', 'the_value');
|
||||||
|
* @desc Create a session cookie.
|
||||||
|
* @example $.cookie('the_cookie', null);
|
||||||
|
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
|
||||||
|
* used when the cookie was set.
|
||||||
|
*
|
||||||
|
* @param String name The name of the cookie.
|
||||||
|
* @param String value The value of the cookie.
|
||||||
|
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
|
||||||
|
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
|
||||||
|
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
|
||||||
|
* If set to null or omitted, the cookie will be a session cookie and will not be retained
|
||||||
|
* when the the browser exits.
|
||||||
|
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
|
||||||
|
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
|
||||||
|
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
|
||||||
|
* require a secure protocol (like HTTPS).
|
||||||
|
* @type undefined
|
||||||
|
*
|
||||||
|
* @name $.cookie
|
||||||
|
* @cat Plugins/Cookie
|
||||||
|
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of a cookie with the given name.
|
||||||
|
*
|
||||||
|
* @example $.cookie('the_cookie');
|
||||||
|
* @desc Get the value of a cookie.
|
||||||
|
*
|
||||||
|
* @param String name The name of the cookie.
|
||||||
|
* @return The value of the cookie.
|
||||||
|
* @type String
|
||||||
|
*
|
||||||
|
* @name $.cookie
|
||||||
|
* @cat Plugins/Cookie
|
||||||
|
* @author Klaus Hartl/klaus.hartl@stilbuero.de
|
||||||
|
*/
|
||||||
|
jQuery.cookie = function(name, value, options) {
|
||||||
|
if (typeof value != 'undefined') { // name and value given, set cookie
|
||||||
|
options = options || {};
|
||||||
|
if (value === null) {
|
||||||
|
value = '';
|
||||||
|
options.expires = -1;
|
||||||
|
}
|
||||||
|
var expires = '';
|
||||||
|
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
|
||||||
|
var date;
|
||||||
|
if (typeof options.expires == 'number') {
|
||||||
|
date = new Date();
|
||||||
|
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
|
||||||
|
} else {
|
||||||
|
date = options.expires;
|
||||||
|
}
|
||||||
|
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
|
||||||
|
}
|
||||||
|
// CAUTION: Needed to parenthesize options.path and options.domain
|
||||||
|
// in the following expressions, otherwise they evaluate to undefined
|
||||||
|
// in the packed version for some reason...
|
||||||
|
var path = options.path ? '; path=' + (options.path) : '';
|
||||||
|
var domain = options.domain ? '; domain=' + (options.domain) : '';
|
||||||
|
var secure = options.secure ? '; secure' : '';
|
||||||
|
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
|
||||||
|
} else { // only name given, get cookie
|
||||||
|
var cookieValue = null;
|
||||||
|
if (document.cookie && document.cookie != '') {
|
||||||
|
var cookies = document.cookie.split(';');
|
||||||
|
for (var i = 0; i < cookies.length; i++) {
|
||||||
|
var cookie = jQuery.trim(cookies[i]);
|
||||||
|
// Does this cookie string begin with the name we want?
|
||||||
|
if (cookie.substring(0, name.length + 1) == (name + '=')) {
|
||||||
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cookieValue;
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,68 @@
|
||||||
|
(function( $ ) {
|
||||||
|
/**
|
||||||
|
* Function that escapes spaces in event names. This is needed because
|
||||||
|
* "_delayedBind-foo bar-1000" refers to two events
|
||||||
|
*/
|
||||||
|
function encodeEvent( event ) {
|
||||||
|
return event.replace( /-/g, '--' ).replace( / /g, '-' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$.fn.extend( {
|
||||||
|
/**
|
||||||
|
* Bind a callback to an event in a delayed fashion.
|
||||||
|
* In detail, this means that the callback will be called a certain
|
||||||
|
* time after the event fires, but the timer is reset every time
|
||||||
|
* the event fires.
|
||||||
|
* @param timeout Number of milliseconds to wait
|
||||||
|
* @param event Name of the event (string)
|
||||||
|
* @param data Data to pass to the event handler (optional)
|
||||||
|
* @param callback Function to call
|
||||||
|
*/
|
||||||
|
delayedBind: function( timeout, event, data, callback ) {
|
||||||
|
var encEvent = encodeEvent( event );
|
||||||
|
return this.each( function() {
|
||||||
|
var that = this;
|
||||||
|
// Bind the top half
|
||||||
|
// Do this only once for every (event, timeout) pair
|
||||||
|
if ( !( $(this).data( '_delayedBindBound-' + encEvent + '-' + timeout ) ) ) {
|
||||||
|
$(this).data( '_delayedBindBound-' + encEvent + '-' + timeout, true );
|
||||||
|
$(this).bind( event, function() {
|
||||||
|
var timerID = $(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout );
|
||||||
|
// Cancel the running timer
|
||||||
|
if ( typeof timerID != 'undefined' )
|
||||||
|
clearTimeout( timerID );
|
||||||
|
timerID = setTimeout( function() {
|
||||||
|
$(that).trigger( '_delayedBind-' + encEvent + '-' + timeout );
|
||||||
|
}, timeout );
|
||||||
|
$(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout, timerID );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom half
|
||||||
|
$(this).bind( '_delayedBind-' + encEvent + '-' + timeout, data, callback );
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cancel the timers for delayed events on the selected elements.
|
||||||
|
*/
|
||||||
|
delayedBindCancel: function( timeout, event ) {
|
||||||
|
var encEvent = encodeEvent( event );
|
||||||
|
return this.each( function() {
|
||||||
|
var timerID = $(this).data( '_delayedBindTimerID-' + encEvent + '-' + timeout );
|
||||||
|
if ( typeof timerID != 'undefined' )
|
||||||
|
clearTimeout( timerID );
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unbind an event bound with delayedBind()
|
||||||
|
*/
|
||||||
|
delayedBindUnbind: function( timeout, event, callback ) {
|
||||||
|
var encEvent = encodeEvent( event );
|
||||||
|
return this.each( function() {
|
||||||
|
$(this).unbind( '_delayedBind-' + encEvent + '-' + timeout, callback );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
} )( jQuery );
|
|
@ -0,0 +1,513 @@
|
||||||
|
( function( $ ) {
|
||||||
|
|
||||||
|
var markApp = $.markApp = $.markApp || {};
|
||||||
|
var modules = $.markApp.modules = $.markApp.modules || {};
|
||||||
|
|
||||||
|
modules.capture = {
|
||||||
|
defaults: {
|
||||||
|
state: 'intro', // possible values -> intro, drawing, submitting
|
||||||
|
invite_code: null,
|
||||||
|
locale: null,
|
||||||
|
contributor_type: null
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
captureLimit: 300,
|
||||||
|
layerManager: null,
|
||||||
|
capturedPoints: 0,
|
||||||
|
strokes: [],
|
||||||
|
framecount: 0,
|
||||||
|
cleanedStrokes: [],
|
||||||
|
lastX: null,
|
||||||
|
lastY: null,
|
||||||
|
captureTime: null,
|
||||||
|
rtl: null,
|
||||||
|
initialized: false,
|
||||||
|
currentStroke: null,
|
||||||
|
mark: null,
|
||||||
|
timeBetweenStrokes: 400, // the amount of time to pause between strokes
|
||||||
|
events: [] // unexecuted events we bind to times to
|
||||||
|
},
|
||||||
|
// Event handlers
|
||||||
|
evt: {
|
||||||
|
resize: function ( context, e ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
lC.layerManager.resizeAll( context.width, context.height );
|
||||||
|
// redraw all marks
|
||||||
|
if( lC.mark && lC.mark.strokes.length > 0 ) {
|
||||||
|
for( var i = 0; i < lC.mark.strokes.length; i++ ) {
|
||||||
|
modules.capture.fn.drawStroke( context, lC.mark.strokes[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mousemove: function( context, e ) {
|
||||||
|
if ( context.mouseDown && context.modules.capture.state == "drawing" )
|
||||||
|
modules.capture.fn.capturePoint( context );
|
||||||
|
},
|
||||||
|
mousedown: function( context, e ) {
|
||||||
|
switch ( context.modules.capture.state ) {
|
||||||
|
case "drawing":
|
||||||
|
// close the country select if it's open
|
||||||
|
if( $( '#location-dialog' ).is( ':visible' ) ) {
|
||||||
|
$( '#location-dialog' )
|
||||||
|
.fadeOut( 'fast' );
|
||||||
|
}
|
||||||
|
// start a new mark if we need to
|
||||||
|
if( !context.modules.capture.mark ) modules.capture.fn.startMark( context );
|
||||||
|
// start a new stroke unless we already have a stroke open for some reason
|
||||||
|
if( !context.modules.capture.currentStroke ) modules.capture.fn.startStroke( context );
|
||||||
|
break;
|
||||||
|
case "intro":
|
||||||
|
// start a new mark if we need to
|
||||||
|
if( !context.modules.capture.mark ) modules.capture.fn.startMark( context );
|
||||||
|
// start a new stroke unless we already have a stroke open for some reason
|
||||||
|
if( !context.modules.capture.currentStroke ) modules.capture.fn.startStroke( context );
|
||||||
|
modules.capture.fn.endIntro( context );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mouseup: function( context, e ) {
|
||||||
|
if( context.modules.capture.state == "drawing" ) {
|
||||||
|
modules.capture.fn.endStroke( context );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ready: function ( context, e ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// hide errything
|
||||||
|
$( '#markmaker' )
|
||||||
|
.hide()
|
||||||
|
.children()
|
||||||
|
.hide();
|
||||||
|
// template dom is ready
|
||||||
|
$( '#markmaker-reset a' )
|
||||||
|
.addClass( 'disabled' )
|
||||||
|
.bind( 'mousedown', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
modules.capture.fn.reset( context );
|
||||||
|
} );
|
||||||
|
$( '#markmaker-submit a' )
|
||||||
|
.addClass( 'disabled' )
|
||||||
|
.bind( 'mousedown', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
modules.capture.fn.submit( context );
|
||||||
|
} );
|
||||||
|
// load the country codes into the dialog
|
||||||
|
context.fn.withCountryCodes( function ( countryCodes ) {
|
||||||
|
var $select = $( '#markmaker-country' );
|
||||||
|
for( var i = 0; i < countryCodes.length; i++ ) {
|
||||||
|
var $option = $( '<option />' )
|
||||||
|
.val( countryCodes[i].code )
|
||||||
|
.text( countryCodes[i].name );
|
||||||
|
$select.append( $option );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
$( '#markmaker-location a' )
|
||||||
|
.bind( 'mousedown', {context: context}, modules.capture.fn.locationDialogToggle );
|
||||||
|
$( '#markmaker-information' )
|
||||||
|
.bind( 'mouseover', {context: context}, modules.capture.fn.informationDialogToggle )
|
||||||
|
.bind( 'mouseout', {context: context}, modules.capture.fn.informationDialogToggle );
|
||||||
|
if ( lC.state == "drawing" ) {
|
||||||
|
modules.capture.fn.initDrawing( context );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$("#sammy #markmaker-country").selectBox({ autoWidth: false });
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
loop: function ( context, e ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
if ( !lC.initialized ) return;
|
||||||
|
// increment the frame counter
|
||||||
|
lC.frameCount++;
|
||||||
|
// Draw the cursor
|
||||||
|
modules.capture.fn.commonLoop( context );
|
||||||
|
// state specific code
|
||||||
|
switch( context.modules.capture.state ) {
|
||||||
|
case "drawing":
|
||||||
|
modules.capture.fn.drawLoop( context );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
init: function ( context, options ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
|
||||||
|
// if we've already set the interface up, just reset it
|
||||||
|
if ( '$capture' in lC ) {
|
||||||
|
// FIXME -- this reinit portion could use some love
|
||||||
|
if( 'state' in options ) {
|
||||||
|
modules.capture.fn.reset( context );
|
||||||
|
if ( options['state'] == 'drawing' ) {
|
||||||
|
if( context.mouseDown )
|
||||||
|
context.fn.trigger( 'mousedown' );
|
||||||
|
}
|
||||||
|
lC.state = options['state'];
|
||||||
|
modules.capture.fn.initDrawing( context );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// allow defaults to be overriden
|
||||||
|
$.extend( lC, modules.capture.defaults );
|
||||||
|
$.extend( lC, options );
|
||||||
|
// but not the cofig
|
||||||
|
$.extend( lC, modules.capture.config );
|
||||||
|
// DOM setup
|
||||||
|
lC.$capture = $( '<div />' )
|
||||||
|
.addClass( "capture-container" );
|
||||||
|
context.$container
|
||||||
|
.css( { 'zIndex': 100, 'cursor': 'none' } )
|
||||||
|
.append( lC.$capture );
|
||||||
|
|
||||||
|
lC.layerManager = new Mark.layerManager( lC.$capture.get( 0 ) );
|
||||||
|
|
||||||
|
// add two layers for the interface to use
|
||||||
|
lC.layerManager.addLayer( 'drawnLayer' );
|
||||||
|
lC.layerManager.addLayer( 'liveDrawingLayer' );
|
||||||
|
|
||||||
|
// trigger resize so our new layers are sized to fit
|
||||||
|
context.fn.trigger( 'resize' );
|
||||||
|
|
||||||
|
lC.initialized = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deinit: function( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// fade out our container
|
||||||
|
lC.$capture.fadeOut( 'fast', function () {
|
||||||
|
// remove all our layers
|
||||||
|
lC.layerManager.removeAll();
|
||||||
|
lC.$capture.remove();
|
||||||
|
lC.initialized = false;
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
initIntro: function ( context ) {
|
||||||
|
|
||||||
|
},
|
||||||
|
initDrawing: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// hide any intro stuff that might be being displayed
|
||||||
|
if( $( '#browse-marks' ).is( ':visible' ) ) {
|
||||||
|
$( '#browse-marks, #click-anywhere, #intro-main-copy' )
|
||||||
|
.fadeOut( 'fast' );
|
||||||
|
$( '#markmaker-legal-line' ).fadeIn( 'slow' );
|
||||||
|
}
|
||||||
|
$( '#markmaker' ).css( 'background-position', '0 ' + ( context.height - 140 ) + 'px' );
|
||||||
|
// update our resize handler
|
||||||
|
$( '#markmaker' )
|
||||||
|
.unbind( 'resize.markApp' )
|
||||||
|
.bind( 'resize.markApp', function ( e, w, h ) {
|
||||||
|
$( '#markmaker' ).css( 'background-position', '0 ' + ( context.height - 140 ) + 'px' );
|
||||||
|
|
||||||
|
// if there are dialogs open, reposition them
|
||||||
|
if( $( '#location-dialog:visible').size() > 0 ) {
|
||||||
|
$( '#location-dialog:visible' )
|
||||||
|
.css( {
|
||||||
|
'bottom': $( '#markmaker-location' ).height() + 25,
|
||||||
|
'left': $( '#markmaker-location' ).offset().left + 32
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
if( !$( '#markmaker' ).is( ':visible' ) ) {
|
||||||
|
$( '#markmaker' )
|
||||||
|
.width( 0 )
|
||||||
|
.show()
|
||||||
|
.animate( { 'width': context.width }, 'slow', function () {
|
||||||
|
$( '#markmaker-controls' ).fadeIn( 'slow', function() {
|
||||||
|
$( '#markmaker-information' ).fadeIn( 'slow' );
|
||||||
|
} );
|
||||||
|
$( '#markmaker-legal-line' ).fadeIn( 'slow' );
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
$( '#markmaker-controls' ).fadeIn( 'slow', function() {
|
||||||
|
$( '#markmaker-information' ).fadeIn( 'slow' );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
// special cases
|
||||||
|
if ( lC.invite_code && lC.contributor_type == "t" ) {
|
||||||
|
lC.captureLimit = 1000;
|
||||||
|
lC.$capture.addClass( 'translator' );
|
||||||
|
} else if ( lC.invite_code && lC.contributor_type == "c" ) {
|
||||||
|
lC.$capture.addClass( 'contributor' );
|
||||||
|
$( '#contributor-fields' )
|
||||||
|
.collapsibleMod( )
|
||||||
|
.fadeIn( 'slow' );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// fades out the intro content and switches into drawing mode
|
||||||
|
endIntro: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// switch to drawing mode
|
||||||
|
context.app.setLocation( '#/mark/new' );
|
||||||
|
},
|
||||||
|
locationDialogToggle: function ( e, context ) {
|
||||||
|
e.preventDefault();
|
||||||
|
if( $( '#location-dialog' ).is( ':visible' ) ) {
|
||||||
|
$( '#location-dialog' )
|
||||||
|
.fadeOut( 'fast' );
|
||||||
|
} else {
|
||||||
|
$( '#location-dialog' )
|
||||||
|
.fadeIn( 'fast' )
|
||||||
|
.css( {
|
||||||
|
'bottom': $( '#markmaker-location' ).height() + 25,
|
||||||
|
'left': $( '#markmaker-location' ).offset().left + 32
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
informationDialogToggle: function ( e, context ) {
|
||||||
|
e.preventDefault();
|
||||||
|
if( e.type == "mouseout") {
|
||||||
|
$( '#information-dialog' )
|
||||||
|
.fadeOut( 'fast' );
|
||||||
|
} else {
|
||||||
|
$( '#information-dialog' )
|
||||||
|
.fadeIn( 'fast' )
|
||||||
|
.css( {
|
||||||
|
'bottom': $( '#markmaker-information' ).height() + 36,
|
||||||
|
'left': $( '#markmaker-information' ).offset().left - $( '#information-dialog' ).width() + 30
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
startMark: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// setup the mark
|
||||||
|
lC.captureTime = ( new Date() ).getTime();
|
||||||
|
lC.rtl = context.mouseX > $( window ).width() / 2;
|
||||||
|
lC.mark = new Mark.gmlMark( [], '', '', lC.captureTime, lC.rtl );
|
||||||
|
// remove the disabled styling from the submit and reset buttons
|
||||||
|
$( '#markmaker-submit a, #markmaker-reset a' ).removeClass( 'disabled' );
|
||||||
|
},
|
||||||
|
endMark: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// close out the mark and prep for submission
|
||||||
|
lC.mark.setupVars();
|
||||||
|
},
|
||||||
|
startStroke: function ( context ) {
|
||||||
|
// start a new, empty stroke
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
lC.currentStroke = [];
|
||||||
|
// set the time relative to the last stroke, plus an offset
|
||||||
|
if( lC.strokes.length > 0 )
|
||||||
|
lC.captureTime = ( new Date() ).getTime() -
|
||||||
|
( lC.strokes[lC.strokes.length - 1][lC.strokes[lC.strokes.length - 1].length - 1].time + lC.timeBetweenStrokes );
|
||||||
|
},
|
||||||
|
endStroke: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// ignore strokes with less than three points
|
||||||
|
if ( lC.currentStroke.length > 2 ) {
|
||||||
|
// close out this stroke
|
||||||
|
lC.strokes.push( lC.currentStroke );
|
||||||
|
// run the simplification algorithim
|
||||||
|
var simpStroke = Mark.simplification.simplifyPath( lC.currentStroke, 1 );
|
||||||
|
// run the weighting algorithm
|
||||||
|
simpStroke = Mark.simplification.weightPath( simpStroke, [5,10,20,40] );
|
||||||
|
lC.mark.strokes.push( simpStroke );
|
||||||
|
lC.cleanedStrokes.push( simpStroke );
|
||||||
|
// draw this stroke the to drawn layer
|
||||||
|
modules.capture.fn.drawStroke( context, simpStroke );
|
||||||
|
// recalculate the captured point count
|
||||||
|
lC.capturedPoints -= lC.currentStroke.length - simpStroke.length;
|
||||||
|
}
|
||||||
|
// set the currentStroke to null
|
||||||
|
lC.currentStroke = null;
|
||||||
|
},
|
||||||
|
capturePoint: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
if( lC.capturedPoints > lC.captureLimit ) {
|
||||||
|
context.fn.trigger( 'mouseup' );
|
||||||
|
modules.capture.fn.closeShop( context );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var time = ( new Date() ).getTime();
|
||||||
|
// create a new point and add it to the current stroke
|
||||||
|
var point = new Mark.gmlPoint( context.mouseX, context.mouseY, time - lC.captureTime, 0 );
|
||||||
|
if( lC.currentStroke.length > 0 ) {
|
||||||
|
var lastPoint = lC.currentStroke[lC.currentStroke.length - 1];
|
||||||
|
point.speed = lastPoint.speedToPoint( point );
|
||||||
|
point.setAngleFromPoint( lastPoint );
|
||||||
|
point.smoothAgainst( lastPoint, 1/100 );
|
||||||
|
} else {
|
||||||
|
// if this isn't the first stroke, draw a connecting line
|
||||||
|
if( lC.strokes.length >= 1 ) {
|
||||||
|
modules.capture.fn.drawGuide( lC.layerManager.layers['drawnLayer'].context, lC.lastX, lC.lastY, point.x, point.y );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lC.currentStroke.push( point );
|
||||||
|
lC.lastX = point.x;
|
||||||
|
lC.lastY = point.y;
|
||||||
|
|
||||||
|
// increment our total points counter
|
||||||
|
lC.capturedPoints++;
|
||||||
|
},
|
||||||
|
reset: function ( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
lC.layerManager.layers['liveDrawingLayer'].clean();
|
||||||
|
lC.layerManager.layers['drawnLayer'].clean();
|
||||||
|
lC.capturedPoints = 0;
|
||||||
|
lC.rtl = null;
|
||||||
|
lC.mouseDown = false
|
||||||
|
lC.lastX = null;
|
||||||
|
lC.lastY = null;
|
||||||
|
lC.strokes = [];
|
||||||
|
lC.currentStroke = null;
|
||||||
|
lC.mark = null;
|
||||||
|
lC.captureTime = null;
|
||||||
|
lC.state = "drawing";
|
||||||
|
$( '#markmaker-submit a, #markmaker-reset a' ).addClass( 'disabled' );
|
||||||
|
$( '#markapp' ).css( { 'cursor': 'none' } );
|
||||||
|
$( '#markmaker-instructions' ).fadeIn();
|
||||||
|
},
|
||||||
|
closeShop: function( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
lC.state = 'preview';
|
||||||
|
// close the mark
|
||||||
|
modules.capture.fn.endMark( context );
|
||||||
|
// clear the drawing layer
|
||||||
|
lC.layerManager.layers['liveDrawingLayer'].clean();
|
||||||
|
// if the user is out of points, draw the line to the opposite side of the screen
|
||||||
|
var g = lC.layerManager.layers['liveDrawingLayer'].context,
|
||||||
|
x = lC.lastX,
|
||||||
|
y = lC.lastY;
|
||||||
|
g.strokeStyle = 'rgba(0,0,0,0.2)';
|
||||||
|
g.lineWidth = 1;
|
||||||
|
g.beginPath();
|
||||||
|
g.dashedLineTo( x, y, lC.rtl ? 0 : lC.layerManager.layers['liveDrawingLayer'].canvas.width, y, [7, 5] );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
// set our cursor back to normal
|
||||||
|
$( '#markapp' ).css( { 'cursor': 'default' } );
|
||||||
|
},
|
||||||
|
submit: function( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
if( lC.state == "submitting" ) return;
|
||||||
|
if( lC.state != "preview" ) modules.capture.fn.closeShop( context );
|
||||||
|
// process our points, and send them off
|
||||||
|
lC.state = "submitting";
|
||||||
|
$( '#markmaker-submit a' ).addClass( 'disabled' );
|
||||||
|
var data = {};
|
||||||
|
data.rtl = lC.rtl;
|
||||||
|
data.strokes = lC.strokes;
|
||||||
|
//data.locale = cfg.locale; // TODO - impliment location awareness
|
||||||
|
var points_obj = JSON.stringify( data );
|
||||||
|
var points_obj_simplified = JSON.stringify( lC.mark );
|
||||||
|
var country_code = $( '#markmaker-country' ).val() == "label" ? "" : $( '#markmaker-country' ).val();
|
||||||
|
// show loader
|
||||||
|
context.fn.showLoader( $( '.translated-strings #submitting-mark' ).text() );
|
||||||
|
var params = {
|
||||||
|
'points_obj': points_obj,
|
||||||
|
'points_obj_simplified': points_obj_simplified,
|
||||||
|
'country_code': country_code
|
||||||
|
};
|
||||||
|
if ( lC.invite_code && lC.contributor_type == "t" ) {
|
||||||
|
params.contributor_locale = context.locale;
|
||||||
|
params.invite = lC.invite_code;
|
||||||
|
} else if (lC.invite_code && lC.contributor_type == "c" ) {
|
||||||
|
params.contributor = $( '#contributor-name' ).val();
|
||||||
|
// add the quote as the marks extra_info
|
||||||
|
lC.mark.extra_info = $( '#contributor-quote' ).val();
|
||||||
|
// re-stringify our points obj
|
||||||
|
params.points_obj_simplified = JSON.stringify( lC.mark );
|
||||||
|
params.invite = lC.invite_code;
|
||||||
|
}
|
||||||
|
$.ajax( {
|
||||||
|
url: '/requests/save_mark',
|
||||||
|
data: params,
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
success: function( data ) {
|
||||||
|
// store the users mark for later access
|
||||||
|
context.fn.storeData( 'userMark', { 'reference': data.mark_reference, 'country_code': country_code } );
|
||||||
|
// now tell the app to redirect to our FRESH mark
|
||||||
|
context.app.setLocation( '#/linear/'+ data.mark_reference + '?playback=true' );
|
||||||
|
// hide loader
|
||||||
|
context.fn.hideLoader();
|
||||||
|
},
|
||||||
|
error: function( data ) {
|
||||||
|
context.fn.showError();
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
drawStroke: function ( context, stroke ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
Mark.thickBrush( lC.layerManager.layers['drawnLayer'].context, [stroke] );
|
||||||
|
lC.layerManager.layers['drawnLayer'].context.fillStyle = "rgba(255,255,255,0.3)";
|
||||||
|
lC.layerManager.layers['drawnLayer'].context.strokeStyle = "rgba(255,255,255,0.3)";
|
||||||
|
Mark.circleBrush( lC.layerManager.layers['drawnLayer'].context, [stroke] );
|
||||||
|
},
|
||||||
|
drawGuide: function( g, x1, y1, x2, y2 ) {
|
||||||
|
g.strokeStyle = 'rgba(0,0,0,0.2)';
|
||||||
|
g.lineWidth = 1;
|
||||||
|
g.beginPath();
|
||||||
|
g.dashedLineTo( x1, y1, x2, y2, [7, 5] );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
},
|
||||||
|
drawCursor: function ( g, x, y, per ) {
|
||||||
|
g.strokeStyle = '#ff5400';
|
||||||
|
g.fillStyle = '#000000';
|
||||||
|
// draw stroke
|
||||||
|
g.beginPath();
|
||||||
|
g.moveTo( x, y );
|
||||||
|
g.lineTo( x + 1, y - 8 );
|
||||||
|
g.lineTo( x + 20, y - 27 );
|
||||||
|
g.lineTo( x + 23, y - 23 );
|
||||||
|
g.lineTo( x, y );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
// draw filling
|
||||||
|
per *= 18.5;
|
||||||
|
per += 4.5;
|
||||||
|
g.beginPath();
|
||||||
|
g.moveTo( x, y );
|
||||||
|
g.lineTo( x + 1, y - 8 );
|
||||||
|
g.lineTo( x + ( per - 3 ), y - ( per + 4 ) );
|
||||||
|
g.lineTo( x + per, y - per );
|
||||||
|
g.lineTo( x, y );
|
||||||
|
g.closePath();
|
||||||
|
g.fill();
|
||||||
|
},
|
||||||
|
commonLoop: function( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
|
||||||
|
// clear the drawing layer
|
||||||
|
lC.layerManager.layers['liveDrawingLayer'].clean();
|
||||||
|
|
||||||
|
// draw the cursor if the cursor is in the frame
|
||||||
|
if( context.mouseIn && ( lC.state == "drawing" || lC.state == "intro" ) ) {
|
||||||
|
modules.capture.fn.drawCursor( lC.layerManager.layers['liveDrawingLayer'].context, context.mouseX, context.mouseY, ( lC.captureLimit - lC.capturedPoints ) / lC.captureLimit );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
introLoop: function( context ) {
|
||||||
|
|
||||||
|
},
|
||||||
|
drawLoop: function( context ) {
|
||||||
|
var lC = context.modules.capture;
|
||||||
|
// Clean the drawing layer
|
||||||
|
if( lC.currentStroke && lC.currentStroke.length > 0 ) {
|
||||||
|
// draw out what we've got in the stroke buffer
|
||||||
|
Mark.thickBrush( lC.layerManager.layers['liveDrawingLayer'].context, [lC.currentStroke] );
|
||||||
|
lC.layerManager.layers['liveDrawingLayer'].context.fillStyle = "rgba(255,255,255,0.3)";
|
||||||
|
lC.layerManager.layers['liveDrawingLayer'].context.strokeStyle = "rgba(255,255,255,0.3)";
|
||||||
|
Mark.circleBrush( lC.layerManager.layers['liveDrawingLayer'].context, [lC.currentStroke] );
|
||||||
|
}
|
||||||
|
if( ! context.mouseIn ) return;
|
||||||
|
if( ! context.mouseDown ) {
|
||||||
|
// draw the guide
|
||||||
|
var x, y;
|
||||||
|
if( lC.strokes.length == 0 ) {
|
||||||
|
x = context.mouseX > $( window ).width() / 2 ? lC.layerManager.layers['liveDrawingLayer'].canvas.width : 0,
|
||||||
|
y = context.mouseY;
|
||||||
|
} else {
|
||||||
|
x = lC.lastX;
|
||||||
|
y = lC.lastY;
|
||||||
|
}
|
||||||
|
modules.capture.fn.drawGuide( lC.layerManager.layers['liveDrawingLayer'].context, x, y, context.mouseX, context.mouseY );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}( jQuery ) );
|
|
@ -0,0 +1,310 @@
|
||||||
|
( function( $ ) {
|
||||||
|
|
||||||
|
// support loose augmentation
|
||||||
|
markApp = $.markApp = $.markApp || {};
|
||||||
|
modules = $.markApp.modules = $.markApp.modules || {};
|
||||||
|
|
||||||
|
// Code for introducing the site.
|
||||||
|
// runs quickly, then unloads
|
||||||
|
// store all data in a flat json file that django recompiles after a new intro mark is added
|
||||||
|
modules.intro = {
|
||||||
|
defaults: {
|
||||||
|
// optional reference mark -- will init the visualization on this mark if passed
|
||||||
|
reference_mark: null
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
// all marks held here
|
||||||
|
marks: {},
|
||||||
|
animationMarks: ['vVR', 'myWb'],
|
||||||
|
playbackTimes: {},
|
||||||
|
vizScene: null, // for rendering the viz preview
|
||||||
|
textScene: null, // for rendering tahe extra text
|
||||||
|
// layer manager
|
||||||
|
layerManager: null,
|
||||||
|
// boolean flag to indicate if this module is fully setup
|
||||||
|
initialized: false,
|
||||||
|
eventChange: false,
|
||||||
|
curLocaleMark: null,
|
||||||
|
animationComplete: false,
|
||||||
|
tweens: {}
|
||||||
|
},
|
||||||
|
evt: {
|
||||||
|
resize: function( context, e ) {
|
||||||
|
context.modules.intro.layerManager.resizeAll( context.width, context.height );
|
||||||
|
context.modules.intro.eventChange = true;
|
||||||
|
|
||||||
|
if ( context.modules.intro.xAnimationComplete ) {
|
||||||
|
// redraw the X
|
||||||
|
modules.intro.fn.drawX( context );
|
||||||
|
// reposition and redraw the translateMark
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
loop: function ( context, e ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
|
||||||
|
// update the position of the camera and draw the viz preview
|
||||||
|
TWEEN.update();
|
||||||
|
lC.layerManager.layers['viz'].clean();
|
||||||
|
Mark.renderer.renderScene( lC.vizScene, { width: context.width, height: context.height } );
|
||||||
|
|
||||||
|
if( lC.curLocaleMark || lC.xMark ) {
|
||||||
|
lC.layerManager.layers['mainMark'].clean();
|
||||||
|
// render the locale mark
|
||||||
|
if( lC.curLocaleMark ) {
|
||||||
|
var scale = 500 / lC.curLocaleMark.bWidth;
|
||||||
|
Mark.renderer.renderMark(
|
||||||
|
lC.layerManager.layers['mainMark'].context,
|
||||||
|
lC.curLocaleMark,
|
||||||
|
{ offset: {x: (context.width / 2) - 115, y: context.height - 240 },
|
||||||
|
scale: {x: scale, y: scale, thickness: scale},
|
||||||
|
color: '255,84,0',
|
||||||
|
timer: lC.textScene.timers[lC.curLocaleMark.reference] } );
|
||||||
|
}
|
||||||
|
if ( lC.xMark ) {
|
||||||
|
// RENDER THE X
|
||||||
|
var xScale = ( ( ( context.width / 2 ) - 200 ) / lC.xMark.bWidth );
|
||||||
|
var yScale = ( ( context.height + 200 ) / lC.xMark.bHeight );
|
||||||
|
Mark.renderer.renderMark(
|
||||||
|
lC.layerManager.layers['mainMark'].context,
|
||||||
|
lC.xMark,
|
||||||
|
{ offset: {x: 10, y: -100 },
|
||||||
|
scale: {x: xScale, y: yScale, thickness: 5},
|
||||||
|
color: '0,0,0',
|
||||||
|
timer: lC.textScene.timers[lC.xMark.reference] } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ready: function( context, e ) {
|
||||||
|
$( '#markmaker' )
|
||||||
|
.hide()
|
||||||
|
.children()
|
||||||
|
.hide();
|
||||||
|
/*
|
||||||
|
* Here's the order in which we want to run this intro
|
||||||
|
* 1. quick viz preview with make your mark in varying languages (2 sec)
|
||||||
|
* 2. dotted line animated across the screen as the viz preview fades out ( 1 sec)
|
||||||
|
* 3. big X draws in (2 sec)
|
||||||
|
* 4. dom elements animate up (1 sec)
|
||||||
|
* 5. Make your Mark draws in (4 sec)
|
||||||
|
*
|
||||||
|
* If any part of this fails, we revert to a simple intro where our intro screens if faded in.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
$.when( modules.intro.fn.initInterface( context ), modules.intro.fn.loadMarks( context ) )
|
||||||
|
.then( function() { modules.intro.fn.runVizPreview( context ); } )
|
||||||
|
.then( function() { modules.intro.fn.startDomAnimation( context ); } )
|
||||||
|
.fail( function() { modules.intro.fn.simpleIntro( context ); } );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
init: function( context, options ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
if ( lC.initialized ) {
|
||||||
|
console.log( "this module isn't really intended to be reloaded" );
|
||||||
|
// now our options into our context
|
||||||
|
$.extend( lC, lC, options );
|
||||||
|
// since merging won't replace null or undefined values, make sure we clean up after it
|
||||||
|
for( option in modules.intro.defaults ) {
|
||||||
|
if ( options[option] == null ) lC[option] = modules.intro.defaults[option];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// allow defaults to be overriden
|
||||||
|
$.extend( lC, modules.intro.defaults, options );
|
||||||
|
// but not the cofig
|
||||||
|
$.extend( lC, lC, modules.intro.config );
|
||||||
|
|
||||||
|
// DOM setup
|
||||||
|
lC.$intro = $( '<div />' )
|
||||||
|
.addClass( "intro-container" );
|
||||||
|
context.$container
|
||||||
|
.append( lC.$intro );
|
||||||
|
|
||||||
|
// scene setup
|
||||||
|
lC.vizScene = new Mark.scene();
|
||||||
|
lC.textScene = new Mark.scene();
|
||||||
|
|
||||||
|
// layer setup
|
||||||
|
lC.layerManager = new Mark.layerManager( lC.$intro.get( 0 ) );
|
||||||
|
// we draw the viz preview to this
|
||||||
|
lC.layerManager.addLayer( 'viz' );
|
||||||
|
lC.vizScene.canvasContext = lC.layerManager.layers['viz'].context;
|
||||||
|
// and then the 'Make Your Mark' on this
|
||||||
|
lC.layerManager.addLayer( 'mainMark' );
|
||||||
|
lC.textScene.canvasContext = lC.layerManager.layers['mainMark'].context;
|
||||||
|
// and for the X
|
||||||
|
lC.layerManager.addLayer( 'X' );
|
||||||
|
// trigger resize so our new layers are sized to fit
|
||||||
|
context.fn.trigger( 'resize' );
|
||||||
|
|
||||||
|
lC.initialized = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
deinit: function( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
lC.$intro.fadeOut( 'fast', function () {
|
||||||
|
// remove all our layers
|
||||||
|
lC.layerManager.removeAll();
|
||||||
|
lC.$intro.remove();
|
||||||
|
lC.initialized = false;
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
initInterface: function ( context ) {
|
||||||
|
$( '#markmaker' )
|
||||||
|
.unbind( 'resize.markApp' )
|
||||||
|
.bind( 'resize.markApp', function ( e, w, h ) {
|
||||||
|
// reposition the elements
|
||||||
|
var rAnchor = ( w / 2 ) + 485;
|
||||||
|
var bOffset = ( h - 140 ); // position of the background graphic
|
||||||
|
var wasHidden = false;
|
||||||
|
$( '#markmaker' ).css( 'background-position', '0 ' + bOffset + 'px' );
|
||||||
|
// if these aren't shown yet, do this quick trick
|
||||||
|
if( !$( '#markmaker' ).is( ':visible' ) ) {
|
||||||
|
wasHidden = true;
|
||||||
|
$( '#markmaker, #browse-marks, #click-anywhere, #intro-main-copy' )
|
||||||
|
.css( { 'display': 'block' } );
|
||||||
|
}
|
||||||
|
$( '#browse-marks' )
|
||||||
|
.css( { 'top': bOffset - 50, 'left': rAnchor - 85 } );
|
||||||
|
$( '#click-anywhere' )
|
||||||
|
.css( { 'top': bOffset + 12, 'left': rAnchor - $( '#intro-main-copy' ).width() } );
|
||||||
|
$( '#intro-main-copy' )
|
||||||
|
.css( { 'top': bOffset - $( '#intro-main-copy' ).height() - 100, 'left': rAnchor - $( '#intro-main-copy' ).width() } );
|
||||||
|
if( wasHidden ) {
|
||||||
|
$( '#markmaker, #browse-marks, #click-anywhere, #intro-main-copy' )
|
||||||
|
.css( { 'display': 'none' } );
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
.trigger( 'resize.markApp', [context.width, context.height] )
|
||||||
|
.width( 0 )
|
||||||
|
.height( context.height );
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
loadMarks: function( context ) {
|
||||||
|
return $.ajax( {
|
||||||
|
url: '/requests/get_translated_marks',
|
||||||
|
dataType: 'JSON'
|
||||||
|
} )
|
||||||
|
.success( function ( data ) {
|
||||||
|
modules.intro.fn.setupMarks( context, data.marks );
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
setupMarks: function( context, marks ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
// FXIME - if this is empty, throw an error
|
||||||
|
if( typeof marks === "undefined" || marks.length == 0 ) return;
|
||||||
|
// set our layer's visiblity to 0
|
||||||
|
$( lC.layerManager.layers['viz'].canvas ).css( 'opacity', 0 );
|
||||||
|
// sort the marks randomly
|
||||||
|
marks.sort( function( a, b ) { return ( Math.round( Math.random() ) - 0.5 ); } );
|
||||||
|
// // duplicate marks until we've got 25
|
||||||
|
// while ( marks.length < 25 ) {
|
||||||
|
// marks = marks.concat( marks );
|
||||||
|
// }
|
||||||
|
var pMark = null;
|
||||||
|
// add them to the scene
|
||||||
|
for ( var i = 0; i < marks.length; i++ ) {
|
||||||
|
try {
|
||||||
|
var points_obj = JSON.parse( marks[i].points_obj_simplified );
|
||||||
|
var mark = new Mark.gmlMark( points_obj.strokes, marks[i].reference, marks[i].country_code, marks[i].date_drawn, points_obj.rtl, marks[i].id, marks[i].is_approved );
|
||||||
|
if ( !lC.currentMark ) lC.currentMark = mark;
|
||||||
|
// if we dont have a permanant ref to this mark yet, create it
|
||||||
|
if( !( marks[i].reference in lC.marks ) ) {
|
||||||
|
lC.marks[mark.reference] = mark;
|
||||||
|
}
|
||||||
|
// position this mark relative to the last one
|
||||||
|
if ( pMark ) mark.positionRelativeTo( pMark, false );
|
||||||
|
if ( marks[i].contributor_locale == context.locale || !lC.curLocaleMark ) {
|
||||||
|
var distantFuture = ( new Date() ).getTime() * 3;
|
||||||
|
lC.curLocaleMark = new Mark.gmlMark( points_obj.strokes, marks[i].reference, marks[i].country_code, marks[i].date_drawn, points_obj.rtl, marks[i].id, marks[i].is_approved );
|
||||||
|
lC.textScene.timers[lC.curLocaleMark.reference] = { 'start': distantFuture, 'end': distantFuture + lC.curLocaleMark.maxTime, 'speed': 2 };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
lC.vizScene.objects.push( mark );
|
||||||
|
pMark = mark;
|
||||||
|
} catch ( e ) {
|
||||||
|
console.warn( "Mark failed import", marks[i].reference );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
runVizPreview: function ( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
// can't do this on less than three marks
|
||||||
|
if( lC.vizScene.objects.length < 3 ) return;
|
||||||
|
// move the camera way back
|
||||||
|
lC.vizScene.camera.position.x = -2000;
|
||||||
|
lC.vizScene.camera.position.z = -3000;
|
||||||
|
var targetMark = lC.vizScene.objects[lC.vizScene.objects.length - 2];
|
||||||
|
// tween the camera on down the line
|
||||||
|
var tween = new TWEEN.Tween( lC.vizScene.camera.position );
|
||||||
|
tween
|
||||||
|
.to( {
|
||||||
|
x: targetMark.position.x + (targetMark.bWidth / 2),
|
||||||
|
y: targetMark.position.y + (targetMark.bHeight / 2),
|
||||||
|
z: targetMark.position.z - 2000 }, 6000 )
|
||||||
|
.onComplete( function( ) {
|
||||||
|
delete lC.tweens['cameraEase'];
|
||||||
|
} )
|
||||||
|
.easing( TWEEN.Easing.Quartic.EaseInOut )
|
||||||
|
.start();
|
||||||
|
lC.tweens['cameraEase'] = tween;
|
||||||
|
$( lC.layerManager.layers['viz'].canvas )
|
||||||
|
.animate( { opacity: '1' }, 'slow' )
|
||||||
|
.delay( 2000 )
|
||||||
|
.animate( { opacity: '0.1'}, 'slow' );
|
||||||
|
// delay the dom animation
|
||||||
|
$( '#markmaker' )
|
||||||
|
.delay( 3000 );
|
||||||
|
},
|
||||||
|
startDomAnimation: function ( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
$( '#markmaker' )
|
||||||
|
.width( 0 )
|
||||||
|
.show()
|
||||||
|
.animate( { 'width': context.width }, 'slow', function () {
|
||||||
|
modules.intro.fn.startMarkAnimations( context );
|
||||||
|
$( '#intro-main-copy' ).fadeIn( 'slow' );
|
||||||
|
$( '#click-anywhere' ).delay( 200 ).fadeIn( 'slow' );
|
||||||
|
$( '#browse-marks' ).delay( 100 ).fadeIn( 'slow' );
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
startMarkAnimations: function ( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
modules.intro.fn.drawX( context );
|
||||||
|
// start drawing the translated mark
|
||||||
|
if( lC.curLocaleMark ) {
|
||||||
|
var now = ( new Date() ).getTime() + 2000;
|
||||||
|
lC.textScene.timers[lC.curLocaleMark.reference] = { 'start': now, 'end': now + lC.curLocaleMark.maxTime, 'speed': 2 };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
drawX: function ( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
// draw the X, with hardcoded data? good idea? maybe?
|
||||||
|
var xMarkData = {"strokes":[[{"x":177,"y":0,"z":0,"time":51,"speed":0,"angle":0,"significance":5},{"x":129,"y":60,"z":0,"time":255,"speed":0.45069390943299864,"angle":0.5880026035475675,"significance":1},{"x":123,"y":65,"z":0,"time":271,"speed":0.4931203163041915,"angle":0.7853981633974483,"significance":1},{"x":103,"y":89,"z":0,"time":339,"speed":0.45069390943299864,"angle":0.5880026035475675,"significance":1},{"x":56,"y":139,"z":0,"time":503,"speed":0.45073896963561083,"angle":0.7853981633974483,"significance":1},{"x":38,"y":162,"z":0,"time":584,"speed":0.3572203090978693,"angle":0.46364760900080615,"significance":1},{"x":9,"y":192,"z":0,"time":691,"speed":0.3535533905932738,"angle":0.7853981633974483,"significance":1},{"x":0,"y":206,"z":0,"time":727,"speed":0.45069390943299864,"angle":0.5880026035475675,"significance":5}],[{"x":11,"y":23,"z":0,"time":1178,"speed":0,"angle":0,"significance":5},{"x":30,"y":49,"z":0,"time":1246,"speed":0.32424352695503,"angle":5.639684198386302,"significance":1},{"x":55,"y":77,"z":0,"time":1321,"speed":0.48790367901871773,"angle":5.497787143782138,"significance":1},{"x":72,"y":100,"z":0,"time":1367,"speed":0.5216642390945547,"angle":5.695182703632019,"significance":1},{"x":85,"y":113,"z":0,"time":1408,"speed":0.5355917833779965,"angle":5.497787143782138,"significance":2},{"x":154,"y":175,"z":0,"time":1662,"speed":0.3311927108182759,"angle":5.497787143782138,"significance":1},{"x":186,"y":196,"z":0,"time":1802,"speed":0.2849548128987055,"angle":5.497787143782138,"significance":5}]],"country_code":"","time":1300925747439,"rtl":false,"maxTime":1802,"reference":"","hoverState":false,"renderedBounds":null,"id":null,"contributor_name":null,"extra_info":null,"color":"0,0,0","hoverColor":"0,139,211","x":454,"y":199,"position":{"x":0,"y":0,"z":0},"rotationAngle":{"x":0,"y":0,"z":0},"sX":0,"sY":0,"bWidth":186,"bHeight":206};
|
||||||
|
|
||||||
|
lC.xMark = new Mark.gmlMark( xMarkData.strokes, "xMark" );
|
||||||
|
|
||||||
|
lC.textScene.objects.push( lC.xMark );
|
||||||
|
var now = ( new Date() ).getTime();
|
||||||
|
lC.textScene.timers[lC.xMark.reference] = { 'start': now, 'end': now + lC.xMark.maxTime, 'speed': 1 };
|
||||||
|
},
|
||||||
|
// fallback function that doesn't bother with anything but the DOM elements
|
||||||
|
simpleIntro: function ( context ) {
|
||||||
|
var lC = context.modules.intro;
|
||||||
|
$( '#markmaker' )
|
||||||
|
.width( 0 )
|
||||||
|
.show()
|
||||||
|
.animate( { 'width': context.width }, 'slow', function () {
|
||||||
|
$( '#intro-main-copy' ).fadeIn( 'slow' );
|
||||||
|
$( '#click-anywhere' ).delay( 200 ).fadeIn( 'slow' );
|
||||||
|
$( '#browse-marks' ).delay( 100 ).fadeIn( 'slow' );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}( jQuery ) );
|
|
@ -0,0 +1,287 @@
|
||||||
|
( function( $ ) {
|
||||||
|
|
||||||
|
// TODO -- support loose augmentation of $.markApp, in case module code is ever loaded before this.
|
||||||
|
|
||||||
|
// The markApp namespace is used for storing available module code, instances of markApp, and any context free functions
|
||||||
|
$.markApp = {
|
||||||
|
// holds all available modules
|
||||||
|
modules: {},
|
||||||
|
// we keep track of all instances of markApp in here
|
||||||
|
instances: [],
|
||||||
|
// helper functions go here
|
||||||
|
fn: {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates a markApp instances with an element, and handles function calls on the instance
|
||||||
|
$.fn.markApp = function( options ) {
|
||||||
|
var $this = $( this );
|
||||||
|
// The context each markApp instance is stored as data on that element
|
||||||
|
var context = $this.data( 'markApp-context' );
|
||||||
|
// On first call, we need to set things up, but on all following calls we can skip right to the API handling
|
||||||
|
if ( !context || typeof context == 'undefined' ) {
|
||||||
|
context = {
|
||||||
|
// useful variables -- jquery objects get prefixed with $
|
||||||
|
app: null,
|
||||||
|
$container: $this,
|
||||||
|
frameCount: 0,
|
||||||
|
width: 0,
|
||||||
|
height: 0,
|
||||||
|
minWidth: 700,
|
||||||
|
minHeight: 500,
|
||||||
|
countries: [],
|
||||||
|
mouseX: null,
|
||||||
|
mouseY: null,
|
||||||
|
mouseDown: false,
|
||||||
|
mouseIn: false,
|
||||||
|
modules: {},
|
||||||
|
usersMark: null,
|
||||||
|
defaultErrorMsg: $( '#default-error-msg' ).text(),
|
||||||
|
defaultLoadingMsg: $( '#default-loading-msg' ).text(),
|
||||||
|
locale: ( window.location.pathname.split("/").length > 1 ) ? window.location.pathname.split("/")[1] : "en", // locale -- set by URL, default to 'en'
|
||||||
|
instance: $.markApp.instances.push( $this ) - 1, // store this instances index in the global instace array
|
||||||
|
// events
|
||||||
|
evt: {
|
||||||
|
resize: function( e ) {
|
||||||
|
var availableWidth = $( window ).width();
|
||||||
|
var availableHeight = $( window ).height() - ( $( 'header' ).height() + $( '#callout-boxes' ).height() );
|
||||||
|
if ( availableWidth < context.minWidth ) availableWidth = context.minWidth;
|
||||||
|
if ( availableHeight < context.minHeight ) availableHeight = context.minHeight;
|
||||||
|
context.$container.parent().width( availableWidth );
|
||||||
|
context.$container.parent().height( availableHeight );
|
||||||
|
context.width = availableWidth;
|
||||||
|
context.height = availableHeight;
|
||||||
|
// resize any elements with the autoResize class
|
||||||
|
$( '.autoResize' )
|
||||||
|
.height( availableHeight )
|
||||||
|
.width( availableWidth )
|
||||||
|
.trigger( 'resize.markApp', [availableWidth, availableHeight] );
|
||||||
|
},
|
||||||
|
mousemove: function( e ) {
|
||||||
|
context.mouseX = e.layerX;
|
||||||
|
context.mouseY = e.layerY;
|
||||||
|
},
|
||||||
|
mousedown: function( e ) {
|
||||||
|
if( 'preventDefault' in e ) e.preventDefault();
|
||||||
|
context.mouseDown = true;
|
||||||
|
},
|
||||||
|
mouseup: function( e ) {
|
||||||
|
if( 'preventDefault' in e ) e.preventDefault();
|
||||||
|
context.mouseDown = false;
|
||||||
|
},
|
||||||
|
mouseover: function( e ) {
|
||||||
|
if( 'preventDefault' in e ) e.preventDefault();
|
||||||
|
context.mouseIn = true;
|
||||||
|
},
|
||||||
|
mouseout: function( e ) {
|
||||||
|
if( 'preventDefault' in e ) e.preventDefault();
|
||||||
|
context.mouseX = null;
|
||||||
|
context.mouseY = null;
|
||||||
|
context.mouseIn = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// publicly accessible functions
|
||||||
|
public_fn: {
|
||||||
|
addModule: function( context, data ) {
|
||||||
|
var moduleName,
|
||||||
|
moduleOptions = {};
|
||||||
|
|
||||||
|
if( typeof data == "string" ) {
|
||||||
|
moduleName = data
|
||||||
|
} else if( typeof data == "object" ) {
|
||||||
|
for ( var moduleData in data ) {
|
||||||
|
moduleName = moduleData
|
||||||
|
moduleOptions = data[moduleData];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $.markApp.modules[moduleName] ) {
|
||||||
|
// give this module it's own space for storing stuff if it doesn't already have it
|
||||||
|
context.modules[moduleName] = context.modules[moduleName] || {};
|
||||||
|
// if it has an init function, run it
|
||||||
|
if( 'init' in $.markApp.modules[moduleName].fn )
|
||||||
|
$.markApp.modules[moduleName].fn.init( context, moduleOptions );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
unloadModule: function( context, moduleName ) {
|
||||||
|
if( moduleName == "all" ) {
|
||||||
|
// unload all the currently loaded modules
|
||||||
|
for ( moduleName in context.modules ) {
|
||||||
|
// if it has a deinit function, run it
|
||||||
|
if( 'deinit' in $.markApp.modules[moduleName].fn )
|
||||||
|
$.markApp.modules[moduleName].fn.deinit( context );
|
||||||
|
// remove it from our modules
|
||||||
|
delete context.modules[moduleName];
|
||||||
|
}
|
||||||
|
} else if ( moduleName in context.modules ) {
|
||||||
|
// if it has a deinit function, run it
|
||||||
|
if( 'deinit' in $.markApp.modules[moduleName].fn )
|
||||||
|
$.markApp.modules[moduleName].fn.deinit( context );
|
||||||
|
// remove it from our modules
|
||||||
|
delete context.modules[moduleName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// internal functions
|
||||||
|
fn: {
|
||||||
|
// trigger event handlers on modules
|
||||||
|
trigger: function( eventName, eventObj, args ) {
|
||||||
|
|
||||||
|
// Add some assurances to our eventObj
|
||||||
|
if( typeof eventObj == "undefined" )
|
||||||
|
eventObj = { 'type': 'custom' };
|
||||||
|
|
||||||
|
// trigger the global handlers first
|
||||||
|
if ( eventName in context.evt ) {
|
||||||
|
// if it returns false, stop the train
|
||||||
|
if ( context.evt[eventName]( eventObj ) == false ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// run the event handler on each module that's got it
|
||||||
|
for( var module in context.modules ) {
|
||||||
|
if( module in $.markApp.modules &&
|
||||||
|
'evt' in $.markApp.modules[module] &&
|
||||||
|
eventName in $.markApp.modules[module].evt ) {
|
||||||
|
$.markApp.modules[module].evt[eventName]( context, eventObj, args );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loop: function( e ) {
|
||||||
|
// reset the delay
|
||||||
|
setTimeout( function() { context.fn.loop( ); }, 42 );
|
||||||
|
// incremenet the counter
|
||||||
|
context.frameCount++;
|
||||||
|
// dispatch the event
|
||||||
|
context.fn.trigger( 'loop', {}, [] );
|
||||||
|
},
|
||||||
|
// useful for delayed loading of the country data
|
||||||
|
withCountryCodes: function ( callback ) {
|
||||||
|
if ( 'US' in context.countries ) {
|
||||||
|
callback( context.countries );
|
||||||
|
} else {
|
||||||
|
$.ajax( {
|
||||||
|
'url': '/media/assets/js/vendor/country_codes.json',
|
||||||
|
'dataType': 'JSON',
|
||||||
|
'success': function ( data ) {
|
||||||
|
context.countries = data;
|
||||||
|
for( var i = 0; i < data.length; i++ ) {
|
||||||
|
context.countries[ data[i].code ] = data[i].name;
|
||||||
|
}
|
||||||
|
callback( context.countries );
|
||||||
|
},
|
||||||
|
'error': function () {
|
||||||
|
// handle error loading countries
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showLoader: function( msg, custom_class ) {
|
||||||
|
var custom_class = custom_class || '';
|
||||||
|
var msg = typeof msg === "string" ? msg : context.defaultLoadingMsg;
|
||||||
|
// append our loader
|
||||||
|
var $loader = $( '<div />' )
|
||||||
|
.width( context.width )
|
||||||
|
.height( context.height )
|
||||||
|
.hide()
|
||||||
|
.addClass( 'overlay-wrapper autoResize' )
|
||||||
|
.addClass( custom_class )
|
||||||
|
.attr( 'id', 'markapp-loader' )
|
||||||
|
.append( $( '<div />' )
|
||||||
|
.text( msg ) );
|
||||||
|
context.$container
|
||||||
|
.append( $loader );
|
||||||
|
$loader.fadeIn( 'fast' );
|
||||||
|
},
|
||||||
|
hideLoader: function( ) {
|
||||||
|
$( '#markapp-loader' ).fadeOut( 'fast', function() {
|
||||||
|
$( this ).remove();
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
showError: function ( msg ) {
|
||||||
|
// TODO -- translate this default string
|
||||||
|
var msg = typeof msg === "string" ? msg : context.defaultErrorMsg;
|
||||||
|
var $error = $( '<div />' )
|
||||||
|
.width( context.width )
|
||||||
|
.height( context.height )
|
||||||
|
.hide()
|
||||||
|
.click( function ( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
context.fn.hideError();
|
||||||
|
} )
|
||||||
|
.addClass( 'overlay-wrapper autoResize' )
|
||||||
|
.attr( 'id', 'markapp-error' )
|
||||||
|
.append( $( '<div />' )
|
||||||
|
.attr( 'id', 'markapp-error-content' )
|
||||||
|
.append( $( '<p />' ).text( msg ) ) );
|
||||||
|
context.$container
|
||||||
|
.append( $error );
|
||||||
|
$error.fadeIn( 'fast' );
|
||||||
|
},
|
||||||
|
hideError: function ( ) {
|
||||||
|
$( '#markapp-error' ).fadeOut( 'fast', function() {
|
||||||
|
$( this ).remove();
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
storeData: function( key, value ) {
|
||||||
|
if ( typeof localStorage != 'undefined' ) {
|
||||||
|
// use localStorage if it exists
|
||||||
|
try {
|
||||||
|
if( typeof value === "object" ) {
|
||||||
|
value = JSON.stringify( value );
|
||||||
|
}
|
||||||
|
localStorage.setItem( key, value );
|
||||||
|
} catch (e) {
|
||||||
|
if ( e == QUOTA_EXCEEDED_ERR ) { /* data wasn't successfully saved due to quota exceed */ }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// use cookies
|
||||||
|
// todo -- impliment cookie fallback....maybe
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getData: function( key ) {
|
||||||
|
if ( typeof localStorage != 'undefined' ) {
|
||||||
|
var item = localStorage.getItem( key );
|
||||||
|
if( item ) {
|
||||||
|
if ( item[0]=="{" ) item = JSON.parse( item );
|
||||||
|
return item;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// bindings
|
||||||
|
$( window )
|
||||||
|
.delayedBind( 300, 'resize', function( e ) {
|
||||||
|
return context.fn.trigger( 'resize', e );
|
||||||
|
} )
|
||||||
|
.bind( 'keydown keypress keyup', function( e ) {
|
||||||
|
return context.fn.trigger( e.type, e );
|
||||||
|
} )
|
||||||
|
.trigger( 'resize' );
|
||||||
|
context.$container
|
||||||
|
.bind( 'mousemove mousedown mouseup mouseover mouseout ready swap', function( e ) {
|
||||||
|
return context.fn.trigger( e.type, e );
|
||||||
|
} );
|
||||||
|
// start the loop
|
||||||
|
context.fn.loop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the arguments to an array to make this easier
|
||||||
|
var args = $.makeArray( arguments );
|
||||||
|
|
||||||
|
// handle public function calls
|
||||||
|
if ( args.length > 0 ) {
|
||||||
|
var call = args.shift();
|
||||||
|
if ( call in context.public_fn ) {
|
||||||
|
context.public_fn[call]( context, typeof args[0] == 'undefined' ? {} : args[0] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this.data( 'markApp-context', context );
|
||||||
|
};
|
||||||
|
|
||||||
|
}( jQuery ) );
|
|
@ -0,0 +1,959 @@
|
||||||
|
( function( $ ) {
|
||||||
|
|
||||||
|
// support loose augmentation
|
||||||
|
markApp = $.markApp = $.markApp || {};
|
||||||
|
modules = $.markApp.modules = $.markApp.modules || {};
|
||||||
|
|
||||||
|
modules.linear = {
|
||||||
|
defaults: {
|
||||||
|
reference_mark: null, // optional reference mark -- will init the visualization on this mark if passed
|
||||||
|
country_code: null, // optional country code -- only loads marks with this county code if present
|
||||||
|
playback: false, // set this to true to immediately play back the initial mark
|
||||||
|
is_flagged: false, // optional flagged flag -- only loads marks that are flagged (for use within moderation)
|
||||||
|
linear_root: 'linear'
|
||||||
|
},
|
||||||
|
config: {
|
||||||
|
marks: {}, // all marks held here
|
||||||
|
flaggings: {}, // loaded from local storage, and used for some local checking that users are flagging things multiple times
|
||||||
|
orderedMarks: [], // array of mark references, arranged by id
|
||||||
|
leftBuffer: [], // mark buffers for the left and right of the marks currently in the scene
|
||||||
|
rightBuffer: [],
|
||||||
|
bufferSize: 20, // amount of marks to keep in a buffer
|
||||||
|
bufferMinSize: 5, // min amount of marks to keep in a buffer before forcing a refill
|
||||||
|
scene: null,
|
||||||
|
// handles camera changes -- could probably be shifted into the camera object
|
||||||
|
cameraChange: {},
|
||||||
|
tweens: {},
|
||||||
|
layerManager: null, // layer manager
|
||||||
|
initialized: false, // boolean flag to indicate if this module is fully setup
|
||||||
|
requestingMarks: false, // prevents more mark request from being sent when set to true
|
||||||
|
moreLeft: true, // Flags for the begining and end of the line. Assume we're not there at the start
|
||||||
|
moreRight: true,
|
||||||
|
hoverMark: null, // holds the mark currently being hovered over
|
||||||
|
currentMark: null,
|
||||||
|
|
||||||
|
playbackTimes: {}, // used for storing mark playback times by reference
|
||||||
|
eventChange: false // flag to tell the render loop if the mouse is causing changes that need rendered
|
||||||
|
},
|
||||||
|
evt: {
|
||||||
|
ready: function ( context, e ) {
|
||||||
|
modules.linear.fn.initInterface( context );
|
||||||
|
},
|
||||||
|
resize: function( context, e ) {
|
||||||
|
context.modules.linear.eventChange = true;
|
||||||
|
context.modules.linear.layerManager.resizeAll( context.width, context.height );
|
||||||
|
},
|
||||||
|
keydown: function ( context, e ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
switch( e.keyCode ) {
|
||||||
|
case 38:
|
||||||
|
// arrow up
|
||||||
|
e.preventDefault();
|
||||||
|
lC.cameraChange.aZ = 10;
|
||||||
|
break;
|
||||||
|
case 40:
|
||||||
|
// arrow down
|
||||||
|
e.preventDefault();
|
||||||
|
lC.cameraChange.aZ = -10;
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
// arrow right -- pan the camera to the right
|
||||||
|
e.preventDefault();
|
||||||
|
// next mark
|
||||||
|
lC.cameraChange.aX = 10;
|
||||||
|
// hide mark info
|
||||||
|
modules.linear.fn.hideMarkInformation( context );
|
||||||
|
break;
|
||||||
|
case 37:
|
||||||
|
// arrow left -- pan the camera to the left
|
||||||
|
e.preventDefault();
|
||||||
|
// prev mark
|
||||||
|
lC.cameraChange.aX = -10;
|
||||||
|
// hide mark info
|
||||||
|
modules.linear.fn.hideMarkInformation( context );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
keyup: function( context, e ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
switch( e.keyCode ) {
|
||||||
|
case 38:
|
||||||
|
case 40:
|
||||||
|
// arrow up
|
||||||
|
e.preventDefault();
|
||||||
|
lC.cameraChange.aZ = 0;
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
case 37:
|
||||||
|
e.preventDefault();
|
||||||
|
lC.cameraChange.aX = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// prevent our bound keys from firing native events
|
||||||
|
keypress: function( context, e ) {
|
||||||
|
switch( e.keyCode ) {
|
||||||
|
case 38:
|
||||||
|
case 40:
|
||||||
|
case 39:
|
||||||
|
case 37:
|
||||||
|
e.preventDefault();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mousedown: function( context, e ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( mark = modules.linear.fn.hitTest( context, context.mouseX, context.mouseY ) ) {
|
||||||
|
// if the mark hasn't changed from what's in our URL, we just need to show the details again
|
||||||
|
if ( mark == lC.currentMark ) {
|
||||||
|
modules.linear.fn.centerCurrentMark( context, function() {
|
||||||
|
modules.linear.fn.showMarkInformation( context );
|
||||||
|
} );
|
||||||
|
// otherwise update the URL, and the module will jump to the referenced mark
|
||||||
|
} else if ( lC.country_code ) {
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/country/' + lC.country_code + '/' + mark.reference );
|
||||||
|
} else {
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/' + mark.reference );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mousemove: function( context, e ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
lC.eventChange = true;
|
||||||
|
// hover test
|
||||||
|
if( mark = modules.linear.fn.hoverTest( context, context.mouseX, context.mouseY, lC.hoverMark ) ) {
|
||||||
|
// reset the old hovered mark
|
||||||
|
if( lC.hoverMark ) lC.hoverMark.color = lC.hoverMark.contributor_name ? '171,73,27' : '0,0,0';
|
||||||
|
// store this hover mark
|
||||||
|
lC.hoverMark = mark;
|
||||||
|
if ( lC.currentMark && lC.hoverMark.reference == lC.currentMark.reference && lC.hoverMark.contributor_name && $( '#mark-information' ).is( ':visible' ) ) {
|
||||||
|
$( '#contributor-quote-box' )
|
||||||
|
.fadeIn( 'fast' )
|
||||||
|
.css( { left: context.mouseX - 15, top: context.mouseY - $( '#contributor-quote-box' ).height() - 15 } );
|
||||||
|
} else {
|
||||||
|
lC.hoverMark.color = '0,139,211';
|
||||||
|
}
|
||||||
|
} else if ( lC.hoverMark ) {
|
||||||
|
lC.hoverMark.color = lC.hoverMark.contributor_name ? '171,73,27' : '0,0,0';
|
||||||
|
lC.hoverMark = null;
|
||||||
|
// fade out any contributor quotes we might happen to be showing
|
||||||
|
$( '#contributor-quote-box:visible' ).fadeOut( 'fast' );
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
loop: function ( context ) {
|
||||||
|
var lC = context.modules.linear,
|
||||||
|
dLayer = lC.layerManager.layers['drawingLayer'];
|
||||||
|
|
||||||
|
// update the position of the camera
|
||||||
|
var lastCameraPosition = {x: lC.scene.camera.position.x, y: lC.scene.camera.position.y, z: lC.scene.camera.position.z };
|
||||||
|
// two ways this can happen
|
||||||
|
if( 'cameraEase' in lC.tweens ) {
|
||||||
|
// with a tween
|
||||||
|
TWEEN.update();
|
||||||
|
} else {
|
||||||
|
// or with physics
|
||||||
|
lC.cameraChange.vZ += lC.cameraChange.aZ;
|
||||||
|
lC.cameraChange.vX += lC.cameraChange.aX;
|
||||||
|
lC.cameraChange.vX *= .93;
|
||||||
|
lC.cameraChange.vZ *= .93;
|
||||||
|
lC.scene.camera.position.x += lC.cameraChange.vX;
|
||||||
|
lC.scene.camera.position.z += lC.cameraChange.vZ;
|
||||||
|
// bring the Y and Z positions close to the current mark
|
||||||
|
var mark = modules.linear.fn.closestMark( context );
|
||||||
|
if ( mark ) {
|
||||||
|
var dY = lC.scene.camera.position.y - ( mark.position.y + ( mark.bHeight / 2 ) );
|
||||||
|
// if Z is not changing, try to maintain
|
||||||
|
// if( )
|
||||||
|
// var dZ = lC.scene.camera.position.z -
|
||||||
|
if ( dY != 0 && Math.abs(dY) >= 10) lC.scene.camera.position.y += ( dY > 0 ? -10 : 10 );
|
||||||
|
}
|
||||||
|
// TODO: fix the Z index while navigating the line
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nothing has changed, return RIGHT NOW
|
||||||
|
if( !lC.eventChange &&
|
||||||
|
lastCameraPosition.x == lC.scene.camera.position.x &&
|
||||||
|
lastCameraPosition.y == lC.scene.camera.position.y &&
|
||||||
|
lastCameraPosition.z == lC.scene.camera.position.z ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// modified hover test -- only removes hover states
|
||||||
|
if( lC.hoverMark && ! modules.linear.fn.hoverTest( context, context.mouseX, context.mouseY, lC.hoverMark ) ) {
|
||||||
|
lC.hoverMark.color = lC.hoverMark.contributor_name ? '171,73,27' : '0,0,0';
|
||||||
|
lC.hoverMark = null;
|
||||||
|
// fade out any contributor quotes we might happen to be showing
|
||||||
|
$( '#contributor-quote-box:visible' ).fadeOut( 'fast' );
|
||||||
|
}
|
||||||
|
|
||||||
|
dLayer.clean();
|
||||||
|
// update scene marks && add more as needed
|
||||||
|
modules.linear.fn.updateScene( context, lC.scene.camera.position.x - 10000, lC.scene.camera.position.x + 10000 );
|
||||||
|
// cleanup the scene and tend to empty buffers
|
||||||
|
modules.linear.fn.updateBuffers( context, lC.scene.camera.position.x - 10000, lC.scene.camera.position.x + 10000 );
|
||||||
|
|
||||||
|
// render the scene
|
||||||
|
Mark.renderer.renderScene( lC.scene, { 'cursor': {x: context.mouseX, y: context.mouseY}, width: context.width, height: context.height } );
|
||||||
|
// ark.renderer.renderScene( lC.scene, dLayer.context, { x: context.mouseX, y: context.mouseY }, context.width, context.height, lC.playbackTimes );
|
||||||
|
|
||||||
|
// set the eventChange flag back to false -- a mouse/keyboard or playback event will need to set it back to true again before we'll render because of it
|
||||||
|
lC.eventChange = false
|
||||||
|
|
||||||
|
// cleanup playback times if necissary
|
||||||
|
for( mark in lC.scene.timers ) {
|
||||||
|
var now = ( new Date() ).getTime();
|
||||||
|
if( lC.scene.timers[mark].end < now ) {
|
||||||
|
delete lC.scene.timers[mark];
|
||||||
|
}
|
||||||
|
lC.eventChange = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
init: function( context, options ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// if this modules has already been initialized, update the options
|
||||||
|
if ( '$linear' in context.modules.linear ) {
|
||||||
|
// before we merge options, check if we need to dump our current data
|
||||||
|
if ( options['country_code'] != lC.country_code ) {
|
||||||
|
modules.linear.fn.dumpAllMarks( context );
|
||||||
|
}
|
||||||
|
// now our options into our context
|
||||||
|
$.extend( lC, lC, options );
|
||||||
|
// since merging won't replace null or undefined values, make sure we clean up after it
|
||||||
|
for( option in modules.linear.defaults ) {
|
||||||
|
if ( options[option] == null ) lC[option] = modules.linear.defaults[option];
|
||||||
|
}
|
||||||
|
// update the interface
|
||||||
|
modules.linear.fn.updateInterface( context );
|
||||||
|
// load our marks
|
||||||
|
modules.linear.fn.initMarks( context );
|
||||||
|
} else {
|
||||||
|
// allow defaults to be overriden
|
||||||
|
$.extend( lC, modules.linear.defaults, options );
|
||||||
|
// but not the cofig
|
||||||
|
$.extend( lC, lC, modules.linear.config );
|
||||||
|
|
||||||
|
// DOM setup
|
||||||
|
lC.$linear = $( '<div />' )
|
||||||
|
.addClass( "linear-container" );
|
||||||
|
context.$container
|
||||||
|
.append( lC.$linear );
|
||||||
|
|
||||||
|
// scene setup
|
||||||
|
lC.scene = new Mark.scene();
|
||||||
|
lC.cameraChange = { aX: 0, aY: 0, aZ: 0, vX: 0, vY: 0, vZ: 0 };
|
||||||
|
// layer setup
|
||||||
|
lC.layerManager = new Mark.layerManager( lC.$linear.get( 0 ) );
|
||||||
|
lC.layerManager.addLayer( 'drawingLayer' );
|
||||||
|
lC.scene.canvasContext = lC.layerManager.layers['drawingLayer'].context;
|
||||||
|
// trigger resize so our new layers are sized to fit
|
||||||
|
context.fn.trigger( 'resize' );
|
||||||
|
|
||||||
|
lC.initialized = true;
|
||||||
|
}
|
||||||
|
// load flaggings
|
||||||
|
lC.flaggings = context.fn.getData( 'markFlaggings' ) || {};
|
||||||
|
},
|
||||||
|
deinit: function( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
lC.$linear.fadeOut( 'fast', function () {
|
||||||
|
// remove all our layers
|
||||||
|
lC.layerManager.removeAll();
|
||||||
|
lC.$linear.remove();
|
||||||
|
lC.initialized = false;
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
initInterface: function( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// hide anything that needs data loaded into it
|
||||||
|
$( '#stats' )
|
||||||
|
.hide( );
|
||||||
|
// enable the controls
|
||||||
|
$( '#mark-browsing-zoom-in a, #mark-browsing-zoom-out a, #mark-browsing-next a, #mark-browsing-prev a' )
|
||||||
|
.click( function( e ){ e.preventDefault(); } )
|
||||||
|
.bind( 'mouseup mouseout', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ( $( this ).data( 'mouseDown' ) ) {
|
||||||
|
if( $( this ).is( '#mark-browsing-zoom-in a, #mark-browsing-zoom-out a' ) ) {
|
||||||
|
context.modules.linear.cameraChange.aZ = 0;
|
||||||
|
} else if( $( this ).is( '#mark-browsing-next a, #mark-browsing-prev a' ) ) {
|
||||||
|
context.modules.linear.cameraChange.aX = 0;
|
||||||
|
}
|
||||||
|
$( this ).data( 'mouseDown', false );
|
||||||
|
}
|
||||||
|
} )
|
||||||
|
.bind( 'mousedown', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
$( this ).data( 'mouseDown', true );
|
||||||
|
if( $( this ).is( '#mark-browsing-zoom-in a, #mark-browsing-zoom-out a' ) ) {
|
||||||
|
context.modules.linear.cameraChange.aZ = $( this ).is( '#mark-browsing-zoom-in a' ) ? 10 : -10;
|
||||||
|
} else if ( $( this ).is( '#mark-browsing-next a, #mark-browsing-prev a' ) ) {
|
||||||
|
context.modules.linear.cameraChange.aX = $( this ).is( '#mark-browsing-next a' ) ? 10 : -10;
|
||||||
|
// hide the mark information
|
||||||
|
modules.linear.fn.hideMarkInformation( context );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
// populate our country filter select box
|
||||||
|
context.fn.withCountryCodes( function ( countryCodes ) {
|
||||||
|
var $select = $( '#country-select' );
|
||||||
|
for( var i = 0; i < countryCodes.length; i++ ) {
|
||||||
|
var $option = $( '<option />' )
|
||||||
|
.val( countryCodes[i].code )
|
||||||
|
.text( countryCodes[i].name );
|
||||||
|
$select.append( $option );
|
||||||
|
}
|
||||||
|
$select.change( function ( ) {
|
||||||
|
var val = $( this ).val();
|
||||||
|
if( val.length != 2 && lC.country_code ) {
|
||||||
|
// redirect back to the unfiltered view
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/' );
|
||||||
|
} else if ( val.length == 2 && val != lC.country_code ) {
|
||||||
|
// redirect to linear mode with the new country code
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/country/' + val + '/' );
|
||||||
|
}
|
||||||
|
// return focus to the viz
|
||||||
|
$( this ).blur();
|
||||||
|
context.$container.focus();
|
||||||
|
} );
|
||||||
|
// select the current mark if we have it
|
||||||
|
if( lC.country_code ) $select.val( lC.country_code );
|
||||||
|
} );
|
||||||
|
|
||||||
|
// hide all the mark detial things
|
||||||
|
$( '#mark-information' ).hide();
|
||||||
|
// setup the mark details
|
||||||
|
$( '#mark-playback' )
|
||||||
|
.click( function ( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
modules.linear.fn.replayCurrentMark( context );
|
||||||
|
} );
|
||||||
|
$( '#mark-flag' )
|
||||||
|
.click( function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
modules.linear.fn.flagCurrentMark( context );
|
||||||
|
} );
|
||||||
|
// Click events for moderation mode
|
||||||
|
$( '#delete-mark' )
|
||||||
|
.click( function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
modules.linear.fn.deleteCurrentMark( context );
|
||||||
|
} );
|
||||||
|
$( '#approve-mark-checkbox' )
|
||||||
|
.change( function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
var shouldApprove = $(this).is(':checked');
|
||||||
|
modules.linear.fn.approveCurrentMark( context, shouldApprove );
|
||||||
|
} );
|
||||||
|
// setup sharing
|
||||||
|
$( '#twitter-share' ).socialShare( {
|
||||||
|
'share_url': 'http://twitter.com/share',
|
||||||
|
'share_params': { 'text': escape( 'Mozilla Firefox Mark Up. The internet is your creation. Show your support to keep it open and free. Make your mark.' ) }
|
||||||
|
} );
|
||||||
|
$( '#facebook-share' ).socialShare( {
|
||||||
|
'share_url': 'http://www.facebook.com/sharer.php',
|
||||||
|
'share_params': { 't': 'The internet is your creation. Show your support to keep it open and free. Make your mark.' }
|
||||||
|
} );
|
||||||
|
// run the interface update
|
||||||
|
modules.linear.fn.updateInterface( context );
|
||||||
|
// load our marks
|
||||||
|
modules.linear.fn.initMarks( context );
|
||||||
|
|
||||||
|
|
||||||
|
$("#sammy #country-select").selectBox({ autoWidth: false });
|
||||||
|
$("#sammy #contributor-select").selectBox({ autoWidth: false });
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
initMarks: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if ( lC.reference_mark && lC.reference_mark != "" ) {
|
||||||
|
// If we were passed a mark to start with, start there
|
||||||
|
if( lC.reference_mark in lC.marks ) {
|
||||||
|
// if we already have this mark, just jump to it
|
||||||
|
modules.linear.fn.jumpToMark( context, lC.reference_mark, lC.playback );
|
||||||
|
} else {
|
||||||
|
// load the mark and it's surrounding marks
|
||||||
|
modules.linear.fn.loadMarks( context, {
|
||||||
|
'reference': lC.reference_mark,
|
||||||
|
'include_forward': 20,
|
||||||
|
'include_back': 20,
|
||||||
|
'include_mark': 1,
|
||||||
|
'success': function ( data ) {
|
||||||
|
if( data.success ) {
|
||||||
|
// push the marks into the leftBuffer
|
||||||
|
modules.linear.fn.setupMarks( context, data.marks );
|
||||||
|
// and jump to our mark
|
||||||
|
modules.linear.fn.jumpToMark( context, lC.reference_mark, lC.playback );
|
||||||
|
} else {
|
||||||
|
// show the error message, with a link back to the main visualization link
|
||||||
|
}
|
||||||
|
lC.requestingMarks = false;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// otherwise start at the first mark
|
||||||
|
modules.linear.fn.loadMarks( context, {
|
||||||
|
'offset': 0,
|
||||||
|
'max': 20,
|
||||||
|
'success': function ( data ) {
|
||||||
|
if( data.success ) {
|
||||||
|
modules.linear.fn.setupMarks( context, data.marks );
|
||||||
|
modules.linear.fn.jumpToMark( context, data.marks[0].reference );
|
||||||
|
} else {
|
||||||
|
// show the error message, with a link back to the main visualization link
|
||||||
|
}
|
||||||
|
lC.requestingMarks = false;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// DOM updates that should run after every new request should go here
|
||||||
|
updateInterface: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// show the appropriate middle link
|
||||||
|
var userMark = context.fn.getData( 'userMark' );
|
||||||
|
if( userMark && ( lC.country_code ? ( userMark.country_code == lC.country_code ) : true ) ) {
|
||||||
|
$( '#your-mark-link' )
|
||||||
|
.attr( 'href', '#/' + lC.linear_root + '/' + context.fn.getData( 'userMark' ).reference )
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
$( '#your-mark-link' )
|
||||||
|
.hide();
|
||||||
|
}
|
||||||
|
// setup the stats
|
||||||
|
var options = {};
|
||||||
|
if( lC.country_code ) {
|
||||||
|
options['country_code'] = lC.country_code;
|
||||||
|
$( "#contributor-select" ).next().hide();
|
||||||
|
$( '#contributor-select-label' ).hide();
|
||||||
|
} else {
|
||||||
|
$( "#contributor-select" ).next().show();
|
||||||
|
$( '#contributor-select-label' ).show();
|
||||||
|
}
|
||||||
|
// if the country has changed, grab updated data
|
||||||
|
if( ! $( '#mark-browsing-options' ).is( '.country-' + ( lC.country_code ? lC.country_code : 'all' ) ) ) {
|
||||||
|
$.ajax( {
|
||||||
|
'url': '/requests/init_viz_data',
|
||||||
|
'data': options,
|
||||||
|
dataType: 'JSON',
|
||||||
|
success: function( data ) {
|
||||||
|
// set the class on the details to indicate country
|
||||||
|
$( '#mark-browsing-options' )
|
||||||
|
.removeAttr( 'class' )
|
||||||
|
.addClass( 'country-' + ( lC.country_code ? lC.country_code : 'all' ) );
|
||||||
|
// setup and show the stats
|
||||||
|
$( '#stats-number-of-marks' )
|
||||||
|
.text( data.total_marks );
|
||||||
|
$( '#stats-number-of-countries' )
|
||||||
|
.text( data.total_countries );
|
||||||
|
var now = new Date();
|
||||||
|
var then = new Date( data.first_mark_at );
|
||||||
|
var days = Math.ceil( ( now.getTime() - then.getTime() ) / ( 1000 * 60 * 60 * 24 ) );
|
||||||
|
$( '#stats-number-of-days' )
|
||||||
|
.text( days );
|
||||||
|
$( '#stats' )
|
||||||
|
.fadeIn( 'fast' );
|
||||||
|
if( lC.country_code ) {
|
||||||
|
$( '#first-mark-link' )
|
||||||
|
.attr( 'href', '#/' + lC.linear_root + '/country/' + lC.country_code + '/' + data.country_first_mark );
|
||||||
|
$( '#last-mark-link' )
|
||||||
|
.attr( 'href', '#/' + lC.linear_root + '/country/' + lC.country_code + '/' + data.country_last_mark );
|
||||||
|
} else {
|
||||||
|
$( '#first-mark-link' )
|
||||||
|
.attr( 'href', '#/' + lC.linear_root + '/' + data.first_mark );
|
||||||
|
$( '#last-mark-link' )
|
||||||
|
.attr( 'href', '#/' + lC.linear_root + '/' + data.last_mark );
|
||||||
|
}
|
||||||
|
// setup collapsibles
|
||||||
|
$( '.collapsible' ).collapsibleMod( { 'previewSelector': '.collapsed-preview' } );
|
||||||
|
// if the contributor box is empty, fill it
|
||||||
|
if( $( '#contributor-select option' ).size() == 1 ) {
|
||||||
|
var $select = $( '#contributor-select' );
|
||||||
|
if ( data.contributor_marks ) {
|
||||||
|
for( var i = 0; i < data.contributor_marks.length; i++ ) {
|
||||||
|
var $option = $( '<option />' )
|
||||||
|
.val( data.contributor_marks[i].reference )
|
||||||
|
.text( data.contributor_marks[i].contributor );
|
||||||
|
$select.append( $option );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$select.change( function ( ) {
|
||||||
|
var val = $( this ).val();
|
||||||
|
if( val.length != "label" ) {
|
||||||
|
// jump to this contributors mark
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/' + val );
|
||||||
|
}
|
||||||
|
// return focus to the viz
|
||||||
|
$( this ).blur();
|
||||||
|
context.$container.focus();
|
||||||
|
} );
|
||||||
|
if( lC.country_code ) {
|
||||||
|
options['country_code'] = lC.country_code;
|
||||||
|
$( "#contributor-select" ).next().hide();
|
||||||
|
$( '#contributor-select-label' ).hide();
|
||||||
|
} else {
|
||||||
|
$( "#contributor-select" ).next().show();
|
||||||
|
$( '#contributor-select-label' ).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dumpAllMarks: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
for( mark in lC.marks )
|
||||||
|
delete lC.marks[mark];
|
||||||
|
lC.scene.objects = [];
|
||||||
|
lC.leftBuffer = [];
|
||||||
|
lC.rightBuffer = [];
|
||||||
|
lC.moreRight = true;
|
||||||
|
lC.moreLeft = true;
|
||||||
|
// whenever we do this, we need to set the camera back to 0,0,-1000
|
||||||
|
lC.scene.camera.position.x = 0;
|
||||||
|
lC.scene.camera.position.y = 0;
|
||||||
|
lC.scene.camera.position.z = -1000;
|
||||||
|
},
|
||||||
|
// TODO -- add nonSequentialAllowed param for dumping non-overlapping sets when we're not doing a controlled update, ie first and last mark buttons
|
||||||
|
loadMarks: function( context, options ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
var callback = options.success;
|
||||||
|
delete options.success;
|
||||||
|
// pass the country code if we have one
|
||||||
|
if ( lC.country_code ) options.country_code = lC.country_code;
|
||||||
|
var url_to_load = options.reference ? '/requests/marks_by_reference' : '/requests/all_marks';
|
||||||
|
if (lC.is_flagged)
|
||||||
|
{
|
||||||
|
url_to_load = '/requests/marks_by_flagged';
|
||||||
|
}
|
||||||
|
// if we're loading based on a reference we dont have, we need to dump everything as we can't ensure we wont drop marks in between
|
||||||
|
if( options.reference && !( options.reference in lC.marks ) ) {
|
||||||
|
// if we're looking for a specific mark see if we already have that one
|
||||||
|
modules.linear.fn.dumpAllMarks( context );
|
||||||
|
context.fn.showLoader( $( '#loading-marks-msg' ).text(), 'overlay-light' );
|
||||||
|
} else if ( ! options.reference ) {
|
||||||
|
context.fn.showLoader( $( '#loading-marks-msg' ).text(), 'overlay-light' );
|
||||||
|
}
|
||||||
|
$.ajax( {
|
||||||
|
url: url_to_load,
|
||||||
|
data: options,
|
||||||
|
dataType: 'JSON'
|
||||||
|
} )
|
||||||
|
.success( callback )
|
||||||
|
.success( function ( data ) {
|
||||||
|
// hide the loader
|
||||||
|
context.fn.hideLoader();
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
setupMarks: function( context, marks ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// if this is empty, return
|
||||||
|
if( marks.length == 0 ) return;
|
||||||
|
// get rid of marks we've already got
|
||||||
|
for( var i = 0; i < marks.length; i++ ) {
|
||||||
|
if( marks[i].reference in lC.marks ) {
|
||||||
|
marks.shift( i, 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort our current marks so we can tell what buffer to load these into
|
||||||
|
var sortedMarks = [];
|
||||||
|
for ( var mark in lC.marks )
|
||||||
|
sortedMarks.push( [mark, lC.marks[mark].id] );
|
||||||
|
sortedMarks.sort( function( a, b ) { return a[1] - b[1] } );
|
||||||
|
|
||||||
|
// default to the right buffer
|
||||||
|
var buffer = sortedMarks.length == 0 || sortedMarks[0][1] < marks[0].id ? lC.rightBuffer: lC.leftBuffer;
|
||||||
|
// var buffer = sortedMarks.length > 0 && sortedMarks[0][1] > marks[0].id ? lC.rightBuffer : lC.leftBuffer;
|
||||||
|
var reverse = buffer == lC.leftBuffer ? true : false;
|
||||||
|
if( reverse ) marks.reverse();
|
||||||
|
// try to establish a previous mark by which we can position the new marks
|
||||||
|
var pMark = buffer.length > 0 ?
|
||||||
|
lC.marks[buffer[ reverse ? 0 : buffer.length - 1 ]] :
|
||||||
|
lC.scene.objects[ reverse ? 0 : lC.scene.objects.length - 1];
|
||||||
|
for ( var i = 0; i < marks.length; i++ ) {
|
||||||
|
// if we already have this one, on to the next one
|
||||||
|
if( marks[i].reference in lC.marks ) continue;
|
||||||
|
var points_obj = JSON.parse( marks[i].points_obj_simplified );
|
||||||
|
// do some validation to make sure this mark wont break the viz
|
||||||
|
if( !( 'strokes' in points_obj ) ||
|
||||||
|
points_obj.strokes.length == 0 ||
|
||||||
|
points_obj.strokes[0].length < 2 ) continue;
|
||||||
|
var mark = new Mark.gmlMark( points_obj.strokes, marks[i].reference, marks[i].country_code, marks[i].date_drawn, points_obj.rtl, marks[i].id, marks[i].is_approved );
|
||||||
|
if( marks[i].contributor ) {
|
||||||
|
mark.contributor_name = marks[i].contributor;
|
||||||
|
mark.extra_info = points_obj.extra_info;
|
||||||
|
mark.color = '171,73,27';
|
||||||
|
}
|
||||||
|
// if ( !lC.currentMark ) lC.currentMark = mark;
|
||||||
|
// stash this mark
|
||||||
|
lC.marks[mark.reference] = mark;
|
||||||
|
// position this mark relative to the last one
|
||||||
|
if ( pMark ) mark.positionRelativeTo( pMark, reverse );
|
||||||
|
|
||||||
|
if( reverse ) {
|
||||||
|
buffer.unshift( mark.reference );
|
||||||
|
} else {
|
||||||
|
buffer.push( mark.reference );
|
||||||
|
}
|
||||||
|
pMark = mark;
|
||||||
|
|
||||||
|
}
|
||||||
|
// reset our ordere marks array
|
||||||
|
// modules.linear.fn.updatedOrderedMarks( context );
|
||||||
|
},
|
||||||
|
// attempts to refill a buffer that's running low
|
||||||
|
refillBuffer: function( context, buffer ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( lC.requestingMarks ) return;
|
||||||
|
lC.requestingMarks = true;
|
||||||
|
var isLeft = buffer == lC.leftBuffer;
|
||||||
|
var lastMark = null;
|
||||||
|
lastMark = buffer.length > 0 ?
|
||||||
|
lC.marks[buffer[ isLeft ? 0 : buffer.length - 1 ]] :
|
||||||
|
lC.scene.objects[ isLeft ? 0 : lC.scene.objects.length - 1];
|
||||||
|
modules.linear.fn.loadMarks( context, {
|
||||||
|
'reference': lastMark.reference,
|
||||||
|
'include_forward': isLeft ? 0 : 20,
|
||||||
|
'include_back': isLeft ? 20 : 0,
|
||||||
|
'include_mark': 0,
|
||||||
|
'success': function ( data ) {
|
||||||
|
if( data.success ) {
|
||||||
|
// push the marks into the leftBuffer
|
||||||
|
modules.linear.fn.setupMarks( context, data.marks );
|
||||||
|
// if we got back less than we asked for, assume we're at the end
|
||||||
|
if ( data.marks.length == 0 ) {
|
||||||
|
lC[ isLeft ? 'moreLeft' : 'moreRight'] = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// if we got an error, assume we're at the end and don't allow more to be loaded
|
||||||
|
lC[ isLeft ? 'moreLeft' : 'moreRight'] = false;
|
||||||
|
}
|
||||||
|
lC.requestingMarks = false;
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
// moves marks from the display to the buffers
|
||||||
|
// also will grab more marks if a buffer length sinks below a threshold
|
||||||
|
updateBuffers: function( context, xMin, xMax ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( lC.scene.objects.length == 0 ) return;
|
||||||
|
// look for marks that need moved into the left buffer
|
||||||
|
var mark = lC.scene.objects[0];
|
||||||
|
while( mark && mark.position.x + mark.bWidth < xMin ) {
|
||||||
|
lC.leftBuffer.push( lC.scene.objects.shift().reference );
|
||||||
|
mark = lC.scene.objects[0];
|
||||||
|
}
|
||||||
|
// look for marks that need moved into the right buffer
|
||||||
|
mark = lC.scene.objects[lC.scene.objects.length - 1];
|
||||||
|
while( mark && mark.position.x > xMax ) {
|
||||||
|
lC.rightBuffer.unshift( lC.scene.objects.pop().reference );
|
||||||
|
mark = lC.scene.objects[lC.scene.objects - 1];
|
||||||
|
}
|
||||||
|
// if either of our buffers are running low, load more marks
|
||||||
|
if ( lC.leftBuffer.length < 5 && lC.scene.objects.length > 0 && lC.moreLeft && !lC.requestingMarks ) {
|
||||||
|
modules.linear.fn.refillBuffer( context, lC.leftBuffer );
|
||||||
|
} else if ( lC.rightBuffer.length < 5 && lC.scene.objects.length > 0 && lC.moreRight && !lC.requestingMarks ) {
|
||||||
|
modules.linear.fn.refillBuffer( context, lC.rightBuffer );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// moves marks from the buffers to the display
|
||||||
|
updateScene: function( context, xMin, xMax) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( lC.rightBuffer.length > 0 ) {
|
||||||
|
// look for marks that need added from the right buffer
|
||||||
|
var mark = lC.marks[lC.rightBuffer[0]];
|
||||||
|
while( mark && mark.position && mark.position.x < xMax ) {
|
||||||
|
lC.scene.objects.push( lC.marks[lC.rightBuffer.shift()] );
|
||||||
|
mark = lC.rightBuffer[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( lC.leftBuffer.length > 0 ) {
|
||||||
|
// look for marks that need added from the left buffer
|
||||||
|
var mark = lC.marks[lC.leftBuffer[lC.leftBuffer.length - 1]];
|
||||||
|
while( mark && mark.position && mark.position.x + mark.bWidth > xMin ) {
|
||||||
|
lC.scene.objects.unshift( lC.marks[lC.leftBuffer.pop()] );
|
||||||
|
mark = lC.leftBuffer[lC.leftBuffer.length - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
jumpToMark: function( context, reference, playback ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// find the mark
|
||||||
|
var oldMark = lC.currentMark;
|
||||||
|
lC.currentMark = lC.marks[reference];
|
||||||
|
// delay playback
|
||||||
|
if ( playback ) {
|
||||||
|
var wayLater = ( new Date() ).getTime() *2;
|
||||||
|
lC.scene.timers[reference] = { 'start': wayLater, 'end': wayLater + lC.currentMark.maxTime, 'speed': 1 };
|
||||||
|
}
|
||||||
|
modules.linear.fn.centerCurrentMark( context, function () {
|
||||||
|
// if we're playing it back, play it back
|
||||||
|
if( playback ) modules.linear.fn.replayCurrentMark( context );
|
||||||
|
// fade up those beautiful details if they're not already shown
|
||||||
|
modules.linear.fn.showMarkInformation( context );
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
// unused but maybe helpful at some point?
|
||||||
|
// updatedOrderedMarks: function( context ) {
|
||||||
|
// var lC = context.modules.linear;
|
||||||
|
// var sortedMarks = [];
|
||||||
|
// for ( var mark in lC.marks )
|
||||||
|
// sortedMarks.push( [mark, lC.marks[mark].id] );
|
||||||
|
// sortedMarks.sort( function( a, b ) { return a[1] - b[1] } );
|
||||||
|
// // clear it out first
|
||||||
|
// lC.orderedMarks = [];
|
||||||
|
// for( var i = 0; i < sortedMarks.length; i++ ) {
|
||||||
|
// lC.orderedMarks.push( sortedMarks[i][0] );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// nextMark: function( context ) {
|
||||||
|
// var lC = context.modules.linear;
|
||||||
|
// var next = lC.orderedMarks[lC.orderedMarks.indexOf( lC.currentMark.reference ) + 1];
|
||||||
|
// if ( next ) {
|
||||||
|
// modules.linear.fn.jumpToMark( context, next );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// prevMark: function( context ) {
|
||||||
|
// var lC = context.modules.linear;
|
||||||
|
// var prev = lC.orderedMarks[lC.orderedMarks.indexOf( lC.currentMark.reference ) - 1];
|
||||||
|
// if ( prev ) {
|
||||||
|
// modules.linear.fn.jumpToMark( context, prev );
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
closestMark: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
var retM = lC.scene.objects[0];
|
||||||
|
for( var i = 1; i < lC.scene.objects.length; i++ ) {
|
||||||
|
var nextM = lC.scene.objects[i];
|
||||||
|
var d = Math.abs( lC.scene.camera.position.x - ( nextM.position.x + ( nextM.bWidth / 2 ) ) );
|
||||||
|
var lastD = Math.abs( lC.scene.camera.position.x - ( retM.position.x + ( retM.bWidth / 2 ) ) );
|
||||||
|
if( d < lastD ) retM = nextM;
|
||||||
|
}
|
||||||
|
return retM;
|
||||||
|
},
|
||||||
|
// wrapper for the hit test method that offers preference to the optional curHoveredMark arg
|
||||||
|
hoverTest: function( context, x, y, curHoveredMark ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// check if we're still over the hover mark
|
||||||
|
if( curHoveredMark &&
|
||||||
|
curHoveredMark.renderedBounds &&
|
||||||
|
x >= curHoveredMark.renderedBounds.minX &&
|
||||||
|
x <= curHoveredMark.renderedBounds.maxX &&
|
||||||
|
y >= curHoveredMark.renderedBounds.minY &&
|
||||||
|
y <= curHoveredMark.renderedBounds.maxY)
|
||||||
|
return curHoveredMark;
|
||||||
|
|
||||||
|
// if that didn't work we need to deffer to hit test
|
||||||
|
return modules.linear.fn.hitTest( context, x, y );
|
||||||
|
},
|
||||||
|
hitTest: function( context, x, y ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// loop through displayed marks, see if any match these coords
|
||||||
|
for( var i = 0; i < lC.scene.objects.length; i++ ) {
|
||||||
|
if( lC.scene.objects[i].renderedBounds &&
|
||||||
|
x >= lC.scene.objects[i].renderedBounds.minX &&
|
||||||
|
x <= lC.scene.objects[i].renderedBounds.maxX &&
|
||||||
|
y >= lC.scene.objects[i].renderedBounds.minY &&
|
||||||
|
y <= lC.scene.objects[i].renderedBounds.maxY ) {
|
||||||
|
return lC.scene.objects[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
showMarkInformation: function( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( !lC.currentMark ) return false;
|
||||||
|
var mark = lC.currentMark;
|
||||||
|
// update the information
|
||||||
|
$( '#mark-id' ).text( mark.id );
|
||||||
|
var d = new Date( mark.time );
|
||||||
|
// get our (hopefully) translated month abbreviation
|
||||||
|
var dateString = [];
|
||||||
|
dateString.push( $( '#month-abreviations li:eq(' + d.getMonth() + ')' ).text() + " " + d.getDate() );
|
||||||
|
dateString.push( d.getHours() + ":" + ( String(d.getMinutes()).length == 1 ? "0" + d.getMinutes() : d.getMinutes() ) );
|
||||||
|
if( mark.country_code ) {
|
||||||
|
context.fn.withCountryCodes( function ( countries ) {
|
||||||
|
$( '#mark-country' ).text( " / " + countries[mark.country_code] );
|
||||||
|
} );
|
||||||
|
} else {
|
||||||
|
$( '#mark-country' ).text( "" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// set the contributor name, if we've got it
|
||||||
|
if( mark.contributor_name ) {
|
||||||
|
$( '#mark-contributor-name' ).text( "- " + mark.contributor_name );
|
||||||
|
$( '#mark-flag' ).hide();
|
||||||
|
$( '#contributor-quote' )
|
||||||
|
.text( mark.extra_info )
|
||||||
|
.html( "“" + $( '#contributor-quote' ).text() + "”" );
|
||||||
|
} else {
|
||||||
|
$( '#mark-contributor-name, #contributor-quote' ).text( "" );
|
||||||
|
$( '#mark-flag' ).show();
|
||||||
|
}
|
||||||
|
|
||||||
|
$( '#mark-timestamp' ).text( dateString.join( " / " ) );
|
||||||
|
$( '#url-share input' ).val( window.location.href );
|
||||||
|
// update the sharing links
|
||||||
|
if (lC.linear_root != "moderate")
|
||||||
|
{
|
||||||
|
$( '#twitter-share' )
|
||||||
|
.data( 'socialShare-context' ).share_params['url'] = window.location.href;
|
||||||
|
$( '#facebook-share' )
|
||||||
|
.data( 'socialShare-context' ).share_params['u'] = window.location.href;
|
||||||
|
}
|
||||||
|
// Update approved state if we're moderating // URK - hate this condition // Watch out // TODO
|
||||||
|
if (lC.linear_root == "moderate")
|
||||||
|
{
|
||||||
|
$("#approve-mark-checkbox").attr('checked', mark.is_approved);
|
||||||
|
}
|
||||||
|
// give the flag the appropriate class
|
||||||
|
if( lC.currentMark.reference in lC.flaggings ) {
|
||||||
|
$( '#mark-flag').addClass( 'disabled' );
|
||||||
|
} else {
|
||||||
|
$( '#mark-flag').removeClass( 'disabled' );
|
||||||
|
}
|
||||||
|
// animate it in if it's hidden
|
||||||
|
$( '#mark-information' ).fadeIn( 'fast' );
|
||||||
|
},
|
||||||
|
hideMarkInformation: function( context ) {
|
||||||
|
$( '#mark-information' ).fadeOut( 'fast' );
|
||||||
|
},
|
||||||
|
replayCurrentMark: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
var now = ( new Date() ).getTime();
|
||||||
|
lC.eventChange = true;
|
||||||
|
lC.scene.timers[lC.currentMark.reference] = { 'start': now, 'end': now + lC.currentMark.maxTime, 'speed': 1 };
|
||||||
|
},
|
||||||
|
flagCurrentMark: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// if this user has already flagged this mark, return
|
||||||
|
if( lC.currentMark.reference in lC.flaggings ) return;
|
||||||
|
$.ajax( {
|
||||||
|
url: '/requests/flag_mark',
|
||||||
|
data: {
|
||||||
|
'reference': lC.currentMark.reference
|
||||||
|
},
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
success: function( data ) {
|
||||||
|
// change the flag icon's class
|
||||||
|
$( '#mark-flag').addClass( 'disabled' );
|
||||||
|
// store the data that this user flagged this mark
|
||||||
|
lC.flaggings[lC.currentMark.reference] = true;
|
||||||
|
context.fn.storeData( 'markFlaggings', lC.flaggings );
|
||||||
|
},
|
||||||
|
error: function ( data ) {
|
||||||
|
// TODO translate this msg
|
||||||
|
context.fn.showError( "Sorry, an error occured." );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
},
|
||||||
|
deleteCurrentMark: function ( context ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// ajax request goes here, with error handling
|
||||||
|
$.ajax( {
|
||||||
|
url: '/requests/delete_mark',
|
||||||
|
data: {
|
||||||
|
'reference': lC.currentMark.reference
|
||||||
|
},
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
success: function( data ) {
|
||||||
|
|
||||||
|
var deletedMarkReference = lC.currentMark.reference,
|
||||||
|
deletedMarkIndex = null;
|
||||||
|
// Delete current mark from marks data
|
||||||
|
delete lC.marks[lC.currentMark.reference];
|
||||||
|
lC.currentMark = null;
|
||||||
|
|
||||||
|
// remove the mark from the scene and reposition the rest
|
||||||
|
for ( var i=0; i < lC.scene.objects.length; i++ ) {
|
||||||
|
// start at the left and run through until you find the deleted mark
|
||||||
|
if( !deletedMarkIndex && lC.scene.objects[i].reference != deletedMarkReference ) continue;
|
||||||
|
// remove it
|
||||||
|
if( !deletedMarkIndex ) {
|
||||||
|
deletedMarkIndex = i;
|
||||||
|
lC.scene.objects.splice( i, 1 );
|
||||||
|
// set current mark to the next one
|
||||||
|
lC.currentMark = lC.scene.objects[i];
|
||||||
|
}
|
||||||
|
// reposition everything after it
|
||||||
|
if ( i == 0 ) {
|
||||||
|
lC.scene.objects[i].positionToStart( );
|
||||||
|
} else {
|
||||||
|
lC.scene.objects[i].positionRelativeTo( lC.scene.objects[i-1] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update the URL
|
||||||
|
context.app.setLocation( '#/' + lC.linear_root + '/' + lC.currentMark.reference );
|
||||||
|
|
||||||
|
lC.eventChange = true;
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function ( data ) {
|
||||||
|
// TODO translate this msg
|
||||||
|
context.fn.showError( "Sorry, an error occured." );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
approveCurrentMark: function ( context, shouldApprove ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
// ajax request goes here, with error handling
|
||||||
|
$.ajax( {
|
||||||
|
url: '/requests/approve_mark',
|
||||||
|
data: {
|
||||||
|
'reference': lC.currentMark.reference,
|
||||||
|
'should_approve': shouldApprove
|
||||||
|
},
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'JSON',
|
||||||
|
success: function( data ) {
|
||||||
|
// TODO
|
||||||
|
console.log( data );
|
||||||
|
// Update approved status locally
|
||||||
|
lC.currentMark.is_approved = shouldApprove;
|
||||||
|
},
|
||||||
|
error: function ( data ) {
|
||||||
|
// TODO translate this msg
|
||||||
|
context.fn.showError( "Sorry, an error occured." );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
centerCurrentMark: function( context, callback ) {
|
||||||
|
var lC = context.modules.linear;
|
||||||
|
if( !lC.currentMark ) return false;
|
||||||
|
modules.linear.fn.showMarkInformation( context );
|
||||||
|
// stop movement
|
||||||
|
lC.cameraChange.aX = 0;
|
||||||
|
lC.cameraChange.vX = 0;
|
||||||
|
lC.cameraChange.aZ = 0;
|
||||||
|
lC.cameraChange.vZ = 0;
|
||||||
|
// tween the camera to the mark
|
||||||
|
var speed = Math.abs( lC.currentMark.position.x - lC.scene.camera.position.x ) / 2;
|
||||||
|
var speed = Math.min( 8000, Math.max( 1000, speed) );
|
||||||
|
var tween = 'cameraEase' in lC.tweens ? lC.tweens['cameraEase'] : new TWEEN.Tween( lC.scene.camera.position );
|
||||||
|
tween
|
||||||
|
.to( {
|
||||||
|
x: lC.currentMark.position.x + ( lC.currentMark.bWidth / 2 ),
|
||||||
|
y: lC.currentMark.position.y + ( lC.currentMark.bHeight / 2 ),
|
||||||
|
z: lC.currentMark.position.z - 1000 }, speed )
|
||||||
|
.onComplete( function( ) {
|
||||||
|
delete lC.tweens['cameraEase'];
|
||||||
|
if ( typeof callback === "function" ) callback( this );
|
||||||
|
} )
|
||||||
|
.easing( TWEEN.Easing.Quartic.EaseInOut )
|
||||||
|
.start();
|
||||||
|
lC.tweens['cameraEase'] = tween;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}( jQuery ) );
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* A generic plugin to assist with those fucking social media buttons we have to put on every god damn website these days.
|
||||||
|
*
|
||||||
|
* Actually, you know what? This is more basic than that. It just opens up a new window with the dimensions you specify
|
||||||
|
* and the URL you specify, with the GET params you specify.
|
||||||
|
*
|
||||||
|
* That just happens to be the basic functionality you need to impliment a twitter or facebook share button.
|
||||||
|
*
|
||||||
|
* USEFUL FACEBOOK INFO:
|
||||||
|
* - url: http://www.facebook.com/sharer.php
|
||||||
|
* - required params:
|
||||||
|
* - u: the url you want to share
|
||||||
|
* - t: the title of the link you want to share
|
||||||
|
*
|
||||||
|
* USEFUL TWITTER INFO:
|
||||||
|
* - url: http://twitter.com/share
|
||||||
|
* - params:
|
||||||
|
* - url: the url you want to share
|
||||||
|
* - text: the message you want to tweet with this url
|
||||||
|
* - via: your twitter account, w/o the @, if you want attributed
|
||||||
|
* - related: a related account. Can also format it with a title like 'adammiller: People who dislike social media buttons'
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
( function( $ ) {
|
||||||
|
|
||||||
|
$.socialShare = {
|
||||||
|
cfg: {
|
||||||
|
'$link': null,
|
||||||
|
'share_url': 'http://twitter.com/share',
|
||||||
|
'share_title': 'Share on Twitter',
|
||||||
|
'share_params': {},
|
||||||
|
'popupWidth': 550,
|
||||||
|
'popupHeight': 450
|
||||||
|
},
|
||||||
|
fn: {
|
||||||
|
'init': function ( container, options ) {
|
||||||
|
var $this = $( container );
|
||||||
|
var context = $.extend( {}, $.socialShare.cfg, options );
|
||||||
|
|
||||||
|
context.$link = $this;
|
||||||
|
|
||||||
|
context.$link.bind( 'click', function( e ) {
|
||||||
|
e.preventDefault();
|
||||||
|
$.socialShare.fn.share( context );
|
||||||
|
} );
|
||||||
|
|
||||||
|
$this.data( 'socialShare-context', context );
|
||||||
|
},
|
||||||
|
'shareURL': function ( context ){
|
||||||
|
var params = [];
|
||||||
|
for( param in context.share_params ) {
|
||||||
|
params.push( param + '=' + escape( context.share_params[param] ) );
|
||||||
|
}
|
||||||
|
return context.share_url + '?' + params.join( "&" );
|
||||||
|
},
|
||||||
|
'share': function ( context ) {
|
||||||
|
// open the pop up
|
||||||
|
window.open(
|
||||||
|
$.socialShare.fn.shareURL( context ),
|
||||||
|
context.share_title,
|
||||||
|
'height=' + context.popupHeight + ',width=' + context.popupWidth
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.fn.socialShare = function( options ) {
|
||||||
|
return $( this ).each( function () {
|
||||||
|
$.socialShare.fn.init( this, options );
|
||||||
|
} );
|
||||||
|
};
|
||||||
|
|
||||||
|
} )( jQuery );
|
|
@ -0,0 +1,822 @@
|
||||||
|
/*
|
||||||
|
|
||||||
|
jQuery selectBox (version 0.1.6)
|
||||||
|
|
||||||
|
A cosmetic, styleable replacement for SELECT elements
|
||||||
|
|
||||||
|
Homepage: http://abeautifulsite.net/blog/2011/01/jquery-selectbox-plugin/
|
||||||
|
Demo page: http://labs.abeautifulsite.net/projects/js/jquery/selectBox/
|
||||||
|
|
||||||
|
Copyright 2011 A Beautiful Site, LLC.
|
||||||
|
|
||||||
|
|
||||||
|
License:
|
||||||
|
|
||||||
|
Licensed under both the MIT license and the GNU GPL (same as jQuery)
|
||||||
|
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
Link to the JS file:
|
||||||
|
|
||||||
|
<script src="jquery.ui-selectbox.min.js" type="text/javascript"></script>
|
||||||
|
|
||||||
|
Add the CSS file (or append contents of your own):
|
||||||
|
|
||||||
|
<link href="jquery.ui-selectbox.css" rel="stylesheet" type="text/css" />
|
||||||
|
|
||||||
|
To create:
|
||||||
|
|
||||||
|
$("SELECT").selectBox()
|
||||||
|
|
||||||
|
To create with options:
|
||||||
|
|
||||||
|
$("SELECT").selectBox({
|
||||||
|
autoWidth: [true|false]
|
||||||
|
});
|
||||||
|
|
||||||
|
To destroy:
|
||||||
|
|
||||||
|
$("SELECT").selectBox('destroy');
|
||||||
|
|
||||||
|
To update the options on the fly:
|
||||||
|
|
||||||
|
$("SELECT").selectBox('setOptions', {
|
||||||
|
|
||||||
|
// Options are created like this
|
||||||
|
'value' : 'displayText',
|
||||||
|
'value' : 'displayText',
|
||||||
|
|
||||||
|
// Optgroups are created like this
|
||||||
|
'optgroupLabel' : {
|
||||||
|
'value' : 'displayText',
|
||||||
|
'value' : 'displayText'
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
To change the value:
|
||||||
|
|
||||||
|
$("SELECT").selectBox('value', 'optionValue');
|
||||||
|
|
||||||
|
Note: you can use any valid selector in lieu of "SELECT".
|
||||||
|
|
||||||
|
|
||||||
|
Events:
|
||||||
|
|
||||||
|
The focus, blur, and change events fire on the *orignal* SELECT element.
|
||||||
|
|
||||||
|
|
||||||
|
Freebies:
|
||||||
|
|
||||||
|
- Includes keyboard support (tab in/out, arrows, page up/down, home/end, enter/esc)
|
||||||
|
|
||||||
|
- Supports jQuery UI .ui-corner-x classes (http://jqueryui.com/docs/Theming/API#Corner_Radius_helpers)
|
||||||
|
|
||||||
|
- Uses CSS3 techniques (fully customizable via CSS)
|
||||||
|
|
||||||
|
|
||||||
|
Change log:
|
||||||
|
|
||||||
|
v0.1 (2011-01-24) - Initial release
|
||||||
|
v0.1.1 (2011-02-09) - Added setOptions method for changing options on the fly
|
||||||
|
- UI control now inherits all classes of the original control
|
||||||
|
v0.1.2 (2011-02-23) - UI control now inherits the style and title attribute of the original control
|
||||||
|
v0.1.3 (2011-02-24) - Added autoWidth option to simulate default browser behavior; fixed bug
|
||||||
|
that caused the UI control to display as inline instead of inline-block
|
||||||
|
after destroy/create; fixed version numbers (old 0.2 = 0.1.1, old 0.3 = 0.1.2)
|
||||||
|
v0.1.4 (2011-02-25) - Added 'value' method; added return $(this) to setOptions method
|
||||||
|
v0.1.5 (2011-03-11) - Fixed bug where special HTML characters did not get escaped properly in the UI control
|
||||||
|
v0.1.6 (2011-03-21) - Fixed bug where initial settings were forgotten when setOptions was called
|
||||||
|
|
||||||
|
Known issues:
|
||||||
|
|
||||||
|
- The change event fires every time an option is changed using the keyboard. This differs
|
||||||
|
from the way change events occur on normal select elements (on blur).
|
||||||
|
|
||||||
|
- Disabled controls will technically accept focus (but no event will be trigger) when tabbed
|
||||||
|
over. This differs from the default browser behavior where the control would normally be
|
||||||
|
skipped.
|
||||||
|
|
||||||
|
- If using the keyboard while the mouse is hovering over the dropdown, the hover events
|
||||||
|
sometimes conflict making it seem like the keyboard selection is buggy (move the mouse
|
||||||
|
out and the behavior goes away)
|
||||||
|
|
||||||
|
- The plugin cannot poll for changes to the original control (i.e. disabling it dynamically).
|
||||||
|
Since the dropdown gets re-generated each time it is shown, this isn't an issue with
|
||||||
|
optgroups and options. Calling scripts should be aware of this.
|
||||||
|
|
||||||
|
- Safari doesn't currently allow focus via tabbing (Chrome does; possible WebKit bug?)
|
||||||
|
|
||||||
|
- Does not support multiple="multiple"
|
||||||
|
|
||||||
|
- Not tested in IE6
|
||||||
|
|
||||||
|
|
||||||
|
Wish list:
|
||||||
|
|
||||||
|
- Enforce that dropdowns always appear in the viewport
|
||||||
|
|
||||||
|
- Predictive selection (auto-selecting of elements while typing)
|
||||||
|
|
||||||
|
Issue: keypress doesn't fire on non-input elements (only in Firefox,
|
||||||
|
but this is against the standard), so we have to use the keydown event.
|
||||||
|
There isn't a reliable way to map extended (i.e. non-ASCII) characters
|
||||||
|
without using the keypress event.
|
||||||
|
|
||||||
|
Aside from that, it should be easy enough to set a timer that waits
|
||||||
|
about two seconds after each keystroke before clearing the filter.
|
||||||
|
Then we just select the first option that matches the filter. This
|
||||||
|
feature should be available with or without the dropdown showing.
|
||||||
|
|
||||||
|
*/
|
||||||
|
if(jQuery) (function($) {
|
||||||
|
|
||||||
|
$.extend($.fn, {
|
||||||
|
|
||||||
|
selectBox: function(o, data) {
|
||||||
|
|
||||||
|
|
||||||
|
var _show = function(event) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
|
||||||
|
// Don't show disabled controls
|
||||||
|
if( $(control).hasClass('ui-selectBox-disabled') ) return false;
|
||||||
|
|
||||||
|
// Hide if the control is selected when the dropdown is already open
|
||||||
|
if( $(control).hasClass('ui-selectBox-focus') && $("#ui-selectBox-dropdown").size() === 1 ) {
|
||||||
|
_hide(event, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove focus and dropdown from any/all other selectBoxes
|
||||||
|
$('.ui-selectBox').not(control).trigger('blur');
|
||||||
|
|
||||||
|
_focus(event);
|
||||||
|
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
// Generate the dropdown
|
||||||
|
$("#ui-selectBox-dropdown").remove();
|
||||||
|
var dropdown = $('<div id="ui-selectBox-dropdown" class="ui-corner-bottom" />');
|
||||||
|
var options = $('<ul />');
|
||||||
|
|
||||||
|
if( $(select).children('optgroup').size() === 0 ) {
|
||||||
|
|
||||||
|
$(select).children('option').each( function() {
|
||||||
|
var text = $(this).text() !== '' ? $(this).text() : '\u00A0';
|
||||||
|
var extraClasses = '';
|
||||||
|
if( $(this).attr('disabled') ) extraClasses += ' ui-selectBox-disabled';
|
||||||
|
$(options).append('<li class="ui-selectBox-option' + extraClasses + '">' + _htmlspecialchars(text) + '</li>');
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
$(dropdown).addClass('ui-selectBox-hasOptgroups');
|
||||||
|
|
||||||
|
$(select).children('optgroup').each( function() {
|
||||||
|
$(options).append('<li class="ui-selectBox-optgroup">' + _htmlspecialchars($(this).attr('label')) + '</li>');
|
||||||
|
$(this).children('option').each( function() {
|
||||||
|
var text = $(this).text() !== '' ? $(this).text() : '\u00A0';
|
||||||
|
var extraClasses = '';
|
||||||
|
if( $(this).attr('disabled') ) extraClasses += ' ui-selectBox-disabled';
|
||||||
|
$(options).append('<li class="ui-selectBox-option' + extraClasses + '">' + _htmlspecialchars(text) + '</li>');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the options
|
||||||
|
$(dropdown).append(options);
|
||||||
|
|
||||||
|
// Select the appropriate option
|
||||||
|
var selectedIndex = $(select)[0].selectedIndex;
|
||||||
|
$(dropdown).find('LI.ui-selectBox-option').eq(selectedIndex).addClass('ui-selectBox-initial ui-selectBox-current');
|
||||||
|
|
||||||
|
// Add option events
|
||||||
|
$(dropdown).find('LI.ui-selectBox-option').hover( function() {
|
||||||
|
$(dropdown).find('.ui-selectBox-current').removeClass('ui-selectBox-current');
|
||||||
|
$(this).addClass('ui-selectBox-current');
|
||||||
|
}, function() {
|
||||||
|
$(this).removeClass('ui-selectBox-current');
|
||||||
|
}).click( { select: select, control: control }, function(event) {
|
||||||
|
_select(event);
|
||||||
|
}).mouseup( { select: select, control: control }, function(event) {
|
||||||
|
$(event.target).trigger('click');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Position and display
|
||||||
|
$('BODY').append(dropdown);
|
||||||
|
var cPos = $(control).offset();
|
||||||
|
var cHeight = $(control).outerHeight();
|
||||||
|
var cWidth = $(control).outerWidth();
|
||||||
|
|
||||||
|
var borderAdjustment = parseInt($(dropdown).css('borderLeftWidth')) + parseInt($(dropdown).css('borderRightWidth'));
|
||||||
|
|
||||||
|
$(dropdown).css({
|
||||||
|
position: 'absolute',
|
||||||
|
zIndex: '999999',
|
||||||
|
top: cPos.top + cHeight,
|
||||||
|
left: cPos.left,
|
||||||
|
width: cWidth - borderAdjustment
|
||||||
|
}).show();
|
||||||
|
|
||||||
|
$(control).removeClass('ui-corner-all').addClass('ui-corner-top');
|
||||||
|
|
||||||
|
_disableSelection(dropdown);
|
||||||
|
_dropdownScrollFix(true);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _hide = function(event, preventBlur) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
|
||||||
|
$("#ui-selectBox-dropdown").remove();
|
||||||
|
$(control).removeClass('ui-corner-top').addClass('ui-corner-all');
|
||||||
|
|
||||||
|
if( !preventBlur ) {
|
||||||
|
_blur(event);
|
||||||
|
} else {
|
||||||
|
$(control).focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _select = function(event, option) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
|
||||||
|
option = option ? option : event.target;
|
||||||
|
|
||||||
|
if( $(option).hasClass('ui-selectBox-disabled') ) return false;
|
||||||
|
|
||||||
|
var oldSelectedIndex = $(select)[0].selectedIndex;
|
||||||
|
$('#ui-selectBox-dropdown .ui-selectBox-optgroup').remove();
|
||||||
|
var newSelectedIndex = $('#ui-selectBox-dropdown').find('LI.ui-selectBox-current').index();
|
||||||
|
|
||||||
|
if( oldSelectedIndex !== newSelectedIndex ) {
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
$(control).find('.ui-selectBox-label').text( $(option).text() );
|
||||||
|
$(select).trigger('change');
|
||||||
|
}
|
||||||
|
|
||||||
|
_hide(event, true);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _focus = function(event) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
|
||||||
|
if( $(control).hasClass('ui-selectBox-disabled') ) return true;
|
||||||
|
if( $(control).hasClass('ui-selectBox-focus') ) return false;
|
||||||
|
|
||||||
|
// Remove dropdown and other focuses
|
||||||
|
$(".ui-selectBox.ui-selectBox-focus").removeClass("ui-selectBox-focus");
|
||||||
|
$("#ui-selectBox-dropdown").remove();
|
||||||
|
|
||||||
|
$(control).addClass('ui-selectBox-focus');
|
||||||
|
$(document).bind('mousedown', { select: select, control: control }, _blur);
|
||||||
|
$(document).bind('keydown', { select: select, control: control }, _key);
|
||||||
|
$(select).trigger('focus');
|
||||||
|
$(control).focus();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _blur = function(event) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
|
||||||
|
// Prevent blur if the click was on the dropdown
|
||||||
|
if( event.target.id === 'ui-selectBox-dropdown' ||
|
||||||
|
$(event.target).parents('#ui-selectBox-dropdown').size() === 1 ) {
|
||||||
|
$(control).trigger('focus');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $(control).hasClass('ui-selectBox-focus') ) {
|
||||||
|
$(control).removeClass('ui-selectBox-focus');
|
||||||
|
$(document).unbind('mousedown', _blur);
|
||||||
|
$(document).unbind('keydown', _key);
|
||||||
|
$(select).trigger('blur');
|
||||||
|
_hide(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _key = function(event) {
|
||||||
|
|
||||||
|
var select = event.data.select;
|
||||||
|
var control = event.data.control;
|
||||||
|
var dropdown = $("#ui-selectBox-dropdown");
|
||||||
|
|
||||||
|
if( $(control).hasClass('ui-selectBox-disabled') ) return false;
|
||||||
|
|
||||||
|
switch( event.keyCode ) {
|
||||||
|
|
||||||
|
case 9: // tab
|
||||||
|
_blur(event);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13: // enter
|
||||||
|
|
||||||
|
if( $(dropdown).size() === 0 ) return false;
|
||||||
|
|
||||||
|
var siblings = $(dropdown).find('.ui-selectBox-option');
|
||||||
|
var currentIndex = -1;
|
||||||
|
$.each(siblings, function(index, option) {
|
||||||
|
if( $(option).hasClass('ui-selectBox-current') ) {
|
||||||
|
currentIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if( currentIndex >= 0 ) {
|
||||||
|
_select(event, $(siblings).eq(currentIndex));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 27: // esc
|
||||||
|
_hide(event, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 38: // up
|
||||||
|
case 37: // left
|
||||||
|
case 33: // page up
|
||||||
|
|
||||||
|
var interval = event.keyCode === 33 ? 20 : 1;
|
||||||
|
|
||||||
|
if( $(dropdown).size() === 0 ) {
|
||||||
|
|
||||||
|
if( event.altKey ) {
|
||||||
|
_show(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Previous selection
|
||||||
|
var totalIndexes = $(select).find('OPTION').size(),
|
||||||
|
oldSelectedIndex = $(select)[0].selectedIndex,
|
||||||
|
newSelectedIndex = $(select)[0].selectedIndex - interval;
|
||||||
|
|
||||||
|
// Look for non-disabled option
|
||||||
|
while( $(select).find('OPTION').eq(newSelectedIndex).attr('disabled') === true && newSelectedIndex >= 0 ) {
|
||||||
|
newSelectedIndex--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for first enabled option
|
||||||
|
if( newSelectedIndex < 0 ) {
|
||||||
|
newSelectedIndex = $(select).find('OPTION:not([disabled]):first').index();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
if( $(select)[0].selectedIndex === -1 ) {
|
||||||
|
newSelectedIndex = 0;
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
}
|
||||||
|
var label = $(select).find('OPTION:selected').text();
|
||||||
|
if( label === '' ) label = '\u00A0'; //
|
||||||
|
$(control).find('.ui-selectBox-label').text(label);
|
||||||
|
|
||||||
|
if( newSelectedIndex !== oldSelectedIndex ) $(select).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine currently selected index (ignoring optgroup LIs)
|
||||||
|
var siblings = $(dropdown).find('.ui-selectBox-option');
|
||||||
|
var currentIndex = -1;
|
||||||
|
$.each(siblings, function(index, option) {
|
||||||
|
if( $(option).hasClass('ui-selectBox-current') ) {
|
||||||
|
currentIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentIndex = currentIndex - interval;
|
||||||
|
if( currentIndex < 0 ) currentIndex = 0;
|
||||||
|
|
||||||
|
$(siblings).removeClass('ui-selectBox-current');
|
||||||
|
$(siblings).eq(currentIndex).addClass('ui-selectBox-current');
|
||||||
|
|
||||||
|
_dropdownScrollFix();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 40: // down
|
||||||
|
case 39: // right
|
||||||
|
case 34: // page down
|
||||||
|
|
||||||
|
var interval = event.keyCode === 34 ? 20 : 1;
|
||||||
|
|
||||||
|
if( $(dropdown).size() === 0 ) {
|
||||||
|
|
||||||
|
if( event.altKey ) {
|
||||||
|
_show(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var totalIndexes = $(select).find('OPTION').size(),
|
||||||
|
oldSelectedIndex = $(select)[0].selectedIndex,
|
||||||
|
newSelectedIndex = $(select)[0].selectedIndex + interval;
|
||||||
|
|
||||||
|
// Look for non-disabled option
|
||||||
|
while( $(select).find('OPTION').eq(newSelectedIndex).attr('disabled') === true && newSelectedIndex <= $(select).find('OPTION').size() ) {
|
||||||
|
newSelectedIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for last enabled option
|
||||||
|
if( newSelectedIndex > totalIndexes - 1 ) {
|
||||||
|
newSelectedIndex = $(select).find('OPTION:not([disabled]):last').index();
|
||||||
|
}
|
||||||
|
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
if( $(select)[0].selectedIndex === -1 ) {
|
||||||
|
newSelectedIndex = $(select).find('OPTION').size() - 1;
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
}
|
||||||
|
var label = $(select).find('OPTION:selected').text();
|
||||||
|
if( label === '' ) label = '\u00A0'; //
|
||||||
|
$(control).find('.ui-selectBox-label').text(label);
|
||||||
|
|
||||||
|
if( newSelectedIndex != oldSelectedIndex ) $(select).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine currently selected index (ignoring optgroup LIs)
|
||||||
|
var siblings = $(dropdown).find('.ui-selectBox-option');
|
||||||
|
var currentIndex = -1;
|
||||||
|
$.each(siblings, function(index, option) {
|
||||||
|
if( $(option).hasClass('ui-selectBox-current') ) {
|
||||||
|
currentIndex = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
currentIndex = currentIndex + interval;
|
||||||
|
if( currentIndex > $(siblings).size() - 1 ) currentIndex = $(siblings).size() - 1;
|
||||||
|
|
||||||
|
$(siblings).removeClass('ui-selectBox-current');
|
||||||
|
$(siblings).eq(currentIndex).addClass('ui-selectBox-current');
|
||||||
|
|
||||||
|
_dropdownScrollFix();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 36: // home
|
||||||
|
case 35: // end
|
||||||
|
|
||||||
|
if( $(dropdown).size() === 0 ) {
|
||||||
|
|
||||||
|
if( event.altKey ) {
|
||||||
|
_show(event);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var oldSelectedIndex = $(select)[0].selectedIndex,
|
||||||
|
newSelectedIndex;
|
||||||
|
|
||||||
|
if( event.keyCode === 36 ) {
|
||||||
|
// First
|
||||||
|
newSelectedIndex = 0;
|
||||||
|
} else {
|
||||||
|
// Last
|
||||||
|
newSelectedIndex = $(select).find('OPTION').size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle disabled options
|
||||||
|
if( $(select).find('OPTION').eq(newSelectedIndex).attr('disabled') === true ) {
|
||||||
|
if( event.keyCode === 36 ) {
|
||||||
|
newSelectedIndex = $(select).find('OPTION:not([disabled]):first').index();
|
||||||
|
} else {
|
||||||
|
newSelectedIndex = $(select).find('OPTION:not([disabled]):last').index();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(select)[0].selectedIndex = newSelectedIndex;
|
||||||
|
var label = $(select).find('OPTION:selected').text();
|
||||||
|
if( label === '' ) label = '\u00A0'; //
|
||||||
|
$(control).find('.ui-selectBox-label').text(label);
|
||||||
|
|
||||||
|
if( newSelectedIndex != oldSelectedIndex ) $(select).trigger('change');
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$(dropdown).find('.ui-selectBox-current').removeClass('ui-selectBox-current');
|
||||||
|
if( event.keyCode === 36 ) {
|
||||||
|
// First
|
||||||
|
$(dropdown).find('.ui-selectBox-option:first').addClass('ui-selectBox-current');
|
||||||
|
} else {
|
||||||
|
// Last
|
||||||
|
$(dropdown).find('.ui-selectBox-option:last').addClass('ui-selectBox-current');
|
||||||
|
}
|
||||||
|
|
||||||
|
_dropdownScrollFix();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _dropdownScrollFix = function(centerSelection) {
|
||||||
|
|
||||||
|
var dropdown = $("#ui-selectBox-dropdown");
|
||||||
|
if( $(dropdown).size() === 0 ) return false;
|
||||||
|
|
||||||
|
var target = $(dropdown).find('.ui-selectBox-current');
|
||||||
|
if( $(target).size() === 0 ) return false;
|
||||||
|
|
||||||
|
var targetTop = parseInt($(target).offset().top - $(dropdown).position().top);
|
||||||
|
var targetBottom = parseInt(targetTop + $(target).outerHeight());
|
||||||
|
|
||||||
|
if( centerSelection ) {
|
||||||
|
|
||||||
|
$(dropdown).scrollTop(
|
||||||
|
$(target).offset().top - $(dropdown).offset().top + $(dropdown).scrollTop() - ($(dropdown).height() / 2)
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if( targetTop < 0 ) {
|
||||||
|
$(dropdown).scrollTop(
|
||||||
|
$(target).offset().top - $(dropdown).offset().top + $(dropdown).scrollTop()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if( targetBottom > $(dropdown).height() ) {
|
||||||
|
$(dropdown).scrollTop(
|
||||||
|
($(target).offset().top + $(target).outerHeight() ) - $(dropdown).offset().top + $(dropdown).scrollTop() - $(dropdown).height()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _disableSelection = function(selector) {
|
||||||
|
|
||||||
|
$(selector)
|
||||||
|
.css('MozUserSelect', 'none')
|
||||||
|
.bind('selectstart', function() {
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
.bind('mousedown', function() {
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var _htmlspecialchars = function(string) {
|
||||||
|
return( string.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, ''') );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
switch( o ) {
|
||||||
|
|
||||||
|
|
||||||
|
case 'destroy':
|
||||||
|
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
var control = $(this).next('.ui-selectBox');
|
||||||
|
|
||||||
|
if( $(select)[0].tagName.toLowerCase() === 'select' ) {
|
||||||
|
$(control).remove();
|
||||||
|
$(select).removeData('selectBox-options').show();
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'disable':
|
||||||
|
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
var control = $(this).next('.ui-selectBox');
|
||||||
|
|
||||||
|
$(select).attr('disabled', true);
|
||||||
|
$(control).addClass('ui-selectBox-disabled');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'enable':
|
||||||
|
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
var control = $(this).next('.ui-selectBox');
|
||||||
|
|
||||||
|
$(select).attr('disabled', false);
|
||||||
|
$(control).removeClass('ui-selectBox-disabled');
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'setOptions':
|
||||||
|
|
||||||
|
if( !data ) return $(this);
|
||||||
|
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
var control = $(this).next('.ui-selectBox');
|
||||||
|
|
||||||
|
switch( typeof(data) ) {
|
||||||
|
|
||||||
|
case 'string':
|
||||||
|
|
||||||
|
$(select).html(data);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
$(select).html('');
|
||||||
|
|
||||||
|
for( var i in data ) {
|
||||||
|
|
||||||
|
if( data[i] === null ) continue;
|
||||||
|
|
||||||
|
if( typeof(data[i]) === 'object' ) {
|
||||||
|
// OPTGROUP
|
||||||
|
var optgroup = $('<optgroup label="' + i + '" />');
|
||||||
|
for( var j in data[i] ) {
|
||||||
|
$(optgroup).append('<option value="' + j + '">' + data[i][j] + '</option>');
|
||||||
|
}
|
||||||
|
$(select).append(optgroup);
|
||||||
|
} else {
|
||||||
|
// OPTION
|
||||||
|
var option = $('<option value="' + i + '">' + data[i] + '</option>');
|
||||||
|
$(select).append(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the options
|
||||||
|
var options = $(select).data('selectBox-options');
|
||||||
|
$(select).selectBox('destroy');
|
||||||
|
$(select).selectBox(options);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
case 'value':
|
||||||
|
|
||||||
|
// Remove dropdown
|
||||||
|
$("#ui-selectBox-dropdown").remove();
|
||||||
|
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
var control = $(this).next('.ui-selectBox');
|
||||||
|
|
||||||
|
// Update value
|
||||||
|
$(select).val(data);
|
||||||
|
|
||||||
|
// Fix corners and update label
|
||||||
|
var label = $(select).find(':selected').text();
|
||||||
|
if( label === '' ) label = '\u00A0'; //
|
||||||
|
$(control).removeClass('ui-corner-top').addClass('ui-corner-all').find('.ui-selectBox-label').text(label);
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
default:
|
||||||
|
|
||||||
|
// Create the control
|
||||||
|
$(this).each( function() {
|
||||||
|
|
||||||
|
// Default options
|
||||||
|
if( !o ) o = {};
|
||||||
|
var options = $.extend({
|
||||||
|
autoWidth: true
|
||||||
|
}, o);
|
||||||
|
|
||||||
|
var select = $(this);
|
||||||
|
|
||||||
|
if( $(this).next('.ui-selectBox').size() === 0 ) {
|
||||||
|
|
||||||
|
// Generate new control
|
||||||
|
var control = $('<a href="#" class="ui-selectBox ui-corner-all" tabindex="' + parseInt($(select).attr('tabindex')) + '" />');
|
||||||
|
|
||||||
|
// Inherit class names, style, and title attributes
|
||||||
|
$(control).addClass($(select).attr('class')).attr({
|
||||||
|
style: ($(select).attr('style') + '').replace(/inline/, 'inline-block'),
|
||||||
|
title: $(select).attr('title')
|
||||||
|
});
|
||||||
|
|
||||||
|
// Store options for later use
|
||||||
|
$(select).data('selectBox-options', options);
|
||||||
|
|
||||||
|
// Auto-width based on longest option
|
||||||
|
if( options.autoWidth ) {
|
||||||
|
|
||||||
|
// Determine character count of longest option
|
||||||
|
var longestOption = '';
|
||||||
|
$(select).find('OPTION').each( function() {
|
||||||
|
if( $(this).text().length > longestOption.length ) longestOption = $(this).text();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a fake option, measure it, set the width, and remove the fake option
|
||||||
|
var div = $('<div class="ui-selectBox-dropdown" style="position: absolute; top: -9999em; left: -9999em; width: auto; display: inline-block;" />');
|
||||||
|
var li = $('<li class="ui-selectBox-option">' + _htmlspecialchars(longestOption) + '</li>');
|
||||||
|
$(div).append(li);
|
||||||
|
$('BODY').append(div);
|
||||||
|
$(control).width(li.outerWidth());
|
||||||
|
$(div).remove();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( $(select)[0].tagName.toLowerCase() !== 'select' || $(select).attr('multiple') === true ) return;
|
||||||
|
if( $(select).attr('disabled') === true ) $(control).addClass('ui-selectBox-disabled');
|
||||||
|
|
||||||
|
var label = $(select).find('OPTION:selected').text();
|
||||||
|
if( label === '' ) label = '\u00A0'; //
|
||||||
|
|
||||||
|
// Add label and arrow
|
||||||
|
$(control).append('<span class="ui-selectBox-label">' + _htmlspecialchars(label) + '</span>');
|
||||||
|
$(control).append('<span class="ui-selectBox-arrow"></span>');
|
||||||
|
$(select).hide().after(control);
|
||||||
|
|
||||||
|
_disableSelection(control);
|
||||||
|
|
||||||
|
$(control)
|
||||||
|
.bind('click', function() { return false; })
|
||||||
|
.bind('mousedown', { select: select, control: control }, _show)
|
||||||
|
.bind('focus', { select: select, control: control }, _focus)
|
||||||
|
.bind('blur', { select: select, control: control }, _blur);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return $(this);
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
})(jQuery);
|
|
@ -0,0 +1,478 @@
|
||||||
|
/*
|
||||||
|
http://www.JSON.org/json2.js
|
||||||
|
2008-11-19
|
||||||
|
|
||||||
|
Public Domain.
|
||||||
|
|
||||||
|
NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
|
||||||
|
|
||||||
|
See http://www.JSON.org/js.html
|
||||||
|
|
||||||
|
This file creates a global JSON object containing two methods: stringify
|
||||||
|
and parse.
|
||||||
|
|
||||||
|
JSON.stringify(value, replacer, space)
|
||||||
|
value any JavaScript value, usually an object or array.
|
||||||
|
|
||||||
|
replacer an optional parameter that determines how object
|
||||||
|
values are stringified for objects. It can be a
|
||||||
|
function or an array of strings.
|
||||||
|
|
||||||
|
space an optional parameter that specifies the indentation
|
||||||
|
of nested structures. If it is omitted, the text will
|
||||||
|
be packed without extra whitespace. If it is a number,
|
||||||
|
it will specify the number of spaces to indent at each
|
||||||
|
level. If it is a string (such as '\t' or ' '),
|
||||||
|
it contains the characters used to indent at each level.
|
||||||
|
|
||||||
|
This method produces a JSON text from a JavaScript value.
|
||||||
|
|
||||||
|
When an object value is found, if the object contains a toJSON
|
||||||
|
method, its toJSON method will be called and the result will be
|
||||||
|
stringified. A toJSON method does not serialize: it returns the
|
||||||
|
value represented by the name/value pair that should be serialized,
|
||||||
|
or undefined if nothing should be serialized. The toJSON method
|
||||||
|
will be passed the key associated with the value, and this will be
|
||||||
|
bound to the object holding the key.
|
||||||
|
|
||||||
|
For example, this would serialize Dates as ISO strings.
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
You can provide an optional replacer method. It will be passed the
|
||||||
|
key and value of each member, with this bound to the containing
|
||||||
|
object. The value that is returned from your method will be
|
||||||
|
serialized. If your method returns undefined, then the member will
|
||||||
|
be excluded from the serialization.
|
||||||
|
|
||||||
|
If the replacer parameter is an array of strings, then it will be
|
||||||
|
used to select the members to be serialized. It filters the results
|
||||||
|
such that only members with keys listed in the replacer array are
|
||||||
|
stringified.
|
||||||
|
|
||||||
|
Values that do not have JSON representations, such as undefined or
|
||||||
|
functions, will not be serialized. Such values in objects will be
|
||||||
|
dropped; in arrays they will be replaced with null. You can use
|
||||||
|
a replacer function to replace those with JSON values.
|
||||||
|
JSON.stringify(undefined) returns undefined.
|
||||||
|
|
||||||
|
The optional space parameter produces a stringification of the
|
||||||
|
value that is filled with line breaks and indentation to make it
|
||||||
|
easier to read.
|
||||||
|
|
||||||
|
If the space parameter is a non-empty string, then that string will
|
||||||
|
be used for indentation. If the space parameter is a number, then
|
||||||
|
the indentation will be that many spaces.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}]);
|
||||||
|
// text is '["e",{"pluribus":"unum"}]'
|
||||||
|
|
||||||
|
|
||||||
|
text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
|
||||||
|
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
|
||||||
|
|
||||||
|
text = JSON.stringify([new Date()], function (key, value) {
|
||||||
|
return this[key] instanceof Date ?
|
||||||
|
'Date(' + this[key] + ')' : value;
|
||||||
|
});
|
||||||
|
// text is '["Date(---current time---)"]'
|
||||||
|
|
||||||
|
|
||||||
|
JSON.parse(text, reviver)
|
||||||
|
This method parses a JSON text to produce an object or array.
|
||||||
|
It can throw a SyntaxError exception.
|
||||||
|
|
||||||
|
The optional reviver parameter is a function that can filter and
|
||||||
|
transform the results. It receives each of the keys and values,
|
||||||
|
and its return value is used instead of the original value.
|
||||||
|
If it returns what it received, then the structure is not modified.
|
||||||
|
If it returns undefined then the member is deleted.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
// Parse the text. Values that look like ISO date strings will
|
||||||
|
// be converted to Date objects.
|
||||||
|
|
||||||
|
myData = JSON.parse(text, function (key, value) {
|
||||||
|
var a;
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
a =
|
||||||
|
/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
|
||||||
|
if (a) {
|
||||||
|
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
|
||||||
|
+a[5], +a[6]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
|
||||||
|
var d;
|
||||||
|
if (typeof value === 'string' &&
|
||||||
|
value.slice(0, 5) === 'Date(' &&
|
||||||
|
value.slice(-1) === ')') {
|
||||||
|
d = new Date(value.slice(5, -1));
|
||||||
|
if (d) {
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
This is a reference implementation. You are free to copy, modify, or
|
||||||
|
redistribute.
|
||||||
|
|
||||||
|
This code should be minified before deployment.
|
||||||
|
See http://javascript.crockford.com/jsmin.html
|
||||||
|
|
||||||
|
USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
|
||||||
|
NOT CONTROL.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jslint evil: true */
|
||||||
|
|
||||||
|
/*global JSON */
|
||||||
|
|
||||||
|
/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
|
||||||
|
call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
|
||||||
|
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
|
||||||
|
lastIndex, length, parse, prototype, push, replace, slice, stringify,
|
||||||
|
test, toJSON, toString, valueOf
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Create a JSON object only if one does not already exist. We create the
|
||||||
|
// methods in a closure to avoid creating global variables.
|
||||||
|
|
||||||
|
if (!this.JSON) {
|
||||||
|
JSON = {};
|
||||||
|
}
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
function f(n) {
|
||||||
|
// Format integers to have at least two digits.
|
||||||
|
return n < 10 ? '0' + n : n;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof Date.prototype.toJSON !== 'function') {
|
||||||
|
|
||||||
|
Date.prototype.toJSON = function (key) {
|
||||||
|
|
||||||
|
return this.getUTCFullYear() + '-' +
|
||||||
|
f(this.getUTCMonth() + 1) + '-' +
|
||||||
|
f(this.getUTCDate()) + 'T' +
|
||||||
|
f(this.getUTCHours()) + ':' +
|
||||||
|
f(this.getUTCMinutes()) + ':' +
|
||||||
|
f(this.getUTCSeconds()) + 'Z';
|
||||||
|
};
|
||||||
|
|
||||||
|
String.prototype.toJSON =
|
||||||
|
Number.prototype.toJSON =
|
||||||
|
Boolean.prototype.toJSON = function (key) {
|
||||||
|
return this.valueOf();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
|
||||||
|
gap,
|
||||||
|
indent,
|
||||||
|
meta = { // table of character substitutions
|
||||||
|
'\b': '\\b',
|
||||||
|
'\t': '\\t',
|
||||||
|
'\n': '\\n',
|
||||||
|
'\f': '\\f',
|
||||||
|
'\r': '\\r',
|
||||||
|
'"' : '\\"',
|
||||||
|
'\\': '\\\\'
|
||||||
|
},
|
||||||
|
rep;
|
||||||
|
|
||||||
|
|
||||||
|
function quote(string) {
|
||||||
|
|
||||||
|
// If the string contains no control characters, no quote characters, and no
|
||||||
|
// backslash characters, then we can safely slap some quotes around it.
|
||||||
|
// Otherwise we must also replace the offending characters with safe escape
|
||||||
|
// sequences.
|
||||||
|
|
||||||
|
escapable.lastIndex = 0;
|
||||||
|
return escapable.test(string) ?
|
||||||
|
'"' + string.replace(escapable, function (a) {
|
||||||
|
var c = meta[a];
|
||||||
|
return typeof c === 'string' ? c :
|
||||||
|
'\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
}) + '"' :
|
||||||
|
'"' + string + '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function str(key, holder) {
|
||||||
|
|
||||||
|
// Produce a string from holder[key].
|
||||||
|
|
||||||
|
var i, // The loop counter.
|
||||||
|
k, // The member key.
|
||||||
|
v, // The member value.
|
||||||
|
length,
|
||||||
|
mind = gap,
|
||||||
|
partial,
|
||||||
|
value = holder[key];
|
||||||
|
|
||||||
|
// If the value has a toJSON method, call it to obtain a replacement value.
|
||||||
|
|
||||||
|
if (value && typeof value === 'object' &&
|
||||||
|
typeof value.toJSON === 'function') {
|
||||||
|
value = value.toJSON(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were called with a replacer function, then call the replacer to
|
||||||
|
// obtain a replacement value.
|
||||||
|
|
||||||
|
if (typeof rep === 'function') {
|
||||||
|
value = rep.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// What happens next depends on the value's type.
|
||||||
|
|
||||||
|
switch (typeof value) {
|
||||||
|
case 'string':
|
||||||
|
return quote(value);
|
||||||
|
|
||||||
|
case 'number':
|
||||||
|
|
||||||
|
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||||
|
|
||||||
|
return isFinite(value) ? String(value) : 'null';
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
case 'null':
|
||||||
|
|
||||||
|
// If the value is a boolean or null, convert it to a string. Note:
|
||||||
|
// typeof null does not produce 'null'. The case is included here in
|
||||||
|
// the remote chance that this gets fixed someday.
|
||||||
|
|
||||||
|
return String(value);
|
||||||
|
|
||||||
|
// If the type is 'object', we might be dealing with an object or an array or
|
||||||
|
// null.
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
|
||||||
|
// Due to a specification blunder in ECMAScript, typeof null is 'object',
|
||||||
|
// so watch out for that case.
|
||||||
|
|
||||||
|
if (!value) {
|
||||||
|
return 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make an array to hold the partial results of stringifying this object value.
|
||||||
|
|
||||||
|
gap += indent;
|
||||||
|
partial = [];
|
||||||
|
|
||||||
|
// Is the value an array?
|
||||||
|
|
||||||
|
if (Object.prototype.toString.apply(value) === '[object Array]') {
|
||||||
|
|
||||||
|
// The value is an array. Stringify every element. Use null as a placeholder
|
||||||
|
// for non-JSON values.
|
||||||
|
|
||||||
|
length = value.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
partial[i] = str(i, value) || 'null';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the elements together, separated with commas, and wrap them in
|
||||||
|
// brackets.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '[]' :
|
||||||
|
gap ? '[\n' + gap +
|
||||||
|
partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + ']' :
|
||||||
|
'[' + partial.join(',') + ']';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the replacer is an array, use it to select the members to be stringified.
|
||||||
|
|
||||||
|
if (rep && typeof rep === 'object') {
|
||||||
|
length = rep.length;
|
||||||
|
for (i = 0; i < length; i += 1) {
|
||||||
|
k = rep[i];
|
||||||
|
if (typeof k === 'string') {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Otherwise, iterate through all of the keys in the object.
|
||||||
|
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = str(k, value);
|
||||||
|
if (v) {
|
||||||
|
partial.push(quote(k) + (gap ? ': ' : ':') + v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join all of the member texts together, separated with commas,
|
||||||
|
// and wrap them in braces.
|
||||||
|
|
||||||
|
v = partial.length === 0 ? '{}' :
|
||||||
|
gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
|
||||||
|
mind + '}' : '{' + partial.join(',') + '}';
|
||||||
|
gap = mind;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a stringify method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.stringify !== 'function') {
|
||||||
|
JSON.stringify = function (value, replacer, space) {
|
||||||
|
|
||||||
|
// The stringify method takes a value and an optional replacer, and an optional
|
||||||
|
// space parameter, and returns a JSON text. The replacer can be a function
|
||||||
|
// that can replace values, or an array of strings that will select the keys.
|
||||||
|
// A default replacer method can be provided. Use of the space parameter can
|
||||||
|
// produce text that is more easily readable.
|
||||||
|
|
||||||
|
var i;
|
||||||
|
gap = '';
|
||||||
|
indent = '';
|
||||||
|
|
||||||
|
// If the space parameter is a number, make an indent string containing that
|
||||||
|
// many spaces.
|
||||||
|
|
||||||
|
if (typeof space === 'number') {
|
||||||
|
for (i = 0; i < space; i += 1) {
|
||||||
|
indent += ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the space parameter is a string, it will be used as the indent string.
|
||||||
|
|
||||||
|
} else if (typeof space === 'string') {
|
||||||
|
indent = space;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a replacer, it must be a function or an array.
|
||||||
|
// Otherwise, throw an error.
|
||||||
|
|
||||||
|
rep = replacer;
|
||||||
|
if (replacer && typeof replacer !== 'function' &&
|
||||||
|
(typeof replacer !== 'object' ||
|
||||||
|
typeof replacer.length !== 'number')) {
|
||||||
|
throw new Error('JSON.stringify');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a fake root object containing our value under the key of ''.
|
||||||
|
// Return the result of stringifying the value.
|
||||||
|
|
||||||
|
return str('', {'': value});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// If the JSON object does not yet have a parse method, give it one.
|
||||||
|
|
||||||
|
if (typeof JSON.parse !== 'function') {
|
||||||
|
JSON.parse = function (text, reviver) {
|
||||||
|
|
||||||
|
// The parse method takes a text and an optional reviver function, and returns
|
||||||
|
// a JavaScript value if the text is a valid JSON text.
|
||||||
|
|
||||||
|
var j;
|
||||||
|
|
||||||
|
function walk(holder, key) {
|
||||||
|
|
||||||
|
// The walk method is used to recursively walk the resulting structure so
|
||||||
|
// that modifications can be made.
|
||||||
|
|
||||||
|
var k, v, value = holder[key];
|
||||||
|
if (value && typeof value === 'object') {
|
||||||
|
for (k in value) {
|
||||||
|
if (Object.hasOwnProperty.call(value, k)) {
|
||||||
|
v = walk(value, k);
|
||||||
|
if (v !== undefined) {
|
||||||
|
value[k] = v;
|
||||||
|
} else {
|
||||||
|
delete value[k];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return reviver.call(holder, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Parsing happens in four stages. In the first stage, we replace certain
|
||||||
|
// Unicode characters with escape sequences. JavaScript handles many characters
|
||||||
|
// incorrectly, either silently deleting them, or treating them as line endings.
|
||||||
|
|
||||||
|
cx.lastIndex = 0;
|
||||||
|
if (cx.test(text)) {
|
||||||
|
text = text.replace(cx, function (a) {
|
||||||
|
return '\\u' +
|
||||||
|
('0000' + a.charCodeAt(0).toString(16)).slice(-4);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// In the second stage, we run the text against regular expressions that look
|
||||||
|
// for non-JSON patterns. We are especially concerned with '()' and 'new'
|
||||||
|
// because they can cause invocation, and '=' because it can cause mutation.
|
||||||
|
// But just to be safe, we want to reject all unexpected forms.
|
||||||
|
|
||||||
|
// We split the second stage into 4 regexp operations in order to work around
|
||||||
|
// crippling inefficiencies in IE's and Safari's regexp engines. First we
|
||||||
|
// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
|
||||||
|
// replace all simple value tokens with ']' characters. Third, we delete all
|
||||||
|
// open brackets that follow a colon or comma or that begin the text. Finally,
|
||||||
|
// we look to see that the remaining characters are only whitespace or ']' or
|
||||||
|
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
|
||||||
|
|
||||||
|
if (/^[\],:{}\s]*$/.
|
||||||
|
test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
|
||||||
|
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
|
||||||
|
replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
|
||||||
|
|
||||||
|
// In the third stage we use the eval function to compile the text into a
|
||||||
|
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
|
||||||
|
// in JavaScript: it can begin a block or an object literal. We wrap the text
|
||||||
|
// in parens to eliminate the ambiguity.
|
||||||
|
|
||||||
|
j = eval('(' + text + ')');
|
||||||
|
|
||||||
|
// In the optional fourth stage, we recursively walk the new structure, passing
|
||||||
|
// each name/value pair to a reviver function for possible transformation.
|
||||||
|
|
||||||
|
return typeof reviver === 'function' ?
|
||||||
|
walk({'': j}, '') : j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the text is not JSON parseable, then a SyntaxError is thrown.
|
||||||
|
|
||||||
|
throw new SyntaxError('JSON.parse');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
})();
|
|
@ -0,0 +1,13 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
// Basic classes for use throughout Mark
|
||||||
|
|
||||||
|
mark.vector = function ( x, y, z ) {
|
||||||
|
this.x = x || 0;
|
||||||
|
this.y = y || 0;
|
||||||
|
this.z = z || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,218 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
mark.dof = 10000;
|
||||||
|
|
||||||
|
mark.thickMarkBrush = function( g, strokes, translateOptions, colorBase, w, h ) {
|
||||||
|
var colorBase = colorBase ? colorBase : '0,0,0';
|
||||||
|
// setup our starting bound
|
||||||
|
var p = Mark.renderer.translatePoint( strokes[0][0], translateOptions );
|
||||||
|
var bounds = { minX: p.x, maxX: p.x, minY: p.y, maxY: p.y };
|
||||||
|
// if this mark isn't even close to being on screen, just return
|
||||||
|
if ( ( w && h ) && ( p.x > w*2 || p.x < -w || p.y > h*2 || p.y < -h || p.z > mark.dof || p.z < 0 ) ) return;
|
||||||
|
// iterate
|
||||||
|
for( var i = 0; i < strokes.length; i++ ) {
|
||||||
|
if( typeof( strokes[i] ) == "undefined" || strokes[i].length <= 1 ) continue;
|
||||||
|
var prevP = null;
|
||||||
|
for( var j=0; j < strokes[i].length; j++ ) {
|
||||||
|
var p = Mark.renderer.translatePoint( strokes[i][j], translateOptions );
|
||||||
|
// if this point is out of the depth of field, on to the next one
|
||||||
|
if( p.z && ( p.z > mark.dof || p.z < 0 ) ) continue;
|
||||||
|
// if this point isn't significant enough, on to the next one
|
||||||
|
if( p.significance && p.significance * ( mark.dof / 5 ) < p.z - 500 ) continue;
|
||||||
|
// if this is the first point in a stroke
|
||||||
|
if( !prevP ) {
|
||||||
|
// if this isn't the first stroke in this mark, and this mark is a reasonable distance from the camera, connect them
|
||||||
|
if( i != 0 && p.z < 1500 ) {
|
||||||
|
var lastStrokePoint = Mark.renderer.translatePoint( strokes[i-1][strokes[i-1].length - 1], translateOptions );
|
||||||
|
if( lastStrokePoint.z && lastStrokePoint.z < mark.dof ) {
|
||||||
|
g.strokeStyle = 'rgba(0,0,0,0.3)';
|
||||||
|
g.lineWidth = 1;
|
||||||
|
g.beginPath();
|
||||||
|
g.dashedLineTo( lastStrokePoint.x, lastStrokePoint.y, p.x, p.y, [6,4] );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
prevP = p;
|
||||||
|
prevPX = 0;
|
||||||
|
prevPY = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
g.lineWidth = 1;
|
||||||
|
// set line width
|
||||||
|
if ( j == strokes[i].length - 1 ) {
|
||||||
|
// if this is the last point, make the widht 0 so we dont have a blunt end
|
||||||
|
var px = 0;
|
||||||
|
var py = 0;
|
||||||
|
} else {
|
||||||
|
var distance = 9 - Math.max( 0, Math.pow(p.speed + 1, 3) );
|
||||||
|
if( translateOptions.mode == "flatScale" && translateOptions.scale.thickness ) {
|
||||||
|
distance *= translateOptions.scale.thickness;
|
||||||
|
} else {
|
||||||
|
if( p.z ) distance *= (2/p.z) * ( h / 2 );
|
||||||
|
}
|
||||||
|
if ( distance < 0.1 ) distance = 0.1;
|
||||||
|
distance += 1;
|
||||||
|
var px = Math.cos( p.angle ) * distance;
|
||||||
|
var py = Math.sin( p.angle ) * distance;
|
||||||
|
}
|
||||||
|
g.strokeStyle = 'rgba(' + colorBase + ',' + ( ( mark.dof - p.z ) / mark.dof )+')';
|
||||||
|
g.fillStyle = 'rgba(' + colorBase + ',' + ( ( mark.dof - p.z ) / mark.dof )+')';
|
||||||
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
g.beginPath();
|
||||||
|
g.lineWidth = 0.5 * ( ( mark.dof - p.z ) / mark.dof );
|
||||||
|
g.moveTo( prevP.x - prevPX - 0.5, prevP.y - prevPY - 0.5 );
|
||||||
|
g.lineTo( prevP.x + prevPX - 0.5, prevP.y + prevPY - 0.5 );
|
||||||
|
g.lineTo( p.x + px - 0.5, p.y + py - 0.5 );
|
||||||
|
g.lineTo( p.x - px - 0.5, p.y - py - 0.5 );
|
||||||
|
g.lineTo( prevP.x - prevPX - 0.5, prevP.y - prevPY - 0.5 );
|
||||||
|
g.fill();
|
||||||
|
g.stroke();
|
||||||
|
} catch( e ) {
|
||||||
|
// console.error( p, prevX, prevY, prevT, px, py, dx, dy, dt );
|
||||||
|
}
|
||||||
|
// expand bounds
|
||||||
|
bounds.minX = p.x < bounds.minX ? p.x : bounds.minX;
|
||||||
|
bounds.minY = p.y < bounds.minY ? p.y : bounds.minY;
|
||||||
|
bounds.maxX = p.x > bounds.maxX ? p.x : bounds.maxX;
|
||||||
|
bounds.maxY = p.y > bounds.maxY ? p.y : bounds.maxY;
|
||||||
|
// stash variables for later
|
||||||
|
prevP = p
|
||||||
|
prevPX = px;
|
||||||
|
prevPY = py;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// return our bounds for storage
|
||||||
|
return bounds;
|
||||||
|
};
|
||||||
|
mark.connectionBrush = function( g, p1, p2, offset1, offset2, w, h ) {
|
||||||
|
var tO = { offset: offset1, w: w, h: h, mode: 'pinhole' };
|
||||||
|
p1 = Mark.renderer.translatePoint( p1, tO );
|
||||||
|
tO.offset = offset2;
|
||||||
|
p2 = Mark.renderer.translatePoint( p2, tO );
|
||||||
|
// if these points are both off the screen, don't render the line
|
||||||
|
if ( ( p1.x > w || p1.x < 0 || p1.y > h || p1.y < 0 ) && ( p2.x > w || p2.x < 0 || p2.y > h || p2.y < 0 ) ) return;
|
||||||
|
// if these points are out of the dof, don't render the line
|
||||||
|
if ( p1.z && p2.z && ( p1.z > mark.dof || p1.z < 0 ) && ( p2.z > mark.dof || p2.z < 0 ) ) return;
|
||||||
|
g.strokeStyle = 'rgba(0,0,0,' + ( ( mark.dof - p1.z ) / (mark.dof*2) )+')';
|
||||||
|
var distance = 3 * (2/p1.z) * ( h / 2 );
|
||||||
|
if ( distance < 1 ) distance = 1;
|
||||||
|
g.lineWidth = distance;
|
||||||
|
g.beginPath();
|
||||||
|
g.moveTo( p1.x, p1.y );
|
||||||
|
g.lineTo( p2.x, p2.y );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
},
|
||||||
|
mark.thickBrush = function( g, strokes, offsetX, offsetY, depth ) {
|
||||||
|
var offsetX = offsetX ? offsetX : 0;
|
||||||
|
var offsetY = offsetY ? offsetY : 0;
|
||||||
|
var depth = depth ? depth : 1;
|
||||||
|
|
||||||
|
for( var i = 0; i < strokes.length; i++ ) {
|
||||||
|
if( typeof( strokes[i] ) == "undefined" || strokes[i].length <= 1 ) continue;
|
||||||
|
// if this is the first point in a stroke
|
||||||
|
if( i > 0 ) {
|
||||||
|
// connect to the last stroke
|
||||||
|
g.strokeStyle = 'rgba(0,0,0,0.1)';
|
||||||
|
g.lineWidth = 1;
|
||||||
|
g.beginPath();
|
||||||
|
var lastX = strokes[i-1][strokes[i-1].length - 1].x,
|
||||||
|
lastY = strokes[i-1][strokes[i-1].length - 1].y,
|
||||||
|
firstX = strokes[i][0].x,
|
||||||
|
firstY = strokes[i][0].y;
|
||||||
|
g.dashedLineTo( lastX + offsetX, lastY + offsetY, firstX + offsetX, firstY + offsetY, [6,4] );
|
||||||
|
g.closePath();
|
||||||
|
g.stroke();
|
||||||
|
}
|
||||||
|
g.lineWidth = 1;
|
||||||
|
g.strokeStyle = '#000000';
|
||||||
|
g.fillStyle = '#000000';
|
||||||
|
var prevPX = 0,
|
||||||
|
prevPY = 0,
|
||||||
|
prevT = strokes[i][0].time,
|
||||||
|
prevX = strokes[i][0].x,
|
||||||
|
prevY = strokes[i][0].y ;
|
||||||
|
for( var j=1; j < strokes[i].length; j++ ) {
|
||||||
|
var p = strokes[i][j];
|
||||||
|
// if this point is insignificant, on to the next one
|
||||||
|
if( p.significance < depth ) continue;
|
||||||
|
// if this is the last stroke
|
||||||
|
if ( j == strokes[i].length - 1 ) {
|
||||||
|
var px = 0;
|
||||||
|
var py = 0;
|
||||||
|
} else {
|
||||||
|
var distance = 9 - Math.pow(p.speed + 1, 3);
|
||||||
|
if ( distance < 0.5 ) distance = 0.5;
|
||||||
|
distance += 1;
|
||||||
|
var px = Math.cos( p.angle ) * distance;
|
||||||
|
var py = Math.sin( p.angle ) * distance;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
g.beginPath();
|
||||||
|
g.moveTo( prevX - prevPX - 0.5 + offsetX, prevY - prevPY - 0.5 + offsetY );
|
||||||
|
g.lineTo( prevX + prevPX - 0.5 + offsetX, prevY + prevPY - 0.5 + offsetY );
|
||||||
|
g.lineTo( p.x + px - 0.5 + offsetX, p.y + py - 0.5 + offsetY );
|
||||||
|
g.lineTo( p.x - px - 0.5 + offsetX, p.y - py - 0.5 + offsetY );
|
||||||
|
g.lineTo( prevX - prevPX - 0.5 + offsetX, prevY - prevPY - 0.5 + offsetY );
|
||||||
|
g.fill();
|
||||||
|
g.stroke();
|
||||||
|
} catch( e ) {
|
||||||
|
// console.error( p, prevX, prevY, prevT, px, py, dx, dy, dt );
|
||||||
|
}
|
||||||
|
prevPX = px;
|
||||||
|
prevPY = py;
|
||||||
|
prevX = p.x;
|
||||||
|
prevY = p.y;
|
||||||
|
prevT = p.time;
|
||||||
|
prevAng = p.angle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mark.circleMarkBrush = function( g, strokes, offsetParent ) {
|
||||||
|
var d = 3;
|
||||||
|
for( var i = 0; i < strokes.length; i++ ) {
|
||||||
|
if( strokes[i].length == 0 ) continue;
|
||||||
|
for( var j=0; j < strokes[i].length; j++ ) {
|
||||||
|
var p = Mark.renderer.translatePoint( strokes[i][j], offsetParent );
|
||||||
|
if( p.z && p.z > mark.dof ) continue;
|
||||||
|
d = 3 * ( ( mark.dof - p.z ) / mark.dof );
|
||||||
|
g.fillStyle = "rgba(255,255,255,0.4)";
|
||||||
|
g.strokeStyle = "rgba(255,255,255,0.4)";
|
||||||
|
g.beginPath();
|
||||||
|
g.arc(p.x, p.y, d, 0, Math.PI*2, true);
|
||||||
|
g.closePath();
|
||||||
|
g.fill();
|
||||||
|
g.stroke();
|
||||||
|
g.lineTo( p.x, p.y );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mark.circleBrush = function( g, strokes, offsetX, offsetY, depth ) {
|
||||||
|
var offsetX = offsetX ? offsetX : 0;
|
||||||
|
var offsetY = offsetY ? offsetY : 0;
|
||||||
|
var depth = depth ? depth : 1;
|
||||||
|
for( var i = 0; i < strokes.length; i++ ) {
|
||||||
|
if( strokes[i].length == 0 ) continue;
|
||||||
|
var p1 = strokes[i][0];
|
||||||
|
g.beginPath();
|
||||||
|
for( var j=0; j < strokes[i].length; j++ ) {
|
||||||
|
var p = strokes[i][j];
|
||||||
|
// if this point is insignificant, on to the next one
|
||||||
|
if( p.significance < depth ) continue;
|
||||||
|
g.beginPath();
|
||||||
|
g.arc(p.x + offsetX, p.y + offsetY, 3, 0, Math.PI*2, true);
|
||||||
|
g.closePath();
|
||||||
|
g.fill();
|
||||||
|
g.stroke();
|
||||||
|
g.lineTo( p.x + offsetX, p.y + offsetY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,20 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
// This is currently very rudimentry
|
||||||
|
// no projection math happening, just some offsets to consult when rendering marks
|
||||||
|
|
||||||
|
mark.camera = function ( ) {
|
||||||
|
|
||||||
|
this.position = new mark.vector( 0, 0 ,-1000 );
|
||||||
|
// currently not used
|
||||||
|
this.targetPosition = new mark.vector( 0, 0, 0 );
|
||||||
|
|
||||||
|
this.tweenTo = function( x, y, z ) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,179 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
mark.gmlMark = function( strokes, reference, country_code, time, rtl, id, is_approved ) {
|
||||||
|
this.strokes = strokes;
|
||||||
|
this.country_code = country_code;
|
||||||
|
this.time = time;
|
||||||
|
this.rtl = rtl;
|
||||||
|
this.maxTime = 0;
|
||||||
|
this.reference = reference;
|
||||||
|
this.hoverState = false;
|
||||||
|
this.renderedBounds = null;
|
||||||
|
this.id = id ? id : null;
|
||||||
|
this.is_approved = is_approved;
|
||||||
|
this.contributor_name = null;
|
||||||
|
this.extra_info = null;
|
||||||
|
|
||||||
|
// colors for this mark
|
||||||
|
this.color = '0,0,0';
|
||||||
|
this.hoverColor = '0,139,211';
|
||||||
|
|
||||||
|
// current position of this mark
|
||||||
|
this.x = 0;
|
||||||
|
this.y = 0;
|
||||||
|
|
||||||
|
// we represent the mark as a plane sitting in 3d space -- all point positions can then be calculatd relative to this
|
||||||
|
// top left corner of the bounding box
|
||||||
|
this.position = {x: 0, y: 0, z: 0};
|
||||||
|
// angle of the plane in 3d space -- values are between -1 and 1, and really we only want to allow rotation around the Y axis
|
||||||
|
this.rotationAngle = {x: 0, y: 0, z: 0};
|
||||||
|
|
||||||
|
// offset of the start point from the origin of the bounding box
|
||||||
|
this.sX = 0;
|
||||||
|
this.sY = 0;
|
||||||
|
|
||||||
|
// bounding box dimensions
|
||||||
|
this.bWidth = 0;
|
||||||
|
this.bHeight = 0;
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
if( this.strokes.length > 0 ) {
|
||||||
|
this.setupVars();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setupVars = function () {
|
||||||
|
this.maxTime = this.lastPoint().time;
|
||||||
|
this.getBoundingBox();
|
||||||
|
};
|
||||||
|
|
||||||
|
// looks for and returns the start of a stroke that is the furthes to the left
|
||||||
|
this.leftmostStrokeStart = function () {
|
||||||
|
var firstPoint = this.strokes[0][0];
|
||||||
|
for ( var i = 1; i < this.strokes.length; i++ ) {
|
||||||
|
var p = this.strokes[i][0];
|
||||||
|
if ( p.x < firstPoint.x ) lastPoint = p;
|
||||||
|
}
|
||||||
|
return firstPoint;
|
||||||
|
}
|
||||||
|
// looks for and returns the end of a stroke that is furthest to the right
|
||||||
|
this.rightmostStrokeEnd = function () {
|
||||||
|
// start with the last point of the first stroke
|
||||||
|
var lastPoint = this.strokes[0][this.strokes[0].length - 1];
|
||||||
|
for ( var i = 1; i < this.strokes.length; i++ ) {
|
||||||
|
var p = this.strokes[i][this.strokes[i].length - 1];
|
||||||
|
if ( p.x > lastPoint.x ) lastPoint = p;
|
||||||
|
}
|
||||||
|
return lastPoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the very first point drawn in this stroke
|
||||||
|
this.firstPoint = function () {
|
||||||
|
return this.strokes[0][0];
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the very last point drawn in this stroke
|
||||||
|
this.lastPoint = function () {
|
||||||
|
return this.strokes[this.strokes.length - 1][this.strokes[this.strokes.length - 1].length - 1];
|
||||||
|
};
|
||||||
|
|
||||||
|
this.translatePoint = function ( point ) {
|
||||||
|
var tP = point.clone();
|
||||||
|
tP.x = this.x + point.x;
|
||||||
|
tP.y = this.y + point.y;
|
||||||
|
return tP;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.getBoundingBox = function () {
|
||||||
|
var p1 = this.strokes[0][0];
|
||||||
|
var maxX = p1.x, minX = p1.x, maxY = p1.y, minY= p1.y;
|
||||||
|
for( var i = 0; i < this.strokes.length; i ++ ) {
|
||||||
|
for( var j = 0; j < this.strokes[i].length; j++ ) {
|
||||||
|
var p = this.strokes[i][j];
|
||||||
|
maxX = p.x > maxX ? p.x : maxX;
|
||||||
|
maxY = p.y > maxY ? p.y : maxY;
|
||||||
|
minX = p.x < minX ? p.x : minX;
|
||||||
|
minY = p.y < minY ? p.y : minY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.bWidth = maxX - minX;
|
||||||
|
this.bHeight = maxY - minY;
|
||||||
|
this.x = minX;
|
||||||
|
this.y = minY;
|
||||||
|
if ( minX != 0 || minY != 0 )
|
||||||
|
this.fitPointsToBounds( minX, minY );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fitPointsToBounds = function ( minX, minY ) {
|
||||||
|
for( var i = 0; i < this.strokes.length; i ++ ) {
|
||||||
|
for( var j = 0; j < this.strokes[i].length; j++ ) {
|
||||||
|
this.strokes[i][j].x -= minX;
|
||||||
|
this.strokes[i][j].y -= minY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// returns a subset of this marks strokes, at a given time
|
||||||
|
this.strokesAtTime = function ( time ) {
|
||||||
|
if( time > this.maxTime ) return this.strokes;
|
||||||
|
var sat = [[]];
|
||||||
|
var curIndex = [0, 0]
|
||||||
|
var nextPoint = this.strokes[curIndex[0]][curIndex[1]];
|
||||||
|
while( nextPoint.time < time ) {
|
||||||
|
sat[sat.length - 1].push( nextPoint );
|
||||||
|
curIndex[1]++;
|
||||||
|
if( this.strokes[curIndex[0]].length == curIndex[1] ) {
|
||||||
|
curIndex[0]++;
|
||||||
|
curIndex[1] = 0;
|
||||||
|
sat.push([]);
|
||||||
|
}
|
||||||
|
nextPoint = this.strokes[curIndex[0]][curIndex[1]];
|
||||||
|
}
|
||||||
|
return sat;
|
||||||
|
},
|
||||||
|
// If reverse is true, we position relative to the start of the mark
|
||||||
|
// if it's false, or ommitted, we position relative to the end of the mark
|
||||||
|
this.positionRelativeTo = function ( mark, reverse ) {
|
||||||
|
var reverse = reverse ? !!reverse : false;
|
||||||
|
var buffer = 50;
|
||||||
|
if ( reverse ) {
|
||||||
|
this.position.x = mark.position.x - buffer - this.bWidth;
|
||||||
|
// this.x = mark.x + mark.firstPoint().x - this.lastPoint().x;
|
||||||
|
this.position.y = mark.position.y + mark.leftmostStrokeStart().y - this.rightmostStrokeEnd().y;
|
||||||
|
// this is based on a static computation in mark.renderer
|
||||||
|
// if you change it there, change it here
|
||||||
|
this.position.z = mark.position.z - ( this.maxTime / 50 );
|
||||||
|
} else {
|
||||||
|
this.position.x = mark.position.x + mark.bWidth + this.leftmostStrokeStart().x + buffer;
|
||||||
|
// this.x = mark.x + mark.rightmostStrokeEnd().x - this.leftmostStrokeStart().x;
|
||||||
|
this.position.y = mark.position.y + mark.rightmostStrokeEnd().y - this.firstPoint().y;
|
||||||
|
// this is based on a static computation in mark.renderer
|
||||||
|
// if you change it there, change it here
|
||||||
|
this.position.z = mark.position.z + ( mark.maxTime / 50 );
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this.positionToStart = function () {
|
||||||
|
this.position.x = 0;
|
||||||
|
this.position.y = 0;
|
||||||
|
this.position.z = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// translates a point according to this marks location in 3d space
|
||||||
|
this.translatePoint = function( x, y, z ) {
|
||||||
|
// find the change in x, y and z from the top lef of our bounding box to the bottom right
|
||||||
|
var dX = ( this.angle.x * this.bWidth ) - this.position.x,
|
||||||
|
dY = ( this.angle.y * this.bHeight ) - this.position.y,
|
||||||
|
dZ = ( this.angle.z * 1 );
|
||||||
|
x = x * this.rotationAngle.x;
|
||||||
|
y = y * this.rotationAngle.y;
|
||||||
|
z = z * this.rotationAngle.z;
|
||||||
|
};
|
||||||
|
|
||||||
|
// doesn't really belong here
|
||||||
|
this.url = function () {
|
||||||
|
return "http://domain.tld/#/mark/" + this.reference;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
};
|
||||||
|
return mark;
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,56 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
mark.gmlPoint = function( x, y, time, speed, z ) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = typeof z == "integer" ? z : 0;
|
||||||
|
this.time = time;
|
||||||
|
this.speed = speed;
|
||||||
|
this.angle = 0;
|
||||||
|
this.significance = 1; // 1-5 value for how significant this point is -- useful for easign the complexity of lines that are far from the camera
|
||||||
|
|
||||||
|
// returns the distance between this and another point
|
||||||
|
this.distanceToPoint = function( point ) {
|
||||||
|
return Math.sqrt( Math.pow( (point.x - this.x ), 2 ) + Math.pow( (point.y - this.y ), 2 ) );
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a speed between this point and a point in the future
|
||||||
|
this.speedToPoint = function( point ) {
|
||||||
|
var dp = this.distanceToPoint( point );
|
||||||
|
var dt = point.time - this.time;
|
||||||
|
return dp / dt;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ensures this point's speed is not changing substantially faster than it should
|
||||||
|
// allowance is a per unit distance change
|
||||||
|
this.smoothAgainst = function( point, allowance ) {
|
||||||
|
var d = this.distanceToPoint( point );
|
||||||
|
var a = allowance * d;
|
||||||
|
if ( Math.abs( this.speed - point.speed ) > a ) {
|
||||||
|
this.speed = this.speed > point.speed ? point.speed + a : point.speed - a;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// considers a prior point and sets this point's angle accordingly
|
||||||
|
// ensures that the angle is a radian value between 0 and 2 * PI
|
||||||
|
this.setAngleFromPoint = function ( point ) {
|
||||||
|
this.angle = Math.atan2( point.y - this.y, point.x - this.x ) + ( Math.PI / 2 );
|
||||||
|
this.angle = this.angle % ( 2 * Math.PI );
|
||||||
|
if( this.angle < 0 ) this.angle = ( 2 * Math.PI ) + this.angle;
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a basic copy of this point
|
||||||
|
this.clone = function () {
|
||||||
|
return { x: this.x, y: this.y, z: this.z, time: this.time, significance: this.significance, angle: this.angle, speed: this.speed };
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a copy of this point translated by x, y
|
||||||
|
this.getTranslatedPoint = function ( x, y ) {
|
||||||
|
var point = this.clone();
|
||||||
|
point.x += x;
|
||||||
|
point.y += y;
|
||||||
|
return point;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
return mark;
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,49 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
mark.layer = function( manager, name ) {
|
||||||
|
|
||||||
|
this.canvas = null;
|
||||||
|
this.context = null;
|
||||||
|
this.dirtyRectangles = [];
|
||||||
|
this.layerName = name;
|
||||||
|
this.manager = manager;
|
||||||
|
|
||||||
|
this.clean = function() {
|
||||||
|
if( this.dirtyRectangles.length == 0 ) {
|
||||||
|
// if theres no dirtyRectangles, clear the whole thing (probably not the best default)
|
||||||
|
this.context.clearRect( 0, 0, this.canvas.width, this.canvas.height );
|
||||||
|
} else {
|
||||||
|
// loop through dirty rectangles, and run clearRect on each
|
||||||
|
for( var i = 0; i< this.dirtyRectangles.length; i++ ) {
|
||||||
|
var rect = this.dirtyRectangles[i];
|
||||||
|
this.context.clearRect( i.x, i.y, i.w, i.h );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setSize = function( w, h ) {
|
||||||
|
if( this.canvas.width != w ) this.canvas.width = w;
|
||||||
|
if( this.canvas.height != h ) this.canvas.height = h;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
this.canvas = document.createElement( 'canvas' );
|
||||||
|
this.context = this.canvas.getContext( '2d' );
|
||||||
|
this.setSize( this.manager.container.scrollWidth, this.manager.container.scrollHeight );
|
||||||
|
this.manager.layerWrapper.appendChild( this.canvas );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.remove = function () {
|
||||||
|
this.manager.layerWrapper.removeChild( this.canvas );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.sendToTop = function () {
|
||||||
|
// this.manager.sendToTop( this );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,42 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
mark.layerManager = function( container ) {
|
||||||
|
|
||||||
|
this.container = container;
|
||||||
|
this.layerWrapper = null;
|
||||||
|
this.layers = {};
|
||||||
|
|
||||||
|
this.init = function () {
|
||||||
|
// attach a new div for our layers to reside in
|
||||||
|
this.layerWrapper = document.createElement( 'div' );
|
||||||
|
this.layerWrapper.className = 'mark-layerManager';
|
||||||
|
this.container.appendChild( this.layerWrapper );
|
||||||
|
};
|
||||||
|
|
||||||
|
// add a layer to our container
|
||||||
|
this.addLayer = function( name ) {
|
||||||
|
var layer = new mark.layer( this, name );
|
||||||
|
this.layers[name] = layer;
|
||||||
|
return layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove all layers from our container
|
||||||
|
this.removeAll = function () {
|
||||||
|
for( var layer in this.layers ) {
|
||||||
|
this.layers[layer].remove();
|
||||||
|
delete this.layers[layer];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// resize all layers to the passed width and height
|
||||||
|
this.resizeAll = function( w, h ) {
|
||||||
|
for( var layer in this.layers ) {
|
||||||
|
this.layers[layer].setSize( w, h );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
};
|
||||||
|
return mark;
|
||||||
|
|
||||||
|
}( Mark || {} ) );
|
|
@ -0,0 +1,199 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
mark.renderer = {
|
||||||
|
// all points are passed through here durring rendering
|
||||||
|
// current supported options
|
||||||
|
// - offset - an object with x, y, and possibly z
|
||||||
|
// - w - output width - defaults to 500
|
||||||
|
// - h - output height - defaults to 500
|
||||||
|
// - mode - which of the translate modes we should use. defaults to 'pinhole'
|
||||||
|
// - scale - a value to scale this points x, y coords by. Only supported by flatScale currently
|
||||||
|
translatePoint: function( point, options ) {
|
||||||
|
var modes = {
|
||||||
|
// simple offset and scale translate
|
||||||
|
'flatScale': function( rP, options ) {
|
||||||
|
var offsetX = ('offset' in options) && ( 'x' in options['offset'] ) ? options.offset.x : 0;
|
||||||
|
var offsetY = ('offset' in options) && ( 'y' in options['offset'] ) ? options.offset.y : 0;
|
||||||
|
var scaleX = ('scale' in options) && ( 'x' in options['scale'] ) ? options.scale.x : 1;
|
||||||
|
var scaleY = ('scale' in options) && ( 'y' in options['scale'] ) ? options.scale.y : 1;
|
||||||
|
rP.x *= scaleX;
|
||||||
|
rP.y *= scaleY;
|
||||||
|
rP.x += offsetX;
|
||||||
|
rP.y += offsetY;
|
||||||
|
return rP;
|
||||||
|
},
|
||||||
|
// maps the point to a 3D parabolic shape and then uses a pinhole camera approace to map it back to 2D coords
|
||||||
|
'pinhole': function( rP, options ) {
|
||||||
|
var offsetX = ('offset' in options) && ( 'x' in options['offset'] ) ? options.offset.x : 0;
|
||||||
|
var offsetY = ('offset' in options) && ( 'y' in options['offset'] ) ? options.offset.y : 0;
|
||||||
|
var offsetZ = ('offset' in options) && ( 'z' in options['offset'] ) ? options.offset.z : 0;
|
||||||
|
var w = ('w' in options) ? options.w : 500;
|
||||||
|
var h = ('h' in options) ? options.h : 500;
|
||||||
|
var spread = 100;
|
||||||
|
var shift = -100;
|
||||||
|
rP.x += offsetX;
|
||||||
|
rP.y += offsetY;
|
||||||
|
if( rP.x > 0 ) {
|
||||||
|
rP.z = Math.pow( ( ( rP.x - shift ) / spread ), 2) + offsetZ;
|
||||||
|
} else {
|
||||||
|
rP.z = Math.pow( ( ( rP.x - shift ) / spread / 2 ), 2) + offsetZ;
|
||||||
|
}
|
||||||
|
// make it a bit deeper based on time
|
||||||
|
if( rP.time ) rP.z += rP.time / 50;
|
||||||
|
var v = 2 / ( rP.z );
|
||||||
|
rP.x = rP.x * v * ( h / 2 ) + ( w / 2 );
|
||||||
|
rP.y = rP.y * v * ( h / 2 ) + ( h / 2 );
|
||||||
|
return rP;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// create a new object based on our point. Basically this will be a clone of the gmlPoint w/o functions
|
||||||
|
var rP = { x: point.x, y: point.y, z: point.z, time: point.time, significance: point.significance, angle: point.angle, speed: point.speed };
|
||||||
|
// run the appropriate function and return the result
|
||||||
|
return ( 'mode' in options ) && ( options['mode'] in modes ) ?
|
||||||
|
modes[options['mode']]( rP, options ) : modes['pinhole']( rP, options );
|
||||||
|
},
|
||||||
|
// returns a subset of strokes for the given time
|
||||||
|
strokesAtTime: function ( strokes, time ) {
|
||||||
|
// if( time > this.maxTime ) return this.strokes;
|
||||||
|
var sat = [[]];
|
||||||
|
var curIndex = [0, 0];
|
||||||
|
var nextPoint = strokes[curIndex[0]][curIndex[1]];
|
||||||
|
while( nextPoint.time < time ) {
|
||||||
|
sat[sat.length - 1].push( nextPoint );
|
||||||
|
curIndex[1]++;
|
||||||
|
if( strokes[curIndex[0]].length == curIndex[1] ) {
|
||||||
|
// next stroke if we've got another
|
||||||
|
if( strokes.length == curIndex[0] + 1 ) break;
|
||||||
|
curIndex[0]++;
|
||||||
|
curIndex[1] = 0;
|
||||||
|
sat.push([]);
|
||||||
|
}
|
||||||
|
nextPoint = strokes[curIndex[0]][curIndex[1]];
|
||||||
|
}
|
||||||
|
return sat;
|
||||||
|
},
|
||||||
|
// renders a scene for the viz
|
||||||
|
// accepted options - cursor { x, y }, width, height
|
||||||
|
renderScene: function( scene, options ) {
|
||||||
|
var lastMarkStart;
|
||||||
|
var w = options.width;
|
||||||
|
var h = options.height;
|
||||||
|
for( var i = scene.objects.length - 1; i >= 0; i-- ) {
|
||||||
|
// set our offset based on the camera and the marks position
|
||||||
|
var offset = {
|
||||||
|
x: scene.objects[i].position.x - scene.camera.position.x,
|
||||||
|
y: scene.objects[i].position.y - scene.camera.position.y,
|
||||||
|
z: scene.objects[i].position.z - scene.camera.position.z
|
||||||
|
};
|
||||||
|
colorBase = scene.objects[i].color;
|
||||||
|
var translateOptions = {
|
||||||
|
offset: offset,
|
||||||
|
w: options.width,
|
||||||
|
h: options.height,
|
||||||
|
mode: 'pinhole'
|
||||||
|
};
|
||||||
|
if( i < scene.objects.length - 1 && !( scene.objects[i].reference in scene.timers ) ) {
|
||||||
|
// draw the connection
|
||||||
|
var offset1 = {
|
||||||
|
x: scene.objects[i+1].position.x - scene.camera.position.x,
|
||||||
|
y: scene.objects[i+1].position.y - scene.camera.position.y,
|
||||||
|
z: scene.objects[i+1].position.z - scene.camera.position.z
|
||||||
|
};
|
||||||
|
var offset2 = {
|
||||||
|
x: scene.objects[i].position.x - scene.camera.position.x,
|
||||||
|
y: scene.objects[i].position.y - scene.camera.position.y,
|
||||||
|
z: scene.objects[i].position.z - scene.camera.position.z
|
||||||
|
};
|
||||||
|
var p1 = scene.objects[i+1].leftmostStrokeStart();
|
||||||
|
var p2 = scene.objects[i].rightmostStrokeEnd();
|
||||||
|
Mark.connectionBrush( scene.canvasContext , p1, p2, offset1, offset2, w, h );
|
||||||
|
}
|
||||||
|
|
||||||
|
var translateOptions = {
|
||||||
|
offset: offset,
|
||||||
|
w: options.width,
|
||||||
|
h: options.height,
|
||||||
|
mode: 'pinhole'
|
||||||
|
};
|
||||||
|
// DRAW THAT MARK
|
||||||
|
if( scene.objects[i].reference in scene.timers ) {
|
||||||
|
// render a mark that is currently being replayed
|
||||||
|
var strokes = mark.renderer.strokesAtTime(
|
||||||
|
scene.objects[i].strokes,
|
||||||
|
( ( new Date() ).getTime() - scene.timers[scene.objects[i].reference].start ) * scene.timers[scene.objects[i].reference].speed );
|
||||||
|
if( strokes && strokes.length > 0 && strokes[0].length > 0 )
|
||||||
|
scene.objects[i].renderedBounds =
|
||||||
|
Mark.thickMarkBrush( scene.canvasContext, strokes, translateOptions, colorBase, options.width, options.height );
|
||||||
|
} else {
|
||||||
|
// render a mark that is not being played back
|
||||||
|
scene.objects[i].renderedBounds =
|
||||||
|
Mark.thickMarkBrush( scene.canvasContext, scene.objects[i].strokes, translateOptions, colorBase, options.width, options.height );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// simpler render method for playing back an individual mark using our flatScale translate method
|
||||||
|
// accepted options - timer, width, height, offset {x, y}, scale, color
|
||||||
|
renderMark: function( canvasContext, aMark, options ) {
|
||||||
|
// DRAW THAT MARK
|
||||||
|
var translateOptions = {
|
||||||
|
offset: options.offset,
|
||||||
|
scale: options.scale,
|
||||||
|
mode: 'flatScale'
|
||||||
|
};
|
||||||
|
if( 'timer' in options && options.timer ) {
|
||||||
|
// render a mark that is currently being replayed
|
||||||
|
var strokes = mark.renderer.strokesAtTime( aMark.strokes, ( ( new Date() ).getTime() - options.timer.start ) * options.timer.speed );
|
||||||
|
if( strokes && strokes.length > 0 && strokes[0].length > 0 )
|
||||||
|
aMark.renderedBounds = Mark.thickMarkBrush( canvasContext, strokes, translateOptions, options.color );
|
||||||
|
} else {
|
||||||
|
// render a mark that is not being played back
|
||||||
|
aMark.renderedBounds = Mark.thickMarkBrush( canvasContext, aMark.strokes, translateOptions, options.color );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
}( Mark || {} ) );
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* The translatePoint Graveyard. Where unloved point translations go to die.
|
||||||
|
|
||||||
|
case 'parabolic':
|
||||||
|
// offset by parent
|
||||||
|
rP.x += offset.x;
|
||||||
|
rP.y += offset.y;
|
||||||
|
// calculate 3d position
|
||||||
|
rP.z = ( rP.x * rP.x / mark.renderer.dof );
|
||||||
|
rP.y += rP.z / 2;
|
||||||
|
// map 3d to 2d
|
||||||
|
var scale = mark.renderer.dof / ( mark.renderer.dof + rP.z );
|
||||||
|
rP.x *= scale * 2;
|
||||||
|
rP.y *= scale;
|
||||||
|
rP.x += 600;
|
||||||
|
rP.y -= 200;
|
||||||
|
break;
|
||||||
|
case 'flat':
|
||||||
|
// offset by parent
|
||||||
|
rP.x += offset.x;
|
||||||
|
rP.y += offset.y;
|
||||||
|
// scale by width and height
|
||||||
|
rP.z = 100;
|
||||||
|
break;
|
||||||
|
case 'linear':
|
||||||
|
// offsets
|
||||||
|
rP.x += offset.x;
|
||||||
|
rP.y += offset.y;
|
||||||
|
// rP.z = ( ( rP.x - 500 ) * ( rP.x / 2000 ) ) - 1500;
|
||||||
|
spread = w * 2;
|
||||||
|
shift = w * .5;
|
||||||
|
rP.z = ( ( rP.x - shift ) * ( ( rP.x - shift ) / spread ) ) + offset.z;
|
||||||
|
// make it a bit deeper based on time
|
||||||
|
if( rP.time ) rP.z += rP.time / 100;
|
||||||
|
var scale = mark.renderer.dof / ( mark.renderer.dof + rP.z );
|
||||||
|
rP.x *= scale;
|
||||||
|
rP.y *= scale;
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,37 @@
|
||||||
|
var Mark = ( function ( mark ) {
|
||||||
|
|
||||||
|
mark.scene = function ( ) {
|
||||||
|
|
||||||
|
this.camera = new Mark.camera();
|
||||||
|
this.objects = [];
|
||||||
|
this.canvasContext = null;
|
||||||
|
this.timers = {};
|
||||||
|
|
||||||
|
this.init = function ( ) {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
this.addObject = function ( object ) {
|
||||||
|
this.objects.push( object );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.removeObject = function ( index ) {
|
||||||
|
this.objects.splice( index, 1 );
|
||||||
|
};
|
||||||
|
|
||||||
|
this.update = function ( ) {
|
||||||
|
var now = ( new Date() ).getTime();
|
||||||
|
for( mark in this.timers ) {
|
||||||
|
if( this.timers[mark].end < now ) {
|
||||||
|
delete this.timers[mark];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return mark;
|
||||||
|
|
||||||
|
}( Mark || {} ) );
|