merging in updates to initial
|
@ -0,0 +1,8 @@
|
|||
settings_local.py
|
||||
*.py[co]
|
||||
*.sw[po]
|
||||
*.pot
|
||||
*.mo
|
||||
pip-log.txt
|
||||
build.py
|
||||
.DS_Store
|
|
@ -0,0 +1,54 @@
|
|||
Markup
|
||||
===
|
||||
|
||||
Firefox MarkUp is a [Django][Django]-based web application...
|
||||
[Django]: http://www.djangoproject.com/
|
||||
|
||||
Getting Started
|
||||
---
|
||||
### Python
|
||||
You need Python 2.6. Also, you probably want to run this application in a
|
||||
[virtualenv][virtualenv] environment
|
||||
|
||||
[virtualenv]: http://pypi.python.org/pypi/virtualenv
|
||||
|
||||
### Dependencies
|
||||
|
||||
run
|
||||
|
||||
easy_install pip
|
||||
|
||||
followed by
|
||||
|
||||
./bootsrap.sh
|
||||
|
||||
|
||||
|
||||
### Django
|
||||
|
||||
South is used for migrations, so to sync the db, run
|
||||
|
||||
manage.py syncdb
|
||||
|
||||
and to run the migs
|
||||
|
||||
manage.py migrate
|
||||
|
||||
|
||||
Then run the invite-generation script. generate_invites.py takes two vars: number of invites to generate, and type of invites to generate. invite-types are 't' for translator, or 'c' for contributor.
|
||||
|
||||
for 5 translator invites, run
|
||||
manage.py generate_invites 5 t
|
||||
for 10 contributor invites, run
|
||||
manage.py generate_invites 10 c
|
||||
|
||||
|
||||
For production environments, uncomment the following in settings:
|
||||
# CACHE_BACKEND = 'caching.backends.memcached://localhost:11211?timeout=500'
|
||||
|
||||
# SESSION_COOKIE_SECURE = True
|
||||
# SESSION_COOKIE_HTTPONLY = True
|
||||
|
||||
and set
|
||||
REDIRECT_TO_SSL = True
|
||||
|
|
@ -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,12 @@
|
|||
from django.forms import ModelForm
|
||||
from ffdemo.markup.models import Mark
|
||||
|
||||
class MarkForm(ModelForm):
|
||||
class Meta:
|
||||
model = Mark
|
||||
fields = ('points_obj', 'country_code')
|
||||
|
||||
|
||||
class LoginForm(ModelForm):
|
||||
class Meta:
|
||||
model = Mark
|
|
@ -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,50 @@
|
|||
# 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 unique constraint on 'Invitation', fields ['invite_code']
|
||||
db.create_unique('markup_invitation', ['invite_code'])
|
||||
|
||||
# Adding index on 'Mark', fields ['reference']
|
||||
db.create_index('markup_mark', ['reference'])
|
||||
|
||||
|
||||
def backwards(self, orm):
|
||||
|
||||
# Removing index on 'Mark', fields ['reference']
|
||||
db.delete_index('markup_mark', ['reference'])
|
||||
|
||||
# Removing unique constraint on 'Invitation', fields ['invite_code']
|
||||
db.delete_unique('markup_invitation', ['invite_code'])
|
||||
|
||||
|
||||
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', [], {'unique': 'True', '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', [], {'db_index': 'True', 'unique': 'True', '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, db_index=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, unique=True, db_index=True)
|
||||
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).filter(contributor_locale__isnull=True).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(contributor_locale__isnull=True,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,119 @@
|
|||
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.views.decorators.cache import cache_page
|
||||
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
|
||||
|
||||
@cache_page(15) # cache for 15 seconds
|
||||
def home(request):
|
||||
mr = settings.MEDIA_ROOT
|
||||
return render_response(request, 'home.html', {'mr':mr})
|
||||
|
||||
@cache_page(60 * 30) # cache for 30 minutes
|
||||
def about(request):
|
||||
return render_response(request, 'about.html')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def about_gml(request):
|
||||
return render_response(request, 'gml.html')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def credits(request):
|
||||
return render_response(request, 'credits.html')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def code(request):
|
||||
return render_response(request, 'code.html')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def mozilla(request):
|
||||
return render_response(request, 'mozilla.html')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
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')
|
||||
|
||||
@cache_page(60 * 30)
|
||||
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})
|
||||
|
||||
@cache_page(30)
|
||||
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})
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def newsletter(request):
|
||||
return render_response(request, 'newsletter.html', {})
|
||||
|
||||
@cache_page(60 * 30)
|
||||
def home_sammy(request):
|
||||
mr = settings.MEDIA_ROOT
|
||||
return render_response(request,'sammy/home.html',{'mr':mr})
|
||||
|
||||
@cache_page(15)
|
||||
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,72 @@
|
|||
from django.db import connection
|
||||
from django.conf import settings
|
||||
from django.utils.encoding import *
|
||||
from urlparse import urlparse
|
||||
|
||||
import re
|
||||
from django import http
|
||||
import django.core.exceptions
|
||||
from django.core import urlresolvers
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils import translation
|
||||
import localeurl
|
||||
from localeurl import utils
|
||||
|
||||
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect, get_host
|
||||
|
||||
class SQLLogMiddleware:
|
||||
def process_response(self, request, response):
|
||||
if settings.DEV and connection.queries:
|
||||
time = sum([float(q['time']) for q in connection.queries])
|
||||
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
|
||||
|
||||
|
||||
|
||||
# SSL Middleware
|
||||
# via: http://djangosnippets.org/snippets/85/
|
||||
|
||||
# __license__ = "Python"
|
||||
# __copyright__ = "Copyright (C) 2007, Stephen Zabel"
|
||||
# __author__ = "Stephen Zabel - sjzabel@gmail.com"
|
||||
# __contributors__ = "Jay Parlar - parlar@gmail.com"
|
||||
|
||||
SSL = 'SSL'
|
||||
|
||||
class SSLRedirect:
|
||||
|
||||
def process_view(self, request, view_func, view_args, view_kwargs):
|
||||
if SSL in view_kwargs:
|
||||
secure = view_kwargs[SSL]
|
||||
del view_kwargs[SSL]
|
||||
else:
|
||||
secure = False
|
||||
|
||||
if not secure == self._is_secure(request):
|
||||
return self._redirect(request, secure)
|
||||
|
||||
def _is_secure(self, request):
|
||||
if request.is_secure():
|
||||
return True
|
||||
|
||||
#Handle the Webfaction case until this gets resolved in the request.is_secure()
|
||||
if 'HTTP_X_FORWARDED_SSL' in request.META:
|
||||
return request.META['HTTP_X_FORWARDED_SSL'] == 'on'
|
||||
|
||||
return False
|
||||
|
||||
def _redirect(self, request, secure):
|
||||
protocol = secure and "https" or "http"
|
||||
newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())
|
||||
if settings.DEBUG and request.method == 'POST':
|
||||
raise RuntimeError, \
|
||||
"""Django can't perform a SSL redirect while maintaining POST data.
|
||||
Please structure your views so that redirects only occur during GETs."""
|
||||
|
||||
return HttpResponsePermanentRedirect(newurl)
|
|
@ -0,0 +1,207 @@
|
|||
import settings_local
|
||||
import os
|
||||
import re
|
||||
|
||||
# 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
|
||||
# SESSION_COOKIE_DOMAIN = None
|
||||
|
||||
# global for enabling SSL redirection of admin views
|
||||
# set True for properly configured production
|
||||
REDIRECT_TO_SSL = False
|
||||
|
||||
ADMINS = (
|
||||
# ('Your Name', 'your_email@domain.com'),
|
||||
)
|
||||
|
||||
MANAGERS = ADMINS
|
||||
|
||||
# Memcached!
|
||||
# CACHE_BACKEND = 'caching.backends.memcached://localhost:11211?timeout=500'
|
||||
|
||||
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
|
||||
|
||||
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 = (
|
||||
#'ffdemo.jinja.Loader',
|
||||
'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',
|
||||
'ffdemo.middleware.SSLRedirect',
|
||||
)
|
||||
|
||||
# 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',
|
||||
)
|
||||
|
||||
# JINJA_TEMPLATE_DIRS = (
|
||||
# PROJECT_PATH+'/templates',
|
||||
# )
|
||||
|
||||
def JINJA_CONFIG():
|
||||
import jinja2
|
||||
config = {'extensions': ['jinja2.ext.loopcontrols',
|
||||
'jinja2.ext.with_', 'caching.ext.cache'],
|
||||
'finalize': lambda x: x if x is not None else ''}
|
||||
return config
|
||||
|
||||
|
||||
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,34 @@
|
|||
{
|
||||
"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.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",
|
||||
"sammy.hash_push_proxy",
|
||||
"sammy.template"
|
||||
]
|
||||
},
|
||||
"compressed_suffix": ".min"
|
||||
}
|
После Ширина: | Высота: | Размер: 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,161 @@
|
|||
( function( $ ) {
|
||||
var app = $.sammy( '#sammy', function() {
|
||||
// ROUTES
|
||||
this.get( '#/', function( context ) {
|
||||
// making our mark
|
||||
// unload the visualization if it's loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'linear' );
|
||||
// load the template
|
||||
this.partial( 'makemark_sammy.html' )
|
||||
.then( function() {
|
||||
// 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 ) {
|
||||
// unload the visualization if it's loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'linear' );
|
||||
|
||||
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() {
|
||||
// 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 ) {
|
||||
// unload the other modules if they're loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||
this.partial( '/en/moderate_sammy.html' )
|
||||
.then( function() {
|
||||
// load the linear module
|
||||
$( '#markapp' ).markApp( 'addModule', { 'linear': { 'is_flagged': true, 'linear_root': 'moderate' } } );
|
||||
} );
|
||||
} );
|
||||
// Moderation via direct reference
|
||||
this.get( '#\/moderate\/(.*)', function( context ) {
|
||||
// unload the other modules if they're loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||
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' } );
|
||||
// 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 ) {
|
||||
// unload the other modules if they're loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||
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' } );
|
||||
// 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 ) {
|
||||
// unload the other modules if they're loaded
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'intro' );
|
||||
$( '#markapp' ).markApp( 'unloadModule', 'capture' );
|
||||
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' } );
|
||||
// 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,32 @@
|
|||
$(document).ready(function ()
|
||||
{
|
||||
$("#community").hover(function ()
|
||||
{
|
||||
$("#coming-soon-tip").toggle();
|
||||
});
|
||||
|
||||
// Query for countries if newsletter
|
||||
if ($("#newsletter-countries").length > 0)
|
||||
{
|
||||
$.ajax( {
|
||||
'url': '/media/assets/js/vendor/country_codes.json',
|
||||
'dataType': 'JSON',
|
||||
'success': function ( data )
|
||||
{
|
||||
for( var i = 0; i < data.length; i++ )
|
||||
{
|
||||
var $select = $( '#newsletter-countries' );
|
||||
var $option = $( '<option />' )
|
||||
.val( data[i].code )
|
||||
.text( data[i].name );
|
||||
$select.append( $option );
|
||||
}
|
||||
},
|
||||
'error': function ()
|
||||
{
|
||||
// handle error loading countries
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -0,0 +1,190 @@
|
|||
(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,translatedStrings:{},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},ready:function(){b.fn.loadTranslations()}},public_fn:{addModule:function(b,d){var c,e={};if(typeof d=="string")c=d;else if(typeof d=="object")for(var j in d){c=j;e=d[j];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 i in b.modules)if(i in a.markApp.modules&&"evt"in a.markApp.modules[i]&&d in a.markApp.modules[i].evt)a.markApp.modules[i].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){c=typeof c==="string"?c:"";d=typeof d==="string"?d:b.fn.getString("default-loading-msg");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.fn.getString("default-error-msg");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 />").html(d)));
|
||||
b.$container.append(d);d.fadeIn("fast")},hideError:function(){a("#markapp-error").fadeOut("fast",function(){a(this).remove()})},loadTranslations:function(){a("div.translated-strings").each(function(){a(this).children().each(function(){var d=a(this);d.is("ol")?(b.translatedStrings[d.attr("id")]=[],d.children().each(function(){b.translatedStrings[d.attr("id")].push(a(this).html())})):b.translatedStrings[d.attr("id")]=d.html()})})},getString:function(a,d){return a in b.translatedStrings?typeof b.translatedStrings[a]===
|
||||
"object"&&typeof d==="number"?b.translatedStrings[a][d]:b.translatedStrings[a]:a},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?"0,139,211":"0,0,0";b.hoverMark=mark;b.currentMark&&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}):(a("#contributor-quote-box:visible").fadeOut("fast"),b.hoverMark.color=b.hoverMark.contributor_name?"255,111,40":"0,139,211")}else if(b.hoverMark)b.hoverMark.color=b.hoverMark.contributor_name?"0,139,211":"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?"0,139,211":"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:d.fn.getString("twitter-msg")}});a("#facebook-share").socialShare({share_url:"http://www.facebook.com/sharer.php",
|
||||
share_params:{t:d.fn.getString("facebook-msg")}});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)):a.fn.showError(b.errorMsg);b.requestingMarks=!1}}):modules.linear.fn.loadMarks(a,{offset:0,max:20,success:function(c){if(c.success){if(modules.linear.fn.setupMarks(a,c.marks),firstMark=b.marks[c.marks[0].reference])b.scene.camera.position.x=-4E3,b.scene.camera.position.z=-3E3,c="cameraEase"in b.tweens?b.tweens.cameraEase:new TWEEN.Tween(b.scene.camera.position),c.to({x:firstMark.bWidth/
|
||||
2,y:firstMark.bHeight/2,z:-1E3},2E3).onComplete(function(){delete b.tweens.cameraEase;typeof callback==="function"&&callback(this)}).easing(TWEEN.Easing.Quartic.EaseInOut).start(),b.tweens.cameraEase=c}else a.fn.showError(b.errorMsg);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("#mark-browsing").collapsibleMod();a("#stats").collapsibleMod({collapsedHeight:10});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 i=a("<option />").val(c.contributor_marks[h].reference).text(c.contributor_marks[h].contributor);g.append(i)}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(d.fn.getString("loading-marks-msg"),"overlay-light")):b.reference||d.fn.showLoader(d.fn.getString("loading-marks-msg"),"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 i=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 j=JSON.parse(b[e].points_obj_simplified);
|
||||
if("strokes"in j&&!(j.strokes.length==0||j.strokes[0].length<2)){f=new Mark.gmlMark(j.strokes,b[e].reference,b[e].country_code,b[e].date_drawn,j.rtl,b[e].id,b[e].is_approved);if(b[e].contributor)f.contributor_name=b[e].contributor,f.extra_info=j.extra_info,f.color="0,139,211";c.marks[f.reference]=f;i&&f.positionRelativeTo(i,h);h?g.unshift(f.reference):g.push(f.reference);i=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==0&&(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(d.fn.getString("month-abbreviations",e.getMonth())+" "+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("#contributor-name").text("- "+c.contributor_name)):(a("#mark-contributor-name, #contributor-quote, #contributor-name").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(b.errorMsg)}})},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(b.errorMs)}})},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(){c.currentMark.is_approved=b},error:function(){d.fn.showError(c.errorMsg)}})},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.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(e>1200?TWEEN.Easing.Quadratic.EaseInOut: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"),a("#translator-fields").find("#translator-locale").text("'"+b.locale+"'").end().collapsibleMod().fadeIn("slow")):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(b.fn.getString("submitting-mark"));var h={points_obj:e,points_obj_simplified:f,country_code:g};if(c.invite_code&&c.contributor_type=="t")h.contributor_locale=b.locale,h.invite=c.invite_code;else if(c.invite_code&&c.contributor_type=="c")h.contributor=a("#contributor-name").val(),c.mark.extra_info=a("#contributor-quote").val(),h.points_obj_simplified=JSON.stringify(c.mark),
|
||||
h.invite=c.invite_code;a.ajax({url:"/requests/save_mark",data:h,type:"POST",dataType:"JSON",success:function(a){h.contributor_locale?b.app.setLocation("#/linear/"):(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(b.fn.getString("submit-error"))}});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:-100},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 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 i=(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:i,end:i+c.curLocaleMark.maxTime,speed:2}}c.vizScene.objects.push(h);e=h}catch(j){}}},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){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,expandedHeight:0,collapsedHeight:0,$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");e.expandedHeight=e.$content.height();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.animate({height:d.collapsedHeight},"fast",function(){d.collapsedHeight==0&&d.$content.hide()});d.collapsed=
|
||||
!0;a.collapsibleMod.fn.saveState(d)},expand:function(d){d.$container.removeClass(d.collapsedClass).addClass(d.expandedClass);d.$content.show().animate({height:d.expandedHeight},"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+"="+encodeURIComponent(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 m=a('<div id="ui-selectBox-dropdown" class="ui-corner-bottom" />'),r=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(r).append('<li class="ui-selectBox-option'+c+'">'+p(b)+"</li>")}):(a(m).addClass("ui-selectBox-hasOptgroups"),a(c).children("optgroup").each(function(){a(r).append('<li class="ui-selectBox-optgroup">'+p(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(r).append('<li class="ui-selectBox-option'+
|
||||
c+'">'+p(b)+"</li>")})}));a(m).append(r);b=a(c)[0].selectedIndex;a(m).find("LI.ui-selectBox-option").eq(b).addClass("ui-selectBox-initial ui-selectBox-current");a(m).find("LI.ui-selectBox-option").hover(function(){a(m).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(m);c=a(d).offset();b=a(d).outerHeight();var h=a(d).outerWidth(),i=parseInt(a(m).css("borderLeftWidth"))+parseInt(a(m).css("borderRightWidth"));a(m).css({position:"absolute",zIndex:"999999",top:c.top+b,left:c.left,width:h-i}).show();a(d).removeClass("ui-corner-all").addClass("ui-corner-top");o(m);j(!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,
|
||||
m=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(m).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},i);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",i),a(c).trigger("blur"),e(b))},i=function(b){var d=b.data.select,l=b.data.control,m=a("#ui-selectBox-dropdown");if(a(l).hasClass("ui-selectBox-disabled"))return!1;switch(b.keyCode){case 9:h(b);break;case 13:if(a(m).size()===0)return!1;d=a(m).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 k=b.keyCode===33?20:1;if(a(m).size()===0){if(b.altKey)return c(b),!1;b=a(d).find("OPTION").size();m=a(d)[0].selectedIndex;for(k=a(d)[0].selectedIndex-k;a(d).find("OPTION").eq(k).attr("disabled")===!0&&k>=0;)k--;k<0&&(k=a(d).find("OPTION:not([disabled]):first").index());a(d)[0].selectedIndex=k;if(a(d)[0].selectedIndex===-1)k=0,a(d)[0].selectedIndex=k;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(l).find(".ui-selectBox-label").text(b);k!==m&&a(d).trigger("change");
|
||||
return!1}d=a(m).find(".ui-selectBox-option");g=-1;a.each(d,function(b,c){a(c).hasClass("ui-selectBox-current")&&(g=b)});g-=k;g<0&&(g=0);a(d).removeClass("ui-selectBox-current");a(d).eq(g).addClass("ui-selectBox-current");j();return!1;case 40:case 39:case 34:k=b.keyCode===34?20:1;if(a(m).size()===0){if(b.altKey)return c(b),!1;b=a(d).find("OPTION").size();m=a(d)[0].selectedIndex;for(k=a(d)[0].selectedIndex+k;a(d).find("OPTION").eq(k).attr("disabled")===!0&&k<=a(d).find("OPTION").size();)k++;k>b-1&&
|
||||
(k=a(d).find("OPTION:not([disabled]):last").index());a(d)[0].selectedIndex=k;if(a(d)[0].selectedIndex===-1)k=a(d).find("OPTION").size()-1,a(d)[0].selectedIndex=k;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(l).find(".ui-selectBox-label").text(b);k!=m&&a(d).trigger("change");return!1}d=a(m).find(".ui-selectBox-option");g=-1;a.each(d,function(b,c){a(c).hasClass("ui-selectBox-current")&&(g=b)});g+=k;g>a(d).size()-1&&(g=a(d).size()-1);a(d).removeClass("ui-selectBox-current");a(d).eq(g).addClass("ui-selectBox-current");
|
||||
j();return!1;case 36:case 35:if(a(m).size()===0){if(b.altKey)return c(b),!1;m=a(d)[0].selectedIndex;k=b.keyCode===36?0:a(d).find("OPTION").size()-1;a(d).find("OPTION").eq(k).attr("disabled")===!0&&(k=b.keyCode===36?a(d).find("OPTION:not([disabled]):first").index():a(d).find("OPTION:not([disabled]):last").index());a(d)[0].selectedIndex=k;b=a(d).find("OPTION:selected").text();b===""&&(b="\u00a0");a(l).find(".ui-selectBox-label").text(b);k!=m&&a(d).trigger("change");return!1}a(m).find(".ui-selectBox-current").removeClass("ui-selectBox-current");
|
||||
b.keyCode===36?a(m).find(".ui-selectBox-option:first").addClass("ui-selectBox-current"):a(m).find(".ui-selectBox-option:last").addClass("ui-selectBox-current");j();return!1}},j=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()))},o=function(b){a(b).css("MozUserSelect","none").bind("selectstart",function(){return!1}).bind("mousedown",function(){return!1});return!0},p=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 l=a('<optgroup label="'+d+'" />'),e;for(e in b[d])a(l).append('<option value="'+e+'">'+b[d][e]+"</option>")}else l=a('<option value="'+d+'">'+b[d]+"</option>");a(c).append(l)}}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 l=a('<a href="#" class="ui-selectBox ui-corner-all" tabindex="'+parseInt(a(e).attr("tabindex"))+'" />');a(l).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 m="";a(e).find("OPTION").each(function(){a(this).text().length>m.length&&(m=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">'+p(m)+"</li>");a(b).append(f);a("BODY").append(b);a(l).width(f.outerWidth());a(b).remove()}a(e)[0].tagName.toLowerCase()!==
|
||||
"select"||a(e).attr("multiple")===!0||(a(e).attr("disabled")===!0&&a(l).addClass("ui-selectBox-disabled"),b=a(e).find("OPTION:selected").text(),b===""&&(b="\u00a0"),a(l).append('<span class="ui-selectBox-label">'+p(b)+"</span>"),a(l).append('<span class="ui-selectBox-arrow"></span>'),a(e).hide().after(l),o(l),a(l).bind("click",function(){return!1}).bind("mousedown",{select:e,control:l},c).bind("focus",{select:e,control:l},g).bind("blur",{select:e,control:l},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,q,l,m=f,r,k=c[a];k&&typeof k==="object"&&typeof k.toJSON==="function"&&(k=k.toJSON(a));typeof i==="function"&&(k=i.call(c,a,k));switch(typeof k){case "string":return d(k);case "number":return isFinite(k)?String(k):"null";case "boolean":case "null":return String(k);case "object":if(!k)return"null";
|
||||
f+=g;r=[];if(Object.prototype.toString.apply(k)==="[object Array]"){l=k.length;for(e=0;e<l;e+=1)r[e]=b(e,k)||"null";q=r.length===0?"[]":f?"[\n"+f+r.join(",\n"+f)+"\n"+m+"]":"["+r.join(",")+"]";f=m;return q}if(i&&typeof i==="object"){l=i.length;for(e=0;e<l;e+=1)h=i[e],typeof h==="string"&&(q=b(h,k))&&r.push(d(h)+(f?": ":":")+q)}else for(h in k)Object.hasOwnProperty.call(k,h)&&(q=b(h,k))&&r.push(d(h)+(f?": ":":")+q);q=r.length===0?"{}":f?"{\n"+f+r.join(",\n"+f)+"\n"+m+"}":"{"+r.join(",")+"}";f=m;return q}}
|
||||
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",'"':'\\"',"\\":"\\\\"},i;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((i=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)},i=function(a,b){return Math.max(a,b)},j={thereYet:g,cap:h};g={thereYet:g,cap:h};if(d-c>0)g.thereYet=f,g.cap=i;if(a-b>0)j.thereYet=f,j.cap=i;this.moveTo(a,d);f=a;i=d;h=0;for(var o=!0;!j.thereYet(f,b)||!g.thereYet(i,c);){var p=Math.atan2(c-d,b-a),n=e[h];f=j.cap(b,f+Math.cos(p)*n);i=g.cap(c,i+Math.sin(p)*n);o?this.lineTo(f,i):this.moveTo(f,
|
||||
i);h=(h+1)%e.length;o=!o}};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.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 i=e.distanceToPoint(d[h]);i>f&&(f=i,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),i={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 j=null,o=0;o<b[f].length;o++)if(h=Mark.renderer.translatePoint(b[f][o],c),!(h.z&&h.z>a.dof)&&!(h.significance&&h.significance*(a.dof/5)<h.z-500))if(j){d.lineWidth=1;if(o==b[f].length-1)var p=
|
||||
0,n=0;else n=9-Math.max(0,Math.pow(h.speed+1,3)),c.mode=="flatScale"&&c.scale.thickness?n*=c.scale.thickness:h.z&&(n*=2/h.z*(g/2)),n<0.1&&(n=0.1),n+=1,p=Math.cos(h.angle)*n,n*=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(j.x-prevPX-0.5,j.y-prevPY-0.5),d.lineTo(j.x+prevPX-0.5,j.y+prevPY-0.5),d.lineTo(h.x+p-0.5,h.y+n-0.5),d.lineTo(h.x-p-0.5,h.y-n-0.5),d.lineTo(j.x-prevPX-
|
||||
0.5,j.y-prevPY-0.5),d.fill(),d.stroke()}catch(q){}i.minX=h.x<i.minX?h.x:i.minX;i.minY=h.y<i.minY?h.y:i.minY;i.maxX=h.x>i.maxX?h.x:i.maxX;i.maxY=h.y>i.maxY?h.y:i.maxY;j=h;prevPX=p;prevPY=n}else{if(f!=0&&h.z<1500&&(j=Mark.renderer.translatePoint(b[f-1][b[f-1].length-1],c),j.z&&j.z<a.dof))d.strokeStyle="rgba(0,0,0,0.3)",d.lineWidth=1,d.beginPath(),d.dashedLineTo(j.x,j.y,h.x,h.y,[6,4]),d.closePath(),d.stroke();j=h;prevPY=prevPX=0}return i}};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,i=0,j=b[g][0].x,o=b[g][0].y,p=1;p<b[g].length;p++){var n=b[g][p];if(!(n.significance<f)){if(p==b[g].length-1)var q=0,l=0;else l=9-Math.pow(n.speed+1,3),l<0.5&&(l=0.5),l+=1,q=Math.cos(n.angle)*l,l*=Math.sin(n.angle);try{a.beginPath(),
|
||||
a.moveTo(j-h-0.5+c,o-i-0.5+e),a.lineTo(j+h-0.5+c,o+i-0.5+e),a.lineTo(n.x+q-0.5+c,n.y+l-0.5+e),a.lineTo(n.x-q-0.5+c,n.y-l-0.5+e),a.lineTo(j-h-0.5+c,o-i-0.5+e),a.fill(),a.stroke()}catch(m){}h=q;i=l;j=n.x;o=n.y;prevAng=n.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 i=b[g][h];i.significance<f||(a.beginPath(),a.arc(i.x+c,i.y+e,3,0,Math.PI*2,!0),a.closePath(),a.fill(),a.stroke(),a.lineTo(i.x+c,i.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.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 l=this.strokes[e][f];b=l.x>b?l.x:b;d=l.y>d?l.y:d;c=l.x<c?l.x:c;a=l.y<a?l.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.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,o="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*(o/2)+e/2;a.y=a.y*c*(o/2)+o/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 i={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},j=d.objects[f+1].leftmostStrokeStart(),o=d.objects[f].rightmostStrokeEnd();Mark.connectionBrush(d.canvasContext,j,o,h,i,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)};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,i=null,j=null,o=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){i=a};this.onUpdate=
|
||||
function(a){j=a;return this};this.onComplete=function(a){o=a;return this};this.update=function(c){var f,q;if(c<g)return!0;c=(c-g)/e;c=c>1?1:c;q=h(c);for(f in b)a[f]=d[f]+b[f]*q;j!==null&&j.call(a,q);if(c==1)return o!==null&&o.call(a),i!==null&&i.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]"},i=function(a){return decodeURIComponent(a.replace(/\+/g," "))},j=encodeURIComponent,o=function(a){return String(a).replace(/&(?!\w+;)/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")},p=function(a){return function(b,c){return this.route.apply(this,
|
||||
[a,b,c])}},n={},q=[];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){q.push(a)};b.log=function(){var c=f(arguments);c.unshift("["+Date()+"]");a.each(q,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:o,h:o,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=[],i,j;!e&&g(d)&&(e=d=b,b="any");b=b.toLowerCase();if(d.constructor==String){for(c.lastIndex=0;(j=c.exec(d))!==null;)h.push(j[1]);d=RegExp("^"+d.replace(c,"([^/]+)")+"$")}typeof e=="string"&&(e=f[e]);i=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){i(b)}):i(b);return this},get:p("get"),post:p("post"),put:p("put"),del:p("delete"),any:p("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,j,n,o,p,q,s;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((q=g.path.exec(this.routablePath(c)))!==null)q.shift(),a.each(q,function(a,b){if(g.param_names[a])d[g.param_names[a]]=i(b);else{if(!d.splat)d.splat=
|
||||
[];d.splat.push(i(b))}});h=new this.context_prototype(this,b,c,d,e);e=this.arounds.slice(0);n=this.befores.slice(0);p=[h].concat(d.splat);j=function(){for(var a;n.length>0;)if(o=n.shift(),f.contextMatchesOptions(h,o[0])&&(a=o[1].apply(h,[h]),a===!1))return!1;f.last_route=g;h.trigger("event-context-before",{context:h});a=g.callback.apply(h,p);h.trigger("event-context-after",{context:h});return a};a.each(e.reverse(),function(a,b){var c=j;j=function(){return b.apply(h,[c])}});try{s=j()}catch(t){this.error(["500 Error",
|
||||
b,c].join(" "),t)}return s}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"?n[a]=b:n[a]},clearTemplateCache:function(){return n={}},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 j(a)+"="+j(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,i(c[0]),i(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,i;g(c)?(d=c,c={}):c=a.extend({},c);d&&this.then(d);if(typeof b==="string"){f=(i=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:i?"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={},i=this.next_engine||b;c?h[c]=d:h=d;e(d,g.event_context.interpolate(f,h,i))});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,102 @@
|
|||
/*
|
||||
* 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,
|
||||
'expandedHeight': 0,
|
||||
'collapsedHeight': 0,
|
||||
'$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' );
|
||||
|
||||
// save our height to expand to
|
||||
context.expandedHeight = context.$content.height();
|
||||
|
||||
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
|
||||
.animate( { 'height': context.collapsedHeight }, 'fast', function() {
|
||||
if ( context.collapsedHeight == 0 )
|
||||
context.$content.hide();
|
||||
} );
|
||||
context.collapsed = true;
|
||||
$.collapsibleMod.fn.saveState( context );
|
||||
},
|
||||
'expand': function ( context ) {
|
||||
context.$container
|
||||
.removeClass( context.collapsedClass )
|
||||
.addClass( context.expandedClass );
|
||||
context.$content
|
||||
.show()
|
||||
.animate( { 'height': context.expandedHeight }, '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,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,526 @@
|
|||
( 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' );
|
||||
$( '#translator-fields' )
|
||||
.find( '#translator-locale' )
|
||||
.text( "'" + context.locale + "'" )
|
||||
.end()
|
||||
.collapsibleMod( )
|
||||
.fadeIn( 'slow' );
|
||||
} 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( context.fn.getString( 'submitting-mark' ) );
|
||||
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 ) {
|
||||
// if we submitted a locale, the mark wont be in the line, so just start at the beginning
|
||||
if ( params.contributor_locale ) {
|
||||
context.app.setLocation( '#/linear/' );
|
||||
context.fn.hideLoader();
|
||||
} else {
|
||||
// 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( context.fn.getString( 'submit-error' ) );
|
||||
}
|
||||
} );
|
||||
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 ) {
|
||||
// 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,317 @@
|
|||
( function( $ ) {
|
||||
|
||||
// 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,
|
||||
translatedStrings: {},
|
||||
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;
|
||||
},
|
||||
ready: function ( e ) {
|
||||
// refresh our translations
|
||||
context.fn.loadTranslations();
|
||||
}
|
||||
},
|
||||
// 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 = typeof custom_class === "string" ? custom_class : '';
|
||||
var msg = typeof msg === "string" ? msg : context.fn.getString( 'default-loading-msg' );
|
||||
// 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 ) {
|
||||
var msg = typeof msg === "string" ? msg : context.fn.getString( 'default-error-msg' );
|
||||
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 />' ).html( msg ) ) );
|
||||
context.$container
|
||||
.append( $error );
|
||||
$error.fadeIn( 'fast' );
|
||||
},
|
||||
hideError: function ( ) {
|
||||
$( '#markapp-error' ).fadeOut( 'fast', function() {
|
||||
$( this ).remove();
|
||||
} );
|
||||
},
|
||||
// parses translated strings out of div.translated-strings
|
||||
// ol's are treated as arrays
|
||||
// everything else as is
|
||||
loadTranslations: function( ) {
|
||||
$( 'div.translated-strings' ).each( function () {
|
||||
$( this ).children().each( function () {
|
||||
var $this = $( this );
|
||||
if ( $this.is( 'ol' ) ) {
|
||||
// if it's an ol, load the strings in each childnode as an array
|
||||
context.translatedStrings[$this.attr( 'id' )] = [];
|
||||
$this.children().each( function () {
|
||||
context.translatedStrings[$this.attr( 'id' )].push( $( this ).html() );
|
||||
} );
|
||||
} else {
|
||||
// otherwise just load the elements contents
|
||||
context.translatedStrings[$this.attr( 'id' )] = $this.html();
|
||||
}
|
||||
} );
|
||||
} );
|
||||
},
|
||||
// looks for a match in translated stings
|
||||
// returns the match if found, else it returns the key
|
||||
getString: function ( key, index ) {
|
||||
if( key in context.translatedStrings ) {
|
||||
if( typeof context.translatedStrings[key] === "object" && typeof index === "number" ) {
|
||||
// if this tranlsation is an array of strings, and we were passed an index val
|
||||
return context.translatedStrings[key][index];
|
||||
} else {
|
||||
// otherwise just return the match
|
||||
return context.translatedStrings[key];
|
||||
}
|
||||
} else {
|
||||
// fallback to returning the passed key if we can't find the translation
|
||||
return key;
|
||||
}
|
||||
},
|
||||
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 */ }
|
||||
}
|
||||
}
|
||||
},
|
||||
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,975 @@
|
|||
( 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 ? '0,139,211' : '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 {
|
||||
$( '#contributor-quote-box:visible' ).fadeOut( 'fast' );
|
||||
lC.hoverMark.color = lC.hoverMark.contributor_name ? '255,111,40' : '0,139,211';
|
||||
}
|
||||
} else if ( lC.hoverMark ) {
|
||||
lC.hoverMark.color = lC.hoverMark.contributor_name ? '0,139,211' : '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 ? '0,139,211' : '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': context.fn.getString( 'twitter-msg' ) }
|
||||
} );
|
||||
$( '#facebook-share' ).socialShare( {
|
||||
'share_url': 'http://www.facebook.com/sharer.php',
|
||||
'share_params': { 't': context.fn.getString( 'facebook-msg' ) }
|
||||
} );
|
||||
// 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
|
||||
context.fn.showError( lC.errorMsg );
|
||||
}
|
||||
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 );
|
||||
// after we load the marks, back the camera away and zoom to the first one
|
||||
if( firstMark = lC.marks[data.marks[0].reference] ) {
|
||||
lC.scene.camera.position.x = -4000;
|
||||
lC.scene.camera.position.z = -3000;
|
||||
var tween = 'cameraEase' in lC.tweens ? lC.tweens['cameraEase'] : new TWEEN.Tween( lC.scene.camera.position );
|
||||
tween
|
||||
.to( {
|
||||
x: ( firstMark.bWidth / 2 ),
|
||||
y: ( firstMark.bHeight / 2 ),
|
||||
z: -1000 }, 2000 )
|
||||
.onComplete( function( ) {
|
||||
delete lC.tweens['cameraEase'];
|
||||
if ( typeof callback === "function" ) callback( this );
|
||||
} )
|
||||
.easing( TWEEN.Easing.Quartic.EaseInOut )
|
||||
.start();
|
||||
lC.tweens['cameraEase'] = tween;
|
||||
}
|
||||
} else {
|
||||
// show the error message, with a link back to the main visualization link
|
||||
context.fn.showError( lC.errorMsg );
|
||||
}
|
||||
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
|
||||
$( '#mark-browsing' ).collapsibleMod( );
|
||||
$( '#stats' ).collapsibleMod( { 'collapsedHeight': 10 } );
|
||||
|
||||
// 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;
|
||||
},
|
||||
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( context.fn.getString( 'loading-marks-msg' ), 'overlay-light' );
|
||||
} else if ( ! options.reference ) {
|
||||
context.fn.showLoader( context.fn.getString( 'loading-marks-msg' ), '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 = '0,139,211';
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
// if ( !lC.currentMark ) lC.currentMark = mark;
|
||||
},
|
||||
// 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( context.fn.getString( 'month-abbreviations', d.getMonth() ) + " " + d.getDate() );
|
||||
// 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() + "”" );
|
||||
$( '#contributor-name' )
|
||||
.text( "- " + mark.contributor_name );
|
||||
} else {
|
||||
$( '#mark-contributor-name, #contributor-quote, #contributor-name' ).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 ) {
|
||||
context.fn.showError( lC.errorMsg );
|
||||
}
|
||||
} );
|
||||
|
||||
},
|
||||
deleteCurrentMark: function ( context ) {
|
||||
var lC = context.modules.linear;
|
||||
$.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( lC.errorMs );
|
||||
}
|
||||
} );
|
||||
},
|
||||
approveCurrentMark: function ( context, shouldApprove ) {
|
||||
var lC = context.modules.linear;
|
||||
$.ajax( {
|
||||
url: '/requests/approve_mark',
|
||||
data: {
|
||||
'reference': lC.currentMark.reference,
|
||||
'should_approve': shouldApprove
|
||||
},
|
||||
type: 'POST',
|
||||
dataType: 'JSON',
|
||||
success: function( data ) {
|
||||
// Update approved status locally
|
||||
lC.currentMark.is_approved = shouldApprove;
|
||||
},
|
||||
error: function ( data ) {
|
||||
context.fn.showError( lC.errorMsg );
|
||||
}
|
||||
} );
|
||||
},
|
||||
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;
|
||||
speed = Math.max( 1000, speed );
|
||||
|
||||
// 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( speed > 1200 ? TWEEN.Easing.Quadratic.EaseInOut : TWEEN.Easing.Quartic.EaseInOut )
|
||||
.start();
|
||||
lC.tweens['cameraEase'] = tween;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}( jQuery ) );
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* A generic plugin to assist with those pesky social media buttons.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* EXAMPLE:
|
||||
* $( '#twitter-share' ).socialShare( {
|
||||
* 'share_url': 'http://twitter.com/share',
|
||||
* 'share_params': { 'text': 'Wow. I love this website. Check. It. Out', 'url': 'http://thegreatestwebsiteever.com/' }
|
||||
* } );
|
||||
*
|
||||
* 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 + '=' + encodeURIComponent( 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 ) ) 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,14 @@
|
|||
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 );
|
||||
|
||||
};
|
||||
|
||||
return mark;
|
||||
|
||||
}( Mark || {} ) );
|
|
@ -0,0 +1,166 @@
|
|||
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';
|
||||
|
||||
// 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;
|
||||
};
|
||||
|
||||
|
||||
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,45 @@
|
|||
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.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,156 @@
|
|||
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 - an object with x, y and possibly thickness values to scale the x, y coords and the stroke thickness by.
|
||||
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 || {} ) );
|
|
@ -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 || {} ) );
|
|
@ -0,0 +1,86 @@
|
|||
var Mark = ( function ( mark ) {
|
||||
mark.simplification = {
|
||||
// helper function
|
||||
Line: function( p1, p2 ) {
|
||||
this.p1 = p1;
|
||||
this.p2 = p2;
|
||||
this.distanceToPoint = function( point ) {
|
||||
// slope
|
||||
var m = ( this.p2.y - this.p1.y ) / ( this.p2.x - this.p1.x );
|
||||
// y offset
|
||||
var b = this.p1.y - ( m * this.p1.x );
|
||||
var d = [];
|
||||
// distance to the linear equation
|
||||
d.push( Math.abs( point.y - ( m * point.x ) - b ) / Math.sqrt( Math.pow( m, 2 ) + 1 ) )
|
||||
// distance to p1
|
||||
d.push( Math.sqrt( Math.pow( ( point.x - this.p1.x ), 2 ) + Math.pow( ( point.y - this.p1.y ), 2 ) ) )
|
||||
// distance to p2
|
||||
d.push( Math.sqrt( Math.pow( ( point.x - this.p2.x ), 2 ) + Math.pow( ( point.y - this.p2.y ), 2 ) ) );
|
||||
// return the smallest distance
|
||||
return d.sort( function( a, b ) {
|
||||
return ( a - b ) //causes an array to be sorted numerically and ascending
|
||||
} )[0];
|
||||
}
|
||||
},
|
||||
// main simplification algorithm
|
||||
douglasPeucker: function( points, tolerance ) {
|
||||
var returnPoints = [];
|
||||
if ( points.length <= 2 ) {
|
||||
return [points[0]];
|
||||
}
|
||||
// make line from start to end
|
||||
var line = new mark.simplification.Line( points[0], points[points.length - 1] );
|
||||
// find the largest distance from intermediate poitns to this line
|
||||
var maxDistance = 0;
|
||||
var maxDistanceIndex = 0;
|
||||
for( var i = 1; i <= points.length - 2; i++ ) {
|
||||
var distance = line.distanceToPoint( points[ i ] );
|
||||
if( distance > maxDistance ) {
|
||||
maxDistance = distance;
|
||||
maxDistanceIndex = i;
|
||||
}
|
||||
}
|
||||
// check if the max distance is greater than our tollerance allows
|
||||
if ( maxDistance >= tolerance ) {
|
||||
var p = points[maxDistanceIndex];
|
||||
line.distanceToPoint( p, true );
|
||||
// include this point in the output
|
||||
returnPoints = returnPoints.concat( mark.simplification.douglasPeucker( points.slice( 0, maxDistanceIndex + 1 ), tolerance ) );
|
||||
// returnPoints.push( points[maxDistanceIndex] );
|
||||
returnPoints = returnPoints.concat( mark.simplification.douglasPeucker( points.slice( maxDistanceIndex, points.length ), tolerance ) );
|
||||
} else {
|
||||
// ditching this point
|
||||
var p = points[maxDistanceIndex];
|
||||
line.distanceToPoint( p, true );
|
||||
returnPoints = [points[0]];
|
||||
}
|
||||
return returnPoints;
|
||||
},
|
||||
// returns a simplified version of a stroke based on the passed tolerance
|
||||
simplifyPath: function( points, tolerance ) {
|
||||
var arr = mark.simplification.douglasPeucker( points, tolerance );
|
||||
// always have to push the very last point on so it doesn't get left off
|
||||
arr.push( points[points.length - 1 ] );
|
||||
return arr;
|
||||
},
|
||||
// weights a stroke based on the passed tolerances
|
||||
weightPath: function( points, tolerances ) {
|
||||
var maxSignificance = tolerances.length + 1;
|
||||
var tmpPoints = points;
|
||||
while( tolerance = tolerances.shift() ) {
|
||||
// limit the points array by the current tolerance
|
||||
tmpPoints = mark.simplification.douglasPeucker( tmpPoints, tolerance );
|
||||
// increment the significance of all points that pass the simplfification
|
||||
for( var i = 0; i < tmpPoints.length; i++ ) {
|
||||
tmpPoints[i].significance++;
|
||||
}
|
||||
}
|
||||
// maker sure the beginning and end of all strokes get the hightest significance
|
||||
points[0].significance = maxSignificance;
|
||||
points[points.length - 1].significance = maxSignificance;
|
||||
return points;
|
||||
}
|
||||
};
|
||||
|
||||
return mark;
|
||||
}( Mark || {} ) );
|
|
@ -0,0 +1,110 @@
|
|||
Sammy.HashPushProxy = function(app, run_interval_every) {
|
||||
this.app = app;
|
||||
// detect if we can use the history api
|
||||
this.supportsHistory = !!( window.history && history.pushState );
|
||||
if( !this.supportsHistory ) {
|
||||
// if history is not supported, start polling
|
||||
this._startPolling( run_interval_every );
|
||||
// and set this as a non native app?
|
||||
this.is_native = false;
|
||||
}
|
||||
};
|
||||
|
||||
Sammy.HashPushProxy.prototype = {
|
||||
|
||||
// bind the proxy events to the current app.
|
||||
bind: function() {
|
||||
var proxy = this, app = this.app;
|
||||
if( this.app.supportsHistory ) {
|
||||
$( window ).bind( 'popstate', function( e ) {
|
||||
proxy.app.trigger( 'location-changed' );
|
||||
} );
|
||||
$( 'a' ).live( 'click', function(e) {
|
||||
// Do not bind external links
|
||||
if ( location.hostname == this.hostname ) {
|
||||
e.preventDefault();
|
||||
// if the history API is supported
|
||||
if ( proxy.historyAPISupported ) {
|
||||
proxy.setLocation( $( this ).attr( 'href' ) );
|
||||
proxy.app.trigger( 'location-changed' );
|
||||
} else {
|
||||
proxy.setLocation( '#' + $( this ).attr( 'href' ) );
|
||||
proxy.app.trigger( 'location-changed' );
|
||||
}
|
||||
|
||||
}
|
||||
} );
|
||||
} else {
|
||||
$( window ).bind( 'hashchange.' + this.app.eventNamespace(), function( e, non_native ) {
|
||||
// if we receive a native hash change event, set the proxy accordingly
|
||||
// and stop polling
|
||||
if ( proxy.is_native === false && !non_native ) {
|
||||
Sammy.log('native hash change exists, using');
|
||||
proxy.is_native = true;
|
||||
window.clearInterval(Sammy.HashLocationProxy._interval);
|
||||
}
|
||||
app.trigger('location-changed');
|
||||
});
|
||||
if (!Sammy.HashLocationProxy._bindings) {
|
||||
Sammy.HashLocationProxy._bindings = 0;
|
||||
}
|
||||
Sammy.HashLocationProxy._bindings++;
|
||||
}
|
||||
},
|
||||
|
||||
// unbind the proxy events from the current app
|
||||
unbind: function() {
|
||||
if( this.app.supportsHistory ) {
|
||||
$('a').unbind('click');
|
||||
$(window).unbind('popstate');
|
||||
} else {
|
||||
$(window).unbind('hashchange.' + this.app.eventNamespace());
|
||||
Sammy.HashLocationProxy._bindings--;
|
||||
if (Sammy.HashLocationProxy._bindings <= 0) {
|
||||
window.clearInterval(Sammy.HashLocationProxy._interval);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// get the current location.
|
||||
getLocation: function() {
|
||||
if( this.app.supportsHistory ) {
|
||||
return window.location.pathname;
|
||||
} else {
|
||||
// Bypass the `window.location.hash` attribute. If a question mark
|
||||
// appears in the hash IE6 will strip it and all of the following
|
||||
// characters from `window.location.hash`.
|
||||
var matches = window.location.toString().match(/^[^#]*(#.+)$/);
|
||||
return matches ? matches[1] : '';
|
||||
}
|
||||
},
|
||||
|
||||
// set the current location to `new_location`
|
||||
setLocation: function( new_location ) {
|
||||
if( this.app.supportsHistory ) {
|
||||
history.pushState( { path: this.path }, '', new_location )
|
||||
} else {
|
||||
return (window.location = new_location);
|
||||
}
|
||||
},
|
||||
|
||||
_startPolling: function(every) {
|
||||
// set up interval
|
||||
var proxy = this;
|
||||
if (!Sammy.HashLocationProxy._interval) {
|
||||
if (!every) { every = 10; }
|
||||
var hashCheck = function() {
|
||||
var current_location = proxy.getLocation();
|
||||
if (!Sammy.HashLocationProxy._last_location ||
|
||||
current_location != Sammy.HashLocationProxy._last_location) {
|
||||
window.setTimeout(function() {
|
||||
$(window).trigger('hashchange', [true]);
|
||||
}, 13);
|
||||
}
|
||||
Sammy.HashLocationProxy._last_location = current_location;
|
||||
};
|
||||
hashCheck();
|
||||
Sammy.HashLocationProxy._interval = window.setInterval(hashCheck, every);
|
||||
}
|
||||
}
|
||||
};
|
|
@ -0,0 +1,141 @@
|
|||
(function($) {
|
||||
|
||||
// Simple JavaScript Templating
|
||||
// John Resig - http://ejohn.org/ - MIT Licensed
|
||||
// adapted from: http://ejohn.org/blog/javascript-micro-templating/
|
||||
// originally $.srender by Greg Borenstein http://ideasfordozens.com in Feb 2009
|
||||
// modified for Sammy by Aaron Quint for caching templates by name
|
||||
var srender_cache = {};
|
||||
var srender = function(name, template, data, options) {
|
||||
var fn, escaped_string;
|
||||
// target is an optional element; if provided, the result will be inserted into it
|
||||
// otherwise the result will simply be returned to the caller
|
||||
if (srender_cache[name]) {
|
||||
fn = srender_cache[name];
|
||||
} else {
|
||||
if (typeof template == 'undefined') {
|
||||
// was a cache check, return false
|
||||
return false;
|
||||
}
|
||||
// If options escape_html is false, dont escape the contents by default
|
||||
if (options && options.escape_html === false) {
|
||||
escaped_string = "\",$1,\"";
|
||||
} else {
|
||||
escaped_string = "\",h($1),\"";
|
||||
}
|
||||
// Generate a reusable function that will serve as a template
|
||||
// generator (and which will be cached).
|
||||
fn = srender_cache[name] = new Function("obj",
|
||||
"var ___$$$___=[],print=function(){___$$$___.push.apply(___$$$___,arguments);};" +
|
||||
|
||||
// Introduce the data as local variables using with(){}
|
||||
"with(obj){___$$$___.push(\"" +
|
||||
|
||||
// Convert the template into pure JavaScript
|
||||
String(template)
|
||||
.replace(/[\r\t\n]/g, " ")
|
||||
.replace(/\"/g, '\\"')
|
||||
.split("<%").join("\t")
|
||||
.replace(/((^|%>)[^\t]*)/g, "$1\r")
|
||||
.replace(/\t=(.*?)%>/g, escaped_string)
|
||||
.replace(/\t!(.*?)%>/g, "\",$1,\"")
|
||||
.split("\t").join("\");")
|
||||
.split("%>").join("___$$$___.push(\"")
|
||||
.split("\r").join("")
|
||||
+ "\");}return ___$$$___.join('');");
|
||||
}
|
||||
|
||||
if (typeof data != 'undefined') {
|
||||
return fn(data);
|
||||
} else {
|
||||
return fn;
|
||||
}
|
||||
};
|
||||
|
||||
Sammy = Sammy || {};
|
||||
|
||||
// `Sammy.Template` is a simple plugin that provides a way to create
|
||||
// and render client side templates. The rendering code is based on John Resig's
|
||||
// quick templates and Greg Borenstien's srender plugin.
|
||||
// This is also a great template/boilerplate for Sammy plugins.
|
||||
//
|
||||
// Templates use `<% %>` tags to denote embedded javascript.
|
||||
//
|
||||
// ### Examples
|
||||
//
|
||||
// Here is an example template (user.template):
|
||||
//
|
||||
// // user.template
|
||||
// <div class="user">
|
||||
// <div class="user-name"><%= user.name %></div>
|
||||
// <% if (user.photo_url) { %>
|
||||
// <div class="photo"><img src="<%= user.photo_url %>" /></div>
|
||||
// <% } %>
|
||||
// </div>
|
||||
//
|
||||
// Given that is a publicly accesible file, you would render it like:
|
||||
//
|
||||
// // app.js
|
||||
// $.sammy(function() {
|
||||
// // include the plugin
|
||||
// this.use('Template');
|
||||
//
|
||||
// this.get('#/', function() {
|
||||
// // the template is rendered in the current context.
|
||||
// this.user = {name: 'Aaron Quint'};
|
||||
// // partial calls template() because of the file extension
|
||||
// this.partial('user.template');
|
||||
// })
|
||||
// });
|
||||
//
|
||||
// You can also pass a second argument to use() that will alias the template
|
||||
// method and therefore allow you to use a different extension for template files
|
||||
// in <tt>partial()</tt>
|
||||
//
|
||||
// // alias to 'tpl'
|
||||
// this.use(Sammy.Template, 'tpl');
|
||||
//
|
||||
// // now .tpl files will be run through srender
|
||||
// this.get('#/', function() {
|
||||
// this.partial('myfile.tpl');
|
||||
// });
|
||||
//
|
||||
// By default, the data passed into the tempalate is passed automatically passed through
|
||||
// Sammy's `escapeHTML` method in order to prevent possible XSS attacks. This is
|
||||
// a problem though if you're using something like `Sammy.Form` which renders HTML
|
||||
// within the templates. You can get around this in two ways. One, you can use the
|
||||
// `<%! %>` instead of `<%= %>`. Two, you can pass the `escape_html = false` option
|
||||
// when interpolating, i.e:
|
||||
//
|
||||
// this.get('#/', function() {
|
||||
// this.template('myform.tpl', {form: "<form></form>"}, {escape_html: false});
|
||||
// });
|
||||
//
|
||||
Sammy.Template = function(app, method_alias) {
|
||||
|
||||
// *Helper:* Uses simple templating to parse ERB like templates.
|
||||
//
|
||||
// ### Arguments
|
||||
//
|
||||
// * `template` A String template. '<% %>' tags are evaluated as Javascript and replaced with the elements in data.
|
||||
// * `data` An Object containing the replacement values for the template.
|
||||
// data is extended with the <tt>EventContext</tt> allowing you to call its methods within the template.
|
||||
// * `name` An optional String name to cache the template.
|
||||
//
|
||||
var template = function(template, data, name, options) {
|
||||
// use name for caching
|
||||
if (typeof name == 'undefined') { name = template; }
|
||||
if (typeof options == 'undefined' && typeof name == 'object') {
|
||||
options = name; name = template;
|
||||
}
|
||||
return srender(name, template, $.extend({}, this, data), options);
|
||||
};
|
||||
|
||||
// set the default method name/extension
|
||||
if (!method_alias) { method_alias = 'template'; }
|
||||
// create the helper at the method alias
|
||||
app.helper(method_alias, template);
|
||||
|
||||
};
|
||||
|
||||
})(jQuery);
|
|
@ -0,0 +1,470 @@
|
|||
/**
|
||||
* @author sole / http://soledadpenades.com
|
||||
* @author mr.doob / http://mrdoob.com
|
||||
* @author Robert Eisele / http://www.xarg.org
|
||||
* @author Philippe / http://philippe.elsass.me
|
||||
* @author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html
|
||||
*/
|
||||
|
||||
var TWEEN = TWEEN || ( function() {
|
||||
|
||||
var i, n, time, tweens = [];
|
||||
|
||||
this.add = function ( tween ) {
|
||||
|
||||
tweens.push( tween );
|
||||
|
||||
};
|
||||
|
||||
this.remove = function ( tween ) {
|
||||
|
||||
i = tweens.indexOf( tween );
|
||||
|
||||
if ( i !== -1 ) {
|
||||
|
||||
tweens.splice( i, 1 );
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.update = function () {
|
||||
|
||||
i = 0;
|
||||
n = tweens.length;
|
||||
time = new Date().getTime();
|
||||
|
||||
while ( i < n ) {
|
||||
|
||||
if ( tweens[ i ].update( time ) ) {
|
||||
|
||||
i++;
|
||||
|
||||
} else {
|
||||
|
||||
tweens.splice( i, 1 );
|
||||
n--;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return this;
|
||||
|
||||
} )();
|
||||
|
||||
TWEEN.Tween = function ( object ) {
|
||||
|
||||
var _object = object,
|
||||
_valuesStart = {},
|
||||
_valuesDelta = {},
|
||||
_valuesEnd = {},
|
||||
_duration = 1000,
|
||||
_delayTime = 0,
|
||||
_startTime = null,
|
||||
_easingFunction = TWEEN.Easing.Linear.EaseNone,
|
||||
_chainedTween = null,
|
||||
_onUpdateCallback = null,
|
||||
_onCompleteCallback = null;
|
||||
|
||||
this.to = function ( properties, duration ) {
|
||||
|
||||
if( duration !== null ) {
|
||||
|
||||
_duration = duration;
|
||||
|
||||
}
|
||||
|
||||
for ( var property in properties ) {
|
||||
|
||||
// This prevents the engine from interpolating null values
|
||||
if ( _object[ property ] === null ) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// The current values are read when the tween starts;
|
||||
// here we only store the final desired values
|
||||
_valuesEnd[ property ] = properties[ property ];
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.start = function () {
|
||||
|
||||
TWEEN.add( this );
|
||||
|
||||
_startTime = new Date().getTime() + _delayTime;
|
||||
|
||||
for ( var property in _valuesEnd ) {
|
||||
|
||||
// Again, prevent dealing with null values
|
||||
if ( _object[ property ] === null ) {
|
||||
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
_valuesStart[ property ] = _object[ property ];
|
||||
_valuesDelta[ property ] = _valuesEnd[ property ] - _object[ property ];
|
||||
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.stop = function () {
|
||||
|
||||
TWEEN.remove( this );
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.delay = function ( amount ) {
|
||||
|
||||
_delayTime = amount;
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.easing = function ( easing ) {
|
||||
|
||||
_easingFunction = easing;
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.chain = function ( chainedTween ) {
|
||||
|
||||
_chainedTween = chainedTween;
|
||||
|
||||
};
|
||||
|
||||
this.onUpdate = function ( onUpdateCallback ) {
|
||||
|
||||
_onUpdateCallback = onUpdateCallback;
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.onComplete = function ( onCompleteCallback ) {
|
||||
|
||||
_onCompleteCallback = onCompleteCallback;
|
||||
return this;
|
||||
|
||||
};
|
||||
|
||||
this.update = function ( time ) {
|
||||
|
||||
var property, elapsed, value;
|
||||
|
||||
if ( time < _startTime ) {
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
elapsed = ( time - _startTime ) / _duration;
|
||||
elapsed = elapsed > 1 ? 1 : elapsed;
|
||||
|
||||
value = _easingFunction( elapsed );
|
||||
|
||||
for ( property in _valuesDelta ) {
|
||||
|
||||
_object[ property ] = _valuesStart[ property ] + _valuesDelta[ property ] * value;
|
||||
|
||||
}
|
||||
|
||||
if ( _onUpdateCallback !== null ) {
|
||||
|
||||
_onUpdateCallback.call( _object, value );
|
||||
|
||||
}
|
||||
|
||||
if ( elapsed == 1 ) {
|
||||
|
||||
if ( _onCompleteCallback !== null ) {
|
||||
|
||||
_onCompleteCallback.call( _object );
|
||||
|
||||
}
|
||||
|
||||
if ( _chainedTween !== null ) {
|
||||
|
||||
_chainedTween.start();
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
this.destroy = function () {
|
||||
|
||||
TWEEN.remove( this );
|
||||
|
||||
};
|
||||
*/
|
||||
}
|
||||
|
||||
TWEEN.Easing = { Linear: {}, Quadratic: {}, Cubic: {}, Quartic: {}, Quintic: {}, Sinusoidal: {}, Exponential: {}, Circular: {}, Elastic: {}, Back: {}, Bounce: {} };
|
||||
|
||||
|
||||
TWEEN.Easing.Linear.EaseNone = function ( k ) {
|
||||
|
||||
return k;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Quadratic.EaseIn = function ( k ) {
|
||||
|
||||
return k * k;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Quadratic.EaseOut = function ( k ) {
|
||||
|
||||
return - k * ( k - 2 );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Quadratic.EaseInOut = function ( k ) {
|
||||
|
||||
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k;
|
||||
return - 0.5 * ( --k * ( k - 2 ) - 1 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Cubic.EaseIn = function ( k ) {
|
||||
|
||||
return k * k * k;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Cubic.EaseOut = function ( k ) {
|
||||
|
||||
return --k * k * k + 1;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Cubic.EaseInOut = function ( k ) {
|
||||
|
||||
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k;
|
||||
return 0.5 * ( ( k -= 2 ) * k * k + 2 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Quartic.EaseIn = function ( k ) {
|
||||
|
||||
return k * k * k * k;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Quartic.EaseOut = function ( k ) {
|
||||
|
||||
return - ( --k * k * k * k - 1 );
|
||||
|
||||
}
|
||||
|
||||
TWEEN.Easing.Quartic.EaseInOut = function ( k ) {
|
||||
|
||||
if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k;
|
||||
return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Quintic.EaseIn = function ( k ) {
|
||||
|
||||
return k * k * k * k * k;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Quintic.EaseOut = function ( k ) {
|
||||
|
||||
return ( k = k - 1 ) * k * k * k * k + 1;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Quintic.EaseInOut = function ( k ) {
|
||||
|
||||
if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k;
|
||||
return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Sinusoidal.EaseIn = function ( k ) {
|
||||
|
||||
return - Math.cos( k * Math.PI / 2 ) + 1;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Sinusoidal.EaseOut = function ( k ) {
|
||||
|
||||
return Math.sin( k * Math.PI / 2 );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Sinusoidal.EaseInOut = function ( k ) {
|
||||
|
||||
return - 0.5 * ( Math.cos( Math.PI * k ) - 1 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Exponential.EaseIn = function ( k ) {
|
||||
|
||||
return k == 0 ? 0 : Math.pow( 2, 10 * ( k - 1 ) );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Exponential.EaseOut = function ( k ) {
|
||||
|
||||
return k == 1 ? 1 : - Math.pow( 2, - 10 * k ) + 1;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Exponential.EaseInOut = function ( k ) {
|
||||
|
||||
if ( k == 0 ) return 0;
|
||||
if ( k == 1 ) return 1;
|
||||
if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 2, 10 * ( k - 1 ) );
|
||||
return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Circular.EaseIn = function ( k ) {
|
||||
|
||||
return - ( Math.sqrt( 1 - k * k ) - 1);
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Circular.EaseOut = function ( k ) {
|
||||
|
||||
return Math.sqrt( 1 - --k * k );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Circular.EaseInOut = function ( k ) {
|
||||
|
||||
if ( ( k /= 0.5 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1);
|
||||
return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1);
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Elastic.EaseIn = function( k ) {
|
||||
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if ( k == 0 ) return 0; if ( k == 1 ) return 1; if ( !p ) p = 0.3;
|
||||
if ( !a || a < 1 ) { a = 1; s = p / 4; }
|
||||
else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
|
||||
return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Elastic.EaseOut = function( k ) {
|
||||
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if ( k == 0 ) return 0; if ( k == 1 ) return 1; if ( !p ) p = 0.3;
|
||||
if ( !a || a < 1 ) { a = 1; s = p / 4; }
|
||||
else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
|
||||
return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Elastic.EaseInOut = function( k ) {
|
||||
|
||||
var s, a = 0.1, p = 0.4;
|
||||
if ( k == 0 ) return 0; if ( k == 1 ) return 1; if ( !p ) p = 0.3;
|
||||
if ( !a || a < 1 ) { a = 1; s = p / 4; }
|
||||
else s = p / ( 2 * Math.PI ) * Math.asin( 1 / a );
|
||||
if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) );
|
||||
return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1;
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Back.EaseIn = function( k ) {
|
||||
|
||||
var s = 1.70158;
|
||||
return k * k * ( ( s + 1 ) * k - s );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Back.EaseOut = function( k ) {
|
||||
|
||||
var s = 1.70158;
|
||||
return ( k = k - 1 ) * k * ( ( s + 1 ) * k + s ) + 1;
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Back.EaseInOut = function( k ) {
|
||||
|
||||
var s = 1.70158 * 1.525;
|
||||
if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) );
|
||||
return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 );
|
||||
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
TWEEN.Easing.Bounce.EaseIn = function( k ) {
|
||||
|
||||
return 1 - TWEEN.Easing.Bounce.EaseOut( 1 - k );
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Bounce.EaseOut = function( k ) {
|
||||
|
||||
if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {
|
||||
|
||||
return 7.5625 * k * k;
|
||||
|
||||
} else if ( k < ( 2 / 2.75 ) ) {
|
||||
|
||||
return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;
|
||||
|
||||
} else if ( k < ( 2.5 / 2.75 ) ) {
|
||||
|
||||
return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;
|
||||
|
||||
} else {
|
||||
|
||||
return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
TWEEN.Easing.Bounce.EaseInOut = function( k ) {
|
||||
|
||||
if ( k < 0.5 ) return TWEEN.Easing.Bounce.EaseIn( k * 2 ) * 0.5;
|
||||
return TWEEN.Easing.Bounce.EaseOut( k * 2 - 1 ) * 0.5 + 0.5;
|
||||
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% block bodytag %}
|
||||
<body class="behind-the-code about">
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<section id="static-content">
|
||||
<section class="col-secondary">
|
||||
<nav id="about-nav">
|
||||
<ul>
|
||||
<li id="about-mozilla"><a href="/about/mozilla">{{ _('About Mozilla') }}</a></li>
|
||||
<li id="about-gml"><a href="/about/gml">{{ _('GML') }}</a></li>
|
||||
<li id="about-evan-roth"><a href="/about/evan-roth">{{ _('Evan Roth') }}</a></li>
|
||||
<li id="about-code"><a href="/about/code">{{ _('Code Repository') }}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
<section class="col-main col-last">
|
||||
{% block about-content %}
|
||||
<h1>{{ _('Behind the Code') }}</h1>
|
||||
{% blocktrans %}
|
||||
<p>A non-profit browser dedicated to placing the future of the Web in the hands of the people. An artist inspired by graffiti and free culture. What happens when these two like-minded entities collaborate? Mark Up, a project that reflects the collective nature of the Web.</p>
|
||||
|
||||
<p>Here’s where you’ll find more information on Mozilla and Evan Roth, and the project born of this collaboration.</p>
|
||||
|
||||
<p>Learn more about the mission of Mark Up and the contribution from respected open Web advocate Lawrence Lessig <a href="/manifesto">here</a>.</p>
|
||||
{% endblocktrans %}
|
||||
{% endblock %}
|
||||
</section>
|
||||
</section>
|
||||
{% endblock %}
|
|
@ -0,0 +1,103 @@
|
|||
{% load i18n %}
|
||||
|
||||
{% load localeurl_tags %}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="title" content="Mozilla Firefox Mark Up">
|
||||
<meta name="description" content="The Web is your creation. Show your support to keep it open and accessible to all. Make your mark." />
|
||||
<link rel="image_src" href="/media/assets/images/site_thumb.jpg" />
|
||||
|
||||
<meta property="og:title" content="Mozilla Firefox Mark Up"/>
|
||||
<meta property="og:type" content="website"/>
|
||||
<meta property="og:url" content="http://markup.mozilla.com"/>
|
||||
<meta property="og:image" content="http://markup.mozilla.com/media/assets/images/site_thumb.jpg"/>
|
||||
<meta property="og:site_name" content="Mozilla Firefox Mark Up"/>
|
||||
<meta property="og:description" content="The Web is your creation. And, Mark Up is an open invitation to show your support for keeping the Web public and accessible to all. Make your mark."/>
|
||||
|
||||
<title>{{ _('Mozilla Firefox Mark Up') }}</title>
|
||||
<link rel="shortcut icon" href="/media/assets/images/favicon.png" />
|
||||
<link href="/media/assets/css/style.css" type="text/css" rel="stylesheet" />
|
||||
<script src="/media/assets/js/jquery-1.5.1.min.js" type="text/javascript"></script>
|
||||
<script src="/media/assets/js/common.js" type="text/javascript"></script>
|
||||
{% block js %}{% endblock %}
|
||||
</head>
|
||||
|
||||
{% block bodytag %}
|
||||
<body>
|
||||
{% endblock %}
|
||||
<header>
|
||||
<section id="main-links">
|
||||
<h2><a href="http://www.mozilla.org/" target="_blank" id="mozilla-logo">{{ _('Mozilla') }}</a></h2>
|
||||
<h1><a href="/">{{ _('Mozilla Mark Up') }}</a></h1>
|
||||
</section>
|
||||
</header>
|
||||
<section id="main-navigation">
|
||||
<nav>
|
||||
<div id="coming-soon-tip">{{ _('Coming soon') }}</div>
|
||||
<ul>
|
||||
<li id="manifesto"><a href="/manifesto">{{ _('Manifesto') }}</a></li>
|
||||
<li id="make-your-mark"><a href="/#/mark/new">{{ _('Make Your Mark') }}</a></li>
|
||||
<li id="behind-the-code"><a href="/about/">{{ _('Behind The Code') }}</a></li>
|
||||
<li id="community" class="disabled">{{ _('Community') }}</li>
|
||||
<li class="download-link"><a href="http://www.mozilla.com/firefox" target="_blank">{{ _('Download Firefox 4') }}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</section>
|
||||
<section id="content">
|
||||
{% block content %}{% endblock %}
|
||||
</section>
|
||||
<footer>
|
||||
<section id="callout-boxes">
|
||||
<div id="callout-boxes-wrapper">
|
||||
<div class="callout-box">
|
||||
<a href="/about"><img src="/media/assets/images/evan_roth.jpg" width="57px" height="57px" alt="{{ _('Evan Roth') }}" /></a>
|
||||
<h3><a href="/about">{{ _('Collaborating with Mark Up') }}</a></h3>
|
||||
<p>{% blocktrans %}Learn more about our collaboration with artist Evan Roth and Lawrence Lessig's contribution.{% endblocktrans %}</p>
|
||||
</div>
|
||||
<div class="callout-box">
|
||||
<a href="/newsletter"><img src="/media/assets/images/world_eater.jpg" width="57px" height="57px" alt="{{ _('Mozilla Newsletter') }}" /></a>
|
||||
<h3><a href="/newsletter">{{ _('Read all about it') }}</a></h3>
|
||||
<p>{% blocktrans %}Subscribe to Mozilla's monthly email newsletter and receive the latest tips and tricks for getting the most out of Firefox.{% endblocktrans %}</p>
|
||||
</div>
|
||||
<div class="callout-box">
|
||||
<a href="https://demos.mozilla.org/" target="_blank"><img src="/media/assets/images/web_of_wonders.jpg" width="57px" height="57px" alt="{{ _('Web Of Wonders') }}" /></a>
|
||||
<h3><a href="https://demos.mozilla.org/" target="_blank">{{ _('Web O\'(pen) Wonder') }}</a></h3>
|
||||
<p>{% blocktrans %}Want to see what the Web is really capable of? Explore the Web O' Wonder demo gallery and prepare to be amazed!{% endblocktrans %}</p>
|
||||
</div>
|
||||
<div class="callout-box last">
|
||||
<a href="http://www.mozilla.com/firefox" target="_blank"><img src="/media/assets/images/firefox_logo.jpg" width="57px" height="57px" alt="{{ _('Download Firefox 4') }}" /></a>
|
||||
<h3><a href="http://www.mozilla.com/firefox" target="_blank">{{ _('Download Firefox 4') }}</a></h3>
|
||||
<p>{% blocktrans %}Enjoy the latest version featuring a new look, more tools and other goodness.{% endblocktrans %}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="language">
|
||||
<a id="current-locale" href="#">{{ locale_code }}</a>
|
||||
<ul id="language-selector">
|
||||
{% for lang in LANGUAGES %}
|
||||
{% ifequal lang.0 LANGUAGE_CODE %}
|
||||
<li class="selected">{{ lang.1 }}</li>
|
||||
{% else %}
|
||||
<li><a href="{{ request.path|chlocale:lang.0 }}">{{ lang.1 }}</a></li>
|
||||
{% endifequal %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</section>
|
||||
<section id='legal'>
|
||||
<p class="legal-blurb">{% blocktrans %}The Mozilla Firefox Mark Up campaign is a publicly accessible campaign site. If you choose to use your formal signature, then please recognize that it will be viewable to those with whom you share it online as well as to anyone who comes to this site.{% endblocktrans %}</p>
|
||||
<p class="legal-blurb last">{% blocktrans %}Mozilla appeals to your sense of propriety and we ask that you avoid offensive or unlawful marks. Mozilla reserves the right to remove marks that are offensive and/or violate the law. See Mozilla’s Legal Notices for more information.{% endblocktrans %}</p>
|
||||
<nav id="legal-links">
|
||||
<ul>
|
||||
<li><a href="http://www.mozilla.com/privacy-policy.html" target="_blank">{{ _('Privacy Policy') }}</a></li>
|
||||
<li><a href="http://www.mozilla.com/about/legal.html" target="_blank">{{ _('Legal Notices') }}</a></li>
|
||||
<li class="last"><a href="http://www.mozilla.com/legal/fraud-report/index.html" target="_blank">{{ _('Report Trademark Abuse') }}</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
<p>{% blocktrans %}Except where otherwise noted, content on this site is licensed under the <a href="http://creativecommons.org/licenses/by-sa/3.0/us/" target="_blank">Creative Commons Attribution Share-Alike License v3.0</a> or any later version.{% endblocktrans %}</p>
|
||||
</section>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>FFDemo</title>
|
||||
<style type="text/css">
|
||||
body { width: 100%; margin: 100px auto; }
|
||||
ul, li { clear: both; list-style: none; margin: 10px; }
|
||||
label { display: block; float: left; width: 100px; }
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
{% block content %}
|
||||
|
||||
{% endblock %}
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
{% extends "about.html" %}
|
||||
{% load i18n %}
|
||||
{% block bodytag %}
|
||||
<body class="behind-the-code about-code">
|
||||
{% endblock %}
|
||||
|
||||
{% block about-content %}
|
||||
<h1>{{ _('Code Repository') }}</h1>
|
||||
{% blocktrans %}<p>We believe creativity should be shared. We believe everything on the Web should be accessible to the people who contribute to it. And that's why we chose to make the code behind Mark Up public.</p>
|
||||
<p>We encourage you to use the code below to keep creating, collaborating and contributing.</p>
|
||||
<p><a href="http://github.com/mozilla/markup">Get Code at GitHub</a></p>{% endblocktrans %}
|
||||
{% endblock %}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% block bodytag %}
|
||||
<body class="community">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section id="static-content">
|
||||
<h1>{{ _('Community') }}</h1>
|
||||
</section>
|
||||
{% endblock %}
|
||||
|